honeybee-radiance 1.66.190__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of honeybee-radiance might be problematic. Click here for more details.
- honeybee_radiance/__init__.py +11 -0
- honeybee_radiance/__main__.py +4 -0
- honeybee_radiance/_extend_honeybee.py +93 -0
- honeybee_radiance/cli/__init__.py +88 -0
- honeybee_radiance/cli/dc.py +400 -0
- honeybee_radiance/cli/edit.py +529 -0
- honeybee_radiance/cli/glare.py +118 -0
- honeybee_radiance/cli/grid.py +859 -0
- honeybee_radiance/cli/lib.py +458 -0
- honeybee_radiance/cli/modifier.py +133 -0
- honeybee_radiance/cli/mtx.py +226 -0
- honeybee_radiance/cli/multiphase.py +1034 -0
- honeybee_radiance/cli/octree.py +640 -0
- honeybee_radiance/cli/postprocess.py +1186 -0
- honeybee_radiance/cli/raytrace.py +219 -0
- honeybee_radiance/cli/rpict.py +125 -0
- honeybee_radiance/cli/schedule.py +56 -0
- honeybee_radiance/cli/setconfig.py +63 -0
- honeybee_radiance/cli/sky.py +545 -0
- honeybee_radiance/cli/study.py +66 -0
- honeybee_radiance/cli/sunpath.py +331 -0
- honeybee_radiance/cli/threephase.py +255 -0
- honeybee_radiance/cli/translate.py +400 -0
- honeybee_radiance/cli/util.py +121 -0
- honeybee_radiance/cli/view.py +261 -0
- honeybee_radiance/cli/viewfactor.py +347 -0
- honeybee_radiance/config.json +6 -0
- honeybee_radiance/config.py +427 -0
- honeybee_radiance/dictutil.py +50 -0
- honeybee_radiance/dynamic/__init__.py +5 -0
- honeybee_radiance/dynamic/group.py +479 -0
- honeybee_radiance/dynamic/multiphase.py +557 -0
- honeybee_radiance/dynamic/state.py +718 -0
- honeybee_radiance/dynamic/stategeo.py +352 -0
- honeybee_radiance/geometry/__init__.py +13 -0
- honeybee_radiance/geometry/bubble.py +42 -0
- honeybee_radiance/geometry/cone.py +215 -0
- honeybee_radiance/geometry/cup.py +54 -0
- honeybee_radiance/geometry/cylinder.py +197 -0
- honeybee_radiance/geometry/geometrybase.py +37 -0
- honeybee_radiance/geometry/instance.py +40 -0
- honeybee_radiance/geometry/mesh.py +38 -0
- honeybee_radiance/geometry/polygon.py +174 -0
- honeybee_radiance/geometry/ring.py +214 -0
- honeybee_radiance/geometry/source.py +182 -0
- honeybee_radiance/geometry/sphere.py +178 -0
- honeybee_radiance/geometry/tube.py +46 -0
- honeybee_radiance/lib/__init__.py +1 -0
- honeybee_radiance/lib/_loadmodifiers.py +72 -0
- honeybee_radiance/lib/_loadmodifiersets.py +69 -0
- honeybee_radiance/lib/modifiers.py +58 -0
- honeybee_radiance/lib/modifiersets.py +63 -0
- honeybee_radiance/lightpath.py +204 -0
- honeybee_radiance/lightsource/__init__.py +1 -0
- honeybee_radiance/lightsource/_gendaylit.py +479 -0
- honeybee_radiance/lightsource/dictutil.py +49 -0
- honeybee_radiance/lightsource/ground.py +160 -0
- honeybee_radiance/lightsource/sky/__init__.py +7 -0
- honeybee_radiance/lightsource/sky/_skybase.py +177 -0
- honeybee_radiance/lightsource/sky/certainirradiance.py +232 -0
- honeybee_radiance/lightsource/sky/cie.py +378 -0
- honeybee_radiance/lightsource/sky/climatebased.py +501 -0
- honeybee_radiance/lightsource/sky/hemisphere.py +160 -0
- honeybee_radiance/lightsource/sky/skydome.py +113 -0
- honeybee_radiance/lightsource/sky/skymatrix.py +163 -0
- honeybee_radiance/lightsource/sky/strutil.py +34 -0
- honeybee_radiance/lightsource/sky/sunmatrix.py +212 -0
- honeybee_radiance/lightsource/sunpath.py +247 -0
- honeybee_radiance/modifier/__init__.py +3 -0
- honeybee_radiance/modifier/material/__init__.py +30 -0
- honeybee_radiance/modifier/material/absdf.py +477 -0
- honeybee_radiance/modifier/material/antimatter.py +54 -0
- honeybee_radiance/modifier/material/ashik2.py +51 -0
- honeybee_radiance/modifier/material/brtdfunc.py +81 -0
- honeybee_radiance/modifier/material/bsdf.py +292 -0
- honeybee_radiance/modifier/material/dielectric.py +53 -0
- honeybee_radiance/modifier/material/glass.py +431 -0
- honeybee_radiance/modifier/material/glow.py +246 -0
- honeybee_radiance/modifier/material/illum.py +51 -0
- honeybee_radiance/modifier/material/interface.py +49 -0
- honeybee_radiance/modifier/material/light.py +206 -0
- honeybee_radiance/modifier/material/materialbase.py +36 -0
- honeybee_radiance/modifier/material/metal.py +167 -0
- honeybee_radiance/modifier/material/metal2.py +41 -0
- honeybee_radiance/modifier/material/metdata.py +41 -0
- honeybee_radiance/modifier/material/metfunc.py +41 -0
- honeybee_radiance/modifier/material/mirror.py +340 -0
- honeybee_radiance/modifier/material/mist.py +86 -0
- honeybee_radiance/modifier/material/plasdata.py +58 -0
- honeybee_radiance/modifier/material/plasfunc.py +59 -0
- honeybee_radiance/modifier/material/plastic.py +354 -0
- honeybee_radiance/modifier/material/plastic2.py +58 -0
- honeybee_radiance/modifier/material/prism1.py +57 -0
- honeybee_radiance/modifier/material/prism2.py +48 -0
- honeybee_radiance/modifier/material/spotlight.py +50 -0
- honeybee_radiance/modifier/material/trans.py +518 -0
- honeybee_radiance/modifier/material/trans2.py +49 -0
- honeybee_radiance/modifier/material/transdata.py +50 -0
- honeybee_radiance/modifier/material/transfunc.py +53 -0
- honeybee_radiance/modifier/mixture/__init__.py +6 -0
- honeybee_radiance/modifier/mixture/mixdata.py +49 -0
- honeybee_radiance/modifier/mixture/mixfunc.py +54 -0
- honeybee_radiance/modifier/mixture/mixpict.py +52 -0
- honeybee_radiance/modifier/mixture/mixtext.py +66 -0
- honeybee_radiance/modifier/mixture/mixturebase.py +28 -0
- honeybee_radiance/modifier/modifierbase.py +40 -0
- honeybee_radiance/modifier/pattern/__init__.py +9 -0
- honeybee_radiance/modifier/pattern/brightdata.py +49 -0
- honeybee_radiance/modifier/pattern/brightfunc.py +47 -0
- honeybee_radiance/modifier/pattern/brighttext.py +81 -0
- honeybee_radiance/modifier/pattern/colordata.py +56 -0
- honeybee_radiance/modifier/pattern/colorfunc.py +47 -0
- honeybee_radiance/modifier/pattern/colorpict.py +54 -0
- honeybee_radiance/modifier/pattern/colortext.py +73 -0
- honeybee_radiance/modifier/pattern/patternbase.py +34 -0
- honeybee_radiance/modifier/texture/__init__.py +4 -0
- honeybee_radiance/modifier/texture/texdata.py +29 -0
- honeybee_radiance/modifier/texture/texfunc.py +26 -0
- honeybee_radiance/modifier/texture/texturebase.py +27 -0
- honeybee_radiance/modifierset.py +1091 -0
- honeybee_radiance/mutil.py +60 -0
- honeybee_radiance/postprocess/__init__.py +1 -0
- honeybee_radiance/postprocess/annual.py +108 -0
- honeybee_radiance/postprocess/annualdaylight.py +425 -0
- honeybee_radiance/postprocess/annualglare.py +201 -0
- honeybee_radiance/postprocess/annualirradiance.py +187 -0
- honeybee_radiance/postprocess/electriclight.py +119 -0
- honeybee_radiance/postprocess/en17037.py +261 -0
- honeybee_radiance/postprocess/leed.py +304 -0
- honeybee_radiance/postprocess/solartracking.py +90 -0
- honeybee_radiance/primitive.py +554 -0
- honeybee_radiance/properties/__init__.py +1 -0
- honeybee_radiance/properties/_base.py +390 -0
- honeybee_radiance/properties/aperture.py +197 -0
- honeybee_radiance/properties/door.py +198 -0
- honeybee_radiance/properties/face.py +123 -0
- honeybee_radiance/properties/model.py +1291 -0
- honeybee_radiance/properties/room.py +490 -0
- honeybee_radiance/properties/shade.py +186 -0
- honeybee_radiance/properties/shademesh.py +116 -0
- honeybee_radiance/putil.py +44 -0
- honeybee_radiance/reader.py +214 -0
- honeybee_radiance/sensor.py +166 -0
- honeybee_radiance/sensorgrid.py +1008 -0
- honeybee_radiance/view.py +1101 -0
- honeybee_radiance/writer.py +951 -0
- honeybee_radiance-1.66.190.dist-info/METADATA +89 -0
- honeybee_radiance-1.66.190.dist-info/RECORD +152 -0
- honeybee_radiance-1.66.190.dist-info/WHEEL +5 -0
- honeybee_radiance-1.66.190.dist-info/entry_points.txt +2 -0
- honeybee_radiance-1.66.190.dist-info/licenses/LICENSE +661 -0
- honeybee_radiance-1.66.190.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Room Radiance Properties."""
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
from ladybug_geometry.geometry3d.pointvector import Vector3D
|
|
6
|
+
from honeybee.facetype import Floor, Wall
|
|
7
|
+
from honeybee.typing import clean_rad_string
|
|
8
|
+
from honeybee.checkdup import is_equivalent
|
|
9
|
+
|
|
10
|
+
from ..sensorgrid import SensorGrid
|
|
11
|
+
from ..view import View
|
|
12
|
+
from ..modifierset import ModifierSet
|
|
13
|
+
from ..lib.modifiersets import generic_modifier_set_visible
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RoomRadianceProperties(object):
|
|
17
|
+
"""Radiance Properties for Honeybee Room.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
host: A honeybee_core Room object that hosts these properties.
|
|
21
|
+
modifier_set: A honeybee ModifierSet object to specify all default
|
|
22
|
+
modifiers for the Faces of the Room. If None, the Room will use
|
|
23
|
+
the honeybee default modifier set, which is only representative
|
|
24
|
+
of typical indoor conditions in the visible spectrum. Default: None.
|
|
25
|
+
|
|
26
|
+
Properties:
|
|
27
|
+
* host
|
|
28
|
+
* modifier_set
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
__slots__ = ('_host', '_modifier_set')
|
|
32
|
+
|
|
33
|
+
def __init__(self, host, modifier_set=None):
|
|
34
|
+
"""Initialize Room radiance properties."""
|
|
35
|
+
# set the main properties of the Room
|
|
36
|
+
self._host = host
|
|
37
|
+
self.modifier_set = modifier_set
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def host(self):
|
|
41
|
+
"""Get the Room object hosting these properties."""
|
|
42
|
+
return self._host
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def modifier_set(self):
|
|
46
|
+
"""Get or set the Room ModifierSet object.
|
|
47
|
+
|
|
48
|
+
If not set, it will be the Honeybee default generic ModifierSet.
|
|
49
|
+
"""
|
|
50
|
+
if self._modifier_set is not None: # set by the user
|
|
51
|
+
return self._modifier_set
|
|
52
|
+
else:
|
|
53
|
+
return generic_modifier_set_visible
|
|
54
|
+
|
|
55
|
+
@modifier_set.setter
|
|
56
|
+
def modifier_set(self, value):
|
|
57
|
+
if value is not None:
|
|
58
|
+
assert isinstance(value, ModifierSet), \
|
|
59
|
+
'Expected ModifierSet. Got {}'.format(type(value))
|
|
60
|
+
value.lock() # lock in case modifier set has multiple references
|
|
61
|
+
self._modifier_set = value
|
|
62
|
+
|
|
63
|
+
def generate_sensor_grid(
|
|
64
|
+
self, x_dim, y_dim=None, offset=1.0, remove_out=False, wall_offset=0):
|
|
65
|
+
"""Get a radiance SensorGrid generated from this Room's floors.
|
|
66
|
+
|
|
67
|
+
The output grid will have this room referenced in its room_identifier
|
|
68
|
+
property. It will also include a Mesh3D object with faces that align
|
|
69
|
+
with the grid positions under the grid's mesh property.
|
|
70
|
+
|
|
71
|
+
Note that the x_dim and y_dim refer to dimensions within the XY coordinate
|
|
72
|
+
system of the floor faces's planes. So rotating the planes of the floor faces
|
|
73
|
+
will result in rotated grid cells.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
x_dim: The x dimension of the grid cells as a number.
|
|
77
|
+
y_dim: The y dimension of the grid cells as a number. If None,
|
|
78
|
+
the y dimension will be assumed to be the same as the x
|
|
79
|
+
dimension. (Default: None).
|
|
80
|
+
offset: A number for how far to offset the grid from the base face.
|
|
81
|
+
(Default is 1.0, which will not offset the grid to be 1 unit above
|
|
82
|
+
the floor).
|
|
83
|
+
remove_out: Boolean to note whether an extra check should be run to remove
|
|
84
|
+
sensor points that lie outside the Room volume. Note that this can
|
|
85
|
+
add significantly to runtime and this check is not necessary
|
|
86
|
+
in the case that all walls are vertical and all floors are
|
|
87
|
+
horizontal (Default: False).
|
|
88
|
+
wall_offset: A number for the distance at which sensors close to walls
|
|
89
|
+
should be removed. Note that this option has no effect unless the
|
|
90
|
+
value is more than half of the x_dim or y_dim. (Default: 0).
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
A honeybee_radiance SensorGrid generated from the floors of the room.
|
|
94
|
+
Will be None if the Room has no floors or the criteria for wall_offset
|
|
95
|
+
and/or remove_out results in all sensors being removed.
|
|
96
|
+
|
|
97
|
+
Usage:
|
|
98
|
+
|
|
99
|
+
.. code-block:: python
|
|
100
|
+
|
|
101
|
+
from honeybee.room import Room
|
|
102
|
+
room = Room.from_box(3.0, 6.0, 3.2, 180)
|
|
103
|
+
south_face = room[3]
|
|
104
|
+
south_face.apertures_by_ratio(0.4, 0.01)
|
|
105
|
+
sensor_grid = room.properties.radiance.generate_grid(0.5, 0.5, 1)
|
|
106
|
+
"""
|
|
107
|
+
# generate the mesh grid from the floor Faces
|
|
108
|
+
floor_grid = self._base_sensor_mesh(
|
|
109
|
+
x_dim, y_dim, offset, remove_out, wall_offset)
|
|
110
|
+
if floor_grid is None: # no valid mesh could be generated
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
# create the sensor grid from the mesh
|
|
114
|
+
sensor_grid = SensorGrid.from_mesh3d(
|
|
115
|
+
clean_rad_string(self.host.display_name), floor_grid)
|
|
116
|
+
sensor_grid.room_identifier = self.host.identifier
|
|
117
|
+
sensor_grid.display_name = self.host.display_name
|
|
118
|
+
sensor_grid.base_geometry = \
|
|
119
|
+
tuple(face.geometry.move(face.normal.reverse() * offset)
|
|
120
|
+
for face in self.host.faces if isinstance(face.type, Floor))
|
|
121
|
+
return sensor_grid
|
|
122
|
+
|
|
123
|
+
def generate_sensor_grid_radial(
|
|
124
|
+
self, x_dim, y_dim=None, offset=1.0, remove_out=False, wall_offset=0,
|
|
125
|
+
dir_count=8, start_vector=Vector3D(0, -1, 0), mesh_radius=None):
|
|
126
|
+
"""Get a SensorGrid of radial directions around positions from the floors.
|
|
127
|
+
|
|
128
|
+
This type of sensor grid is particularly helpful for studies of multiple view
|
|
129
|
+
directions, such as imageless glare studies.
|
|
130
|
+
|
|
131
|
+
The output grid will have this room referenced in its room_identifier
|
|
132
|
+
property. It will also include a Mesh3D of radial faces around each position
|
|
133
|
+
under the grid's mesh property. Note that the x_dim and y_dim refer to
|
|
134
|
+
dimensions within the XY coordinate system of the floor faces's planes.
|
|
135
|
+
So rotating the planes of the floor faces will result in rotated grid cells.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
x_dim: The x dimension of the grid cells as a number.
|
|
139
|
+
y_dim: The y dimension of the grid cells as a number. If None,
|
|
140
|
+
the y dimension will be assumed to be the same as the x
|
|
141
|
+
dimension. (Default: None).
|
|
142
|
+
offset: A number for how far to offset the grid from the base face.
|
|
143
|
+
(Default: 1.0, which will not offset the grid to be 1 unit above
|
|
144
|
+
the floor).
|
|
145
|
+
remove_out: Boolean to note whether an extra check should be run to remove
|
|
146
|
+
sensor points that lie outside the Room volume. Note that this can
|
|
147
|
+
add significantly to runtime and this check is not necessary
|
|
148
|
+
in the case that all walls are vertical and all floors are
|
|
149
|
+
horizontal (Default: False).
|
|
150
|
+
wall_offset: A number for the distance at which sensors close to walls
|
|
151
|
+
should be removed. Note that this option has no effect unless the
|
|
152
|
+
value is more than half of the x_dim or y_dim. (Default: 0).
|
|
153
|
+
dir_count: A positive integer for the number of radial directions
|
|
154
|
+
to be generated around each position. (Default: 8).
|
|
155
|
+
start_vector: A Vector3D to set the start direction of the generated
|
|
156
|
+
directions. This can be used to orient the resulting sensors to
|
|
157
|
+
specific parts of the scene. It can also change the elevation of the
|
|
158
|
+
resulting directions since this start vector will always be rotated in
|
|
159
|
+
the XY plane to generate the resulting directions. (Default: (0, -1, 0)).
|
|
160
|
+
mesh_radius: An optional number to override the radius of the meshes
|
|
161
|
+
generated around each sensor. If None, it will be equal to 45%
|
|
162
|
+
of the x_dim or y_dim (whichever is smaller). Set to zero to ensure
|
|
163
|
+
no mesh is added to the resulting sensor grids. (Default: None).
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
A honeybee_radiance SensorGrid generated from the floors of the room.
|
|
167
|
+
Will be None if the Room has no floors or the criteria for wall_offset
|
|
168
|
+
and/or remove_out results in all sensors being removed.
|
|
169
|
+
"""
|
|
170
|
+
# generate the mesh grid from the floor Faces
|
|
171
|
+
floor_grid = self._base_sensor_mesh(
|
|
172
|
+
x_dim, y_dim, offset, remove_out, wall_offset)
|
|
173
|
+
if floor_grid is None: # no valid mesh could be generated
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
# create the sensor grid from the mesh
|
|
177
|
+
if mesh_radius is None:
|
|
178
|
+
small_dim = x_dim if y_dim is None else min((x_dim, y_dim))
|
|
179
|
+
mesh_radius = small_dim * 0.45
|
|
180
|
+
grid_name = '{}_Radial'.format(clean_rad_string(self.host.display_name))
|
|
181
|
+
sensor_grid = SensorGrid.from_mesh3d_radial(
|
|
182
|
+
grid_name, floor_grid, dir_count, start_vector, mesh_radius)
|
|
183
|
+
sensor_grid.room_identifier = self.host.identifier
|
|
184
|
+
sensor_grid.display_name = self.host.display_name
|
|
185
|
+
sensor_grid.base_geometry = \
|
|
186
|
+
tuple(face.geometry.move(face.normal.reverse() * offset)
|
|
187
|
+
for face in self.host.faces if isinstance(face.type, Floor))
|
|
188
|
+
return sensor_grid
|
|
189
|
+
|
|
190
|
+
def generate_exterior_face_sensor_grid(
|
|
191
|
+
self, dimension, offset=0.1, face_type='Wall', punched_geometry=False):
|
|
192
|
+
"""Get a radiance SensorGrid generated from the exterior Faces of this room.
|
|
193
|
+
|
|
194
|
+
This will be None if the Room has no exterior Faces.
|
|
195
|
+
|
|
196
|
+
The output grid will have this room referenced in its room_identifier
|
|
197
|
+
property. It will also include a Mesh3D object with faces that align
|
|
198
|
+
with the grid positions under the grid's mesh property.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
dimension: The dimension of the grid cells as a number.
|
|
202
|
+
offset: A number for how far to offset the grid from the base face.
|
|
203
|
+
Positive numbers indicate an offset towards the exterior. (Default
|
|
204
|
+
is 0.1, which will offset the grid to be 0.1 unit from the faces).
|
|
205
|
+
face_type: Text to specify the type of face that will be used to
|
|
206
|
+
generate grids. Note that only Faces with Outdoors boundary
|
|
207
|
+
conditions will be used, meaning that most Floors will typically
|
|
208
|
+
be excluded unless they represent the underside of a cantilever.
|
|
209
|
+
Choose from the following. (Default: Wall).
|
|
210
|
+
|
|
211
|
+
* Wall
|
|
212
|
+
* Roof
|
|
213
|
+
* Floor
|
|
214
|
+
* All
|
|
215
|
+
|
|
216
|
+
punched_geometry: Boolean to note whether the punched_geometry of the faces
|
|
217
|
+
should be used (True) with the areas of sub-faces removed from the grid
|
|
218
|
+
or the full geometry should be used (False). (Default:False).
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
A honeybee_radiance SensorGrid generated from the exterior Faces
|
|
222
|
+
of the room. Will be None if the Room has no exterior Faces.
|
|
223
|
+
|
|
224
|
+
Usage:
|
|
225
|
+
|
|
226
|
+
.. code-block:: python
|
|
227
|
+
|
|
228
|
+
from honeybee.room import Room
|
|
229
|
+
room = Room.from_box(3.0, 6.0, 3.2, 180)
|
|
230
|
+
s_grid = room.properties.radiance.generate_exterior_face_sensor_grid(0.5)
|
|
231
|
+
"""
|
|
232
|
+
# generate the mesh grid from the exterior Faces
|
|
233
|
+
face_grid = self.host.generate_exterior_face_grid(
|
|
234
|
+
dimension, offset, face_type, punched_geometry)
|
|
235
|
+
if face_grid is None: # no valid mesh could be generated
|
|
236
|
+
return None
|
|
237
|
+
# create the sensor grid from the mesh
|
|
238
|
+
f_nm = 'Faces' if face_type.title() == 'All' else face_type.title()
|
|
239
|
+
grid_name = '{}_Exterior{}'.format(self.host.display_name, f_nm)
|
|
240
|
+
sensor_grid = SensorGrid.from_mesh3d(clean_rad_string(grid_name), face_grid)
|
|
241
|
+
sensor_grid.room_identifier = self.host.identifier
|
|
242
|
+
sensor_grid.display_name = self.host.display_name
|
|
243
|
+
return sensor_grid
|
|
244
|
+
|
|
245
|
+
def generate_exterior_aperture_sensor_grid(
|
|
246
|
+
self, dimension, offset=0.1, aperture_type='All'):
|
|
247
|
+
"""Get a radiance SensorGrid generated from the exterior Apertures of this room.
|
|
248
|
+
|
|
249
|
+
Will be None if the Room has no exterior Apertures.
|
|
250
|
+
|
|
251
|
+
The output grid will have this room referenced in its room_identifier
|
|
252
|
+
property. It will also include a Mesh3D object with faces that align
|
|
253
|
+
with the grid positions under the grid's mesh property.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
dimension: The dimension of the grid cells as a number.
|
|
257
|
+
offset: A number for how far to offset the grid from the base face.
|
|
258
|
+
Positive numbers indicate an offset towards the exterior while
|
|
259
|
+
negative numbers indicate an offset towards the interior, essentially
|
|
260
|
+
modeling the value of sun on the building interior. (Default
|
|
261
|
+
is 0.1, which will offset the grid to be 0.1 unit from the faces).
|
|
262
|
+
aperture_type: Text to specify the type of Aperture that will be used to
|
|
263
|
+
generate grids. Window indicates Apertures in Walls. Skylights
|
|
264
|
+
are in parent Roof faces. Choose from the following. (Default: All).
|
|
265
|
+
|
|
266
|
+
* Window
|
|
267
|
+
* Skylight
|
|
268
|
+
* All
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
A honeybee_radiance SensorGrid generated from the exterior Apertures
|
|
272
|
+
of the room. Will be None if the Room has no exterior Apertures or
|
|
273
|
+
if the grid size is too large for the Apertures.
|
|
274
|
+
|
|
275
|
+
Usage:
|
|
276
|
+
|
|
277
|
+
.. code-block:: python
|
|
278
|
+
|
|
279
|
+
from honeybee.room import Room
|
|
280
|
+
room = Room.from_box(3.0, 6.0, 3.2, 180)
|
|
281
|
+
room[3].apertures_by_ratio(0.4)
|
|
282
|
+
s_grid = room.properties.radiance.generate_exterior_aperture_sensor_grid(0.5)
|
|
283
|
+
"""
|
|
284
|
+
# generate the mesh grid from the exterior Apertures
|
|
285
|
+
ap_grid = self.host.generate_exterior_aperture_grid(
|
|
286
|
+
dimension, offset, aperture_type)
|
|
287
|
+
if ap_grid is None: # no valid mesh could be generated
|
|
288
|
+
return None
|
|
289
|
+
# create the sensor grid from the mesh
|
|
290
|
+
f_nm = 'Apertures' if aperture_type.title() == 'All' else aperture_type.title()
|
|
291
|
+
grid_name = '{}_Exterior{}'.format(self.host.display_name, f_nm)
|
|
292
|
+
sensor_grid = SensorGrid.from_mesh3d(clean_rad_string(grid_name), ap_grid)
|
|
293
|
+
sensor_grid.room_identifier = self.host.identifier
|
|
294
|
+
sensor_grid.display_name = self.host.display_name
|
|
295
|
+
return sensor_grid
|
|
296
|
+
|
|
297
|
+
def generate_view(self, direction, up_vector=(0, 0, 1), type='v', h_size=60,
|
|
298
|
+
v_size=60, shift=None, lift=None):
|
|
299
|
+
"""Get a single view in the center of the room facing a given direction.
|
|
300
|
+
|
|
301
|
+
Note that the view will be located at the center of the bounding box
|
|
302
|
+
around the room geometry and not the volume centroid. Also note that
|
|
303
|
+
the view may not lie inside the room if the room is highly concave.
|
|
304
|
+
|
|
305
|
+
The output view will have this room referenced in their room_identifier
|
|
306
|
+
property.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
direction: Set the view direction (-vd) vector to (x, y, z). The
|
|
310
|
+
length of this vector indicates the focal distance as needed by
|
|
311
|
+
the pixel depth of field (-pd) in rpict.
|
|
312
|
+
up_vector: Set the view up (-vu) vector (vertical direction) to
|
|
313
|
+
(x, y, z) default: (0, 0, 1).
|
|
314
|
+
type: A single character for the view type (-vt). Choose from the following.
|
|
315
|
+
|
|
316
|
+
* v - Perspective
|
|
317
|
+
* h - Hemispherical fisheye
|
|
318
|
+
* l - Parallel
|
|
319
|
+
* c - Cylindrical panorama
|
|
320
|
+
* a - Angular fisheye
|
|
321
|
+
* s - Planisphere [stereographic] projection
|
|
322
|
+
|
|
323
|
+
For more detailed description about view types check rpict manual
|
|
324
|
+
page: (http://radsite.lbl.gov/radiance/man_html/rpict.1.html)
|
|
325
|
+
h_size: Set the view horizontal size (-vh). For a perspective
|
|
326
|
+
projection (including fisheye views), val is the horizontal field
|
|
327
|
+
of view (in degrees). For a parallel projection, val is the view
|
|
328
|
+
width in world coordinates.
|
|
329
|
+
v_size: Set the view vertical size (-vv). For a perspective
|
|
330
|
+
projection (including fisheye views), val is the horizontal field
|
|
331
|
+
of view (in degrees). For a parallel projection, val is the view
|
|
332
|
+
width in world coordinates.
|
|
333
|
+
shift: Set the view shift (-vs). This is the amount the actual
|
|
334
|
+
image will be shifted to the right of the specified view. This
|
|
335
|
+
option is useful for generating skewed perspectives or rendering
|
|
336
|
+
an image a piece at a time. A value of 1 means that the rendered
|
|
337
|
+
image starts just to the right of the normal view. A value of -1
|
|
338
|
+
would be to the left. Larger or fractional values are permitted
|
|
339
|
+
as well.
|
|
340
|
+
lift: Set the view lift (-vl) to a value. This is the amount the
|
|
341
|
+
actual image will be lifted up from the specified view.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
A honeybee_radiance View generated in the center of the Room.
|
|
345
|
+
|
|
346
|
+
Usage:
|
|
347
|
+
|
|
348
|
+
.. code-block:: python
|
|
349
|
+
|
|
350
|
+
from honeybee.room import Room
|
|
351
|
+
room = Room.from_box(3.0, 6.0, 3.2, 180)
|
|
352
|
+
south_face = room[3]
|
|
353
|
+
south_face.apertures_by_ratio(0.4, 0.01)
|
|
354
|
+
view = room.properties.radiance.generate_view((0, -1, 0))
|
|
355
|
+
"""
|
|
356
|
+
pos = (self.host.center.x, self.host.center.y, self.host.center.z)
|
|
357
|
+
view = View(self.host.identifier, pos, direction, up_vector, type,
|
|
358
|
+
h_size, v_size, shift, lift)
|
|
359
|
+
view.room_identifier = self.host.identifier
|
|
360
|
+
view.display_name = self.host.display_name
|
|
361
|
+
return view
|
|
362
|
+
|
|
363
|
+
@classmethod
|
|
364
|
+
def from_dict(cls, data, host):
|
|
365
|
+
"""Create RoomRadianceProperties from a dictionary.
|
|
366
|
+
|
|
367
|
+
Note that the dictionary must be a non-abridged version for this
|
|
368
|
+
classmethod to work.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
data: A dictionary representation of RoomRadianceProperties with the
|
|
372
|
+
format below.
|
|
373
|
+
host: A Room object that hosts these properties.
|
|
374
|
+
|
|
375
|
+
.. code-block:: python
|
|
376
|
+
|
|
377
|
+
{
|
|
378
|
+
'type': 'RoomRadianceProperties',
|
|
379
|
+
'modifier_set': {}, # ModifierSet dictionary
|
|
380
|
+
}
|
|
381
|
+
"""
|
|
382
|
+
assert data['type'] == 'RoomRadianceProperties', \
|
|
383
|
+
'Expected RoomRadianceProperties. Got {}.'.format(data['type'])
|
|
384
|
+
|
|
385
|
+
new_prop = cls(host)
|
|
386
|
+
if 'modifier_set' in data and data['modifier_set'] is not None:
|
|
387
|
+
new_prop.modifier_set = ModifierSet.from_dict(data['modifier_set'])
|
|
388
|
+
return new_prop
|
|
389
|
+
|
|
390
|
+
def apply_properties_from_dict(self, abridged_data, modifier_sets):
|
|
391
|
+
"""Apply properties from a RoomRadiancePropertiesAbridged dictionary.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
abridged_data: A RoomRadiancePropertiesAbridged dictionary (typically
|
|
395
|
+
coming from a Model) with the format below.
|
|
396
|
+
modifier_sets: A dictionary of ModifierSets with identifiers of the sets
|
|
397
|
+
as keys, which will be used to re-assign modifier_sets.
|
|
398
|
+
|
|
399
|
+
.. code-block:: python
|
|
400
|
+
|
|
401
|
+
{
|
|
402
|
+
'type': 'RoomRadiancePropertiesAbridged',
|
|
403
|
+
'modifier_set': str, # ModifierSet identifier
|
|
404
|
+
}
|
|
405
|
+
"""
|
|
406
|
+
if 'modifier_set' in abridged_data and abridged_data['modifier_set'] is not None:
|
|
407
|
+
self.modifier_set = modifier_sets[abridged_data['modifier_set']]
|
|
408
|
+
|
|
409
|
+
def to_dict(self, abridged=False):
|
|
410
|
+
"""Return Room radiance properties as a dictionary.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
abridged: Boolean for whether the full dictionary of the Room should
|
|
414
|
+
be written (False) or just the identifier of the the individual
|
|
415
|
+
properties (True). Default: False.
|
|
416
|
+
"""
|
|
417
|
+
base = {'radiance': {}}
|
|
418
|
+
base['radiance']['type'] = 'RoomRadianceProperties' if not \
|
|
419
|
+
abridged else 'RoomRadiancePropertiesAbridged'
|
|
420
|
+
|
|
421
|
+
# write the ModifierSet into the dictionary
|
|
422
|
+
if self._modifier_set is not None:
|
|
423
|
+
base['radiance']['modifier_set'] = \
|
|
424
|
+
self._modifier_set.identifier if abridged else \
|
|
425
|
+
self._modifier_set.to_dict()
|
|
426
|
+
|
|
427
|
+
return base
|
|
428
|
+
|
|
429
|
+
def duplicate(self, new_host=None):
|
|
430
|
+
"""Get a copy of this object.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
new_host: A new Room object that hosts these properties.
|
|
434
|
+
If None, the properties will be duplicated with the same host.
|
|
435
|
+
"""
|
|
436
|
+
_host = new_host or self._host
|
|
437
|
+
new_room = RoomRadianceProperties(_host, self._modifier_set)
|
|
438
|
+
return new_room
|
|
439
|
+
|
|
440
|
+
def is_equivalent(self, other):
|
|
441
|
+
"""Check to see if these Radiance properties are equivalent to another object.
|
|
442
|
+
"""
|
|
443
|
+
if not is_equivalent(self._modifier_set, other._modifier_set):
|
|
444
|
+
return False
|
|
445
|
+
return True
|
|
446
|
+
|
|
447
|
+
def _base_sensor_mesh(self, x_dim, y_dim, offset, remove_out, wall_offset):
|
|
448
|
+
"""Get a base Mesh3D from the Room floors to be used for sensor girds."""
|
|
449
|
+
# generate the mesh grid from the floor Faces
|
|
450
|
+
floor_grid = self.host.generate_grid(x_dim, y_dim, offset)
|
|
451
|
+
if floor_grid is None: # no floors in the host Room
|
|
452
|
+
return None
|
|
453
|
+
|
|
454
|
+
# remove any outdoor sensors if this has been requested
|
|
455
|
+
if remove_out:
|
|
456
|
+
geo = self.host.geometry
|
|
457
|
+
pattern = [geo.is_point_inside(pt) for pt in floor_grid.face_centroids]
|
|
458
|
+
try:
|
|
459
|
+
floor_grid, vertex_pattern = floor_grid.remove_faces(pattern)
|
|
460
|
+
except AssertionError: # the grid lies completely outside of the room
|
|
461
|
+
return None
|
|
462
|
+
|
|
463
|
+
# remove any sensors within a certain distance of the walls, if requested
|
|
464
|
+
if wall_offset >= x_dim / 2 or (y_dim is not None and wall_offset >= y_dim / 2):
|
|
465
|
+
wall_geos = [f.geometry for f in self.host.faces if isinstance(f.type, Wall)]
|
|
466
|
+
pattern = []
|
|
467
|
+
for pt in floor_grid.face_centroids:
|
|
468
|
+
for wg in wall_geos:
|
|
469
|
+
close_pt = wg.plane.closest_point(pt)
|
|
470
|
+
p_dist = pt.distance_to_point(close_pt)
|
|
471
|
+
if p_dist <= wall_offset:
|
|
472
|
+
close_pt_2d = wg.plane.xyz_to_xy(close_pt)
|
|
473
|
+
g_dist = wg.polygon2d.distance_to_point(close_pt_2d)
|
|
474
|
+
f_dist = math.sqrt(p_dist ** 2 + g_dist ** 2)
|
|
475
|
+
if f_dist <= wall_offset:
|
|
476
|
+
pattern.append(False)
|
|
477
|
+
break
|
|
478
|
+
else:
|
|
479
|
+
pattern.append(True)
|
|
480
|
+
try:
|
|
481
|
+
floor_grid, vertex_pattern = floor_grid.remove_faces(pattern)
|
|
482
|
+
except AssertionError: # the grid lies completely outside of the room
|
|
483
|
+
return None
|
|
484
|
+
return floor_grid
|
|
485
|
+
|
|
486
|
+
def ToString(self):
|
|
487
|
+
return self.__repr__()
|
|
488
|
+
|
|
489
|
+
def __repr__(self):
|
|
490
|
+
return 'Room Radiance Properties: [host: {}]'.format(self.host.display_name)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Shade Radiance Properties."""
|
|
3
|
+
from ._base import _DynamicRadianceProperties
|
|
4
|
+
from ..modifier import Modifier
|
|
5
|
+
from ..dynamic.state import RadianceShadeState
|
|
6
|
+
from ..lib.modifiers import generic_context
|
|
7
|
+
from ..lib.modifiersets import generic_modifier_set_visible
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ShadeRadianceProperties(_DynamicRadianceProperties):
|
|
11
|
+
"""Radiance Properties for Honeybee Shade.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
host: A honeybee_core Shade object that hosts these properties.
|
|
15
|
+
modifier: A Honeybee Radiance Modifier object for the shade. If None,
|
|
16
|
+
it will be set by the parent Room ModifierSet or the Honeybee
|
|
17
|
+
default generic ModifierSet.
|
|
18
|
+
modifier_blk: A Honeybee Radiance Modifier object to be used for this
|
|
19
|
+
shade in direct solar simulations and in isolation studies (assessing
|
|
20
|
+
the contribution of individual Apertures). If None, this will be
|
|
21
|
+
a completely black material if the Shade's modifier is opaque and
|
|
22
|
+
will be equal to the modifier if the Shade's modifier is non-opaque.
|
|
23
|
+
dynamic_group_identifier: An optional string to note the dynamic group
|
|
24
|
+
to which the Shade is a part of. Shades sharing the same
|
|
25
|
+
dynamic_group_identifier will have their states change in unison.
|
|
26
|
+
If None, the Shade is assumed to be static.
|
|
27
|
+
|
|
28
|
+
Properties:
|
|
29
|
+
* host
|
|
30
|
+
* modifier
|
|
31
|
+
* modifier_blk
|
|
32
|
+
* dynamic_group_identifier
|
|
33
|
+
* states
|
|
34
|
+
* state_count
|
|
35
|
+
* is_opaque
|
|
36
|
+
* is_modifier_set_on_object
|
|
37
|
+
* is_blk_overridden
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
__slots__ = ()
|
|
41
|
+
|
|
42
|
+
def __init__(self, host, modifier=None, modifier_blk=None,
|
|
43
|
+
dynamic_group_identifier=None):
|
|
44
|
+
"""Initialize Shade radiance properties."""
|
|
45
|
+
_DynamicRadianceProperties.__init__(
|
|
46
|
+
self, host, modifier, modifier_blk, dynamic_group_identifier)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def modifier(self):
|
|
50
|
+
"""Get or set the Shade modifier.
|
|
51
|
+
|
|
52
|
+
If the modifier is not set on the shade-level, then it will be assigned
|
|
53
|
+
based on the ModifierSet assigned to the parent Room. If the parent Room's
|
|
54
|
+
ModifierSet has no modifier for the Shade type, it will be assigned using the
|
|
55
|
+
honeybee default generic ModifierSet. If there is no parent Room, it will
|
|
56
|
+
be the generic context material.
|
|
57
|
+
"""
|
|
58
|
+
if self._modifier: # set by user
|
|
59
|
+
return self._modifier
|
|
60
|
+
elif not self._host.has_parent: # orphaned shade
|
|
61
|
+
return generic_context if self._host.is_detached else \
|
|
62
|
+
generic_modifier_set_visible.shade_set.exterior_modifier
|
|
63
|
+
else: # shade with a parent modifier set
|
|
64
|
+
m_set = self._parent_modifier_set(self._host.parent)
|
|
65
|
+
if m_set is None:
|
|
66
|
+
m_set = generic_modifier_set_visible
|
|
67
|
+
return m_set.get_shade_modifier(self._host.is_indoor)
|
|
68
|
+
|
|
69
|
+
@modifier.setter
|
|
70
|
+
def modifier(self, value):
|
|
71
|
+
if value is not None:
|
|
72
|
+
assert isinstance(value, Modifier), \
|
|
73
|
+
'Expected Radiance Modifier for shade. Got {}'.format(type(value))
|
|
74
|
+
value.lock() # lock editing in case modifier has multiple references
|
|
75
|
+
self._modifier = value
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def from_dict(cls, data, host):
|
|
79
|
+
"""Create ShadeRadianceProperties from a dictionary.
|
|
80
|
+
|
|
81
|
+
Note that the dictionary must be a non-abridged version for this
|
|
82
|
+
classmethod to work.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
data: A dictionary representation of ShadeRadianceProperties with the
|
|
86
|
+
format below.
|
|
87
|
+
host: A Shade object that hosts these properties.
|
|
88
|
+
|
|
89
|
+
.. code-block:: python
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
'type': 'ShadeRadianceProperties',
|
|
93
|
+
'modifier': {}, # A Honeybee Radiance Modifier dictionary
|
|
94
|
+
'modifier_blk': {}, # A Honeybee Radiance Modifier dictionary
|
|
95
|
+
'dynamic_group_identifier': str, # An optional dynamic group identifier
|
|
96
|
+
'states': [] # An optional list of states
|
|
97
|
+
}
|
|
98
|
+
"""
|
|
99
|
+
assert data['type'] == 'ShadeRadianceProperties', \
|
|
100
|
+
'Expected ShadeRadianceProperties. Got {}.'.format(data['type'])
|
|
101
|
+
new_prop = cls(host)
|
|
102
|
+
new_prop = cls._restore_modifiers_from_dict(new_prop, data)
|
|
103
|
+
return cls._restore_states_from_dict(new_prop, data)
|
|
104
|
+
|
|
105
|
+
def apply_properties_from_dict(self, abridged_data, modifiers):
|
|
106
|
+
"""Apply properties from a ShadeRadiancePropertiesAbridged dictionary.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
abridged_data: A ShadeRadiancePropertiesAbridged dictionary (typically
|
|
110
|
+
coming from a Model) with the format below.
|
|
111
|
+
modifiers: A dictionary of modifiers with modifier identifiers as keys,
|
|
112
|
+
which will be used to re-assign modifiers.
|
|
113
|
+
|
|
114
|
+
.. code-block:: python
|
|
115
|
+
|
|
116
|
+
{
|
|
117
|
+
'type': 'ShadeRadiancePropertiesAbridged',
|
|
118
|
+
'modifier': str, # A Honeybee Radiance Modifier identifier
|
|
119
|
+
'modifier_blk': str, # A Honeybee Radiance Modifier identifier
|
|
120
|
+
'dynamic_group_identifier': str, # An optional dynamic group identifier
|
|
121
|
+
'states': [] # An optional list of states
|
|
122
|
+
}
|
|
123
|
+
"""
|
|
124
|
+
self._apply_modifiers_from_dict(abridged_data, modifiers)
|
|
125
|
+
self._apply_states_from_dict(abridged_data, modifiers)
|
|
126
|
+
|
|
127
|
+
def to_dict(self, abridged=False):
|
|
128
|
+
"""Return radiance properties as a dictionary.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
132
|
+
object should be returned (False) or just an abridged version (True).
|
|
133
|
+
Default: False.
|
|
134
|
+
"""
|
|
135
|
+
base = {'radiance': {}}
|
|
136
|
+
base['radiance']['type'] = 'ShadeRadianceProperties' if not \
|
|
137
|
+
abridged else 'ShadeRadiancePropertiesAbridged'
|
|
138
|
+
self._add_modifiers_to_dict(base, abridged)
|
|
139
|
+
return self._add_states_to_dict(base, abridged)
|
|
140
|
+
|
|
141
|
+
def _check_state(self, obj):
|
|
142
|
+
assert isinstance(obj, RadianceShadeState), \
|
|
143
|
+
'Expected RadianceShadeState. Got {}.'.format(type(obj))
|
|
144
|
+
assert obj.parent is None, \
|
|
145
|
+
'RadianceShadeState cannot already have a parent object.'
|
|
146
|
+
obj._parent = self.host
|
|
147
|
+
return obj
|
|
148
|
+
|
|
149
|
+
def _apply_states_from_dict(self, abridged_data, modifiers):
|
|
150
|
+
"""Apply states from an Abridged dictionary.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
abridged_data: An Abridged dictionary (typically coming from a Model).
|
|
154
|
+
modifiers: A dictionary of modifiers with modifier identifiers as keys,
|
|
155
|
+
which will be used to re-assign modifiers.
|
|
156
|
+
"""
|
|
157
|
+
if 'dynamic_group_identifier' in abridged_data and \
|
|
158
|
+
abridged_data['dynamic_group_identifier'] is not None:
|
|
159
|
+
self.dynamic_group_identifier = abridged_data['dynamic_group_identifier']
|
|
160
|
+
if 'states' in abridged_data and abridged_data['states'] is not None:
|
|
161
|
+
self.states = [RadianceShadeState.from_dict_abridged(st, modifiers)
|
|
162
|
+
for st in abridged_data['states']]
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _restore_states_from_dict(new_prop, data):
|
|
166
|
+
"""Restore states from a data dictionary to a new properties object."""
|
|
167
|
+
if 'dynamic_group_identifier' in data and \
|
|
168
|
+
data['dynamic_group_identifier'] is not None:
|
|
169
|
+
new_prop.dynamic_group_identifier = data['dynamic_group_identifier']
|
|
170
|
+
if 'states' in data and data['states'] is not None:
|
|
171
|
+
new_prop.states = [RadianceShadeState.from_dict(shd)
|
|
172
|
+
for shd in data['states']]
|
|
173
|
+
return new_prop
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def _parent_modifier_set(host_parent):
|
|
177
|
+
"""Recursively search through host parents to find a ModifierSet."""
|
|
178
|
+
if hasattr(host_parent.properties.radiance, 'modifier_set'):
|
|
179
|
+
return host_parent.properties.radiance.modifier_set
|
|
180
|
+
elif host_parent.has_parent:
|
|
181
|
+
return ShadeRadianceProperties._parent_modifier_set(host_parent.parent)
|
|
182
|
+
else:
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
def __repr__(self):
|
|
186
|
+
return 'Shade Radiance Properties:\n host: {}'.format(self.host.identifier)
|