topologicpy 0.8.54__py3-none-any.whl → 0.8.57__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.
- topologicpy/Graph.py +220 -3
- topologicpy/Honeybee.py +527 -2
- topologicpy/Kuzu.py +589 -0
- topologicpy/Vertex.py +78 -48
- topologicpy/version.py +1 -1
- {topologicpy-0.8.54.dist-info → topologicpy-0.8.57.dist-info}/METADATA +1 -1
- {topologicpy-0.8.54.dist-info → topologicpy-0.8.57.dist-info}/RECORD +10 -9
- {topologicpy-0.8.54.dist-info → topologicpy-0.8.57.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.54.dist-info → topologicpy-0.8.57.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.54.dist-info → topologicpy-0.8.57.dist-info}/top_level.txt +0 -0
topologicpy/Honeybee.py
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
# You should have received a copy of the GNU Affero General Public License along with
|
15
15
|
# this program. If not, see <https://www.gnu.org/licenses/>.
|
16
16
|
|
17
|
+
from __future__ import annotations
|
17
18
|
import os
|
18
19
|
import warnings
|
19
20
|
|
@@ -112,6 +113,530 @@ import json
|
|
112
113
|
import topologic_core as topologic
|
113
114
|
|
114
115
|
class Honeybee:
|
116
|
+
@staticmethod
|
117
|
+
def ByHBJSONDictionary(
|
118
|
+
dictionary,
|
119
|
+
includeRooms: bool = True,
|
120
|
+
includeFaces: bool = True,
|
121
|
+
includeShades: bool = True,
|
122
|
+
includeApertures: bool = True,
|
123
|
+
includeDoors: bool = True,
|
124
|
+
includeOrphanedRooms: bool = True,
|
125
|
+
includeOrphanedFaces: bool = True,
|
126
|
+
includeOrphanedShades: bool = True,
|
127
|
+
includeOrphanedApertures: bool = True,
|
128
|
+
includeOrphanedDoors: bool = True,
|
129
|
+
tolerance: float = 0.0001,
|
130
|
+
silent: bool = False):
|
131
|
+
"""
|
132
|
+
Import an HBJSON model from a python dictionary and return a python dictionary. See: https://github.com/ladybug-tools/honeybee-schema/wiki/1.1-Model-Schema
|
133
|
+
|
134
|
+
Parameters
|
135
|
+
----------
|
136
|
+
dictionary : dict
|
137
|
+
The HBJSON model as a Python dictionary (e.g., loaded via ``json.load``).
|
138
|
+
includeRooms : bool, optional
|
139
|
+
If True, parse rooms and attempt to create one ``Cell`` per room. Default is True.
|
140
|
+
includeFaces : bool, optional
|
141
|
+
If True, include top-level planar faces found outside rooms (e.g., at root "faces"). Default is True.
|
142
|
+
includeShades : bool, optional
|
143
|
+
If True, include context/standalone shades (e.g., ``context_geometry.shades``). Default is True.
|
144
|
+
includeApertures : bool, optional
|
145
|
+
If True, include **room** apertures (e.g., windows) as separate ``Face`` objects (not cut from hosts). Default is True.
|
146
|
+
includeDoors : bool, optional
|
147
|
+
If True, include **room** doors as separate ``Face`` objects (not cut from hosts). Default is True.
|
148
|
+
includeOrphanedRooms : bool, optional
|
149
|
+
If True, include the topology of the room when a room fails to close as a ``Cell``. This may be a ``Shell`` or a ``Cluster``. Default is True.
|
150
|
+
includeOrphanedFaces : bool, optional
|
151
|
+
If True, include planar faces listed at the HBJSON root (e.g., "faces"). Default is True.
|
152
|
+
includeOrphanedShades : bool, optional
|
153
|
+
If True, include shades listed at the HBJSON root (e.g., "orphaned_shades"). Default is True.
|
154
|
+
includeOrphanedApertures : bool, optional
|
155
|
+
If True, include apertures listed at the HBJSON root (e.g., "orphaned_apertures"). Default is True.
|
156
|
+
includeOrphanedDoors : bool, optional
|
157
|
+
If True, include doors listed at the HBJSON root (e.g., "orphaned_doors"). Default is True.
|
158
|
+
tolerance : float , optional
|
159
|
+
The desired tolerance. Default is 0.0001.
|
160
|
+
silent : bool , optional
|
161
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
162
|
+
|
163
|
+
Returns
|
164
|
+
-------
|
165
|
+
dict
|
166
|
+
The created cluster of vertices, edges, faces, and cells.
|
167
|
+
- 'rooms': list of Cells (one per successfully closed room)
|
168
|
+
- 'faces': list of Faces (all faces that make up the rooms)
|
169
|
+
- 'shades': list of Faces (all shade faces)
|
170
|
+
- 'apertures': list of Faces (all apertures, never cut from hosts)
|
171
|
+
- 'doors': list of Faces (all doors, never cut from hosts)
|
172
|
+
- 'orphanedRooms': list of Topologies (context/top-level topologies (e.g. Shells or Clustser) that failed to form a Cell)
|
173
|
+
- 'orphanedFaces': list of Faces (context/top-level faces + host faces of rooms that failed to form a Cell)
|
174
|
+
- 'orphanedShades': list of Faces (context/top-level shade faces that failed to have a parent cell)
|
175
|
+
- 'orphanedApertures': list of Faces (apertures that failed to have a parent face)
|
176
|
+
- 'orphanedDoors': list of Faces (doors that failed to have a parent face)
|
177
|
+
- 'properties': hierarchical dict copied verbatim from HBJSON['properties']
|
178
|
+
"""
|
179
|
+
|
180
|
+
from topologicpy.Vertex import Vertex
|
181
|
+
from topologicpy.Edge import Edge
|
182
|
+
from topologicpy.Wire import Wire
|
183
|
+
from topologicpy.Face import Face
|
184
|
+
from topologicpy.Shell import Shell
|
185
|
+
from topologicpy.Cell import Cell
|
186
|
+
from topologicpy.Cluster import Cluster
|
187
|
+
from topologicpy.Topology import Topology
|
188
|
+
from topologicpy.Dictionary import Dictionary
|
189
|
+
from topologicpy.Helper import Helper
|
190
|
+
from typing import Any, Dict, List, Optional, Tuple
|
191
|
+
|
192
|
+
if not isinstance(dictionary, dict):
|
193
|
+
if not silent:
|
194
|
+
print("Honeybee.ByHBJSONDictionary - Error: The input dictionary parameter is not a valid python dictionary. Returning None.")
|
195
|
+
return None
|
196
|
+
|
197
|
+
# ---------------------- helpers ----------------------
|
198
|
+
def _close(points: List[List[float]]) -> List[List[float]]:
|
199
|
+
if not points:
|
200
|
+
return points
|
201
|
+
p0, pN = points[0], points[-1]
|
202
|
+
if (abs(p0[0]-pN[0]) > tolerance or
|
203
|
+
abs(p0[1]-pN[1]) > tolerance or
|
204
|
+
abs(p0[2]-pN[2]) > tolerance):
|
205
|
+
return points + [p0]
|
206
|
+
return points
|
207
|
+
|
208
|
+
def _V(p: List[float]) -> Vertex:
|
209
|
+
return Vertex.ByCoordinates(float(p[0]), float(p[1]), float(p[2]))
|
210
|
+
|
211
|
+
# Tolerance-filtered wire (your spec)
|
212
|
+
def _wire(points: List[List[float]], tolerance: float = 1e-6) -> Wire:
|
213
|
+
pts = _close(points)
|
214
|
+
verts = [_V(x) for x in pts]
|
215
|
+
edges = [
|
216
|
+
Edge.ByVertices(verts[i], verts[i+1], tolerance=tolerance, silent=True)
|
217
|
+
for i in range(len(verts)-1)
|
218
|
+
if Vertex.Distance(verts[i], verts[i+1]) > tolerance
|
219
|
+
]
|
220
|
+
w = None
|
221
|
+
try:
|
222
|
+
w = Wire.ByEdges(edges, tolerance=tolerance, silent=True)
|
223
|
+
except:
|
224
|
+
w = Topology.SelfMerge(Cluster.ByTopologies(edges), tolerance=tolerance)
|
225
|
+
if w == None:
|
226
|
+
if not silent:
|
227
|
+
print("Honeybee.ByHBSJONDictionary - Error: Could not build wire. Returning None.")
|
228
|
+
return w
|
229
|
+
|
230
|
+
def _face_from_boundary(boundary: List[List[float]]) -> Face:
|
231
|
+
w = _wire(boundary, tolerance)
|
232
|
+
if w:
|
233
|
+
f = Face.ByWire(w, tolerance=tolerance, silent=True)
|
234
|
+
if not f:
|
235
|
+
if not silent:
|
236
|
+
print("Honeybee.ByHBSJONDictionary - Error: Could not build face. Returning the wire")
|
237
|
+
return w
|
238
|
+
return f
|
239
|
+
if not silent:
|
240
|
+
print("Honeybee.ByHBSJONDictionary - Error: Could not build face. Returning None")
|
241
|
+
return None
|
242
|
+
|
243
|
+
def _attach_all(top: Topology, full_py_dict: Dict[str, Any]) -> Topology:
|
244
|
+
# Attach the entire available dict (no filtering)
|
245
|
+
try:
|
246
|
+
keys = list(full_py_dict.keys())
|
247
|
+
values = [full_py_dict[k] for k in keys]
|
248
|
+
d = Dictionary.ByKeysValues(keys, values)
|
249
|
+
return Topology.SetDictionary(top, d)
|
250
|
+
except Exception:
|
251
|
+
return top # be robust to non-serializable values
|
252
|
+
|
253
|
+
def _build_host_face_cut_holes(fobj: Dict[str, Any]) -> Optional[Face]:
|
254
|
+
"""
|
255
|
+
Build host face from outer boundary and cut ONLY explicit 'holes' (NOT apertures/doors).
|
256
|
+
Attach the full fobj dict.
|
257
|
+
"""
|
258
|
+
geom = fobj.get("geometry") or {}
|
259
|
+
boundary = geom.get("boundary") or fobj.get("boundary")
|
260
|
+
holes = geom.get("holes") or fobj.get("holes") or []
|
261
|
+
|
262
|
+
if not boundary or len(boundary) < 3:
|
263
|
+
return None
|
264
|
+
|
265
|
+
hosts = _face_from_boundary(boundary)
|
266
|
+
if Topology.IsInstance(hosts, "face") or Topology.IsInstance(hosts, "wire"):
|
267
|
+
hosts = [hosts]
|
268
|
+
|
269
|
+
for host in hosts:
|
270
|
+
# Subtract explicit hole loops (if any)
|
271
|
+
hole_faces: List[Face] = []
|
272
|
+
for h in holes:
|
273
|
+
if h and len(h) >= 3:
|
274
|
+
hole_faces.append(_face_from_boundary(h))
|
275
|
+
|
276
|
+
if hole_faces:
|
277
|
+
hole_cluster = Cluster.ByTopologies(hole_faces)
|
278
|
+
try:
|
279
|
+
host = Topology.Difference(host, hole_cluster)
|
280
|
+
except Exception as e:
|
281
|
+
if not silent:
|
282
|
+
name = fobj.get("identifier") or fobj.get("name") or "unnamed"
|
283
|
+
print(f"HBJSON Import: Hole cutting failed on face '{name}'. Keeping uncut. Error: {e}")
|
284
|
+
_attach_all(host, fobj)
|
285
|
+
return hosts
|
286
|
+
|
287
|
+
def _aperture_faces_from(fobj: Dict[str, Any], kind: str) -> List[Face]:
|
288
|
+
"""
|
289
|
+
Build separate faces for apertures/doors on a host (DO NOT cut from host).
|
290
|
+
'kind' ∈ {'apertures','doors'}. Attach full dict for each.
|
291
|
+
"""
|
292
|
+
out: List[Face] = []
|
293
|
+
ap_list = fobj.get(kind) or []
|
294
|
+
for ap in ap_list:
|
295
|
+
g = ap.get("geometry") or {}
|
296
|
+
boundary = g.get("boundary") or ap.get("boundary")
|
297
|
+
if not boundary or len(boundary) < 3:
|
298
|
+
continue
|
299
|
+
f = _face_from_boundary(boundary)
|
300
|
+
out.append(_attach_all(f, ap))
|
301
|
+
return out
|
302
|
+
|
303
|
+
def _orphaned_aperture_faces(ap_list: List[Dict[str, Any]]) -> List[Face]:
|
304
|
+
out: List[Face] = []
|
305
|
+
for ap in ap_list or []:
|
306
|
+
g = ap.get("geometry") or {}
|
307
|
+
boundary = g.get("boundary") or ap.get("boundary")
|
308
|
+
if not boundary or len(boundary) < 3:
|
309
|
+
continue
|
310
|
+
f = _face_from_boundary(boundary)
|
311
|
+
out.append(_attach_all(f, ap))
|
312
|
+
return out
|
313
|
+
|
314
|
+
def _room_to_cell_and_apertures(room: Dict[str, Any]) -> Tuple[Optional[Cell], List[Face], List[Face]]:
|
315
|
+
"""
|
316
|
+
Build host faces (cut 'holes' only) and aperture faces for a room.
|
317
|
+
Return (cell_or_none, host_faces, aperture_faces).
|
318
|
+
"""
|
319
|
+
hb_faces = room.get("faces") or room.get("Faces") or []
|
320
|
+
rm_faces: List[Face] = []
|
321
|
+
sh_faces = room.get("shades") or room.get("Shades") or []
|
322
|
+
ap_faces: List[Face] = []
|
323
|
+
dr_faces: List[Face] = []
|
324
|
+
|
325
|
+
|
326
|
+
for fobj in hb_faces:
|
327
|
+
hosts = _build_host_face_cut_holes(fobj)
|
328
|
+
if hosts:
|
329
|
+
rm_faces.extend(hosts)
|
330
|
+
ap_faces.extend(_aperture_faces_from(fobj, "apertures"))
|
331
|
+
dr_faces.extend(_aperture_faces_from(fobj, "doors"))
|
332
|
+
|
333
|
+
# Room Shades
|
334
|
+
for sh in sh_faces:
|
335
|
+
shades = _build_host_face_cut_holes(sh)
|
336
|
+
if shades:
|
337
|
+
sh_faces.extend(shades)
|
338
|
+
# Try to make a Cell. If it fails, we DO NOT return a Shell/Cluster in rooms;
|
339
|
+
# instead we will salvage host faces into the 'faces' bucket.
|
340
|
+
if rm_faces:
|
341
|
+
selectors = []
|
342
|
+
for rm_face in rm_faces:
|
343
|
+
s = Topology.InternalVertex(rm_face)
|
344
|
+
face_d = Topology.Dictionary(rm_face)
|
345
|
+
s = Topology.SetDictionary(s, face_d)
|
346
|
+
selectors.append(s)
|
347
|
+
cell = Cell.ByFaces(Helper.Flatten(rm_faces), tolerance=0.001, silent=True)
|
348
|
+
if Topology.IsInstance(cell, "cell"):
|
349
|
+
cell = _attach_all(cell, room) # attach full room dict
|
350
|
+
else:
|
351
|
+
cell = Shell.ByFaces(Helper.Flatten(rm_faces), tolerance=0.001, silent=True)
|
352
|
+
if not cell:
|
353
|
+
cell = Cluster.ByTopologies(Helper.Flatten(rm_faces), silent=True)
|
354
|
+
if Topology.IsInstance(cell, "topology"):
|
355
|
+
cell = _attach_all(cell, room) # attach full room dict
|
356
|
+
|
357
|
+
if Topology.IsInstance(cell, "Topology"):
|
358
|
+
cell = Topology.TransferDictionariesBySelectors(cell, selectors,tranFaces=True, numWorkers=1)
|
359
|
+
return cell, rm_faces, sh_faces, ap_faces, dr_faces
|
360
|
+
# No host faces -> no cell
|
361
|
+
return None, [], sh_faces, ap_faces, dr_faces
|
362
|
+
|
363
|
+
rooms: List[Cell] = []
|
364
|
+
faces: List[Face] = []
|
365
|
+
shades: List[Face] = []
|
366
|
+
apertures: List[Face] = []
|
367
|
+
doors: List[Face] = []
|
368
|
+
orphaned_rooms: List[Cell] = []
|
369
|
+
orphaned_faces: List[Face] = []
|
370
|
+
orphaned_shades: List[Face] = []
|
371
|
+
orphaned_apertures: List[Face] = []
|
372
|
+
orphaned_doors: List[Face] = []
|
373
|
+
|
374
|
+
# Rooms → Cells (when possible) + collect apertures. If a Cell cannot be made,
|
375
|
+
# the room goes to the orphaned_rooms list.
|
376
|
+
for room in (dictionary.get("rooms") or dictionary.get("Rooms") or []):
|
377
|
+
cell, host_faces, sh_faces, ap_faces, dr_faces = _room_to_cell_and_apertures(room)
|
378
|
+
|
379
|
+
if includeRooms and Topology.IsInstance(cell, "cell"):
|
380
|
+
rooms.append(cell)
|
381
|
+
elif includeOrphanedRooms and Topology.IsInstance(cell, "topology"):
|
382
|
+
orphaned_rooms.append(cell)
|
383
|
+
if cell:
|
384
|
+
if includeFaces and host_faces:
|
385
|
+
faces.extend(host_faces)
|
386
|
+
if includeShades and sh_faces:
|
387
|
+
shades.extend(sh_faces)
|
388
|
+
if includeApertures and ap_faces:
|
389
|
+
apertures.extend(ap_faces)
|
390
|
+
if includeDoors and dr_faces:
|
391
|
+
doors.extend(dr_faces)
|
392
|
+
|
393
|
+
# Explicit orphaned faces → 'orphaned_faces'
|
394
|
+
if includeOrphanedFaces:
|
395
|
+
explicit_orphaned_faces = dictionary.get("orphaned_faces") or dictionary.get("OrphanedFaces") or []
|
396
|
+
for f in explicit_orphaned_faces:
|
397
|
+
hf = _build_host_face_cut_holes(f)
|
398
|
+
if hf:
|
399
|
+
orphaned_faces.extend(hf)
|
400
|
+
# Some files also place planar surfaces at top-level 'faces'
|
401
|
+
for fobj in (dictionary.get("faces") or dictionary.get("Faces") or []):
|
402
|
+
hf = _build_host_face_cut_holes(fobj)
|
403
|
+
if hf:
|
404
|
+
orphaned_faces.extend(hf)
|
405
|
+
|
406
|
+
# Explicit orphaned shades (and/or context shades)
|
407
|
+
if includeOrphanedShades:
|
408
|
+
explicit_orphaned_shades = dictionary.get("orphaned_shades") or dictionary.get("OrphanedShades") or []
|
409
|
+
for s in explicit_orphaned_shades:
|
410
|
+
hf = _build_host_face_cut_holes(s)
|
411
|
+
if hf:
|
412
|
+
orphaned_shades.extend(hf)
|
413
|
+
|
414
|
+
ctx = dictionary.get("context_geometry") or dictionary.get("Context") or {}
|
415
|
+
shade_list = []
|
416
|
+
if isinstance(ctx, dict):
|
417
|
+
shade_list = ctx.get("shades") or ctx.get("Shades") or []
|
418
|
+
elif isinstance(ctx, list):
|
419
|
+
shade_list = ctx
|
420
|
+
for s in shade_list:
|
421
|
+
hf = _build_host_face_cut_holes(s)
|
422
|
+
if hf:
|
423
|
+
orphaned_shades.extend(hf)
|
424
|
+
# Some files might also place planar shade surfaces at top-level 'shades'
|
425
|
+
for fobj in (dictionary.get("shades") or dictionary.get("Shades") or []):
|
426
|
+
hf = _build_host_face_cut_holes(fobj)
|
427
|
+
if hf:
|
428
|
+
orphaned_shades.extend(hf)
|
429
|
+
|
430
|
+
# Explicit orphaned apertures → 'orphaned_apertures'
|
431
|
+
if includeOrphanedApertures:
|
432
|
+
orphaned_ap_list = dictionary.get("orphaned_apertures") or dictionary.get("OrphanedApertures") or []
|
433
|
+
if orphaned_ap_list:
|
434
|
+
orphaned_apertures.extend(_orphaned_aperture_faces(orphaned_ap_list))
|
435
|
+
|
436
|
+
# Explicit orphaned doors → 'orphaned_doors'
|
437
|
+
if includeOrphanedDoors:
|
438
|
+
orphaned_dr_list = dictionary.get("orphaned_doors") or dictionary.get("OrphanedDoors") or []
|
439
|
+
if orphaned_dr_list:
|
440
|
+
orphaned_doors.extend(_orphaned_aperture_faces(orphaned_dr_list)) #You can use the same function as apertures.
|
441
|
+
|
442
|
+
# Properties → hierarchical dict verbatim
|
443
|
+
props_root = dictionary.get("properties") or dictionary.get("Properties") or {}
|
444
|
+
properties = {
|
445
|
+
"radiance": props_root.get("radiance") or props_root.get("Radiance") or {},
|
446
|
+
"energy": props_root.get("energy") or props_root.get("Energy") or {},
|
447
|
+
}
|
448
|
+
|
449
|
+
return {
|
450
|
+
"rooms": rooms,
|
451
|
+
"faces": faces,
|
452
|
+
"shades": shades,
|
453
|
+
"apertures": apertures,
|
454
|
+
"doors": doors,
|
455
|
+
"orphanedRooms": orphaned_rooms,
|
456
|
+
"orphanedFaces": orphaned_faces,
|
457
|
+
"orphanedShades": orphaned_shades,
|
458
|
+
"orphanedApertures": orphaned_apertures,
|
459
|
+
"orphanedDoors": orphaned_doors,
|
460
|
+
"properties": properties
|
461
|
+
}
|
462
|
+
|
463
|
+
@staticmethod
|
464
|
+
def ByHBJSONPath(
|
465
|
+
path: str,
|
466
|
+
includeRooms: bool = True,
|
467
|
+
includeFaces: bool = True,
|
468
|
+
includeShades: bool = True,
|
469
|
+
includeApertures: bool = True,
|
470
|
+
includeDoors: bool = True,
|
471
|
+
includeOrphanedRooms: bool = True,
|
472
|
+
includeOrphanedFaces: bool = True,
|
473
|
+
includeOrphanedShades: bool = True,
|
474
|
+
includeOrphanedApertures: bool = True,
|
475
|
+
includeOrphanedDoors: bool = True,
|
476
|
+
tolerance: float = 0.0001,
|
477
|
+
silent: bool = False):
|
478
|
+
"""
|
479
|
+
Import an HBJSON model from a file path and return a python dictionary. See: https://github.com/ladybug-tools/honeybee-schema/wiki/1.1-Model-Schema
|
480
|
+
|
481
|
+
Parameters
|
482
|
+
----------
|
483
|
+
dictionary : dict
|
484
|
+
The HBJSON model as a Python dictionary (e.g., loaded via ``json.load``).
|
485
|
+
includeRooms : bool, optional
|
486
|
+
If True, parse rooms and attempt to create one ``Cell`` per room. Default is True.
|
487
|
+
includeFaces : bool, optional
|
488
|
+
If True, include top-level planar faces found outside rooms (e.g., at root "faces"). Default is True.
|
489
|
+
includeShades : bool, optional
|
490
|
+
If True, include context/standalone shades (e.g., ``context_geometry.shades``). Default is True.
|
491
|
+
includeApertures : bool, optional
|
492
|
+
If True, include **room** apertures (e.g., windows) as separate ``Face`` objects (not cut from hosts). Default is True.
|
493
|
+
includeDoors : bool, optional
|
494
|
+
If True, include **room** doors as separate ``Face`` objects (not cut from hosts). Default is True.
|
495
|
+
includeOrphanedRooms : bool, optional
|
496
|
+
If True, include the topology of the room when a room fails to close as a ``Cell``. This may be a ``Shell`` or a ``Cluster``. Default is True.
|
497
|
+
includeOrphanedFaces : bool, optional
|
498
|
+
If True, include planar faces listed at the HBJSON root (e.g., "faces"). Default is True.
|
499
|
+
includeOrphanedShades : bool, optional
|
500
|
+
If True, include shades listed at the HBJSON root (e.g., "orphaned_shades"). Default is True.
|
501
|
+
includeOrphanedApertures : bool, optional
|
502
|
+
If True, include apertures listed at the HBJSON root (e.g., "orphaned_apertures"). Default is True.
|
503
|
+
includeOrphanedDoors : bool, optional
|
504
|
+
If True, include doors listed at the HBJSON root (e.g., "orphaned_doors"). Default is True.
|
505
|
+
tolerance : float , optional
|
506
|
+
The desired tolerance. Default is 0.0001.
|
507
|
+
silent : bool , optional
|
508
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
509
|
+
|
510
|
+
Returns
|
511
|
+
-------
|
512
|
+
dict
|
513
|
+
The created cluster of vertices, edges, faces, and cells.
|
514
|
+
- 'rooms': list of Cells (one per successfully closed room)
|
515
|
+
- 'faces': list of Faces (all faces that make up the rooms)
|
516
|
+
- 'shades': list of Faces (all shade faces)
|
517
|
+
- 'apertures': list of Faces (all apertures, never cut from hosts)
|
518
|
+
- 'doors': list of Faces (all doors, never cut from hosts)
|
519
|
+
- 'orphanedRooms': list of Topologies (context/top-level topologies (e.g. Shells or Clustser) that failed to form a Cell)
|
520
|
+
- 'orphanedFaces': list of Faces (context/top-level faces + host faces of rooms that failed to form a Cell)
|
521
|
+
- 'orphanedShades': list of Faces (context/top-level shade faces that failed to have a parent cell)
|
522
|
+
- 'orphanedApertures': list of Faces (apertures that failed to have a parent face)
|
523
|
+
- 'orphanedDoors': list of Faces (doors that failed to have a parent face)
|
524
|
+
- 'properties': hierarchical dict copied verbatim from HBJSON['properties']
|
525
|
+
"""
|
526
|
+
|
527
|
+
import json
|
528
|
+
if not path:
|
529
|
+
if not silent:
|
530
|
+
print("Honeybee.ByHBJSONPath - Error: the input path parameter is not a valid path. Returning None.")
|
531
|
+
return None
|
532
|
+
with open(path) as file:
|
533
|
+
try:
|
534
|
+
hbjson_dict = json.load(file)
|
535
|
+
except:
|
536
|
+
if not silent:
|
537
|
+
print("Honeybee.ByHBJSONPath - Error: Could not open the HBJSON file. Returning None.")
|
538
|
+
return None
|
539
|
+
return Honeybee.ByHBJSONDictionary(hbjson_dict,
|
540
|
+
includeRooms = includeRooms,
|
541
|
+
includeFaces = includeFaces,
|
542
|
+
includeShades = includeShades,
|
543
|
+
includeApertures = includeApertures,
|
544
|
+
includeDoors = includeDoors,
|
545
|
+
includeOrphanedRooms = includeOrphanedRooms,
|
546
|
+
includeOrphanedFaces = includeOrphanedFaces,
|
547
|
+
includeOrphanedShades = includeOrphanedShades,
|
548
|
+
includeOrphanedApertures = includeOrphanedApertures,
|
549
|
+
includeOrphanedDoors = includeOrphanedDoors,
|
550
|
+
tolerance = tolerance,
|
551
|
+
silent = silent)
|
552
|
+
|
553
|
+
@staticmethod
|
554
|
+
def ByHBJSONString(
|
555
|
+
string,
|
556
|
+
includeRooms: bool = True,
|
557
|
+
includeFaces: bool = True,
|
558
|
+
includeShades: bool = True,
|
559
|
+
includeApertures: bool = True,
|
560
|
+
includeDoors: bool = True,
|
561
|
+
includeOrphanedRooms: bool = True,
|
562
|
+
includeOrphanedFaces: bool = True,
|
563
|
+
includeOrphanedShades: bool = True,
|
564
|
+
includeOrphanedApertures: bool = True,
|
565
|
+
includeOrphanedDoors: bool = True,
|
566
|
+
tolerance: float = 0.0001,
|
567
|
+
silent: bool = False):
|
568
|
+
"""
|
569
|
+
Import an HBJSON model from a file path and return a python dictionary. See: https://github.com/ladybug-tools/honeybee-schema/wiki/1.1-Model-Schema
|
570
|
+
|
571
|
+
Parameters
|
572
|
+
----------
|
573
|
+
string : str
|
574
|
+
The HBJSON model as a string.
|
575
|
+
includeRooms : bool, optional
|
576
|
+
If True, parse rooms and attempt to create one ``Cell`` per room. Default is True.
|
577
|
+
includeFaces : bool, optional
|
578
|
+
If True, include top-level planar faces found outside rooms (e.g., at root "faces"). Default is True.
|
579
|
+
includeShades : bool, optional
|
580
|
+
If True, include context/standalone shades (e.g., ``context_geometry.shades``). Default is True.
|
581
|
+
includeApertures : bool, optional
|
582
|
+
If True, include **room** apertures (e.g., windows) as separate ``Face`` objects (not cut from hosts). Default is True.
|
583
|
+
includeDoors : bool, optional
|
584
|
+
If True, include **room** doors as separate ``Face`` objects (not cut from hosts). Default is True.
|
585
|
+
includeOrphanedRooms : bool, optional
|
586
|
+
If True, include the topology of the room when a room fails to close as a ``Cell``. This may be a ``Shell`` or a ``Cluster``. Default is True.
|
587
|
+
includeOrphanedFaces : bool, optional
|
588
|
+
If True, include planar faces listed at the HBJSON root (e.g., "faces"). Default is True.
|
589
|
+
includeOrphanedShades : bool, optional
|
590
|
+
If True, include shades listed at the HBJSON root (e.g., "orphaned_shades"). Default is True.
|
591
|
+
includeOrphanedApertures : bool, optional
|
592
|
+
If True, include apertures listed at the HBJSON root (e.g., "orphaned_apertures"). Default is True.
|
593
|
+
includeOrphanedDoors : bool, optional
|
594
|
+
If True, include doors listed at the HBJSON root (e.g., "orphaned_doors"). Default is True.
|
595
|
+
tolerance : float , optional
|
596
|
+
The desired tolerance. Default is 0.0001.
|
597
|
+
silent : bool , optional
|
598
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
599
|
+
|
600
|
+
Returns
|
601
|
+
-------
|
602
|
+
dict
|
603
|
+
The created cluster of vertices, edges, faces, and cells.
|
604
|
+
- 'rooms': list of Cells (one per successfully closed room)
|
605
|
+
- 'faces': list of Faces (all faces that make up the rooms)
|
606
|
+
- 'shades': list of Faces (all shade faces)
|
607
|
+
- 'apertures': list of Faces (all apertures, never cut from hosts)
|
608
|
+
- 'doors': list of Faces (all doors, never cut from hosts)
|
609
|
+
- 'orphanedRooms': list of Topologies (context/top-level topologies (e.g. Shells or Clustser) that failed to form a Cell)
|
610
|
+
- 'orphanedFaces': list of Faces (context/top-level faces + host faces of rooms that failed to form a Cell)
|
611
|
+
- 'orphanedShades': list of Faces (context/top-level shade faces that failed to have a parent cell)
|
612
|
+
- 'orphanedApertures': list of Faces (apertures that failed to have a parent face)
|
613
|
+
- 'orphanedDoors': list of Faces (doors that failed to have a parent face)
|
614
|
+
- 'properties': hierarchical dict copied verbatim from HBJSON['properties']
|
615
|
+
"""
|
616
|
+
|
617
|
+
if not isinstance(string, str):
|
618
|
+
if not silent:
|
619
|
+
print("Honeybee.ByHBJSONString - Error: The input string parameter is not a valid string. Returning None.")
|
620
|
+
return None
|
621
|
+
hbjson_dict = json.loads(string)
|
622
|
+
if not isinstance(hbjson_dict, dict):
|
623
|
+
if not silent:
|
624
|
+
print("Honeybee.ByHBJSONString - Error: Could not convert the input string into a valid HBJSON dictionary. Returning None.")
|
625
|
+
return None
|
626
|
+
return Honeybee.ByHBJSONDictionary(hbjson_dict,
|
627
|
+
includeRooms = includeRooms,
|
628
|
+
includeFaces = includeFaces,
|
629
|
+
includeShades = includeShades,
|
630
|
+
includeApertures = includeApertures,
|
631
|
+
includeDoors = includeDoors,
|
632
|
+
includeOrphanedRooms = includeOrphanedRooms,
|
633
|
+
includeOrphanedFaces = includeOrphanedFaces,
|
634
|
+
includeOrphanedShades = includeOrphanedShades,
|
635
|
+
includeOrphanedApertures = includeOrphanedApertures,
|
636
|
+
includeOrphanedDoors = includeOrphanedDoors,
|
637
|
+
tolerance = tolerance,
|
638
|
+
silent = silent)
|
639
|
+
|
115
640
|
@staticmethod
|
116
641
|
def ConstructionSetByIdentifier(id):
|
117
642
|
"""
|
@@ -175,7 +700,7 @@ class Honeybee:
|
|
175
700
|
path = path+".hbjson"
|
176
701
|
|
177
702
|
if not overwrite and exists(path):
|
178
|
-
print("
|
703
|
+
print("Honeybee.ExportToHBJSON - Error: a file already exists at the specified path and overwrite is set to False. Returning None.")
|
179
704
|
return None
|
180
705
|
f = None
|
181
706
|
try:
|
@@ -184,7 +709,7 @@ class Honeybee:
|
|
184
709
|
else:
|
185
710
|
f = open(path, "x") # Try to create a new File
|
186
711
|
except:
|
187
|
-
print("
|
712
|
+
print("Honeybee.ExportToHBJSON - Error: Could not create a new file at the following location: "+path+". Returning None.")
|
188
713
|
return None
|
189
714
|
if (f):
|
190
715
|
json.dump(model.to_dict(), f, indent=4)
|