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,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()
|