dragonfly-display 0.3.7__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.
- dragonfly_display/__init__.py +2 -0
- dragonfly_display/__main__.py +4 -0
- dragonfly_display/_extend_dragonfly.py +10 -0
- dragonfly_display/cli/__init__.py +537 -0
- dragonfly_display/model.py +189 -0
- dragonfly_display-0.3.7.dist-info/METADATA +97 -0
- dragonfly_display-0.3.7.dist-info/RECORD +11 -0
- dragonfly_display-0.3.7.dist-info/WHEEL +5 -0
- dragonfly_display-0.3.7.dist-info/entry_points.txt +2 -0
- dragonfly_display-0.3.7.dist-info/licenses/LICENSE +661 -0
- dragonfly_display-0.3.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
# import the core dragonfly modules
|
|
3
|
+
from dragonfly.model import Model
|
|
4
|
+
|
|
5
|
+
# import the extension functions
|
|
6
|
+
from .model import model_to_vis_set, model_comparison_to_vis_set
|
|
7
|
+
|
|
8
|
+
# inject the methods onto the classes
|
|
9
|
+
Model.to_vis_set = model_to_vis_set
|
|
10
|
+
Model.to_vis_set_comparison = model_comparison_to_vis_set
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
"""dragonfly-display commands."""
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
import logging
|
|
6
|
+
import json
|
|
7
|
+
import base64
|
|
8
|
+
import pickle
|
|
9
|
+
import tempfile
|
|
10
|
+
import uuid
|
|
11
|
+
|
|
12
|
+
from ladybug.color import Color
|
|
13
|
+
from honeybee_display.attr import FaceAttribute, RoomAttribute
|
|
14
|
+
|
|
15
|
+
from dragonfly.model import Model
|
|
16
|
+
from dragonfly.cli import main
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# command group for all display extension commands.
|
|
23
|
+
@click.group(help='dragonfly display commands.')
|
|
24
|
+
@click.version_option()
|
|
25
|
+
def display():
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@display.command('model-to-vis')
|
|
30
|
+
@click.argument('model-file', type=click.Path(
|
|
31
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
32
|
+
@click.option(
|
|
33
|
+
'--multiplier/--full-geometry', ' /-fg', help='Flag to note if the '
|
|
34
|
+
'multipliers on each Building story should be passed along to the '
|
|
35
|
+
'generated Honeybee Room objects or if full geometry objects should be '
|
|
36
|
+
'written for each story in the building.', default=True, show_default=True)
|
|
37
|
+
@click.option(
|
|
38
|
+
'--plenum/--no-plenum', '-p/-np', help='Flag to indicate whether '
|
|
39
|
+
'ceiling/floor plenum depths assigned to Room2Ds should generate '
|
|
40
|
+
'distinct 3D Rooms in the translation.', default=True, show_default=True)
|
|
41
|
+
@click.option(
|
|
42
|
+
'--no-ceil-adjacency/--ceil-adjacency', ' /-a', help='Flag to indicate '
|
|
43
|
+
'whether adjacencies should be solved between interior stories when '
|
|
44
|
+
'Room2D floor and ceiling geometries are coplanar. This ensures '
|
|
45
|
+
'that Surface boundary conditions are used instead of Adiabatic ones.',
|
|
46
|
+
default=True, show_default=True)
|
|
47
|
+
@click.option(
|
|
48
|
+
'--merge-method', help='Text to describe how the Room2Ds should '
|
|
49
|
+
'be merged into individual Rooms during the translation. Specifying a '
|
|
50
|
+
'value here can be an effective way to reduce the number of Room '
|
|
51
|
+
'volumes in the resulting 3D Honeybee Model and, ultimately, yield '
|
|
52
|
+
'a faster simulation time in the destination engine with fewer results '
|
|
53
|
+
'to manage. Choose from: None, Zones, PlenumZones, Stories, PlenumStories.',
|
|
54
|
+
type=str, default='None', show_default=True)
|
|
55
|
+
@click.option(
|
|
56
|
+
'--color-by', '-c', help='Text for the property that dictates the colors of '
|
|
57
|
+
'the Model geometry. Choose from: type, boundary_condition, none. '
|
|
58
|
+
'If none, only a wireframe of the Model will be generated (assuming the '
|
|
59
|
+
'--exclude-wireframe option is not used). None is useful when the primary '
|
|
60
|
+
'purpose of the visualization is to display results in relation to the Model '
|
|
61
|
+
'geometry or display some room_attr or face_attr as an AnalysisGeometry '
|
|
62
|
+
'or Text labels.', type=str, default='type', show_default=True)
|
|
63
|
+
@click.option(
|
|
64
|
+
'--wireframe/--exclude-wireframe', ' /-xw', help='Flag to note whether a '
|
|
65
|
+
'ContextGeometry dedicated to the Model Wireframe (in DisplayLineSegment3D) should '
|
|
66
|
+
'be included in the output VisualizationSet.', default=True, show_default=True)
|
|
67
|
+
@click.option(
|
|
68
|
+
'--mesh/--faces', help='Flag to note whether the colored model geometries should '
|
|
69
|
+
'be represented with DisplayMesh3D objects instead of DisplayFace3D objects. '
|
|
70
|
+
'Meshes can usually be rendered faster and they scale well for large models '
|
|
71
|
+
'but all geometry is triangulated (meaning that their wireframe in certain '
|
|
72
|
+
'platforms might not appear ideal).', default=True, show_default=True)
|
|
73
|
+
@click.option(
|
|
74
|
+
'--show-color-by/--hide-color-by', ' /-hcb', help='Flag to note whether the '
|
|
75
|
+
'color-by geometry should be hidden or shown by default. Hiding the color-by '
|
|
76
|
+
'geometry is useful when the primary purpose of the visualization is to display '
|
|
77
|
+
'grid-data or room/face attributes but it is still desirable to have the option '
|
|
78
|
+
'to turn on the geometry.', default=True, show_default=True)
|
|
79
|
+
@click.option(
|
|
80
|
+
'--room-attr', '-r', help='An optional text string of an attribute that the Model '
|
|
81
|
+
'Rooms have, which will be used to construct a visualization of this attribute '
|
|
82
|
+
'in the resulting VisualizationSet. Multiple instances of this option can be passed '
|
|
83
|
+
'and a separate VisualizationData will be added to the AnalysisGeometry that '
|
|
84
|
+
'represents the attribute in the resulting VisualizationSet (or a separate '
|
|
85
|
+
'ContextGeometry layer if --text-attr is True). Room attributes '
|
|
86
|
+
'input here can have . that separates the nested attributes from '
|
|
87
|
+
'one another. For example, properties.energy.program_type.',
|
|
88
|
+
type=click.STRING, multiple=True, default=None, show_default=True)
|
|
89
|
+
@click.option(
|
|
90
|
+
'--face-attr', '-f', help='An optional text string of an attribute that the Model '
|
|
91
|
+
'Faces have, which will be used to construct a visualization of this attribute in '
|
|
92
|
+
'the resulting VisualizationSet. Multiple instances of this option can be passed and'
|
|
93
|
+
' a separate VisualizationData will be added to the AnalysisGeometry that '
|
|
94
|
+
'represents the attribute in the resulting VisualizationSet (or a separate '
|
|
95
|
+
'ContextGeometry layer if --text-attr is True). Face attributes '
|
|
96
|
+
'input here can have . that separates the nested attributes from '
|
|
97
|
+
'one another. For example, properties.energy.construction.',
|
|
98
|
+
type=click.STRING, multiple=True, default=None, show_default=True)
|
|
99
|
+
@click.option(
|
|
100
|
+
'--color-attr/--text-attr', help='Flag to note whether to note whether the '
|
|
101
|
+
'input room-attr and face-attr should be expressed as a colored AnalysisGeometry '
|
|
102
|
+
'or a ContextGeometry as text labels.', default=True, show_default=True)
|
|
103
|
+
@click.option(
|
|
104
|
+
'--grid-display-mode', '-m', help='Text that dictates how the ContextGeometry '
|
|
105
|
+
'for Model SensorGrids should display in the resulting visualization. The Default '
|
|
106
|
+
'option will draw sensor points whenever there is no grid_data_path and will not '
|
|
107
|
+
'draw them at all when grid data is provided, assuming the AnalysisGeometry of '
|
|
108
|
+
'the grids is sufficient. Choose from: Default, Points, Wireframe, Surface, '
|
|
109
|
+
'SurfaceWithEdges, None.',
|
|
110
|
+
type=str, default='Default', show_default=True)
|
|
111
|
+
@click.option(
|
|
112
|
+
'--show-grid/--hide-grid', ' /-hg', help='Flag to note whether the SensorGrid '
|
|
113
|
+
'ContextGeometry should be hidden or shown by default.',
|
|
114
|
+
default=True, show_default=True)
|
|
115
|
+
@click.option(
|
|
116
|
+
'--output-format', '-of', help='Text for the output format of the resulting '
|
|
117
|
+
'VisualizationSet File (.vsf). Choose from: vsf, json, pkl, vtkjs, html. Note '
|
|
118
|
+
'that both vsf and json refer to the the JSON version of the VisualizationSet '
|
|
119
|
+
'file and the distinction between the two is only for help in coordinating file '
|
|
120
|
+
'extensions (since both .vsf and .json can be acceptable). Also note that '
|
|
121
|
+
'ladybug-vtk must be installed in order for the vtkjs or html options to be usable '
|
|
122
|
+
'and the html format refers to a web page with the vtkjs file embedded within it.',
|
|
123
|
+
type=str, default='vsf', show_default=True)
|
|
124
|
+
@click.option(
|
|
125
|
+
'--output-file', help='Optional file to output the string of the visualization '
|
|
126
|
+
'file contents. By default, it will be printed out to stdout.',
|
|
127
|
+
type=click.File('w'), default='-', show_default=True)
|
|
128
|
+
def model_to_vis_set_cli(
|
|
129
|
+
model_file, multiplier, plenum, no_ceil_adjacency, merge_method,
|
|
130
|
+
color_by, wireframe, mesh, show_color_by,
|
|
131
|
+
room_attr, face_attr, color_attr, grid_display_mode, show_grid,
|
|
132
|
+
output_format, output_file
|
|
133
|
+
):
|
|
134
|
+
"""Translate a Dragonfly Model file (.dfjson) to a VisualizationSet file (.vsf).
|
|
135
|
+
|
|
136
|
+
This command can also optionally translate the Dragonfly Model to a .vtkjs file,
|
|
137
|
+
which can be visualized in the open source Visual ToolKit (VTK) platform.
|
|
138
|
+
|
|
139
|
+
\b
|
|
140
|
+
Args:
|
|
141
|
+
model_file: Full path to a Dragonfly Model (DFJSON or DFpkl) file.
|
|
142
|
+
"""
|
|
143
|
+
try:
|
|
144
|
+
# process all of the CLI input so that it can be passed to the function
|
|
145
|
+
full_geometry = not multiplier
|
|
146
|
+
no_plenum = not plenum
|
|
147
|
+
ceil_adjacency = not no_ceil_adjacency
|
|
148
|
+
exclude_wireframe = not wireframe
|
|
149
|
+
faces = not mesh
|
|
150
|
+
hide_color_by = not show_color_by
|
|
151
|
+
room_attrs = [] if len(room_attr) == 0 or room_attr[0] == '' else room_attr
|
|
152
|
+
face_attrs = [] if len(face_attr) == 0 or face_attr[0] == '' else face_attr
|
|
153
|
+
text_labels = not color_attr
|
|
154
|
+
hide_grid = not show_grid
|
|
155
|
+
|
|
156
|
+
# pass the input to the function in order to convert the model
|
|
157
|
+
model_to_vis_set(
|
|
158
|
+
model_file, full_geometry, no_plenum, ceil_adjacency, merge_method,
|
|
159
|
+
color_by, exclude_wireframe, faces, hide_color_by,
|
|
160
|
+
room_attrs, face_attrs, text_labels, grid_display_mode,
|
|
161
|
+
hide_grid, output_format, output_file)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
_logger.exception('Failed to translate Model to VisualizationSet.\n{}'.format(e))
|
|
164
|
+
sys.exit(1)
|
|
165
|
+
else:
|
|
166
|
+
sys.exit(0)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def model_to_vis_set(
|
|
170
|
+
model_file, full_geometry=False, no_plenum=False, ceil_adjacency=False,
|
|
171
|
+
merge_method='Default', color_by='type', exclude_wireframe=False,
|
|
172
|
+
faces=False, hide_color_by=False,
|
|
173
|
+
room_attr=(), face_attr=(), text_attr=False, grid_display_mode='Default',
|
|
174
|
+
hide_grid=False, output_format='vsf', output_file=None,
|
|
175
|
+
multiplier=True, plenum=True, no_ceil_adjacency=True, wireframe=True, mesh=True,
|
|
176
|
+
show_color_by=True, color_attr=True, show_grid=True
|
|
177
|
+
):
|
|
178
|
+
"""Translate a Dragonfly Model file (.dfjson) to a VisualizationSet file (.vsf).
|
|
179
|
+
|
|
180
|
+
This function can also optionally translate the Dragonfly Model to a .vtkjs file,
|
|
181
|
+
which can be visualized in the open source Visual ToolKit (VTK) platform.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
model_file: Path to a Dragonfly Model (DFJSON or DFpkl) file.
|
|
185
|
+
full_geometry: Boolean to note if the multipliers on each Story should
|
|
186
|
+
be passed along to the generated Honeybee Room objects or if full
|
|
187
|
+
geometry objects should be written for each story in the building.
|
|
188
|
+
no_plenum: Boolean to indicate whether ceiling/floor plenum depths
|
|
189
|
+
assigned to Room2Ds should generate distinct 3D Rooms in the
|
|
190
|
+
translation. (Default: False).
|
|
191
|
+
ceil_adjacency: Boolean to indicate whether adjacencies should be solved
|
|
192
|
+
between interior stories when Room2D floor and ceiling geometries
|
|
193
|
+
are coplanar. This ensures that Surface boundary conditions are used
|
|
194
|
+
instead of Adiabatic ones.
|
|
195
|
+
merge_method: An optional text string to describe how the Room2Ds should
|
|
196
|
+
be merged into individual Rooms during the translation. Specifying a
|
|
197
|
+
value here can be an effective way to reduce the number of Room volumes
|
|
198
|
+
in the resulting Model. Note that Room2Ds will only be merged if they
|
|
199
|
+
form a contiguous volume. Otherwise, there will be multiple Rooms per
|
|
200
|
+
zone or story, each with an integer added at the end of their
|
|
201
|
+
identifiers. Choose from the following options:
|
|
202
|
+
|
|
203
|
+
* None - No merging of Room2Ds will occur
|
|
204
|
+
* Zones - Room2Ds in the same zone will be merged
|
|
205
|
+
* PlenumZones - Only plenums in the same zone will be merged
|
|
206
|
+
* Stories - Rooms in the same story will be merged
|
|
207
|
+
* PlenumStories - Only plenums in the same story will be merged
|
|
208
|
+
|
|
209
|
+
color_by: Text for the property that dictates the colors of the Model
|
|
210
|
+
geometry. Choose from: type, boundary_condition, none. If none, only
|
|
211
|
+
a wireframe of the Model will be generated (assuming the exclude_wireframe
|
|
212
|
+
option is not used). None is useful when the primary purpose of the
|
|
213
|
+
visualization is to display results in relation to the Model geometry
|
|
214
|
+
or display some room_attr or face_attr as an AnalysisGeometry or Text labels.
|
|
215
|
+
exclude_wireframe: Boolean to note whether a ContextGeometry dedicated to
|
|
216
|
+
the Model Wireframe (in DisplayLineSegment3D) should be included in
|
|
217
|
+
the output visualization.
|
|
218
|
+
faces: Boolean to note whether the colored model geometries should be
|
|
219
|
+
represented with DisplayMesh3D objects instead of DisplayFace3D objects.
|
|
220
|
+
Meshes can usually be rendered faster and they scale well for large models
|
|
221
|
+
but all geometry is triangulated (meaning that their wireframe in certain
|
|
222
|
+
platforms might not appear ideal).
|
|
223
|
+
hide_color_by: Boolean to note whether the color-by geometry should be
|
|
224
|
+
hidden or shown by default. Hiding the color-by geometry is useful
|
|
225
|
+
when the primary purpose of the visualization is to display grid_data
|
|
226
|
+
or room/face attributes but it is still desirable to have the option
|
|
227
|
+
to turn on the geometry.
|
|
228
|
+
room_attr: An optional text string of an attribute that the Model Rooms
|
|
229
|
+
have, which will be used to construct a visualization of this attribute
|
|
230
|
+
in the resulting VisualizationSet. A list of text can also
|
|
231
|
+
be passed and a separate VisualizationData will be added to the
|
|
232
|
+
AnalysisGeometry that represents the attribute in the resulting
|
|
233
|
+
VisualizationSet (or a separate ContextGeometry layer if text_attr
|
|
234
|
+
is True). Room attributes input here can have . that separates the nested
|
|
235
|
+
attributes from one another. For example, properties.energy.program_type.
|
|
236
|
+
face_attr: An optional text string of an attribute that the Model Faces
|
|
237
|
+
have, which will be used to construct a visualization of this attribute
|
|
238
|
+
in the resulting VisualizationSet. A list of text can also be passed and
|
|
239
|
+
a separate VisualizationData will be added to the AnalysisGeometry that '
|
|
240
|
+
represents the attribute in the resulting VisualizationSet (or a separate '
|
|
241
|
+
ContextGeometry layer if text_attr is True). Face attributes input
|
|
242
|
+
here can have . that separates the nested attributes from one another.
|
|
243
|
+
For example, properties.energy.construction.
|
|
244
|
+
text_attr: Boolean to note whether to note whether the input room_attr
|
|
245
|
+
and face_attr should be expressed as a colored AnalysisGeometry
|
|
246
|
+
or a ContextGeometry as text labels.
|
|
247
|
+
grid_display_mode: Text that dictates how the ContextGeometry for Model
|
|
248
|
+
SensorGrids should display in the resulting visualization. The Default
|
|
249
|
+
option will draw sensor points whenever there is no grid_data_path
|
|
250
|
+
and will not draw them at all when grid data is provided, assuming
|
|
251
|
+
the AnalysisGeometry of the grids is sufficient. Choose from: Default,
|
|
252
|
+
Points, Wireframe, Surface, SurfaceWithEdges, None.
|
|
253
|
+
hide_grid: Boolean to note whether the SensorGrid ContextGeometry should
|
|
254
|
+
be hidden or shown by default.
|
|
255
|
+
output_format: Text for the output format of the resulting VisualizationSet
|
|
256
|
+
File (.vsf). Choose from: vsf, json, pkl, vtkjs, html. Note that both
|
|
257
|
+
vsf and json refer to the the JSON version of the VisualizationSet
|
|
258
|
+
file and the distinction between the two is only for help in
|
|
259
|
+
coordinating file extensions (since both .vsf and .json can be
|
|
260
|
+
acceptable). Also note that ladybug-vtk must be installed in order
|
|
261
|
+
for the vtkjs or html options to be usable and the html format
|
|
262
|
+
refers to a web page with the vtkjs file embedded within it.
|
|
263
|
+
output_file: Optional file to output the string of the visualization
|
|
264
|
+
file contents. If None, the string will simply be returned from
|
|
265
|
+
this method.
|
|
266
|
+
"""
|
|
267
|
+
# load the model object and process simpler attributes
|
|
268
|
+
model_obj = Model.from_file(model_file)
|
|
269
|
+
room_attrs = [room_attr] if isinstance(room_attr, str) else room_attr
|
|
270
|
+
face_attrs = [face_attr] if isinstance(face_attr, str) else face_attr
|
|
271
|
+
wireframe = not exclude_wireframe
|
|
272
|
+
mesh = not faces
|
|
273
|
+
color_attr = not text_attr
|
|
274
|
+
reset_coordinates = True if output_format.lower() in ('vtkjs', 'html') else False
|
|
275
|
+
|
|
276
|
+
# load the room and face attributes
|
|
277
|
+
face_attributes = []
|
|
278
|
+
for fa in face_attrs:
|
|
279
|
+
faa = FaceAttribute(name=fa, attrs=[fa], color=color_attr, text=text_attr)
|
|
280
|
+
face_attributes.append(faa)
|
|
281
|
+
room_attributes = []
|
|
282
|
+
for ra in room_attrs:
|
|
283
|
+
raa = RoomAttribute(name=ra, attrs=[ra], color=color_attr, text=text_attr)
|
|
284
|
+
room_attributes.append(raa)
|
|
285
|
+
|
|
286
|
+
# create the VisualizationSet
|
|
287
|
+
multiplier = not full_geometry
|
|
288
|
+
vis_set = model_obj.to_vis_set(
|
|
289
|
+
multiplier, no_plenum, ceil_adjacency, merge_method=merge_method,
|
|
290
|
+
color_by=color_by, include_wireframe=wireframe, use_mesh=mesh,
|
|
291
|
+
hide_color_by=hide_color_by,
|
|
292
|
+
room_attrs=room_attributes, face_attrs=face_attributes,
|
|
293
|
+
grid_display_mode=grid_display_mode, hide_grid=hide_grid,
|
|
294
|
+
reset_coordinates=reset_coordinates
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# output the VisualizationSet through the CLI
|
|
298
|
+
return _output_vis_set_to_format(vis_set, output_format, output_file)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@display.command('model-comparison-to-vis')
|
|
302
|
+
@click.argument('base-model-file', type=click.Path(
|
|
303
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
304
|
+
@click.argument('incoming-model-file', type=click.Path(
|
|
305
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
306
|
+
@click.option(
|
|
307
|
+
'--multiplier/--full-geometry', ' /-fg', help='Flag to note if the '
|
|
308
|
+
'multipliers on each Building story should be passed along to the '
|
|
309
|
+
'generated Honeybee Room objects or if full geometry objects should be '
|
|
310
|
+
'written for each story in the building.', default=True, show_default=True)
|
|
311
|
+
@click.option(
|
|
312
|
+
'--plenum/--no-plenum', '-p/-np', help='Flag to indicate whether '
|
|
313
|
+
'ceiling/floor plenum depths assigned to Room2Ds should generate '
|
|
314
|
+
'distinct 3D Rooms in the translation.', default=True, show_default=True)
|
|
315
|
+
@click.option(
|
|
316
|
+
'--no-ceil-adjacency/--ceil-adjacency', ' /-a', help='Flag to indicate '
|
|
317
|
+
'whether adjacencies should be solved between interior stories when '
|
|
318
|
+
'Room2D floor and ceiling geometries are coplanar. This ensures '
|
|
319
|
+
'that Surface boundary conditions are used instead of Adiabatic ones.',
|
|
320
|
+
default=True, show_default=True)
|
|
321
|
+
@click.option(
|
|
322
|
+
'--merge-method', help='Text to describe how the Room2Ds should '
|
|
323
|
+
'be merged into individual Rooms during the translation. Specifying a '
|
|
324
|
+
'value here can be an effective way to reduce the number of Room '
|
|
325
|
+
'volumes in the resulting 3D Honeybee Model and, ultimately, yield '
|
|
326
|
+
'a faster simulation time in the destination engine with fewer results '
|
|
327
|
+
'to manage. Choose from: None, Zones, PlenumZones, Stories, PlenumStories.',
|
|
328
|
+
type=str, default='None', show_default=True)
|
|
329
|
+
@click.option(
|
|
330
|
+
'--base-color', '-bc', help='An optional hexadecimal code for the color '
|
|
331
|
+
'of the base model.', type=str, default='#74eded', show_default=True)
|
|
332
|
+
@click.option(
|
|
333
|
+
'--incoming-color', '-ic', help='An optional hexadecimal code for the color '
|
|
334
|
+
'of the incoming model.', type=str, default='#ed7474', show_default=True)
|
|
335
|
+
@click.option(
|
|
336
|
+
'--output-format', '-of', help='Text for the output format of the resulting '
|
|
337
|
+
'VisualizationSet File (.vsf). Choose from: vsf, json, pkl, vtkjs, html. Note '
|
|
338
|
+
'that both vsf and json refer to the the JSON version of the VisualizationSet '
|
|
339
|
+
'file and the distinction between the two is only for help in coordinating file '
|
|
340
|
+
'extensions (since both .vsf and .json can be acceptable). Also note that '
|
|
341
|
+
'ladybug-vtk must be installed in order for the vtkjs or html options to be usable '
|
|
342
|
+
'and the html format refers to a web page with the vtkjs file embedded within it.',
|
|
343
|
+
type=str, default='vsf', show_default=True)
|
|
344
|
+
@click.option(
|
|
345
|
+
'--output-file', help='Optional file to output the he string of the visualization '
|
|
346
|
+
'file contents. By default, it will be printed out to stdout',
|
|
347
|
+
type=click.File('w'), default='-', show_default=True)
|
|
348
|
+
def model_comparison_to_vis_set_cli(
|
|
349
|
+
base_model_file, incoming_model_file, multiplier, plenum, no_ceil_adjacency,
|
|
350
|
+
merge_method, base_color, incoming_color, output_format, output_file
|
|
351
|
+
):
|
|
352
|
+
"""Translate two Dragonfly Models to be compared to a VisualizationSet.
|
|
353
|
+
|
|
354
|
+
This command can also optionally translate the Dragonfly Model to a .vtkjs file,
|
|
355
|
+
which can be visualized in the open source Visual ToolKit (VTK) platform.
|
|
356
|
+
|
|
357
|
+
\b
|
|
358
|
+
Args:
|
|
359
|
+
base_model_file: Full path to a Dragonfly Model (DFJSON or HBpkl) file
|
|
360
|
+
representing the base model used in the comparison. Typically, this
|
|
361
|
+
is the model with more data to be kept.
|
|
362
|
+
incoming_model_file: Full path to a Dragonfly Model (DFJSON or HBpkl) file
|
|
363
|
+
representing the incoming model used in the comparison. Typically,
|
|
364
|
+
this is the model with new data to be evaluated against the base model.
|
|
365
|
+
"""
|
|
366
|
+
try:
|
|
367
|
+
# process all of the CLI input so that it can be passed to the function
|
|
368
|
+
full_geometry = not multiplier
|
|
369
|
+
no_plenum = not plenum
|
|
370
|
+
ceil_adjacency = not no_ceil_adjacency
|
|
371
|
+
|
|
372
|
+
# pass the input to the function in order to convert the model
|
|
373
|
+
model_comparison_to_vis_set(
|
|
374
|
+
base_model_file, incoming_model_file, full_geometry, no_plenum,
|
|
375
|
+
ceil_adjacency, merge_method, base_color, incoming_color,
|
|
376
|
+
output_format, output_file
|
|
377
|
+
)
|
|
378
|
+
except Exception as e:
|
|
379
|
+
_logger.exception('Failed to translate Model to VisualizationSet.\n{}'.format(e))
|
|
380
|
+
sys.exit(1)
|
|
381
|
+
else:
|
|
382
|
+
sys.exit(0)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def model_comparison_to_vis_set(
|
|
386
|
+
base_model_file, incoming_model_file, full_geometry=False, no_plenum=False,
|
|
387
|
+
ceil_adjacency=False, merge_method='None',
|
|
388
|
+
base_color='#74eded', incoming_color='#ed7474',
|
|
389
|
+
output_format='vsf', output_file=None,
|
|
390
|
+
multiplier=True, plenum=True, no_ceil_adjacency=True
|
|
391
|
+
):
|
|
392
|
+
"""Translate two Honeybee Models to be compared to a VisualizationSet.
|
|
393
|
+
|
|
394
|
+
This command can also optionally translate the Honeybee Model to a .vtkjs file,
|
|
395
|
+
which can be visualized in the open source Visual ToolKit (VTK) platform.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
base_model_file: Full path to a Honeybee Model (HBJSON or HBpkl) file
|
|
399
|
+
representing the base model used in the comparison. Typically, this
|
|
400
|
+
is the model with more data to be kept.
|
|
401
|
+
incoming_model_file: Full path to a Honeybee Model (HBJSON or HBpkl) file
|
|
402
|
+
representing the incoming model used in the comparison. Typically,
|
|
403
|
+
this is the model with new data to be evaluated against the base model.
|
|
404
|
+
full_geometry: Boolean to note if the multipliers on each Story should
|
|
405
|
+
be passed along to the generated Honeybee Room objects or if full
|
|
406
|
+
geometry objects should be written for each story in the building.
|
|
407
|
+
no_plenum: Boolean to indicate whether ceiling/floor plenum depths
|
|
408
|
+
assigned to Room2Ds should generate distinct 3D Rooms in the
|
|
409
|
+
translation. (Default: False).
|
|
410
|
+
ceil_adjacency: Boolean to indicate whether adjacencies should be solved
|
|
411
|
+
between interior stories when Room2D floor and ceiling geometries
|
|
412
|
+
are coplanar. This ensures that Surface boundary conditions are used
|
|
413
|
+
instead of Adiabatic ones.
|
|
414
|
+
merge_method: An optional text string to describe how the Room2Ds should
|
|
415
|
+
be merged into individual Rooms during the translation. Specifying a
|
|
416
|
+
value here can be an effective way to reduce the number of Room volumes
|
|
417
|
+
in the resulting Model. Note that Room2Ds will only be merged if they
|
|
418
|
+
form a contiguous volume. Otherwise, there will be multiple Rooms per
|
|
419
|
+
zone or story, each with an integer added at the end of their
|
|
420
|
+
identifiers. Choose from the following options:
|
|
421
|
+
|
|
422
|
+
* None - No merging of Room2Ds will occur
|
|
423
|
+
* Zones - Room2Ds in the same zone will be merged
|
|
424
|
+
* PlenumZones - Only plenums in the same zone will be merged
|
|
425
|
+
* Stories - Rooms in the same story will be merged
|
|
426
|
+
* PlenumStories - Only plenums in the same story will be merged
|
|
427
|
+
|
|
428
|
+
base_color: An optional hexadecimal code for the color of the base
|
|
429
|
+
model. (Default: #74eded).
|
|
430
|
+
incoming_color: An optional hexadecimal code for the color of the incoming
|
|
431
|
+
model. (Default: #ed7474).
|
|
432
|
+
output_format: Text for the output format of the resulting VisualizationSet
|
|
433
|
+
File (.vsf). Choose from: vsf, json, pkl, vtkjs, html. Note that both
|
|
434
|
+
vsf and json refer to the the JSON version of the VisualizationSet
|
|
435
|
+
file and the distinction between the two is only for help in
|
|
436
|
+
coordinating file extensions (since both .vsf and .json can be
|
|
437
|
+
acceptable). Also note that ladybug-vtk must be installed in order
|
|
438
|
+
for the vtkjs or html options to be usable and the html format
|
|
439
|
+
refers to a web page with the vtkjs file embedded within it.
|
|
440
|
+
output_file: Optional file to output the string of the visualization
|
|
441
|
+
file contents. If None, the string will simply be returned from
|
|
442
|
+
this method.
|
|
443
|
+
"""
|
|
444
|
+
# load the model objects and process the colors from the hex codes
|
|
445
|
+
base_model = Model.from_file(base_model_file)
|
|
446
|
+
incoming_model = Model.from_file(incoming_model_file)
|
|
447
|
+
base_color = Color.from_hex(base_color)
|
|
448
|
+
incoming_color = Color.from_hex(incoming_color)
|
|
449
|
+
base_color.a = 128
|
|
450
|
+
incoming_color.a = 128
|
|
451
|
+
reset_coordinates = True if output_format.lower() in ('vtkjs', 'html') else False
|
|
452
|
+
|
|
453
|
+
# create the VisualizationSet
|
|
454
|
+
multiplier = not full_geometry
|
|
455
|
+
vis_set = base_model.to_vis_set_comparison(
|
|
456
|
+
incoming_model, multiplier, no_plenum, ceil_adjacency, merge_method,
|
|
457
|
+
base_color, incoming_color, reset_coordinates=reset_coordinates)
|
|
458
|
+
|
|
459
|
+
# output the VisualizationSet through the CLI
|
|
460
|
+
return _output_vis_set_to_format(vis_set, output_format, output_file)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def _output_vis_set_to_format(vis_set, output_format, output_file):
|
|
464
|
+
"""Process a VisualizationSet for output from the CLI.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
vis_set: The VisualizationSet to be output form the CLI.
|
|
468
|
+
output_format: Text for the output format of the resulting VisualizationSet File.
|
|
469
|
+
output_file: Optional file to output the string of the visualization
|
|
470
|
+
file contents. If None, the string will simply be returned from
|
|
471
|
+
this method.
|
|
472
|
+
"""
|
|
473
|
+
# output the visualization in the correct format
|
|
474
|
+
output_format = output_format.lower()
|
|
475
|
+
if output_format in ('vsf', 'json'):
|
|
476
|
+
if output_file is None:
|
|
477
|
+
return json.dumps(vis_set.to_dict())
|
|
478
|
+
elif isinstance(output_file, str):
|
|
479
|
+
with open(output_file, 'w') as of:
|
|
480
|
+
of.write(json.dumps(vis_set.to_dict()))
|
|
481
|
+
else:
|
|
482
|
+
output_file.write(json.dumps(vis_set.to_dict()))
|
|
483
|
+
elif output_format == 'pkl':
|
|
484
|
+
if output_file is None:
|
|
485
|
+
return pickle.dumps(vis_set.to_dict())
|
|
486
|
+
elif isinstance(output_file, str):
|
|
487
|
+
with open(output_file, 'w') as of:
|
|
488
|
+
of.write(pickle.dumps(vis_set.to_dict()))
|
|
489
|
+
elif output_file.name == '<stdout>':
|
|
490
|
+
output_file.write(pickle.dumps(vis_set.to_dict()))
|
|
491
|
+
else:
|
|
492
|
+
out_folder, out_file = os.path.split(output_file.name)
|
|
493
|
+
vis_set.to_pkl(out_file, out_folder)
|
|
494
|
+
elif output_format in ('vtkjs', 'html'):
|
|
495
|
+
if output_file is None or (not isinstance(output_file, str)
|
|
496
|
+
and output_file.name == '<stdout>'):
|
|
497
|
+
# get a temporary file
|
|
498
|
+
out_file = str(uuid.uuid4())[:6]
|
|
499
|
+
out_folder = tempfile.gettempdir()
|
|
500
|
+
else:
|
|
501
|
+
f_path = output_file if isinstance(output_file, str) else output_file.name
|
|
502
|
+
out_folder, out_file = os.path.split(f_path)
|
|
503
|
+
if out_file.endswith('.vtkjs'):
|
|
504
|
+
out_file = out_file[:-6]
|
|
505
|
+
elif out_file.endswith('.html'):
|
|
506
|
+
out_file = out_file[:-5]
|
|
507
|
+
try:
|
|
508
|
+
if output_format == 'vtkjs':
|
|
509
|
+
vis_set.to_vtkjs(output_folder=out_folder, file_name=out_file)
|
|
510
|
+
if output_format == 'html':
|
|
511
|
+
vis_set.to_html(output_folder=out_folder, file_name=out_file)
|
|
512
|
+
except AttributeError as ae:
|
|
513
|
+
raise AttributeError(
|
|
514
|
+
'Ladybug-vtk must be installed in order to use --output-format '
|
|
515
|
+
'vtkjs.\n{}'.format(ae))
|
|
516
|
+
if output_file is None or (not isinstance(output_file, str)
|
|
517
|
+
and output_file.name == '<stdout>'):
|
|
518
|
+
# load file contents
|
|
519
|
+
out_file_ext = out_file + '.' + output_format
|
|
520
|
+
out_file_path = os.path.join(out_folder, out_file_ext)
|
|
521
|
+
if output_format == 'html':
|
|
522
|
+
with open(out_file_path, encoding='utf-8') as of:
|
|
523
|
+
f_contents = of.read()
|
|
524
|
+
else: # vtkjs can only be read as binary
|
|
525
|
+
with open(out_file_path, 'rb') as of:
|
|
526
|
+
f_contents = of.read()
|
|
527
|
+
b = base64.b64encode(f_contents)
|
|
528
|
+
f_contents = b.decode('utf-8')
|
|
529
|
+
if output_file is None:
|
|
530
|
+
return f_contents
|
|
531
|
+
output_file.write(f_contents)
|
|
532
|
+
else:
|
|
533
|
+
raise ValueError('Unrecognized output-format "{}".'.format(output_format))
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
# add display sub-group to dragonfly CLI
|
|
537
|
+
main.add_command(display)
|