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,116 @@
1
+ # coding=utf-8
2
+ """ShadeMesh Radiance Properties."""
3
+ from ._base import _RadianceProperties
4
+ from ..modifier import Modifier
5
+ from ..lib.modifiers import generic_context
6
+ from ..lib.modifiersets import generic_modifier_set_visible
7
+
8
+
9
+ class ShadeMeshRadianceProperties(_RadianceProperties):
10
+ """Radiance Properties for Honeybee ShadeMesh.
11
+
12
+ Args:
13
+ host: A honeybee_core ShadeMesh object that hosts these properties.
14
+ modifier: A Honeybee Radiance Modifier object for the shade mesh. If None,
15
+ it will be set by the default generic ModifierSet.
16
+ modifier_blk: A Honeybee Radiance Modifier object to be used for this
17
+ shade mesh in direct solar simulations and in isolation studies (assessing
18
+ the contribution of individual Apertures). If None, this will be
19
+ a completely black material if the Shade's modifier is opaque and
20
+ will be equal to the modifier if the Shade's modifier is non-opaque.
21
+
22
+ Properties:
23
+ * host
24
+ * modifier
25
+ * modifier_blk
26
+ * is_opaque
27
+ * is_modifier_set_on_object
28
+ * is_blk_overridden
29
+ """
30
+
31
+ __slots__ = ()
32
+
33
+ def __init__(self, host, modifier=None, modifier_blk=None):
34
+ """Initialize ShadeMesh radiance properties."""
35
+ _RadianceProperties.__init__(self, host, modifier, modifier_blk)
36
+
37
+ @property
38
+ def modifier(self):
39
+ """Get or set the ShadeMesh modifier.
40
+
41
+ If the modifier is not set on the shade-level, then it will be the
42
+ generic context material or the generic exterior shade modifier if it
43
+ is not detached.
44
+ """
45
+ if self._modifier: # set by user
46
+ return self._modifier
47
+ return generic_context if self._host.is_detached else \
48
+ generic_modifier_set_visible.shade_set.exterior_modifier
49
+
50
+ @modifier.setter
51
+ def modifier(self, value):
52
+ if value is not None:
53
+ assert isinstance(value, Modifier), \
54
+ 'Expected Radiance Modifier for ShadeMesh. Got {}'.format(type(value))
55
+ value.lock() # lock editing in case modifier has multiple references
56
+ self._modifier = value
57
+
58
+ @classmethod
59
+ def from_dict(cls, data, host):
60
+ """Create ShadeMeshRadianceProperties from a dictionary.
61
+
62
+ Note that the dictionary must be a non-abridged version for this
63
+ classmethod to work.
64
+
65
+ Args:
66
+ data: A dictionary representation of ShadeMeshRadianceProperties with the
67
+ format below.
68
+ host: A ShadeMesh object that hosts these properties.
69
+
70
+ .. code-block:: python
71
+
72
+ {
73
+ 'type': 'ShadeMeshRadianceProperties',
74
+ 'modifier': {}, # A Honeybee Radiance Modifier dictionary
75
+ 'modifier_blk': {} # A Honeybee Radiance Modifier dictionary
76
+ }
77
+ """
78
+ assert data['type'] == 'ShadeMeshRadianceProperties', \
79
+ 'Expected ShadeMeshRadianceProperties. Got {}.'.format(data['type'])
80
+ new_prop = cls(host)
81
+ return cls._restore_modifiers_from_dict(new_prop, data)
82
+
83
+ def apply_properties_from_dict(self, abridged_data, modifiers):
84
+ """Apply properties from a ShadeMeshRadiancePropertiesAbridged dictionary.
85
+
86
+ Args:
87
+ abridged_data: A ShadeMeshRadiancePropertiesAbridged dictionary (typically
88
+ coming from a Model) with the format below.
89
+ modifiers: A dictionary of modifiers with modifier identifiers as keys,
90
+ which will be used to re-assign modifiers.
91
+
92
+ .. code-block:: python
93
+
94
+ {
95
+ 'type': 'ShadeMeshRadiancePropertiesAbridged',
96
+ 'modifier': str, # A Honeybee Radiance Modifier identifier
97
+ 'modifier_blk': str # A Honeybee Radiance Modifier identifier
98
+ }
99
+ """
100
+ self._apply_modifiers_from_dict(abridged_data, modifiers)
101
+
102
+ def to_dict(self, abridged=False):
103
+ """Return radiance properties as a dictionary.
104
+
105
+ Args:
106
+ abridged: Boolean to note whether the full dictionary describing the
107
+ object should be returned (False) or just an abridged version (True).
108
+ Default: False.
109
+ """
110
+ base = {'radiance': {}}
111
+ base['radiance']['type'] = 'ShadeMeshRadianceProperties' if not \
112
+ abridged else 'ShadeMeshRadiancePropertiesAbridged'
113
+ return self._add_modifiers_to_dict(base, abridged)
114
+
115
+ def __repr__(self):
116
+ return 'ShadeMesh Radiance Properties:\n host: {}'.format(self.host.identifier)
@@ -0,0 +1,44 @@
1
+ """Primitive utility functions."""
2
+ from honeybee_radiance.mutil import modifier_class_from_type_string
3
+ import honeybee_radiance.geometry as geometry
4
+ from honeybee_radiance.primitive import Primitive
5
+
6
+
7
+ def primitive_class_from_type_string(type_string):
8
+ """Get the class of any primitive using its 'type' string.
9
+
10
+ Note that this function returns the class itself and not a class instance.
11
+
12
+ Args:
13
+ type_string: Text for the name of a primitive module/class. This should
14
+ usually be lowercase and should be the same as the 'type' key used
15
+ in the dictionary representation of the primitive.
16
+ """
17
+ if type_string in Primitive.GEOMETRYTYPES:
18
+ target_module = geometry
19
+ else:
20
+ try:
21
+ return modifier_class_from_type_string(type_string)
22
+ except ValueError:
23
+ raise NotImplementedError(
24
+ 'Honeybee currently does not support %s' % type_string)
25
+ class_name = type_string.capitalize()
26
+ return getattr(target_module, class_name)
27
+
28
+
29
+ def dict_to_primitive(pdict):
30
+ """Convert a dictionary representation of any primitive to a class instance.
31
+
32
+ The returned object will have the correct class type and will not be the
33
+ generic Primitive base class. Note that this function is recursive and will
34
+ re-serialize modifiers of modifiers.
35
+
36
+ Args:
37
+ pdict: A dictionary of any Radiance Primitive (Geometry or Modifier).
38
+ """
39
+ primitive_class = primitive_class_from_type_string(pdict['type'])
40
+
41
+ if 'values' in pdict:
42
+ return primitive_class.from_primitive_dict(pdict)
43
+ else:
44
+ return primitive_class.from_dict(pdict)
@@ -0,0 +1,214 @@
1
+ """A collection of auxiliary functions for working with radiance files and objects."""
2
+ import re
3
+ import os
4
+
5
+
6
+ # TODO: Add support for comments [#] and commands [!]
7
+ def parse_from_string(full_string):
8
+ """Separate a Radiance file string into multiple strings for each object.
9
+
10
+ Args:
11
+ full_string: Radiance data as a single string. The string can be multiline.
12
+
13
+ Returns:
14
+ A list of strings. Each string represents a different Radiance primitive
15
+ (geometry or modifier). Comments [#] and commands [!] are excluded.
16
+ """
17
+ raw_rad_objects = re.findall(
18
+ r'^\s*([^0-9].*(\s*[\d.-]+.*)*)',
19
+ full_string,
20
+ re.MULTILINE)
21
+
22
+ rad_objects = (' '.join(radiance_object[0].split())
23
+ for radiance_object in raw_rad_objects)
24
+
25
+ filtered_objects = tuple(rad_object for rad_object in rad_objects
26
+ if rad_object and rad_object[0] not in ['#', '!'])
27
+
28
+ return filtered_objects
29
+
30
+
31
+ def parse_from_file(file_path):
32
+ """Parse a Radiance file.
33
+
34
+ This function breaks down the file into a list of radiance objects as separate
35
+ strings.
36
+
37
+ Args:
38
+ file_path: Path to Radiance file
39
+
40
+ Returns:
41
+ A list of strings. Each string represents a different Radiance object.
42
+
43
+ Usage:
44
+
45
+ .. code-block:: python
46
+
47
+ rad_obj_strs = parse_from_file('some_file.rad')
48
+ """
49
+
50
+ assert os.path.isfile(file_path), "Can't find %s." % file_path
51
+
52
+ with open(file_path, "r") as rad_file:
53
+ return parse_from_string(rad_file.read())
54
+
55
+
56
+ def string_to_dicts(string):
57
+ """Convert a radiance string to a list of primitive dictionaries.
58
+
59
+ These primitive dictionaries can be seralized to honeybee-radiance Python
60
+ objects using the from_primitive_dict methods on all primitive classes.
61
+
62
+ If the primitive modifier is not void or the primitive has other dependencies,
63
+ the dependency must also be part of the input string and this method will
64
+ ensure that the dependent output dictionaries are correctly nested so that
65
+ they can be correctly serialized.
66
+
67
+ Returns:
68
+ A list of dictionaries.
69
+ """
70
+ def find_object(target, index):
71
+ for o_count, other_obj in enumerate(objects[:-(index + 1)]):
72
+ if other_obj['identifier'] == target:
73
+ return o_count, other_obj
74
+
75
+ input_objects = parse_from_string(string)
76
+
77
+ if not input_objects:
78
+ raise ValueError(
79
+ '{} includes no radiance objects.'.format(string)
80
+ )
81
+
82
+ # break down each object and convert it to a dict
83
+ objects = [string_to_dict(inp) for inp in input_objects]
84
+
85
+ # start from the last material and try to find dependencies if any)
86
+ rev_objects = list(reversed(objects))
87
+ remove_index = []
88
+ for count, obj in enumerate(rev_objects):
89
+
90
+ if obj['modifier'] != 'void':
91
+ # try to find it in objects and add replace it
92
+ try:
93
+ o_count, other_obj = find_object(obj['modifier'], count)
94
+ except TypeError:
95
+ # didn't find any
96
+ raise ValueError(
97
+ 'Failed to find "{}" modifier for "{}" in input string'.format(
98
+ obj['modifier'], obj['identifier']
99
+ )
100
+ )
101
+ else:
102
+ objects[-(count + 1)]['modifier'] = other_obj
103
+ remove_index.append(o_count)
104
+
105
+ if len(obj['values'][0]) != 0:
106
+ for value in obj['values'][0]:
107
+ if '(' in value or '"' in value:
108
+ continue
109
+ # search for dependencies
110
+ try:
111
+ o_count, other_obj = find_object(value, count)
112
+ except TypeError:
113
+ # didn't find any
114
+ pass
115
+ else:
116
+ objects[-(count + 1)]['dependencies'].append(other_obj)
117
+ remove_index.append(o_count)
118
+
119
+ if remove_index:
120
+ return [obj for index, obj in enumerate(objects) if index not in remove_index]
121
+ else:
122
+ return objects
123
+
124
+
125
+ # pattern one handles whitespaces inside ( )
126
+ # pattern two handles whitespaces inside " "
127
+ # I assume someone who knows re better than I do can do this in a single run!
128
+ split_pattern_one = re.compile(r"\s+(?=[^(\")]*(?:\(|$))")
129
+ split_pattern_two = re.compile(r"\s+(?=[^()]*(?:\"\w))")
130
+
131
+
132
+ def string_to_dict(string):
133
+ """Get a single Radiance string object as a primitive dictionary."""
134
+ data = [
135
+ d for dt in re.split(split_pattern_one, string)
136
+ for d in re.split(split_pattern_one, str(dt))
137
+ ]
138
+
139
+ modifier, primitive_type, identifier = data[:3]
140
+ base_data = data[3:]
141
+
142
+ count_1 = int(base_data[0])
143
+ count_2 = int(base_data[count_1 + 1])
144
+ count_3 = int(base_data[count_1 + count_2 + 2])
145
+
146
+ l1 = [] if count_1 == 0 else base_data[1: count_1 + 1]
147
+ l2 = [] if count_2 == 0 \
148
+ else base_data[count_1 + 2: count_1 + count_2 + 2]
149
+ l3 = [] if count_3 == 0 \
150
+ else base_data[count_1 + count_2 + 3: count_1 + count_2 + count_3 + 3]
151
+
152
+ return {
153
+ 'modifier': modifier,
154
+ 'type': primitive_type,
155
+ 'identifier': identifier,
156
+ 'values': [l1, l2, l3],
157
+ 'dependencies': []
158
+ }
159
+
160
+
161
+ def parse_header(filepath):
162
+ """Return radiance file header if exist.
163
+
164
+ This method returns all the lines between `#?RADIANCE` and `FORMAT=*` and number of
165
+ header lines including the white line after last header line.
166
+
167
+ Args:
168
+ filepath: Full path to Radiance file.
169
+
170
+ Returns:
171
+ line_count, header as a single multiline string
172
+ """
173
+ try:
174
+ inf = open(filepath, 'r', encoding='utf-8')
175
+ except:
176
+ # python 2
177
+ inf = open(filepath, 'r')
178
+ try:
179
+ first_line = next(inf)
180
+ if first_line[:10] != '#?RADIANCE':
181
+ raise ValueError(
182
+ 'File with Radiance header must start with #?RADIANCE '
183
+ 'not {}.'.format(first_line)
184
+ )
185
+ header_lines = [first_line]
186
+ for line in inf:
187
+ header_lines.append(line)
188
+ if line[:7] == 'FORMAT=':
189
+ break
190
+ return len(header_lines) + 1, '\n'.join(header_lines)
191
+ finally:
192
+ inf.close()
193
+
194
+
195
+ def sensor_count_from_file(filepath):
196
+ """Return sensor count of a sensor grid file.
197
+
198
+ This function returns the sensor count of a sensor grid file. Comments [#] and
199
+ empty lines will not be counted.
200
+
201
+ Args:
202
+ filepath: Full path to Radiance pts file.
203
+
204
+ Returns:
205
+ sensor_count
206
+ """
207
+ sensor_count = 0
208
+ with open(filepath, 'r') as pts_file:
209
+ for l in pts_file:
210
+ if not l.strip() or l[0] == '#':
211
+ pass
212
+ else:
213
+ sensor_count += 1
214
+ return sensor_count
@@ -0,0 +1,166 @@
1
+ """A light version of test points."""
2
+ from __future__ import division
3
+ import honeybee.typing as typing
4
+
5
+ import ladybug_geometry.geometry3d.pointvector as pv
6
+
7
+ import math
8
+
9
+
10
+ class Sensor(object):
11
+ """A radiance sensor.
12
+
13
+ Args:
14
+ pos: Position of sensor as (x, y, z) (Default: (0, 0, 0)).
15
+ dir: Direction of sensor as (x, y, z) (Default: (0, 0, 1)).
16
+
17
+ Properties:
18
+ * pos
19
+ * dir
20
+
21
+ """
22
+ __slots__ = ('_pos', '_dir')
23
+
24
+ def __init__(self, pos=None, dir=None):
25
+ """Create a sensor."""
26
+ self.pos = pos
27
+ self.dir = dir
28
+
29
+ @classmethod
30
+ def from_dict(cls, sensor_dict):
31
+ """Create a sensor from dictionary.
32
+
33
+ .. code-block:: python
34
+
35
+ {
36
+ 'pos': [0, 0, 0], # array of 3 numbers for the sensor position
37
+ 'dir': [0, 0, 1] # array of 3 numbers for the sensor direction
38
+ }
39
+ """
40
+ pos = sensor_dict['pos'] if 'pos' in sensor_dict else None
41
+ direct = sensor_dict['dir'] if 'dir' in sensor_dict else None
42
+ return cls(pos, direct)
43
+
44
+ @classmethod
45
+ def from_raw_values(cls, x=0, y=0, z=0, dx=0, dy=0, dz=1):
46
+ """Create a sensor from 6 values.
47
+
48
+ x, y, z are the position of the point and dx, dy and dz is the direction.
49
+ """
50
+ return cls((x, y, z), (dx, dy, dz))
51
+
52
+ @property
53
+ def pos(self):
54
+ """Get or set the position of the sensor as a tuple of 3 (x, y, z) numbers."""
55
+ return self._pos
56
+
57
+ @pos.setter
58
+ def pos(self, value):
59
+ self._pos = typing.tuple_with_length(value) if value is not None else (0, 0, 0)
60
+
61
+ @property
62
+ def dir(self):
63
+ """Get or set the dir of the sensor as a tuple of 3 (x, y, z) numbers."""
64
+ return self._dir
65
+
66
+ @dir.setter
67
+ def dir(self, value):
68
+ self._dir = typing.tuple_with_length(value) if value is not None else (0, 0, 1)
69
+
70
+ def move(self, moving_vec):
71
+ """Move this sensor along a vector.
72
+
73
+ Args:
74
+ moving_vec: A ladybug_geometry Vector3D with the direction and distance
75
+ to move the sensor.
76
+ """
77
+ self.pos = tuple(pv.Point3D(*self.pos).move(moving_vec))
78
+
79
+ def rotate(self, axis, angle, origin):
80
+ """Rotate this sensor by a certain angle around an axis and origin.
81
+
82
+ Args:
83
+ axis: Rotation axis as a Vector3D.
84
+ angle: An angle for rotation in degrees.
85
+ origin: A ladybug_geometry Point3D for the origin around which the
86
+ object will be rotated.
87
+ """
88
+ rad_angle = math.radians(angle)
89
+ self.pos = tuple(pv.Point3D(*self.pos).rotate(axis, rad_angle, origin))
90
+ self.dir = tuple(pv.Vector3D(*self.dir).rotate(axis, rad_angle))
91
+
92
+ def rotate_xy(self, angle, origin):
93
+ """Rotate this sensor counterclockwise in the world XY plane by a certain angle.
94
+
95
+ Args:
96
+ angle: An angle in degrees.
97
+ origin: A ladybug_geometry Point3D for the origin around which the
98
+ object will be rotated.
99
+ """
100
+ rad_angle = math.radians(angle)
101
+ self.pos = tuple(pv.Point3D(*self.pos).rotate_xy(rad_angle, origin))
102
+ self.dir = tuple(pv.Vector3D(*self.dir).rotate_xy(rad_angle))
103
+
104
+ def reflect(self, plane):
105
+ """Reflect this sensor across a plane.
106
+
107
+ Args:
108
+ plane: A ladybug_geometry Plane across which the object will
109
+ be reflected.
110
+ """
111
+ self.pos = tuple(pv.Point3D(*self.pos).reflect(plane.n, plane.o))
112
+ self.dir = tuple(pv.Vector3D(*self.dir).reflect(plane.n))
113
+
114
+ def scale(self, factor, origin=None):
115
+ """Scale this sensor by a factor from an origin point.
116
+
117
+ Args:
118
+ factor: A number representing how much the object should be scaled.
119
+ origin: A ladybug_geometry Point3D representing the origin from which
120
+ to scale. If None, it will be scaled from the World origin (0, 0, 0).
121
+ """
122
+ self.pos = tuple(pv.Point3D(*self.pos).scale(factor, origin))
123
+
124
+ def duplicate(self):
125
+ """Duplicate the sensor."""
126
+ return Sensor(self.pos, self.dir)
127
+
128
+ def ToString(self):
129
+ """Overwrite .NET ToString."""
130
+ return self.__repr__()
131
+
132
+ def to_radiance(self):
133
+ """Return Radiance string for a test point."""
134
+ return '%s %s' % (
135
+ ' '.join(str(v) for v in self.pos),
136
+ ' '.join(str(v) for v in self.dir)
137
+ )
138
+
139
+ def to_dict(self):
140
+ """Get the sensor as a dictionary.
141
+
142
+ .. code-block:: python
143
+
144
+ {
145
+ 'pos': [0, 0, 0], # array of 3 numbers for the sensor position
146
+ 'dir': [0, 0, 1] # array of 3 numbers for the sensor direction
147
+ }
148
+ """
149
+ return {'pos': self.pos, 'dir': self.dir}
150
+
151
+ def __key(self):
152
+ """A tuple based on the object properties, useful for hashing."""
153
+ return (hash(self.pos), hash(self.dir))
154
+
155
+ def __hash__(self):
156
+ return hash(self.__key())
157
+
158
+ def __eq__(self, other):
159
+ return isinstance(other, Sensor) and self.__key() == other.__key()
160
+
161
+ def __ne__(self, value):
162
+ return not self.__eq__(value)
163
+
164
+ def __repr__(self):
165
+ """Get the string representation of the sensor grid."""
166
+ return self.to_radiance()