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.

Files changed (152) hide show
  1. honeybee_radiance/__init__.py +11 -0
  2. honeybee_radiance/__main__.py +4 -0
  3. honeybee_radiance/_extend_honeybee.py +93 -0
  4. honeybee_radiance/cli/__init__.py +88 -0
  5. honeybee_radiance/cli/dc.py +400 -0
  6. honeybee_radiance/cli/edit.py +529 -0
  7. honeybee_radiance/cli/glare.py +118 -0
  8. honeybee_radiance/cli/grid.py +859 -0
  9. honeybee_radiance/cli/lib.py +458 -0
  10. honeybee_radiance/cli/modifier.py +133 -0
  11. honeybee_radiance/cli/mtx.py +226 -0
  12. honeybee_radiance/cli/multiphase.py +1034 -0
  13. honeybee_radiance/cli/octree.py +640 -0
  14. honeybee_radiance/cli/postprocess.py +1186 -0
  15. honeybee_radiance/cli/raytrace.py +219 -0
  16. honeybee_radiance/cli/rpict.py +125 -0
  17. honeybee_radiance/cli/schedule.py +56 -0
  18. honeybee_radiance/cli/setconfig.py +63 -0
  19. honeybee_radiance/cli/sky.py +545 -0
  20. honeybee_radiance/cli/study.py +66 -0
  21. honeybee_radiance/cli/sunpath.py +331 -0
  22. honeybee_radiance/cli/threephase.py +255 -0
  23. honeybee_radiance/cli/translate.py +400 -0
  24. honeybee_radiance/cli/util.py +121 -0
  25. honeybee_radiance/cli/view.py +261 -0
  26. honeybee_radiance/cli/viewfactor.py +347 -0
  27. honeybee_radiance/config.json +6 -0
  28. honeybee_radiance/config.py +427 -0
  29. honeybee_radiance/dictutil.py +50 -0
  30. honeybee_radiance/dynamic/__init__.py +5 -0
  31. honeybee_radiance/dynamic/group.py +479 -0
  32. honeybee_radiance/dynamic/multiphase.py +557 -0
  33. honeybee_radiance/dynamic/state.py +718 -0
  34. honeybee_radiance/dynamic/stategeo.py +352 -0
  35. honeybee_radiance/geometry/__init__.py +13 -0
  36. honeybee_radiance/geometry/bubble.py +42 -0
  37. honeybee_radiance/geometry/cone.py +215 -0
  38. honeybee_radiance/geometry/cup.py +54 -0
  39. honeybee_radiance/geometry/cylinder.py +197 -0
  40. honeybee_radiance/geometry/geometrybase.py +37 -0
  41. honeybee_radiance/geometry/instance.py +40 -0
  42. honeybee_radiance/geometry/mesh.py +38 -0
  43. honeybee_radiance/geometry/polygon.py +174 -0
  44. honeybee_radiance/geometry/ring.py +214 -0
  45. honeybee_radiance/geometry/source.py +182 -0
  46. honeybee_radiance/geometry/sphere.py +178 -0
  47. honeybee_radiance/geometry/tube.py +46 -0
  48. honeybee_radiance/lib/__init__.py +1 -0
  49. honeybee_radiance/lib/_loadmodifiers.py +72 -0
  50. honeybee_radiance/lib/_loadmodifiersets.py +69 -0
  51. honeybee_radiance/lib/modifiers.py +58 -0
  52. honeybee_radiance/lib/modifiersets.py +63 -0
  53. honeybee_radiance/lightpath.py +204 -0
  54. honeybee_radiance/lightsource/__init__.py +1 -0
  55. honeybee_radiance/lightsource/_gendaylit.py +479 -0
  56. honeybee_radiance/lightsource/dictutil.py +49 -0
  57. honeybee_radiance/lightsource/ground.py +160 -0
  58. honeybee_radiance/lightsource/sky/__init__.py +7 -0
  59. honeybee_radiance/lightsource/sky/_skybase.py +177 -0
  60. honeybee_radiance/lightsource/sky/certainirradiance.py +232 -0
  61. honeybee_radiance/lightsource/sky/cie.py +378 -0
  62. honeybee_radiance/lightsource/sky/climatebased.py +501 -0
  63. honeybee_radiance/lightsource/sky/hemisphere.py +160 -0
  64. honeybee_radiance/lightsource/sky/skydome.py +113 -0
  65. honeybee_radiance/lightsource/sky/skymatrix.py +163 -0
  66. honeybee_radiance/lightsource/sky/strutil.py +34 -0
  67. honeybee_radiance/lightsource/sky/sunmatrix.py +212 -0
  68. honeybee_radiance/lightsource/sunpath.py +247 -0
  69. honeybee_radiance/modifier/__init__.py +3 -0
  70. honeybee_radiance/modifier/material/__init__.py +30 -0
  71. honeybee_radiance/modifier/material/absdf.py +477 -0
  72. honeybee_radiance/modifier/material/antimatter.py +54 -0
  73. honeybee_radiance/modifier/material/ashik2.py +51 -0
  74. honeybee_radiance/modifier/material/brtdfunc.py +81 -0
  75. honeybee_radiance/modifier/material/bsdf.py +292 -0
  76. honeybee_radiance/modifier/material/dielectric.py +53 -0
  77. honeybee_radiance/modifier/material/glass.py +431 -0
  78. honeybee_radiance/modifier/material/glow.py +246 -0
  79. honeybee_radiance/modifier/material/illum.py +51 -0
  80. honeybee_radiance/modifier/material/interface.py +49 -0
  81. honeybee_radiance/modifier/material/light.py +206 -0
  82. honeybee_radiance/modifier/material/materialbase.py +36 -0
  83. honeybee_radiance/modifier/material/metal.py +167 -0
  84. honeybee_radiance/modifier/material/metal2.py +41 -0
  85. honeybee_radiance/modifier/material/metdata.py +41 -0
  86. honeybee_radiance/modifier/material/metfunc.py +41 -0
  87. honeybee_radiance/modifier/material/mirror.py +340 -0
  88. honeybee_radiance/modifier/material/mist.py +86 -0
  89. honeybee_radiance/modifier/material/plasdata.py +58 -0
  90. honeybee_radiance/modifier/material/plasfunc.py +59 -0
  91. honeybee_radiance/modifier/material/plastic.py +354 -0
  92. honeybee_radiance/modifier/material/plastic2.py +58 -0
  93. honeybee_radiance/modifier/material/prism1.py +57 -0
  94. honeybee_radiance/modifier/material/prism2.py +48 -0
  95. honeybee_radiance/modifier/material/spotlight.py +50 -0
  96. honeybee_radiance/modifier/material/trans.py +518 -0
  97. honeybee_radiance/modifier/material/trans2.py +49 -0
  98. honeybee_radiance/modifier/material/transdata.py +50 -0
  99. honeybee_radiance/modifier/material/transfunc.py +53 -0
  100. honeybee_radiance/modifier/mixture/__init__.py +6 -0
  101. honeybee_radiance/modifier/mixture/mixdata.py +49 -0
  102. honeybee_radiance/modifier/mixture/mixfunc.py +54 -0
  103. honeybee_radiance/modifier/mixture/mixpict.py +52 -0
  104. honeybee_radiance/modifier/mixture/mixtext.py +66 -0
  105. honeybee_radiance/modifier/mixture/mixturebase.py +28 -0
  106. honeybee_radiance/modifier/modifierbase.py +40 -0
  107. honeybee_radiance/modifier/pattern/__init__.py +9 -0
  108. honeybee_radiance/modifier/pattern/brightdata.py +49 -0
  109. honeybee_radiance/modifier/pattern/brightfunc.py +47 -0
  110. honeybee_radiance/modifier/pattern/brighttext.py +81 -0
  111. honeybee_radiance/modifier/pattern/colordata.py +56 -0
  112. honeybee_radiance/modifier/pattern/colorfunc.py +47 -0
  113. honeybee_radiance/modifier/pattern/colorpict.py +54 -0
  114. honeybee_radiance/modifier/pattern/colortext.py +73 -0
  115. honeybee_radiance/modifier/pattern/patternbase.py +34 -0
  116. honeybee_radiance/modifier/texture/__init__.py +4 -0
  117. honeybee_radiance/modifier/texture/texdata.py +29 -0
  118. honeybee_radiance/modifier/texture/texfunc.py +26 -0
  119. honeybee_radiance/modifier/texture/texturebase.py +27 -0
  120. honeybee_radiance/modifierset.py +1091 -0
  121. honeybee_radiance/mutil.py +60 -0
  122. honeybee_radiance/postprocess/__init__.py +1 -0
  123. honeybee_radiance/postprocess/annual.py +108 -0
  124. honeybee_radiance/postprocess/annualdaylight.py +425 -0
  125. honeybee_radiance/postprocess/annualglare.py +201 -0
  126. honeybee_radiance/postprocess/annualirradiance.py +187 -0
  127. honeybee_radiance/postprocess/electriclight.py +119 -0
  128. honeybee_radiance/postprocess/en17037.py +261 -0
  129. honeybee_radiance/postprocess/leed.py +304 -0
  130. honeybee_radiance/postprocess/solartracking.py +90 -0
  131. honeybee_radiance/primitive.py +554 -0
  132. honeybee_radiance/properties/__init__.py +1 -0
  133. honeybee_radiance/properties/_base.py +390 -0
  134. honeybee_radiance/properties/aperture.py +197 -0
  135. honeybee_radiance/properties/door.py +198 -0
  136. honeybee_radiance/properties/face.py +123 -0
  137. honeybee_radiance/properties/model.py +1291 -0
  138. honeybee_radiance/properties/room.py +490 -0
  139. honeybee_radiance/properties/shade.py +186 -0
  140. honeybee_radiance/properties/shademesh.py +116 -0
  141. honeybee_radiance/putil.py +44 -0
  142. honeybee_radiance/reader.py +214 -0
  143. honeybee_radiance/sensor.py +166 -0
  144. honeybee_radiance/sensorgrid.py +1008 -0
  145. honeybee_radiance/view.py +1101 -0
  146. honeybee_radiance/writer.py +951 -0
  147. honeybee_radiance-1.66.190.dist-info/METADATA +89 -0
  148. honeybee_radiance-1.66.190.dist-info/RECORD +152 -0
  149. honeybee_radiance-1.66.190.dist-info/WHEEL +5 -0
  150. honeybee_radiance-1.66.190.dist-info/entry_points.txt +2 -0
  151. honeybee_radiance-1.66.190.dist-info/licenses/LICENSE +661 -0
  152. honeybee_radiance-1.66.190.dist-info/top_level.txt +1 -0
@@ -0,0 +1,718 @@
1
+ # coding=utf-8
2
+ """Object representing a single state for a dynamic object."""
3
+ from __future__ import division
4
+
5
+ from .stategeo import StateGeometry
6
+ from ..geometry import Polygon
7
+ from ..modifier import Modifier
8
+ from ..mutil import dict_to_modifier
9
+ from ..lib.modifiers import white_glow
10
+
11
+ from ladybug_geometry.geometry3d.face import Face3D
12
+
13
+ import math
14
+
15
+
16
+ class _RadianceState(object):
17
+ """Object representing a single state for a dynamic object.
18
+
19
+ Args:
20
+ modifier: A Honeybee Radiance Modifier object to be applied to this state's
21
+ parent in this state. This is used to swap out the modifier in
22
+ multi-phase studies. If None, it will be the parent's default modifier.
23
+ shades: An optional array of StateGeometry objects to be included
24
+ with this state. The StateGeometry objects cannot already have
25
+ another parent state.
26
+
27
+ Properties:
28
+ * modifier
29
+ * shades
30
+ * modifier_direct
31
+ * parent
32
+ * has_parent
33
+ """
34
+
35
+ __slots__ = ('_modifier', '_shades', '_modifier_direct', '_parent')
36
+
37
+ def __init__(self, modifier=None, shades=None):
38
+ """Initialize RadianceState."""
39
+ self._parent = None # will be set when the state is assigned
40
+ self.modifier = modifier
41
+ self.shades = shades
42
+ self._modifier_direct = None
43
+
44
+ @property
45
+ def modifier(self):
46
+ """Get or set the modifier to be applied to the parent in this state.
47
+ """
48
+ if not self._modifier and self.has_parent: # use the parent's default
49
+ return self.parent.properties.radiance.modifier
50
+ return self._modifier
51
+
52
+ @modifier.setter
53
+ def modifier(self, value):
54
+ if value is not None:
55
+ assert isinstance(value, Modifier), \
56
+ 'Expected Modifier for RadianceState. Got {}'.format(type(value))
57
+ value.lock() # lock editing in case modifier has multiple references
58
+ self._modifier = value
59
+
60
+ @property
61
+ def shades(self):
62
+ """Get or set an array of StateGeometry objects to be included with this state.
63
+
64
+ The StateGeometry objects cannot already have another parent state.
65
+ """
66
+ return tuple(self._shades)
67
+
68
+ @shades.setter
69
+ def shades(self, value):
70
+ if value is not None:
71
+ try:
72
+ self._shades = [self._check_shade(sh) for sh in value]
73
+ except (ValueError, TypeError):
74
+ raise TypeError('RadianceState shades must be an iterable. '
75
+ 'Got {}.'.format(type(value)))
76
+ else:
77
+ self._shades = []
78
+
79
+ @property
80
+ def modifier_direct(self):
81
+ """Get or set a modifier for the parent to be used in direct studies.
82
+
83
+ If None, it will be the same as the modifier of this state if that modifier
84
+ is nonopaque. Otherwise, it will be the modifier_blk of the parent.
85
+ """
86
+ if not self._modifier_direct: # use the state's default modifier
87
+ mod = self.modifier
88
+ if mod is None or not mod.is_opaque:
89
+ return mod
90
+ return self._parent.properties.radiance.modifier_blk
91
+ return self._modifier_direct
92
+
93
+ @modifier_direct.setter
94
+ def modifier_direct(self, value):
95
+ if value is not None:
96
+ assert isinstance(value, Modifier), \
97
+ 'Expected Modifier for RadianceState. Got {}'.format(type(value))
98
+ value.lock() # lock editing in case modifier has multiple references
99
+ self._modifier_direct = value
100
+
101
+ @property
102
+ def parent(self):
103
+ """Get the parent of this State if assigned. None if not assigned."""
104
+ return self._parent
105
+
106
+ @property
107
+ def has_parent(self):
108
+ """Get a boolean noting whether this State has a parent."""
109
+ return self._parent is not None
110
+
111
+ def remove_shades(self):
112
+ """Remove all shades assigned to this object."""
113
+ for shade in self._shades:
114
+ shade._parent = None
115
+ self._shades = []
116
+
117
+ def add_shades(self, shades):
118
+ """Add an array of Shade objects to this state.
119
+
120
+ Args:
121
+ shades: An array of Shade objects to add to the this state.
122
+ """
123
+ for shade in shades:
124
+ self._shades.append(self._check_shade(shade))
125
+
126
+ def add_shade(self, shade):
127
+ """Add a Shade object to this state.
128
+
129
+ Args:
130
+ shade: A Shade object to add to the this state.
131
+ """
132
+ self._shades.append(self._check_shade(shade))
133
+
134
+ def move(self, moving_vec):
135
+ """Move all shades assigned to this state along a vector.
136
+
137
+ Args:
138
+ moving_vec: A ladybug_geometry Vector3D with the direction and distance
139
+ to move the shades.
140
+ """
141
+ for shd in self._shades:
142
+ shd.move(moving_vec)
143
+
144
+ def rotate(self, axis, angle, origin):
145
+ """Rotate all shades assigned to this state.
146
+
147
+ Args:
148
+ axis: A ladybug_geometry Vector3D axis representing the axis of rotation.
149
+ angle: An angle for rotation in degrees.
150
+ origin: A ladybug_geometry Point3D for the origin around which the
151
+ object will be rotated.
152
+ """
153
+ for shd in self._shades:
154
+ shd.rotate(axis, angle, origin)
155
+
156
+ def rotate_xy(self, angle, origin):
157
+ """Rotate all shades counterclockwise in the world XY plane.
158
+
159
+ Args:
160
+ angle: An angle in degrees.
161
+ origin: A ladybug_geometry Point3D for the origin around which the
162
+ object will be rotated.
163
+ """
164
+ for shd in self._shades:
165
+ shd.rotate_xy(angle, origin)
166
+
167
+ def reflect(self, plane):
168
+ """Reflect all shades assigned to this state across a plane.
169
+
170
+ Args:
171
+ plane: A ladybug_geometry Plane across which the object will
172
+ be reflected.
173
+ """
174
+ for shd in self._shades:
175
+ shd.reflect(plane)
176
+
177
+ def scale(self, factor, origin=None):
178
+ """Scale all shades assigned to this state by a factor.
179
+
180
+ Args:
181
+ factor: A number representing how much the object should be scaled.
182
+ origin: A ladybug_geometry Point3D representing the origin from which
183
+ to scale. If None, it will be scaled from the World origin (0, 0, 0).
184
+ """
185
+ for shd in self._shades:
186
+ shd.scale(factor, origin)
187
+
188
+ def to_radiance(self, direct=False, minimal=False):
189
+ """Generate a RAD string representation of this state.
190
+
191
+ Note that the resulting string lacks modifiers but includes both the
192
+ parent geometry and the geometry of any shades.
193
+
194
+ Args:
195
+ direct: Boolean to note whether to write the "direct" version of the
196
+ state, which will have the modifier_direct applied to the parent
197
+ of the state and use the modifier_blk assigned to each of the
198
+ shades. (Default: False)
199
+ minimal: Boolean to note whether the radiance string should be written
200
+ in a minimal format (with spaces instead of line breaks). Default: False.
201
+ """
202
+ assert self.has_parent, 'State must have a parent to use to_radiance.'
203
+ modifier = self.modifier_direct if direct else self.modifier
204
+ base_poly = Polygon(self.parent.identifier, self.parent.vertices, modifier)
205
+ rad_strs = [base_poly.to_radiance(minimal, False, False)]
206
+ for shd in self._shades:
207
+ rad_strs.append(shd.to_radiance(direct, minimal))
208
+ return '\n\n'.join(rad_strs)
209
+
210
+ def duplicate(self):
211
+ """Get a copy of this object."""
212
+ return self.__copy__()
213
+
214
+ def _check_shade(self, shade):
215
+ assert isinstance(shade, StateGeometry), \
216
+ 'Expected StateGeometry for RadianceState. Got {}.'.format(type(shade))
217
+ assert shade.parent is None, \
218
+ 'StateGeometry for a RadianceState cannot already have a parent object.'
219
+ shade._parent = self
220
+ return shade
221
+
222
+ def _duplicate_shades(self, new_state):
223
+ """Add duplicated child shades to a duplicated new_state."""
224
+ new_state._shades = [shd.duplicate() for shd in self._shades]
225
+ for shd in new_state._shades:
226
+ shd._parent = new_state
227
+
228
+ def __copy__(self):
229
+ new_obj = _RadianceState(self._modifier)
230
+ self._duplicate_shades(new_obj)
231
+ new_obj._modifier_direct = self._modifier_direct
232
+ return new_obj
233
+
234
+ def ToString(self):
235
+ return self.__repr__()
236
+
237
+ def __repr__(self):
238
+ return 'State: ({})'.format(self.modifier.display_name) \
239
+ if self.modifier is not None else 'State: ()'
240
+
241
+
242
+ class RadianceShadeState(_RadianceState):
243
+ """Object representing a single state for a dynamic Shade.
244
+
245
+ Args:
246
+ modifier: A Honeybee Radiance Modifier object to be applied to this state's
247
+ parent in this state. This can be used to change the transmittance of
248
+ deciduous trees, change the modifier of a ground surface to account
249
+ for snow reflectance, etc. If None, it will be the parent's default
250
+ modifier.
251
+ shades: An optional array of StateGeometry objects to be included
252
+ with this state. The StateGeometry objects cannot already have
253
+ another parent state.
254
+
255
+ Properties:
256
+ * modifier
257
+ * shades
258
+ * modifier_direct
259
+ * parent
260
+ * has_parent
261
+ """
262
+ __slots__ = ()
263
+
264
+ def __init__(self, modifier=None, shades=None):
265
+ """Initialize RadianceShadeState."""
266
+ _RadianceState.__init__(self, modifier, shades)
267
+
268
+ @classmethod
269
+ def from_dict(cls, data):
270
+ """Create RadianceShadeState from a dictionary.
271
+
272
+ Note that the dictionary must be a non-abridged version for this
273
+ classmethod to work.
274
+
275
+ Args:
276
+ data: A dictionary representation of RadianceShadeState with the
277
+ format below.
278
+
279
+ .. code-block:: python
280
+
281
+ {
282
+ 'type': 'RadianceShadeState',
283
+ 'modifier': {}, # A Honeybee Radiance Modifier dictionary
284
+ 'shades': [], # A list of StateGeometry dictionaries
285
+ 'modifier_direct': {} # A Honeybee Radiance Modifier dictionary
286
+ }
287
+ """
288
+ assert data['type'] == 'RadianceShadeState', \
289
+ 'Expected RadianceShadeState. Got {}.'.format(data['type'])
290
+ new_state = cls()
291
+ if 'modifier' in data and data['modifier'] is not None:
292
+ new_state.modifier = dict_to_modifier(data['modifier'])
293
+ if 'shades' in data and data['shades'] is not None:
294
+ new_state.shades = [StateGeometry.from_dict(shd) for shd in data['shades']]
295
+ if 'modifier_direct' in data and data['modifier_direct'] is not None:
296
+ new_state.modifier_direct = dict_to_modifier(data['modifier_direct'])
297
+ return new_state
298
+
299
+ @classmethod
300
+ def from_dict_abridged(cls, data, modifiers):
301
+ """Create RadianceShadeState from an abridged dictionary.
302
+
303
+ Args:
304
+ data: A dictionary representation of RadianceShadeStateAbridged with
305
+ the format below.
306
+ modifiers: A dictionary of modifiers with modifier identifiers as keys,
307
+ which will be used to re-assign modifiers.
308
+
309
+ .. code-block:: python
310
+
311
+ {
312
+ 'type': 'RadianceShadeStateAbridged',
313
+ 'modifier': str, # An identifier of a honeybee-radiance modifier
314
+ 'shades': [], # A list of abridged StateGeometry dictionaries
315
+ 'modifier_direct': str # An identifier of a honeybee-radiance modifier
316
+ }
317
+ """
318
+ assert data['type'] == 'RadianceShadeStateAbridged', \
319
+ 'Expected RadianceShadeStateAbridged. Got {}.'.format(data['type'])
320
+ new_state = cls()
321
+ if 'modifier' in data and data['modifier'] is not None:
322
+ new_state.modifier = modifiers[data['modifier']]
323
+ if 'shades' in data and data['shades'] is not None:
324
+ new_state.shades = [StateGeometry.from_dict_abridged(shd, modifiers)
325
+ for shd in data['shades']]
326
+ if 'modifier_direct' in data and data['modifier_direct'] is not None:
327
+ new_state.modifier_direct = modifiers[data['modifier_direct']]
328
+ return new_state
329
+
330
+ def to_dict(self, abridged=False):
331
+ """Convert RadianceShadeState to a dictionary.
332
+
333
+ Args:
334
+ abridged: Boolean to note whether the full dictionary describing the
335
+ object should be returned (False) or just an abridged version (True).
336
+ Default: False.
337
+ """
338
+ base = {'type': 'RadianceShadeStateAbridged'} if abridged else \
339
+ {'type': 'RadianceShadeState'}
340
+ if self._modifier:
341
+ base['modifier'] = self._modifier.identifier if abridged else \
342
+ self._modifier.to_dict()
343
+ if len(self._shades) != 0:
344
+ base['shades'] = [shd.to_dict(abridged=abridged) for shd in self.shades]
345
+ if self._modifier_direct is not None:
346
+ base['modifier_direct'] = self._modifier_direct.identifier if abridged \
347
+ else self._modifier.to_dict()
348
+ return base
349
+
350
+ def __copy__(self):
351
+ new_obj = RadianceShadeState(self._modifier)
352
+ self._duplicate_shades(new_obj)
353
+ new_obj._modifier_direct = self._modifier_direct
354
+ return new_obj
355
+
356
+
357
+ class RadianceSubFaceState(_RadianceState):
358
+ """Object representing a single state for a dynamic Aperture or Door.
359
+
360
+ Args:
361
+ modifier: A Honeybee Radiance Modifier object to be applied to this state's
362
+ parent in this state. This is used to swap out the modifier in
363
+ multi-phase studies. If None, it will be the parent's default modifier.
364
+ shades: An optional array of StateGeometry objects to be included
365
+ with this state. The StateGeometry objects cannot already have
366
+ another parent state.
367
+
368
+ Properties:
369
+ * modifier
370
+ * shades
371
+ * modifier_direct
372
+ * vmtx_geometry
373
+ * dmtx_geometry
374
+ * mtxs_default
375
+ * parent
376
+ * has_parent
377
+ """
378
+ __slots__ = ('_vmtx_geometry', '_dmtx_geometry')
379
+
380
+ def __init__(self, modifier=None, shades=None):
381
+ """Initialize RadianceSubFaceState."""
382
+ _RadianceState.__init__(self, modifier, shades)
383
+ self._vmtx_geometry = None
384
+ self._dmtx_geometry = None
385
+
386
+ @property
387
+ def modifier_direct(self):
388
+ """Get or set a modifier for the parent to be used in direct studies.
389
+
390
+ If None, it will be the same as the modifier of this state. This property
391
+ is only used in 2-phase and 5-phase studies and should usually be left
392
+ as None in 2-phase studies. In 5-phase studies, this will be used for
393
+ the 5th phase.
394
+ """
395
+ if not self._modifier_direct: # use the state's default modifier
396
+ return self.modifier
397
+ return self._modifier_direct
398
+
399
+ @modifier_direct.setter
400
+ def modifier_direct(self, value):
401
+ if value is not None:
402
+ assert isinstance(value, Modifier), \
403
+ 'Expected Modifier for RadianceState. Got {}'.format(type(value))
404
+ value.lock() # lock editing in case modifier has multiple references
405
+ self._modifier_direct = value
406
+
407
+ @property
408
+ def vmtx_geometry(self):
409
+ """Get or set a Face3D to be used for the inward-facing vmtx file.
410
+
411
+ If None, it will be a flipped (inward-facing) version of this state's parent.
412
+ Note that this property is only used in 3-phase and 5-phase studies and
413
+ its usual purpose is to account for thickness of the tmtx (BSDF) layer.
414
+ Also note that the gen_geo_from_vmtx_offset or gen_geos_from_tmtx_thickness
415
+ methods can be used to automatically generate this geometry without the
416
+ need to set it here.
417
+ """
418
+ if not self._vmtx_geometry: # use the inward-version of the parent geometry
419
+ return self.parent.geometry.flip() if self.has_parent else None
420
+ return self._vmtx_geometry
421
+
422
+ @vmtx_geometry.setter
423
+ def vmtx_geometry(self, value):
424
+ if value is not None:
425
+ assert isinstance(value, Face3D), \
426
+ 'Expected Face3D for RadianceSubFaceState vmtx_geometry. ' \
427
+ 'Got {}'.format(type(value))
428
+ self._vmtx_geometry = value
429
+
430
+ @property
431
+ def dmtx_geometry(self):
432
+ """Get or set a Face3D to be used for the outward-facing dmtx file.
433
+
434
+ If None, it will be a flipped (inward-facing) version of this state's parent.
435
+ Note that this property is only used in 3-phase and 5-phase studies and
436
+ its usual purpose is to account for thickness of the tmtx (BSDF) layer.
437
+ Also note that the gen_geo_from_dmtx_offset or gen_geos_from_tmtx_thickness
438
+ methods can be used to automatically generate this geometry without the
439
+ need to set it here.
440
+ """
441
+ if not self._dmtx_geometry: # use the inward-version of the parent geometry
442
+ return self.parent.geometry.flip() if self.has_parent else None
443
+ return self._dmtx_geometry
444
+
445
+ @dmtx_geometry.setter
446
+ def dmtx_geometry(self, value):
447
+ if value is not None:
448
+ assert isinstance(value, Face3D), \
449
+ 'Expected Face3D for RadianceSubFaceState dmtx_geometry. ' \
450
+ 'Got {}'.format(type(value))
451
+ self._dmtx_geometry = value
452
+
453
+ @property
454
+ def mtxs_default(self):
455
+ """Get a boolean noting whether the vmtx_geometry and dmtx_geometry are None.
456
+
457
+ This indicates that the vmtx_geometry and dmtx_geometry are both just a
458
+ flipped version of the parent geometry.
459
+ """
460
+ return self._vmtx_geometry is None and self._dmtx_geometry is None
461
+
462
+ def gen_geos_from_tmtx_thickness(self, thickness):
463
+ """Auto-generate the vmtx_geometry and dmtx_geometry using a tmtx thickness.
464
+
465
+ Args:
466
+ thickness: A number for the thickness of the tmtx layer. The state's
467
+ vmtx_geometry will be set to the the parent geometry moved half
468
+ of this thickness inward. The dmtx_geometry will be set to the
469
+ parent geometry moved half of this thickness outward.
470
+ """
471
+ assert self.has_parent, \
472
+ 'State must have a parent to use gen_geos_from_tmtx_thickness.'
473
+ dist = thickness / 2
474
+ out_vec = self.parent.normal * dist
475
+ in_vec = out_vec.reverse()
476
+ base_geo = self.parent.geometry.flip()
477
+ self.dmtx_geometry = base_geo.move(out_vec)
478
+ self.vmtx_geometry = base_geo.move(in_vec)
479
+
480
+ def gen_geo_from_vmtx_offset(self, offset):
481
+ """Auto-generate the vmtx_geometry using an offset from the parent geometry.
482
+
483
+ Args:
484
+ offset: A number for the offset of the vmtx layer from the parent geometry.
485
+ """
486
+ assert self.has_parent, \
487
+ 'State must have a parent to use gen_geo_from_vmtx_offset.'
488
+ in_vec = self.parent.normal.reverse() * offset
489
+ base_geo = self.parent.geometry.flip()
490
+ self.vmtx_geometry = base_geo.move(in_vec)
491
+
492
+ def gen_geo_from_dmtx_offset(self, offset):
493
+ """Auto-generate the dmtx_geometry using an offset from the parent geometry.
494
+
495
+ Args:
496
+ offset: A number for the offset of the dmtx layer from the parent geometry.
497
+ """
498
+ assert self.has_parent, \
499
+ 'State must have a parent to use gen_geo_from_dmtx_offset.'
500
+ out_vec = self.parent.normal * offset
501
+ base_geo = self.parent.geometry.flip()
502
+ self.vmtx_geometry = base_geo.move(out_vec)
503
+
504
+ def move(self, moving_vec):
505
+ """Move all shades and mtx geometry assigned to this state along a vector.
506
+
507
+ Args:
508
+ moving_vec: A ladybug_geometry Vector3D with the direction and distance
509
+ to move the shades.
510
+ """
511
+ for shd in self._shades:
512
+ shd.move(moving_vec)
513
+ if self._vmtx_geometry:
514
+ self._vmtx_geometry = self._vmtx_geometry.move(moving_vec)
515
+ if self._dmtx_geometry:
516
+ self._dmtx_geometry = self._dmtx_geometry.move(moving_vec)
517
+
518
+ def rotate(self, axis, angle, origin):
519
+ """Rotate all shades and mtx geometry assigned to this state.
520
+
521
+ Args:
522
+ axis: A ladybug_geometry Vector3D axis representing the axis of rotation.
523
+ angle: An angle for rotation in degrees.
524
+ origin: A ladybug_geometry Point3D for the origin around which the
525
+ object will be rotated.
526
+ """
527
+ for shd in self._shades:
528
+ shd.rotate(axis, angle, origin)
529
+ if self._vmtx_geometry:
530
+ self._vmtx_geometry = self._vmtx_geometry.rotate(
531
+ axis, math.radians(angle), origin)
532
+ if self._dmtx_geometry:
533
+ self._dmtx_geometry = self._dmtx_geometry.rotate(
534
+ axis, math.radians(angle), origin)
535
+
536
+ def rotate_xy(self, angle, origin):
537
+ """Rotate all shades and mtx geometry counterclockwise in the world XY plane.
538
+
539
+ Args:
540
+ angle: An angle in degrees.
541
+ origin: A ladybug_geometry Point3D for the origin around which the
542
+ object will be rotated.
543
+ """
544
+ for shd in self._shades:
545
+ shd.rotate_xy(angle, origin)
546
+ if self._vmtx_geometry:
547
+ self._vmtx_geometry = self._vmtx_geometry.rotate_xy(
548
+ math.radians(angle), origin)
549
+ if self._dmtx_geometry:
550
+ self._dmtx_geometry = self._dmtx_geometry.rotate_xy(
551
+ math.radians(angle), origin)
552
+
553
+ def reflect(self, plane):
554
+ """Reflect all shades and mtx geometry assigned to this state across a plane.
555
+
556
+ Args:
557
+ plane: A ladybug_geometry Plane across which the object will
558
+ be reflected.
559
+ """
560
+ for shd in self._shades:
561
+ shd.reflect(plane)
562
+ if self._vmtx_geometry:
563
+ self._vmtx_geometry = self._vmtx_geometry.reflect(plane.n, plane.o)
564
+ if self._dmtx_geometry:
565
+ self._dmtx_geometry = self._dmtx_geometry.reflect(plane.n, plane.o)
566
+
567
+ def scale(self, factor, origin=None):
568
+ """Scale all shades and mtx geometry assigned to this state by a factor.
569
+
570
+ Args:
571
+ factor: A number representing how much the object should be scaled.
572
+ origin: A ladybug_geometry Point3D representing the origin from which
573
+ to scale. If None, it will be scaled from the World origin (0, 0, 0).
574
+ """
575
+ for shd in self._shades:
576
+ shd.scale(factor, origin)
577
+ if self._vmtx_geometry:
578
+ self._vmtx_geometry = self._vmtx_geometry.scale(factor, origin)
579
+ if self._dmtx_geometry:
580
+ self._dmtx_geometry = self._dmtx_geometry.scale(factor, origin)
581
+
582
+ def vmtx_to_radiance(self, modifier=white_glow, minimal=False):
583
+ """Generate a RAD string representation of this state's vmtx.
584
+
585
+ The resulting string lacks modifiers and only includes the vmtx_geometry.
586
+
587
+ Args:
588
+ modifier: A modifier assigned to the vmtx_geometry. (Default: white_glow)
589
+ minimal: Boolean to note whether the radiance string should be written
590
+ in a minimal format (spaces instead of line breaks). (Default: False)
591
+ """
592
+ assert self.has_parent, 'State must have a parent to use vmtx_to_radiance.'
593
+ vmtx_poly = Polygon(self.parent.identifier,
594
+ self.vmtx_geometry.vertices, modifier)
595
+ return vmtx_poly.to_radiance(minimal, False, False)
596
+
597
+ def dmtx_to_radiance(self, minimal=False):
598
+ """Generate a RAD string representation of this state's dmtx.
599
+
600
+ The resulting string lacks modifiers and only includes the dmtx_geometry.
601
+
602
+ Args:
603
+ minimal: Boolean to note whether the radiance string should be written
604
+ in a minimal format (with spaces instead of line breaks). Default: False.
605
+ """
606
+ assert self.has_parent, 'State must have a parent to use dmtx_to_radiance.'
607
+ dmtx_poly = Polygon(self.parent.identifier,
608
+ self.dmtx_geometry.vertices, white_glow)
609
+ return dmtx_poly.to_radiance(minimal, False, False)
610
+
611
+ @classmethod
612
+ def from_dict(cls, data):
613
+ """Create RadianceSubFaceState from a dictionary.
614
+
615
+ Note that the dictionary must be a non-abridged version for this
616
+ classmethod to work.
617
+
618
+ Args:
619
+ data: A dictionary representation of RadianceSubFaceState with the
620
+ format below.
621
+
622
+ .. code-block:: python
623
+
624
+ {
625
+ 'type': 'RadianceSubFaceState',
626
+ 'modifier': {}, # A Honeybee Radiance Modifier dictionary
627
+ 'shades': [], # A list of abridged StateGeometry dictionaries
628
+ 'modifier_direct': {}, # A Honeybee Radiance Modifier dictionary
629
+ 'vmtx_geometry': {}, # A Face3D for the view matrix geometry
630
+ 'dmtx_geometry': {} # A Face3D for the daylight matrix geometry
631
+ }
632
+ """
633
+ assert data['type'] == 'RadianceSubFaceState', \
634
+ 'Expected RadianceSubFaceState. Got {}.'.format(data['type'])
635
+ new_state = cls()
636
+ if 'modifier' in data and data['modifier'] is not None:
637
+ new_state.modifier = dict_to_modifier(data['modifier'])
638
+ if 'shades' in data and data['shades'] is not None:
639
+ new_state.shades = [StateGeometry.from_dict(shd) for shd in data['shades']]
640
+ if 'modifier_direct' in data and data['modifier_direct'] is not None:
641
+ new_state.modifier_direct = dict_to_modifier(data['modifier_direct'])
642
+ if 'vmtx_geometry' in data and data['vmtx_geometry'] is not None:
643
+ new_state.vmtx_geometry = Face3D.from_dict(data['vmtx_geometry'])
644
+ if 'dmtx_geometry' in data and data['dmtx_geometry'] is not None:
645
+ new_state.dmtx_geometry = Face3D.from_dict(data['dmtx_geometry'])
646
+ return new_state
647
+
648
+ @classmethod
649
+ def from_dict_abridged(cls, data, modifiers):
650
+ """Create RadianceSubFaceState from an abridged dictionary.
651
+
652
+ Note that the dictionary must be a non-abridged version for this
653
+ classmethod to work.
654
+
655
+ Args:
656
+ data: A dictionary representation of RadianceSubFaceStateAbridged
657
+ with the format below.
658
+ modifiers: A dictionary of modifiers with modifier identifiers as keys,
659
+ which will be used to re-assign modifiers.
660
+
661
+ .. code-block:: python
662
+
663
+ {
664
+ 'type': 'RadianceSubFaceStateAbridged',
665
+ 'modifier': str, # An identifier of a honeybee-radiance modifier
666
+ 'shades': [], # A list of abridged StateGeometry dictionaries
667
+ 'modifier_direct': str, # An identifier of a honeybee-radiance modifier
668
+ 'vmtx_geometry': {}, # A Face3D for the view matrix geometry
669
+ 'dmtx_geometry': {} # A Face3D for the daylight matrix geometry
670
+ }
671
+ """
672
+ assert data['type'] == 'RadianceSubFaceStateAbridged', \
673
+ 'Expected RadianceSubFaceStateAbridged. Got {}.'.format(data['type'])
674
+ new_state = cls()
675
+ if 'modifier' in data and data['modifier'] is not None:
676
+ new_state.modifier = modifiers[data['modifier']]
677
+ if 'shades' in data and data['shades'] is not None:
678
+ new_state.shades = [StateGeometry.from_dict_abridged(shd, modifiers)
679
+ for shd in data['shades']]
680
+ if 'modifier_direct' in data and data['modifier_direct'] is not None:
681
+ new_state.modifier_direct = modifiers[data['modifier_direct']]
682
+ if 'vmtx_geometry' in data and data['vmtx_geometry'] is not None:
683
+ new_state.vmtx_geometry = Face3D.from_dict(data['vmtx_geometry'])
684
+ if 'dmtx_geometry' in data and data['dmtx_geometry'] is not None:
685
+ new_state.dmtx_geometry = Face3D.from_dict(data['dmtx_geometry'])
686
+ return new_state
687
+
688
+ def to_dict(self, abridged=False):
689
+ """Convert RadianceSubFaceState to a dictionary.
690
+
691
+ Args:
692
+ abridged: Boolean to note whether the full dictionary describing the
693
+ object should be returned (False) or just an abridged version (True).
694
+ Default: False.
695
+ """
696
+ base = {'type': 'RadianceSubFaceStateAbridged'} if abridged else \
697
+ {'type': 'RadianceSubFaceState'}
698
+ if self._modifier:
699
+ base['modifier'] = self._modifier.identifier if abridged else \
700
+ self._modifier.to_dict()
701
+ if len(self._shades) != 0:
702
+ base['shades'] = [shd.to_dict(abridged=abridged) for shd in self.shades]
703
+ if self._modifier_direct is not None:
704
+ base['modifier_direct'] = self._modifier_direct.identifier if abridged \
705
+ else self._modifier.to_dict()
706
+ if self._vmtx_geometry is not None:
707
+ base['vmtx_geometry'] = self._vmtx_geometry.to_dict()
708
+ if self._dmtx_geometry is not None:
709
+ base['dmtx_geometry'] = self._dmtx_geometry.to_dict()
710
+ return base
711
+
712
+ def __copy__(self):
713
+ new_obj = RadianceSubFaceState(self._modifier)
714
+ self._duplicate_shades(new_obj)
715
+ new_obj._modifier_direct = self._modifier_direct
716
+ new_obj._vmtx_geometry = self._vmtx_geometry
717
+ new_obj._dmtx_geometry = self._dmtx_geometry
718
+ return new_obj