topologicpy 0.4.8__py3-none-any.whl → 0.4.9__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/Aperture.py +46 -0
- topologicpy/Cell.py +1780 -0
- topologicpy/CellComplex.py +791 -0
- topologicpy/Cluster.py +591 -0
- topologicpy/Color.py +157 -0
- topologicpy/Context.py +56 -0
- topologicpy/DGL.py +2661 -0
- topologicpy/Dictionary.py +470 -0
- topologicpy/Edge.py +855 -0
- topologicpy/EnergyModel.py +1052 -0
- topologicpy/Face.py +1810 -0
- topologicpy/Graph.py +3526 -0
- topologicpy/Graph_Export.py +858 -0
- topologicpy/Grid.py +338 -0
- topologicpy/Helper.py +182 -0
- topologicpy/Honeybee.py +424 -0
- topologicpy/Matrix.py +255 -0
- topologicpy/Neo4jGraph.py +311 -0
- topologicpy/Plotly.py +1396 -0
- topologicpy/Polyskel.py +524 -0
- topologicpy/Process.py +1368 -0
- topologicpy/SQL.py +48 -0
- topologicpy/Shell.py +1418 -0
- topologicpy/Speckle.py +433 -0
- topologicpy/Topology.py +5854 -0
- topologicpy/UnitTest.py +29 -0
- topologicpy/Vector.py +555 -0
- topologicpy/Vertex.py +714 -0
- topologicpy/Wire.py +2346 -0
- topologicpy/__init__.py +20 -0
- topologicpy/bin/linux/topologic/__init__.py +2 -0
- topologicpy/bin/linux/topologic/topologic.cpython-310-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-311-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-38-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-39-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBO-6bdf205d.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBRep-2960a069.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBool-c44b74bd.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKFillet-9a670ba0.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG2d-8f31849e.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG3d-4c6bce57.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMath-72572fa8.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMesh-2a060427.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKOffset-6cab68ff.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKPrim-eb1262b3.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libgcc_s-32c1665e.so.1 +0 -0
- topologicpy/bin/linux/topologic.libs/libstdc++-672d7b41.so.6.0.30 +0 -0
- topologicpy/bin/windows/topologic/TKBO-f6b191de.dll +0 -0
- topologicpy/bin/windows/topologic/TKBRep-e56a600e.dll +0 -0
- topologicpy/bin/windows/topologic/TKBool-7b8d47ae.dll +0 -0
- topologicpy/bin/windows/topologic/TKFillet-0ddbf0a8.dll +0 -0
- topologicpy/bin/windows/topologic/TKG2d-2e2dee3d.dll +0 -0
- topologicpy/bin/windows/topologic/TKG3d-6674513d.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomAlgo-d240e370.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomBase-df87aba5.dll +0 -0
- topologicpy/bin/windows/topologic/TKMath-45bd625a.dll +0 -0
- topologicpy/bin/windows/topologic/TKMesh-d6e826b1.dll +0 -0
- topologicpy/bin/windows/topologic/TKOffset-79b9cc94.dll +0 -0
- topologicpy/bin/windows/topologic/TKPrim-aa430a86.dll +0 -0
- topologicpy/bin/windows/topologic/TKShHealing-bb48be89.dll +0 -0
- topologicpy/bin/windows/topologic/TKTopAlgo-7d0d1e22.dll +0 -0
- topologicpy/bin/windows/topologic/TKernel-08c8cfbb.dll +0 -0
- topologicpy/bin/windows/topologic/__init__.py +2 -0
- topologicpy/bin/windows/topologic/topologic.cp310-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp311-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp38-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp39-win_amd64.pyd +0 -0
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/METADATA +1 -1
- topologicpy-0.4.9.dist-info/RECORD +77 -0
- topologicpy-0.4.9.dist-info/top_level.txt +1 -0
- topologicpy-0.4.8.dist-info/RECORD +0 -5
- topologicpy-0.4.8.dist-info/top_level.txt +0 -1
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/LICENSE +0 -0
- {topologicpy-0.4.8.dist-info → topologicpy-0.4.9.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
import topologic
|
|
2
|
+
import warnings
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
class CellComplex(topologic.CellComplex):
|
|
6
|
+
@staticmethod
|
|
7
|
+
def Box(origin: topologic.Vertex = None, width: float = 1.0, length: float = 1.0, height: float = 1.0, uSides: int = 2, vSides: int = 2, wSides: int = 2,
|
|
8
|
+
direction: list = [0,0,1], placement: str = "center") -> topologic.CellComplex:
|
|
9
|
+
"""
|
|
10
|
+
Creates a box with internal cells.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
origin : topologic.Vertex , optional
|
|
15
|
+
The origin location of the box. The default is None which results in the box being placed at (0,0,0).
|
|
16
|
+
width : float , optional
|
|
17
|
+
The width of the box. The default is 1.
|
|
18
|
+
length : float , optional
|
|
19
|
+
The length of the box. The default is 1.
|
|
20
|
+
height : float , optional
|
|
21
|
+
The height of the box.
|
|
22
|
+
uSides : int , optional
|
|
23
|
+
The number of sides along the width. The default is 1.
|
|
24
|
+
vSides : int, optional
|
|
25
|
+
The number of sides along the length. The default is 1.
|
|
26
|
+
wSides : int , optional
|
|
27
|
+
The number of sides along the height. The default is 1.
|
|
28
|
+
direction : list , optional
|
|
29
|
+
The vector representing the up direction of the box. The default is [0,0,1].
|
|
30
|
+
placement : str , optional
|
|
31
|
+
The description of the placement of the origin of the box. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
topologic.CellComplex
|
|
36
|
+
The created box.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
return CellComplex.Prism(origin=origin, width=width, length=length, height=height, uSides=uSides, vSides=vSides, wSides=wSides,
|
|
40
|
+
direction=direction, placement=placement)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def ByCells(cells: list, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
44
|
+
"""
|
|
45
|
+
Creates a cellcomplex by merging the input cells.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
cells : list
|
|
50
|
+
The list of input cells.
|
|
51
|
+
tolerance : float , optional
|
|
52
|
+
The desired tolerance. The default is 0.0001.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
topologic.CellComplex
|
|
57
|
+
The created cellcomplex.
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
if not cells:
|
|
61
|
+
return None
|
|
62
|
+
if not isinstance(cells, list):
|
|
63
|
+
return None
|
|
64
|
+
cells = [x for x in cells if isinstance(x, topologic.Cell)]
|
|
65
|
+
if len(cells) < 1:
|
|
66
|
+
return None
|
|
67
|
+
cellComplex = topologic.CellComplex.ByCells(cells, tolerance)
|
|
68
|
+
if not cellComplex:
|
|
69
|
+
warnings.warn("Warning: Default CellComplex.ByCells method failed. Attempting to Merge the Cells.", UserWarning)
|
|
70
|
+
result = cells[0]
|
|
71
|
+
remainder = cells[1:]
|
|
72
|
+
cluster = topologic.Cluster.ByTopologies(remainder, False)
|
|
73
|
+
result = result.Merge(cluster, False)
|
|
74
|
+
if result.Type() != 64: #64 is the type of a CellComplex
|
|
75
|
+
warnings.warn("Warning: Input Cells do not form a CellComplex", UserWarning)
|
|
76
|
+
if result.Type() > 64:
|
|
77
|
+
returnCellComplexes = []
|
|
78
|
+
_ = result.CellComplexes(None, returnCellComplexes)
|
|
79
|
+
return returnCellComplexes[0]
|
|
80
|
+
else:
|
|
81
|
+
return None
|
|
82
|
+
else:
|
|
83
|
+
return cellComplex
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def ByCellsCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
87
|
+
"""
|
|
88
|
+
Creates a cellcomplex by merging the cells within the input cluster.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
cluster : topologic.Cluster
|
|
93
|
+
The input cluster of cells.
|
|
94
|
+
tolerance : float , optional
|
|
95
|
+
The desired tolerance. The default is 0.0001.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
topologic.CellComplex
|
|
100
|
+
The created cellcomplex.
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
if not cluster:
|
|
104
|
+
return None
|
|
105
|
+
if not isinstance(cluster, topologic.Cluster):
|
|
106
|
+
return None
|
|
107
|
+
cells = []
|
|
108
|
+
_ = cluster.Cells(None, cells)
|
|
109
|
+
return CellComplex.ByCells(cells, tolerance)
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def ByFaces(faces: list, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
113
|
+
"""
|
|
114
|
+
Creates a cellcomplex by merging the input faces.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
faces : topologic.Face
|
|
119
|
+
The input faces.
|
|
120
|
+
tolerance : float , optional
|
|
121
|
+
The desired tolerance. The default is 0.0001.
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
topologic.CellComplex
|
|
126
|
+
The created cellcomplex.
|
|
127
|
+
|
|
128
|
+
"""
|
|
129
|
+
if not faces:
|
|
130
|
+
return None
|
|
131
|
+
if not isinstance(faces, list):
|
|
132
|
+
return None
|
|
133
|
+
faces = [x for x in faces if isinstance(x, topologic.Face)]
|
|
134
|
+
if len(faces) < 1:
|
|
135
|
+
return None
|
|
136
|
+
try:
|
|
137
|
+
cellComplex = topologic.CellComplex.ByFaces(faces, tolerance, False)
|
|
138
|
+
except:
|
|
139
|
+
cellComplex = None
|
|
140
|
+
if not cellComplex:
|
|
141
|
+
print("Warning: Default CellComplex.ByFaces method failed. Attempting to Merge the Faces.")
|
|
142
|
+
cellComplex = faces[0]
|
|
143
|
+
for i in range(1,len(faces)):
|
|
144
|
+
newCellComplex = None
|
|
145
|
+
try:
|
|
146
|
+
newCellComplex = cellComplex.Merge(faces[i], False)
|
|
147
|
+
except:
|
|
148
|
+
print("Warning: Failed to merge Face #"+str(i)+". Skipping.")
|
|
149
|
+
if newCellComplex:
|
|
150
|
+
cellComplex = newCellComplex
|
|
151
|
+
if cellComplex.Type() != 64: #64 is the type of a CellComplex
|
|
152
|
+
print("Warning: Input Faces do not form a CellComplex")
|
|
153
|
+
if cellComplex.Type() > 64:
|
|
154
|
+
returnCellComplexes = []
|
|
155
|
+
_ = cellComplex.CellComplexes(None, returnCellComplexes)
|
|
156
|
+
if len(returnCellComplexes) > 0:
|
|
157
|
+
return returnCellComplexes[0]
|
|
158
|
+
else:
|
|
159
|
+
return None
|
|
160
|
+
else:
|
|
161
|
+
return None
|
|
162
|
+
else:
|
|
163
|
+
return cellComplex
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def ByFacesCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
167
|
+
"""
|
|
168
|
+
Creates a cellcomplex by merging the faces within the input cluster.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
cluster : topologic.Cluster
|
|
173
|
+
The input cluster of faces.
|
|
174
|
+
tolerance : float , optional
|
|
175
|
+
The desired tolerance. The default is 0.0001.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
topologic.CellComplex
|
|
180
|
+
The created cellcomplex.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
if not cluster:
|
|
184
|
+
return None
|
|
185
|
+
if not isinstance(cluster, topologic.Cluster):
|
|
186
|
+
return None
|
|
187
|
+
faces = []
|
|
188
|
+
_ = cluster.Faces(None, faces)
|
|
189
|
+
return CellComplex.ByFaces(faces, tolerance)
|
|
190
|
+
|
|
191
|
+
@staticmethod
|
|
192
|
+
def ByWires(wires: list, triangulate: bool = True, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
193
|
+
"""
|
|
194
|
+
Creates a cellcomplex by lofting through the input wires.
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
wires : list
|
|
199
|
+
The input list of wires.
|
|
200
|
+
triangulate : bool , optional
|
|
201
|
+
If set to True, the faces will be triangulated. The default is True.
|
|
202
|
+
tolerance : float , optional
|
|
203
|
+
The desired tolerance. The default is 0.0001.
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
topologic.CellComplex
|
|
208
|
+
The created cellcomplex.
|
|
209
|
+
|
|
210
|
+
"""
|
|
211
|
+
from topologicpy.Face import Face
|
|
212
|
+
from topologicpy.Cluster import Cluster
|
|
213
|
+
from topologicpy.Topology import Topology
|
|
214
|
+
|
|
215
|
+
faces = [topologic.Face.ByExternalBoundary(wires[0]), topologic.Face.ByExternalBoundary(wires[-1])]
|
|
216
|
+
if triangulate == True:
|
|
217
|
+
triangles = []
|
|
218
|
+
for face in faces:
|
|
219
|
+
if len(Topology.Vertices(face)) > 3:
|
|
220
|
+
triangles += Face.Triangulate(face)
|
|
221
|
+
else:
|
|
222
|
+
triangles += [face]
|
|
223
|
+
faces = triangles
|
|
224
|
+
for i in range(len(wires)-1):
|
|
225
|
+
wire1 = wires[i]
|
|
226
|
+
wire2 = wires[i+1]
|
|
227
|
+
f = topologic.Face.ByExternalBoundary(wire2)
|
|
228
|
+
if triangulate == True:
|
|
229
|
+
if len(Topology.Vertices(face)) > 3:
|
|
230
|
+
triangles = Face.Triangulate(face)
|
|
231
|
+
else:
|
|
232
|
+
triangles = [face]
|
|
233
|
+
faces += triangles
|
|
234
|
+
else:
|
|
235
|
+
faces.append(f)
|
|
236
|
+
w1_edges = []
|
|
237
|
+
_ = wire1.Edges(None, w1_edges)
|
|
238
|
+
w2_edges = []
|
|
239
|
+
_ = wire2.Edges(None, w2_edges)
|
|
240
|
+
if len(w1_edges) != len(w2_edges):
|
|
241
|
+
return None
|
|
242
|
+
for j in range (len(w1_edges)):
|
|
243
|
+
e1 = w1_edges[j]
|
|
244
|
+
e2 = w2_edges[j]
|
|
245
|
+
e3 = None
|
|
246
|
+
e4 = None
|
|
247
|
+
try:
|
|
248
|
+
e3 = topologic.Edge.ByStartVertexEndVertex(e1.StartVertex(), e2.StartVertex())
|
|
249
|
+
except:
|
|
250
|
+
try:
|
|
251
|
+
e4 = topologic.Edge.ByStartVertexEndVertex(e1.EndVertex(), e2.EndVertex())
|
|
252
|
+
f = topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e2, e4]))
|
|
253
|
+
if triangulate == True:
|
|
254
|
+
if len(Topology.Vertices(face)) > 3:
|
|
255
|
+
triangles = Face.Triangulate(face)
|
|
256
|
+
else:
|
|
257
|
+
triangles = [face]
|
|
258
|
+
faces += triangles
|
|
259
|
+
else:
|
|
260
|
+
faces.append(f)
|
|
261
|
+
except:
|
|
262
|
+
pass
|
|
263
|
+
try:
|
|
264
|
+
e4 = topologic.Edge.ByStartVertexEndVertex(e1.EndVertex(), e2.EndVertex())
|
|
265
|
+
except:
|
|
266
|
+
try:
|
|
267
|
+
e3 = topologic.Edge.ByStartVertexEndVertex(e1.StartVertex(), e2.StartVertex())
|
|
268
|
+
f = topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e2, e3]))
|
|
269
|
+
if triangulate == True:
|
|
270
|
+
if len(Topology.Vertices(face)) > 3:
|
|
271
|
+
triangles = Face.Triangulate(face)
|
|
272
|
+
else:
|
|
273
|
+
triangles = [face]
|
|
274
|
+
faces += triangles
|
|
275
|
+
else:
|
|
276
|
+
faces.append(f)
|
|
277
|
+
except:
|
|
278
|
+
pass
|
|
279
|
+
if e3 and e4:
|
|
280
|
+
if triangulate == True:
|
|
281
|
+
e5 = topologic.Edge.ByStartVertexEndVertex(e1.StartVertex(), e2.EndVertex())
|
|
282
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e5, e4])))
|
|
283
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e2, e5, e3])))
|
|
284
|
+
else:
|
|
285
|
+
try:
|
|
286
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e4, e2, e3])))
|
|
287
|
+
except:
|
|
288
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e3, e2, e4])))
|
|
289
|
+
elif e3:
|
|
290
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e3, e2])))
|
|
291
|
+
elif e4:
|
|
292
|
+
faces.append(topologic.Face.ByExternalBoundary(topologic.Wire.ByEdges([e1, e4, e2])))
|
|
293
|
+
return CellComplex.ByFaces(faces, tolerance)
|
|
294
|
+
|
|
295
|
+
@staticmethod
|
|
296
|
+
def ByWiresCluster(cluster: topologic.Cluster, triangulate: bool = True, tolerance: float = 0.0001) -> topologic.CellComplex:
|
|
297
|
+
"""
|
|
298
|
+
Creates a cellcomplex by lofting through the wires in the input cluster.
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
cluster : topologic.Cluster
|
|
303
|
+
The input cluster of wires.
|
|
304
|
+
triangulate : bool , optional
|
|
305
|
+
If set to True, the faces will be triangulated. The default is True.
|
|
306
|
+
tolerance : float , optional
|
|
307
|
+
The desired tolerance. The default is 0.0001.
|
|
308
|
+
|
|
309
|
+
Returns
|
|
310
|
+
-------
|
|
311
|
+
topologic.CellComplex
|
|
312
|
+
The created cellcomplex.
|
|
313
|
+
|
|
314
|
+
"""
|
|
315
|
+
if not cluster:
|
|
316
|
+
return None
|
|
317
|
+
if not isinstance(cluster, topologic.Cluster):
|
|
318
|
+
return None
|
|
319
|
+
wires = []
|
|
320
|
+
_ = cluster.Wires(None, wires)
|
|
321
|
+
return CellComplex.ByWires(wires, triangulate=triangulate, tolerance=tolerance)
|
|
322
|
+
|
|
323
|
+
@staticmethod
|
|
324
|
+
def Cells(cellComplex: topologic.CellComplex) -> list:
|
|
325
|
+
"""
|
|
326
|
+
Returns the cells of the input cellComplex.
|
|
327
|
+
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
cellComplex : topologic.CellComplex
|
|
331
|
+
The input cellComplex.
|
|
332
|
+
|
|
333
|
+
Returns
|
|
334
|
+
-------
|
|
335
|
+
list
|
|
336
|
+
The list of cells.
|
|
337
|
+
|
|
338
|
+
"""
|
|
339
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
340
|
+
return None
|
|
341
|
+
cells = []
|
|
342
|
+
_ = cellComplex.Cells(None, cells)
|
|
343
|
+
return cells
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def Decompose(cellComplex: topologic.CellComplex, tiltAngle: float = 10.0, tolerance: float = 0.0001) -> dict:
|
|
347
|
+
"""
|
|
348
|
+
Decomposes the input cellComplex into its logical components. This method assumes that the positive Z direction is UP.
|
|
349
|
+
|
|
350
|
+
Parameters
|
|
351
|
+
----------
|
|
352
|
+
cellComplex : topologic.CellComplex
|
|
353
|
+
the input cellComplex.
|
|
354
|
+
tiltAngle : float , optional
|
|
355
|
+
The threshold tilt angle in degrees to determine if a face is vertical, horizontal, or tilted. The tilt angle is measured from the nearest cardinal direction. The default is 10.
|
|
356
|
+
tolerance : float , optional
|
|
357
|
+
The desired tolerance. The default is 0.0001.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
dictionary
|
|
362
|
+
A dictionary with the following keys and values:
|
|
363
|
+
1. "externalVerticalFaces": list of external vertical faces
|
|
364
|
+
2. "internalVerticalFaces": list of internal vertical faces
|
|
365
|
+
3. "topHorizontalFaces": list of top horizontal faces
|
|
366
|
+
4. "bottomHorizontalFaces": list of bottom horizontal faces
|
|
367
|
+
5. "internalHorizontalFaces": list of internal horizontal faces
|
|
368
|
+
6. "externalInclinedFaces": list of external inclined faces
|
|
369
|
+
7. "internalInclinedFaces": list of internal inclined faces
|
|
370
|
+
8. "externalVerticalApertures": list of external vertical apertures
|
|
371
|
+
9. "internalVerticalApertures": list of internal vertical apertures
|
|
372
|
+
10. "topHorizontalApertures": list of top horizontal apertures
|
|
373
|
+
11. "bottomHorizontalApertures": list of bottom horizontal apertures
|
|
374
|
+
12. "internalHorizontalApertures": list of internal horizontal apertures
|
|
375
|
+
13. "externalInclinedApertures": list of external inclined apertures
|
|
376
|
+
14. "internalInclinedApertures": list of internal inclined apertures
|
|
377
|
+
|
|
378
|
+
"""
|
|
379
|
+
from topologicpy.Face import Face
|
|
380
|
+
from topologicpy.Vector import Vector
|
|
381
|
+
from topologicpy.Aperture import Aperture
|
|
382
|
+
from topologicpy.Topology import Topology
|
|
383
|
+
from numpy import arctan, pi, signbit, arctan2, rad2deg
|
|
384
|
+
|
|
385
|
+
def angleCode(f, up, tiltAngle):
|
|
386
|
+
dirA = Face.NormalAtParameters(f)
|
|
387
|
+
ang = round(Vector.Angle(dirA, up), 2)
|
|
388
|
+
if abs(ang - 90) < tiltAngle:
|
|
389
|
+
code = 0
|
|
390
|
+
elif abs(ang) < tiltAngle:
|
|
391
|
+
code = 1
|
|
392
|
+
elif abs(ang - 180) < tiltAngle:
|
|
393
|
+
code = 2
|
|
394
|
+
else:
|
|
395
|
+
code = 3
|
|
396
|
+
return code
|
|
397
|
+
|
|
398
|
+
def getApertures(topology):
|
|
399
|
+
apertures = []
|
|
400
|
+
apTopologies = []
|
|
401
|
+
apertures = Topology.Apertures(topology)
|
|
402
|
+
for aperture in apertures:
|
|
403
|
+
apTopologies.append(Aperture.Topology(aperture))
|
|
404
|
+
return apTopologies
|
|
405
|
+
|
|
406
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
407
|
+
return None
|
|
408
|
+
externalVerticalFaces = []
|
|
409
|
+
internalVerticalFaces = []
|
|
410
|
+
topHorizontalFaces = []
|
|
411
|
+
bottomHorizontalFaces = []
|
|
412
|
+
internalHorizontalFaces = []
|
|
413
|
+
externalInclinedFaces = []
|
|
414
|
+
internalInclinedFaces = []
|
|
415
|
+
externalVerticalApertures = []
|
|
416
|
+
internalVerticalApertures = []
|
|
417
|
+
topHorizontalApertures = []
|
|
418
|
+
bottomHorizontalApertures = []
|
|
419
|
+
internalHorizontalApertures = []
|
|
420
|
+
externalInclinedApertures = []
|
|
421
|
+
internalInclinedApertures = []
|
|
422
|
+
tiltAngle = abs(tiltAngle)
|
|
423
|
+
faces = CellComplex.Faces(cellComplex)
|
|
424
|
+
zList = []
|
|
425
|
+
for f in faces:
|
|
426
|
+
zList.append(f.Centroid().Z())
|
|
427
|
+
zMin = min(zList)
|
|
428
|
+
zMax = max(zList)
|
|
429
|
+
up = [0,0,1]
|
|
430
|
+
for aFace in faces:
|
|
431
|
+
aCode = angleCode(aFace, up, tiltAngle)
|
|
432
|
+
cells = []
|
|
433
|
+
aFace.Cells(cellComplex, cells)
|
|
434
|
+
n = len(cells)
|
|
435
|
+
if aCode == 0:
|
|
436
|
+
if n == 1:
|
|
437
|
+
externalVerticalFaces.append(aFace)
|
|
438
|
+
externalVerticalApertures += getApertures(aFace)
|
|
439
|
+
else:
|
|
440
|
+
internalVerticalFaces.append(aFace)
|
|
441
|
+
internalVerticalApertures += getApertures(aFace)
|
|
442
|
+
elif aCode == 1:
|
|
443
|
+
if n == 1:
|
|
444
|
+
if abs(aFace.Centroid().Z() - zMin) < tolerance:
|
|
445
|
+
bottomHorizontalFaces.append(aFace)
|
|
446
|
+
bottomHorizontalApertures += getApertures(aFace)
|
|
447
|
+
else:
|
|
448
|
+
topHorizontalFaces.append(aFace)
|
|
449
|
+
topHorizontalApertures += getApertures(aFace)
|
|
450
|
+
else:
|
|
451
|
+
internalHorizontalFaces.append(aFace)
|
|
452
|
+
internalHorizontalApertures += getApertures(aFace)
|
|
453
|
+
elif aCode == 2:
|
|
454
|
+
if n == 1:
|
|
455
|
+
if abs(aFace.Centroid().Z() - zMax) < tolerance:
|
|
456
|
+
topHorizontalFaces.append(aFace)
|
|
457
|
+
topHorizontalApertures += getApertures(aFace)
|
|
458
|
+
else:
|
|
459
|
+
bottomHorizontalFaces.append(aFace)
|
|
460
|
+
bottomHorizontalApertures += getApertures(aFace)
|
|
461
|
+
else:
|
|
462
|
+
internalHorizontalFaces.append(aFace)
|
|
463
|
+
internalHorizontalApertures += getApertures(aFace)
|
|
464
|
+
elif aCode == 3:
|
|
465
|
+
if n == 1:
|
|
466
|
+
externalInclinedFaces.append(aFace)
|
|
467
|
+
externalInclinedApertures += getApertures(aFace)
|
|
468
|
+
else:
|
|
469
|
+
internalInclinedFaces.append(aFace)
|
|
470
|
+
internalInclinedApertures += getApertures(aFace)
|
|
471
|
+
|
|
472
|
+
d = {
|
|
473
|
+
"externalVerticalFaces" : externalVerticalFaces,
|
|
474
|
+
"internalVerticalFaces" : internalVerticalFaces,
|
|
475
|
+
"topHorizontalFaces" : topHorizontalFaces,
|
|
476
|
+
"bottomHorizontalFaces" : bottomHorizontalFaces,
|
|
477
|
+
"internalHorizontalFaces" : internalHorizontalFaces,
|
|
478
|
+
"externalInclinedFaces" : externalInclinedFaces,
|
|
479
|
+
"internalInclinedFaces" : internalInclinedFaces,
|
|
480
|
+
"externalVerticalApertures" : externalVerticalApertures,
|
|
481
|
+
"internalVerticalApertures" : internalVerticalApertures,
|
|
482
|
+
"topHorizontalApertures" : topHorizontalApertures,
|
|
483
|
+
"bottomHorizontalApertures" : bottomHorizontalApertures,
|
|
484
|
+
"internalHorizontalApertures" : internalHorizontalApertures,
|
|
485
|
+
"externalInclinedApertures" : externalInclinedApertures,
|
|
486
|
+
"internalInclinedApertures" : internalInclinedApertures
|
|
487
|
+
}
|
|
488
|
+
return d
|
|
489
|
+
|
|
490
|
+
@staticmethod
|
|
491
|
+
def Edges(cellComplex: topologic.CellComplex) -> list:
|
|
492
|
+
"""
|
|
493
|
+
Returns the edges of the input cellComplex.
|
|
494
|
+
|
|
495
|
+
Parameters
|
|
496
|
+
----------
|
|
497
|
+
cellComplex : topologic.CellComplex
|
|
498
|
+
The input cellComplex.
|
|
499
|
+
|
|
500
|
+
Returns
|
|
501
|
+
-------
|
|
502
|
+
list
|
|
503
|
+
The list of edges.
|
|
504
|
+
|
|
505
|
+
"""
|
|
506
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
507
|
+
return None
|
|
508
|
+
edges = []
|
|
509
|
+
_ = cellComplex.Edges(None, edges)
|
|
510
|
+
return edges
|
|
511
|
+
|
|
512
|
+
@staticmethod
|
|
513
|
+
def ExternalBoundary(cellComplex: topologic.CellComplex) -> topologic.Cell:
|
|
514
|
+
"""
|
|
515
|
+
Returns the external boundary (cell) of the input cellComplex.
|
|
516
|
+
|
|
517
|
+
Parameters
|
|
518
|
+
----------
|
|
519
|
+
cellComplex : topologic.CellComplex
|
|
520
|
+
The input cellComplex.
|
|
521
|
+
|
|
522
|
+
Returns
|
|
523
|
+
-------
|
|
524
|
+
topologic.Cell
|
|
525
|
+
The external boundary of the input cellComplex.
|
|
526
|
+
|
|
527
|
+
"""
|
|
528
|
+
return cellComplex.ExternalBoundary()
|
|
529
|
+
|
|
530
|
+
@staticmethod
|
|
531
|
+
def ExternalFaces(cellComplex: topologic.CellComplex) -> list:
|
|
532
|
+
"""
|
|
533
|
+
Returns the external faces of the input cellComplex.
|
|
534
|
+
|
|
535
|
+
Parameters
|
|
536
|
+
----------
|
|
537
|
+
cellComplex : topologic.CellComplex
|
|
538
|
+
The input cellComplex.
|
|
539
|
+
|
|
540
|
+
Returns
|
|
541
|
+
-------
|
|
542
|
+
list
|
|
543
|
+
The list of external faces.
|
|
544
|
+
|
|
545
|
+
"""
|
|
546
|
+
from topologicpy.Cell import Cell
|
|
547
|
+
cell = cellComplex.ExternalBoundary()
|
|
548
|
+
return Cell.Faces(cell)
|
|
549
|
+
|
|
550
|
+
@staticmethod
|
|
551
|
+
def Faces(cellComplex: topologic.CellComplex) -> list:
|
|
552
|
+
"""
|
|
553
|
+
Returns the faces of the input cellComplex.
|
|
554
|
+
|
|
555
|
+
Parameters
|
|
556
|
+
----------
|
|
557
|
+
cellComplex : topologic.CellComplex
|
|
558
|
+
The input cellComplex.
|
|
559
|
+
|
|
560
|
+
Returns
|
|
561
|
+
-------
|
|
562
|
+
list
|
|
563
|
+
The list of faces.
|
|
564
|
+
|
|
565
|
+
"""
|
|
566
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
567
|
+
return None
|
|
568
|
+
faces = []
|
|
569
|
+
_ = cellComplex.Faces(None, faces)
|
|
570
|
+
return faces
|
|
571
|
+
|
|
572
|
+
@staticmethod
|
|
573
|
+
def InternalFaces(cellComplex: topologic.CellComplex) -> list:
|
|
574
|
+
"""
|
|
575
|
+
Returns the internal boundaries (faces) of the input cellComplex.
|
|
576
|
+
|
|
577
|
+
Parameters
|
|
578
|
+
----------
|
|
579
|
+
cellComplex : topologic.CellComplex
|
|
580
|
+
The input cellComplex.
|
|
581
|
+
|
|
582
|
+
Returns
|
|
583
|
+
-------
|
|
584
|
+
list
|
|
585
|
+
The list of internal faces of the input cellComplex.
|
|
586
|
+
|
|
587
|
+
"""
|
|
588
|
+
faces = []
|
|
589
|
+
_ = cellComplex.InternalBoundaries(faces)
|
|
590
|
+
return faces
|
|
591
|
+
|
|
592
|
+
@staticmethod
|
|
593
|
+
def NonManifoldFaces(cellComplex: topologic.CellComplex) -> list:
|
|
594
|
+
"""
|
|
595
|
+
Returns the non-manifold faces of the input cellComplex.
|
|
596
|
+
|
|
597
|
+
Parameters
|
|
598
|
+
----------
|
|
599
|
+
cellComplex : topologic.CellComplex
|
|
600
|
+
The input cellComplex.
|
|
601
|
+
|
|
602
|
+
Returns
|
|
603
|
+
-------
|
|
604
|
+
list
|
|
605
|
+
The list of non-manifold faces of the input cellComplex.
|
|
606
|
+
|
|
607
|
+
"""
|
|
608
|
+
faces = []
|
|
609
|
+
_ = cellComplex.NonManifoldFaces(faces)
|
|
610
|
+
return faces
|
|
611
|
+
|
|
612
|
+
@staticmethod
|
|
613
|
+
def Prism(origin: topologic.Vertex = None, width: float = 1.0, length: float = 1.0, height: float = 1.0, uSides: int = 2, vSides: int = 2, wSides: int = 2,
|
|
614
|
+
direction: list = [0,0,1], placement: str = "center") -> topologic.CellComplex:
|
|
615
|
+
"""
|
|
616
|
+
Creates a prismatic cellComplex with internal cells.
|
|
617
|
+
|
|
618
|
+
Parameters
|
|
619
|
+
----------
|
|
620
|
+
origin : topologic.Vertex , optional
|
|
621
|
+
The origin location of the prism. The default is None which results in the prism being placed at (0,0,0).
|
|
622
|
+
width : float , optional
|
|
623
|
+
The width of the prism. The default is 1.
|
|
624
|
+
length : float , optional
|
|
625
|
+
The length of the prism. The default is 1.
|
|
626
|
+
height : float , optional
|
|
627
|
+
The height of the prism.
|
|
628
|
+
uSides : int , optional
|
|
629
|
+
The number of sides along the width. The default is 1.
|
|
630
|
+
vSides : int , optional
|
|
631
|
+
The number of sides along the length. The default is 1.
|
|
632
|
+
wSides : int , optional
|
|
633
|
+
The number of sides along the height. The default is 1.
|
|
634
|
+
direction : list , optional
|
|
635
|
+
The vector representing the up direction of the prism. The default is [0,0,1].
|
|
636
|
+
placement : str , optional
|
|
637
|
+
The description of the placement of the origin of the prism. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
|
|
638
|
+
|
|
639
|
+
Returns
|
|
640
|
+
-------
|
|
641
|
+
topologic.CellComplex
|
|
642
|
+
The created prism.
|
|
643
|
+
|
|
644
|
+
"""
|
|
645
|
+
from topologicpy.Vertex import Vertex
|
|
646
|
+
from topologicpy.Wire import Wire
|
|
647
|
+
from topologicpy.Face import Face
|
|
648
|
+
from topologicpy.Cell import Cell
|
|
649
|
+
from topologicpy.Cluster import Cluster
|
|
650
|
+
from topologicpy.Topology import Topology
|
|
651
|
+
|
|
652
|
+
if not isinstance(origin, topologic.Vertex):
|
|
653
|
+
origin = Vertex.ByCoordinates(0,0,0)
|
|
654
|
+
|
|
655
|
+
uOffset = float(width) / float(uSides)
|
|
656
|
+
vOffset = float(length) / float(vSides)
|
|
657
|
+
wOffset = float(height) / float(wSides)
|
|
658
|
+
if placement.lower() == "center":
|
|
659
|
+
xOffset = width*0.5
|
|
660
|
+
yOffset = length*0.5
|
|
661
|
+
zOffset = height*0.5
|
|
662
|
+
elif placement.lower() == "bottom":
|
|
663
|
+
xOffset = width*0.5
|
|
664
|
+
yOffset = length*0.5
|
|
665
|
+
zOffset = 0
|
|
666
|
+
else:
|
|
667
|
+
xOffset = 0
|
|
668
|
+
yOffset = 0
|
|
669
|
+
zOffset = 0
|
|
670
|
+
cells = []
|
|
671
|
+
for i in range(uSides):
|
|
672
|
+
for j in range(vSides):
|
|
673
|
+
for k in range(wSides):
|
|
674
|
+
cOrigin = Vertex.ByCoordinates(origin.X()+i*uOffset - xOffset, origin.Y()+ j*vOffset - yOffset, origin.Z() + k*wOffset - zOffset)
|
|
675
|
+
cells.append(Cell.Prism(cOrigin, width=uOffset, length=vOffset, height=wOffset, placement="lowerleft"))
|
|
676
|
+
prism = CellComplex.ByCells(cells)
|
|
677
|
+
if prism:
|
|
678
|
+
x1 = origin.X()
|
|
679
|
+
y1 = origin.Y()
|
|
680
|
+
z1 = origin.Z()
|
|
681
|
+
x2 = origin.X() + direction[0]
|
|
682
|
+
y2 = origin.Y() + direction[1]
|
|
683
|
+
z2 = origin.Z() + direction[2]
|
|
684
|
+
dx = x2 - x1
|
|
685
|
+
dy = y2 - y1
|
|
686
|
+
dz = z2 - z1
|
|
687
|
+
dist = math.sqrt(dx**2 + dy**2 + dz**2)
|
|
688
|
+
phi = math.degrees(math.atan2(dy, dx)) # Rotation around Y-Axis
|
|
689
|
+
if dist < 0.0001:
|
|
690
|
+
theta = 0
|
|
691
|
+
else:
|
|
692
|
+
theta = math.degrees(math.acos(dz/dist)) # Rotation around Z-Axis
|
|
693
|
+
prism = Topology.Rotate(prism, origin, 0, 1, 0, theta)
|
|
694
|
+
prism = Topology.Rotate(prism, origin, 0, 0, 1, phi)
|
|
695
|
+
return prism
|
|
696
|
+
else:
|
|
697
|
+
return None
|
|
698
|
+
|
|
699
|
+
@staticmethod
|
|
700
|
+
def Shells(cellComplex: topologic.CellComplex) -> list:
|
|
701
|
+
"""
|
|
702
|
+
Returns the shells of the input cellComplex.
|
|
703
|
+
|
|
704
|
+
Parameters
|
|
705
|
+
----------
|
|
706
|
+
cellComplex : topologic.CellComplex
|
|
707
|
+
The input cellComplex.
|
|
708
|
+
|
|
709
|
+
Returns
|
|
710
|
+
-------
|
|
711
|
+
list
|
|
712
|
+
The list of shells.
|
|
713
|
+
|
|
714
|
+
"""
|
|
715
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
716
|
+
return None
|
|
717
|
+
shells = []
|
|
718
|
+
_ = cellComplex.Shells(None, shells)
|
|
719
|
+
return shells
|
|
720
|
+
|
|
721
|
+
@staticmethod
|
|
722
|
+
def Vertices(cellComplex: topologic.CellComplex) -> list:
|
|
723
|
+
"""
|
|
724
|
+
Returns the vertices of the input cellComplex.
|
|
725
|
+
|
|
726
|
+
Parameters
|
|
727
|
+
----------
|
|
728
|
+
cellComplex : topologic.CellComplex
|
|
729
|
+
The input cellComplex.
|
|
730
|
+
|
|
731
|
+
Returns
|
|
732
|
+
-------
|
|
733
|
+
list
|
|
734
|
+
The list of vertices.
|
|
735
|
+
|
|
736
|
+
"""
|
|
737
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
738
|
+
return None
|
|
739
|
+
vertices = []
|
|
740
|
+
_ = cellComplex.Vertices(None, vertices)
|
|
741
|
+
return vertices
|
|
742
|
+
|
|
743
|
+
@staticmethod
|
|
744
|
+
def Volume(cellComplex: topologic.CellComplex, mantissa: int = 4) -> float:
|
|
745
|
+
"""
|
|
746
|
+
Returns the volume of the input cellComplex.
|
|
747
|
+
|
|
748
|
+
Parameters
|
|
749
|
+
----------
|
|
750
|
+
cellComplex : topologic.CellComplex
|
|
751
|
+
The input cellComplex.
|
|
752
|
+
manitssa: int , optional
|
|
753
|
+
The desired length of the mantissa. The default is 4.
|
|
754
|
+
|
|
755
|
+
Returns
|
|
756
|
+
-------
|
|
757
|
+
float
|
|
758
|
+
The volume of the input cellComplex.
|
|
759
|
+
|
|
760
|
+
"""
|
|
761
|
+
from topologicpy.Cell import Cell
|
|
762
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
763
|
+
return None
|
|
764
|
+
cells = CellComplex.Cells(cellComplex)
|
|
765
|
+
volume = 0
|
|
766
|
+
for cell in cells:
|
|
767
|
+
volume += Cell.Volume(cell)
|
|
768
|
+
return round(volume, mantissa)
|
|
769
|
+
|
|
770
|
+
@staticmethod
|
|
771
|
+
def Wires(cellComplex: topologic.CellComplex) -> list:
|
|
772
|
+
"""
|
|
773
|
+
Returns the wires of the input cellComplex.
|
|
774
|
+
|
|
775
|
+
Parameters
|
|
776
|
+
----------
|
|
777
|
+
cellComplex : topologic.CellComplex
|
|
778
|
+
The input cellComplex.
|
|
779
|
+
|
|
780
|
+
Returns
|
|
781
|
+
-------
|
|
782
|
+
list
|
|
783
|
+
The list of wires.
|
|
784
|
+
|
|
785
|
+
"""
|
|
786
|
+
if not isinstance(cellComplex, topologic.CellComplex):
|
|
787
|
+
return None
|
|
788
|
+
wires = []
|
|
789
|
+
_ = cellComplex.Wires(None, wires)
|
|
790
|
+
return wires
|
|
791
|
+
|