topologicpy 0.8.21__py3-none-any.whl → 0.8.23__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/ANN.py +1 -1
- topologicpy/Aperture.py +1 -1
- topologicpy/BVH.py +1 -1
- topologicpy/CSG.py +389 -0
- topologicpy/Cell.py +38 -1
- topologicpy/CellComplex.py +39 -1
- topologicpy/Cluster.py +1 -1
- topologicpy/Color.py +1 -1
- topologicpy/Context.py +1 -1
- topologicpy/DGL.py +1 -1
- topologicpy/Dictionary.py +7 -5
- topologicpy/Edge.py +1 -1
- topologicpy/EnergyModel.py +1 -1
- topologicpy/Face.py +1 -1
- topologicpy/Graph.py +119 -60
- topologicpy/Grid.py +1 -1
- topologicpy/Helper.py +1 -1
- topologicpy/Honeybee.py +1 -1
- topologicpy/Matrix.py +1 -1
- topologicpy/Neo4j.py +1 -1
- topologicpy/Plotly.py +3 -3
- topologicpy/Polyskel.py +1 -1
- topologicpy/PyG.py +1 -1
- topologicpy/Shell.py +1 -1
- topologicpy/Speckle.py +1 -1
- topologicpy/Sun.py +1 -1
- topologicpy/Topology.py +32 -27
- topologicpy/Vector.py +1 -1
- topologicpy/Vertex.py +1 -1
- topologicpy/Wire.py +1 -1
- topologicpy/__init__.py +1 -1
- topologicpy/version.py +1 -1
- {topologicpy-0.8.21.dist-info → topologicpy-0.8.23.dist-info}/METADATA +1 -1
- topologicpy-0.8.23.dist-info/RECORD +37 -0
- {topologicpy-0.8.21.dist-info → topologicpy-0.8.23.dist-info}/WHEEL +1 -1
- topologicpy-0.8.21.dist-info/RECORD +0 -36
- {topologicpy-0.8.21.dist-info → topologicpy-0.8.23.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.21.dist-info → topologicpy-0.8.23.dist-info}/top_level.txt +0 -0
topologicpy/ANN.py
CHANGED
topologicpy/Aperture.py
CHANGED
topologicpy/BVH.py
CHANGED
topologicpy/CSG.py
ADDED
@@ -0,0 +1,389 @@
|
|
1
|
+
# Copyright (C) 2025
|
2
|
+
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free Software
|
6
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
7
|
+
# version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License along with
|
15
|
+
# this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
class CSG():
|
18
|
+
@staticmethod
|
19
|
+
def _unique_coords(used_coords=[], width=10, length=10, height=10, max_attempts=1000, mantissa=6, tolerance=0.0001):
|
20
|
+
import math
|
21
|
+
import random
|
22
|
+
|
23
|
+
def is_too_close(p1, p2):
|
24
|
+
return math.dist(p1, p2) < tolerance
|
25
|
+
|
26
|
+
if used_coords == []:
|
27
|
+
return [0,0,0]
|
28
|
+
|
29
|
+
attempts = 0
|
30
|
+
while attempts < max_attempts:
|
31
|
+
x = round(random.uniform(0, width), mantissa)
|
32
|
+
y = round(random.uniform(0, length), mantissa)
|
33
|
+
z = round(random.uniform(0, height), mantissa)
|
34
|
+
candidate = [x, y, z]
|
35
|
+
if all(not is_too_close(candidate, used) for used in used_coords):
|
36
|
+
return candidate
|
37
|
+
attempts += 1
|
38
|
+
|
39
|
+
raise RuntimeError("Could not find a unique coordinate within the attempt limit.")
|
40
|
+
|
41
|
+
@staticmethod
|
42
|
+
def AddTopologyVertex(graph, topology, matrix: list = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
43
|
+
"""
|
44
|
+
Adds a topology vertex to the graph.
|
45
|
+
|
46
|
+
Parameters
|
47
|
+
----------
|
48
|
+
graph : topologic_core.Graph
|
49
|
+
The input graph.
|
50
|
+
topology : topologic_core.Topology
|
51
|
+
The input topology..
|
52
|
+
matrix : list , optional
|
53
|
+
The desired 4X4 transformation matrix to apply to the result before any further operations. The default is None.
|
54
|
+
mantissa : int , optional
|
55
|
+
The desired length of the mantissa. The default is 6.
|
56
|
+
tolerance : float , optional
|
57
|
+
The desired tolerance. The default is 0.0001.
|
58
|
+
silent : bool , optional
|
59
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
60
|
+
|
61
|
+
Returns
|
62
|
+
-------
|
63
|
+
topologic_core.Vertex
|
64
|
+
The added vertex.
|
65
|
+
"""
|
66
|
+
|
67
|
+
from topologicpy.Vertex import Vertex
|
68
|
+
from topologicpy.Dictionary import Dictionary
|
69
|
+
from topologicpy.Matrix import Matrix
|
70
|
+
from topologicpy.Topology import Topology
|
71
|
+
from topologicpy.Graph import Graph
|
72
|
+
|
73
|
+
if matrix == None:
|
74
|
+
matrix = Matrix.Identity()
|
75
|
+
if graph == None:
|
76
|
+
used_coords = []
|
77
|
+
else:
|
78
|
+
used_coords = [Vertex.Coordinates(v, mantissa=mantissa) for v in Graph.Vertices(graph)]
|
79
|
+
loc = CSG._unique_coords(used_coords=used_coords, width=10, length=10, height=10, max_attempts=1000, mantissa=mantissa, tolerance=tolerance)
|
80
|
+
v = Vertex.ByCoordinates(loc)
|
81
|
+
keys = ["brep",
|
82
|
+
"brepType",
|
83
|
+
"brepTypeString",
|
84
|
+
"matrix",
|
85
|
+
"type",
|
86
|
+
"id"]
|
87
|
+
values = [Topology.BREPString(topology),
|
88
|
+
Topology.Type(topology),
|
89
|
+
Topology.TypeAsString(topology),
|
90
|
+
matrix,
|
91
|
+
"topology",
|
92
|
+
Topology.UUID(v)]
|
93
|
+
|
94
|
+
d = Dictionary.ByKeysValues(keys, values)
|
95
|
+
v = Topology.SetDictionary(v, d)
|
96
|
+
if graph == None:
|
97
|
+
graph = Graph.ByVerticesEdges([v], [])
|
98
|
+
else:
|
99
|
+
graph = Graph.AddVertex(graph, v, tolerance=tolerance, silent=silent)
|
100
|
+
return v
|
101
|
+
|
102
|
+
@staticmethod
|
103
|
+
def AddOperationVertex(graph, operation, a, b, matrix = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
104
|
+
"""
|
105
|
+
Adds an operation vertex to the graph that performs a CSG operation on two child vertices. For ordered operations, the order of a and b inputs is important.
|
106
|
+
|
107
|
+
Parameters
|
108
|
+
----------
|
109
|
+
graph : topologic_core.Graph
|
110
|
+
The input graph.
|
111
|
+
operation : str
|
112
|
+
The operation to perform. One of "union", "difference", "intersection", "xor", "merge", "impose", "imprint", "slice".
|
113
|
+
a : topologic_core.Vertex
|
114
|
+
The first input vertex.
|
115
|
+
b : topologic_core.Vertex
|
116
|
+
The second input vertex.
|
117
|
+
matrix : list , optional
|
118
|
+
The desired 4X4 transformation matrix to apply to the result before any further operations. The default is None.
|
119
|
+
mantissa : int , optional
|
120
|
+
The desired length of the mantissa. The default is 6.
|
121
|
+
tolerance : float , optional
|
122
|
+
The desired tolerance. The default is 0.0001.
|
123
|
+
silent : bool , optional
|
124
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
125
|
+
|
126
|
+
Returns
|
127
|
+
-------
|
128
|
+
topologic_core.Vertex
|
129
|
+
The added vertex.
|
130
|
+
"""
|
131
|
+
from topologicpy.Vertex import Vertex
|
132
|
+
from topologicpy.Dictionary import Dictionary
|
133
|
+
from topologicpy.Topology import Topology
|
134
|
+
from topologicpy.Graph import Graph
|
135
|
+
|
136
|
+
if graph == None:
|
137
|
+
used_coords = []
|
138
|
+
else:
|
139
|
+
used_coords = [Vertex.Coordinates(v, mantissa=mantissa) for v in Graph.Vertices(graph)]
|
140
|
+
loc = CSG._unique_coords(used_coords=used_coords, width=10, length=10, height=10, max_attempts=1000, mantissa=mantissa, tolerance=tolerance)
|
141
|
+
v = Vertex.ByCoordinates(loc)
|
142
|
+
a_id = Dictionary.ValueAtKey(Topology.Dictionary(a), "id")
|
143
|
+
b_id = Dictionary.ValueAtKey(Topology.Dictionary(b), "id")
|
144
|
+
|
145
|
+
keys = ["brep",
|
146
|
+
"brepType",
|
147
|
+
"brepTypeString",
|
148
|
+
"matrix",
|
149
|
+
"type",
|
150
|
+
"id",
|
151
|
+
"operation",
|
152
|
+
"a_id",
|
153
|
+
"b_id"]
|
154
|
+
values = [None,
|
155
|
+
None,
|
156
|
+
None,
|
157
|
+
matrix,
|
158
|
+
"operation",
|
159
|
+
Topology.UUID(v),
|
160
|
+
operation,
|
161
|
+
a_id,
|
162
|
+
b_id]
|
163
|
+
|
164
|
+
d = Dictionary.ByKeysValues(keys, values)
|
165
|
+
v = Topology.SetDictionary(v, d)
|
166
|
+
return v
|
167
|
+
|
168
|
+
@staticmethod
|
169
|
+
def Connect(graph, vertexA, vertexB, tolerance: float = 0.0001, silent: bool = False):
|
170
|
+
"""
|
171
|
+
Connects two vertices in the graph with a directional edge from vertexA to vertexB.
|
172
|
+
|
173
|
+
Parameters
|
174
|
+
----------
|
175
|
+
graph : topologic_core.Graph
|
176
|
+
The input graph.
|
177
|
+
vertexA : topologic_core.Vertex
|
178
|
+
The first input vertex.
|
179
|
+
vertexB : topologic_core.Vertex
|
180
|
+
The second input vertex.
|
181
|
+
matrix : list , optional
|
182
|
+
The desired 4X4 transformation matrix to apply to the result before any further operations. The default is None.
|
183
|
+
tolerance : float , optional
|
184
|
+
The desired tolerance. The default is 0.0001.
|
185
|
+
silent : bool , optional
|
186
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
187
|
+
|
188
|
+
Returns
|
189
|
+
-------
|
190
|
+
topologic_core.Vertex
|
191
|
+
The added vertex.
|
192
|
+
"""
|
193
|
+
from topologicpy.Graph import Graph
|
194
|
+
from topologicpy.Edge import Edge
|
195
|
+
from topologicpy.Topology import Topology
|
196
|
+
|
197
|
+
if not Topology.IsInstance(vertexA, "Vertex"):
|
198
|
+
if not silent:
|
199
|
+
print("CSG.Connect - Error: The input vertexA parameter is not a valid vertex. Returning None.")
|
200
|
+
return None
|
201
|
+
if not Topology.IsInstance(vertexB, "Vertex"):
|
202
|
+
if not silent:
|
203
|
+
print("CSG.Connect - Error: The input vertexB parameter is not a valid vertex. Returning None.")
|
204
|
+
return None
|
205
|
+
edge = Edge.ByVertices(vertexA, vertexB, tolerance=tolerance)
|
206
|
+
if graph == None:
|
207
|
+
vertices = [vertexA, vertexB]
|
208
|
+
edges = [edge]
|
209
|
+
else:
|
210
|
+
if not Topology.IsInstance(graph, "Graph"):
|
211
|
+
if not silent:
|
212
|
+
print("CSG.Connect - Error: The input graph parameter is not a valid graph. Returning None.")
|
213
|
+
return None
|
214
|
+
vertices = Graph.Vertices(graph)
|
215
|
+
edges = Graph.Edges(graph)
|
216
|
+
if len(edges) > 0:
|
217
|
+
edges.append(edge)
|
218
|
+
else:
|
219
|
+
edges = [edge]
|
220
|
+
graph = Graph.ByVerticesEdges(vertices, edges)
|
221
|
+
return graph
|
222
|
+
|
223
|
+
@staticmethod
|
224
|
+
def Init():
|
225
|
+
"""
|
226
|
+
Returns an initial empty graph.
|
227
|
+
|
228
|
+
Parameters
|
229
|
+
----------
|
230
|
+
|
231
|
+
Returns
|
232
|
+
-------
|
233
|
+
topologic_core.Graph
|
234
|
+
The initialized empty graph.
|
235
|
+
"""
|
236
|
+
|
237
|
+
from topologicpy.Graph import Graph
|
238
|
+
|
239
|
+
return Graph.ByVerticesEdges([], [])
|
240
|
+
|
241
|
+
@staticmethod
|
242
|
+
def Invoke(graph, silent: bool = False):
|
243
|
+
"""
|
244
|
+
Traverses the graph and evaluates all CSG operations from leaves to root, returning the final result.
|
245
|
+
|
246
|
+
Parameters
|
247
|
+
----------
|
248
|
+
graph : topologic_core.Graph
|
249
|
+
The input graph.
|
250
|
+
silent : bool , optional
|
251
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
252
|
+
|
253
|
+
Returns
|
254
|
+
-------
|
255
|
+
topologic_core.Topology
|
256
|
+
The final topology.
|
257
|
+
"""
|
258
|
+
|
259
|
+
from topologicpy.Topology import Topology
|
260
|
+
from topologicpy.Dictionary import Dictionary
|
261
|
+
from topologicpy.Graph import Graph
|
262
|
+
|
263
|
+
if not Topology.IsInstance(graph, "Graph"):
|
264
|
+
if not silent:
|
265
|
+
print("CSG.Connect - Error: The input graphA parameter is not a valid graph. Returning None.")
|
266
|
+
return None
|
267
|
+
|
268
|
+
def traverse(vertex):
|
269
|
+
d = Topology.Dictionary(vertex)
|
270
|
+
node_type = Dictionary.ValueAtKey(d, "type")
|
271
|
+
|
272
|
+
if node_type == "topology":
|
273
|
+
topology = Topology.ByBREPString(Dictionary.ValueAtKey(d, "brep"))
|
274
|
+
matrix = Dictionary.ValueAtKey(d, "matrix")
|
275
|
+
topology = Topology.Transform(topology, matrix)
|
276
|
+
topology = Topology.SetDictionary(topology, d)
|
277
|
+
return topology
|
278
|
+
|
279
|
+
elif node_type == "operation":
|
280
|
+
op = Dictionary.ValueAtKey(d, "operation")
|
281
|
+
a_id = Dictionary.ValueAtKey(d, "a_id")
|
282
|
+
|
283
|
+
children = Graph.IncomingVertices(graph, vertex, directed=True)
|
284
|
+
if len(children) != 2:
|
285
|
+
if not silent:
|
286
|
+
print(f"CSG.Invoke - Error: Operation '{op}' must have exactly 2 children. Returning None.")
|
287
|
+
return None
|
288
|
+
|
289
|
+
child_0 = children[0]
|
290
|
+
child_1 = children[1]
|
291
|
+
child_0_id = Dictionary.ValueAtKey(Topology.Dictionary(child_0), "id")
|
292
|
+
if child_0_id != a_id:
|
293
|
+
child_0 = children[1]
|
294
|
+
child_1 = children[0]
|
295
|
+
a = traverse(child_0)
|
296
|
+
b = traverse(child_1)
|
297
|
+
if op.lower() == "union":
|
298
|
+
result = Topology.Union(a, b, silent=silent)
|
299
|
+
elif op.lower() == "intersection":
|
300
|
+
result = Topology.Intersect(a, b, silent=silent)
|
301
|
+
elif op.lower() == "difference":
|
302
|
+
result = Topology.Difference(a, b, silent=silent)
|
303
|
+
elif op.lower() == "xor" or "sym" in op.lower():
|
304
|
+
result = Topology.SymmeticDifference(a, b, silent=silent)
|
305
|
+
elif op.lower() == "merge":
|
306
|
+
result = Topology.Merge(a, b, silent=silent)
|
307
|
+
elif op.lower() == "impose":
|
308
|
+
result = Topology.Impose(a, b, silent=silent)
|
309
|
+
elif op.lower() == "imprint":
|
310
|
+
result = Topology.Imprint(a, b, silent=silent)
|
311
|
+
elif op.lower() == "slice":
|
312
|
+
result = Topology.Slice(a, b, silent=silent)
|
313
|
+
else:
|
314
|
+
if not silent:
|
315
|
+
print(f"CSG.Invoke - Error: Unknown operation '{op}'. Returning None.")
|
316
|
+
return None
|
317
|
+
keys = ["brep",
|
318
|
+
"brepType",
|
319
|
+
"brepTypeString"]
|
320
|
+
values = [Topology.BREPString(result),
|
321
|
+
Topology.Type(result),
|
322
|
+
Topology.TypeAsString(result)]
|
323
|
+
d = Dictionary.SetValuesAtKeys(d, keys=keys, values=values)
|
324
|
+
vertex = Topology.SetDictionary(vertex, d)
|
325
|
+
matrix = Dictionary.ValueAtKey(d, "matrix")
|
326
|
+
if not matrix == None:
|
327
|
+
result = Topology.Transform(result, matrix)
|
328
|
+
result = Topology.SetDictionary(result, d)
|
329
|
+
return result
|
330
|
+
else:
|
331
|
+
if not silent:
|
332
|
+
print(f"CSG.Invoke - Error: Unknown node type '{node_type}'. Returning None.")
|
333
|
+
return None
|
334
|
+
|
335
|
+
# Assume root is the vertex with no outgoing edges
|
336
|
+
roots = [v for v in Graph.Vertices(graph) if not Graph.OutgoingVertices(graph, v, directed=True)]
|
337
|
+
if len(roots) != 1:
|
338
|
+
if not silent:
|
339
|
+
print("CSG.Invoke - Error: Graph must have exactly one root node. Returning None.")
|
340
|
+
return None
|
341
|
+
|
342
|
+
return traverse(roots[0])
|
343
|
+
|
344
|
+
def Topologies(graph, xOffset: float = 0, yOffset: float = 0, zOffset: float = 0, scale: float = 1, silent: bool = False):
|
345
|
+
"""
|
346
|
+
Places each geometry (using its centroid) at its corresponding vertex location in the graph.
|
347
|
+
|
348
|
+
Parameters
|
349
|
+
----------
|
350
|
+
graph : topologic_core.Graph
|
351
|
+
The input graph.
|
352
|
+
xOffset : float , optional
|
353
|
+
An additional x offset. The default is 0.
|
354
|
+
yOffset : float , optional
|
355
|
+
An additional y offset. The default is 0.
|
356
|
+
zOffset : float , optional
|
357
|
+
An additional z offset. The default is 0.
|
358
|
+
scale : float , optional
|
359
|
+
A desired scale to resize the placed topologies. The default is 1.
|
360
|
+
silent : bool , optional
|
361
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
362
|
+
|
363
|
+
Returns
|
364
|
+
-------
|
365
|
+
list
|
366
|
+
The list of topologies placed at their corresponding location in the graph.
|
367
|
+
"""
|
368
|
+
|
369
|
+
from topologicpy.Topology import Topology
|
370
|
+
from topologicpy.Dictionary import Dictionary
|
371
|
+
from topologicpy.Graph import Graph
|
372
|
+
|
373
|
+
if not Topology.IsInstance(graph, "Graph"):
|
374
|
+
if not silent:
|
375
|
+
print("CSG.Topologies - Error: The input graph parameter is not a valid graph. Returning None.")
|
376
|
+
return None
|
377
|
+
placed_topologies= []
|
378
|
+
|
379
|
+
for vertex in Graph.Vertices(graph):
|
380
|
+
geom = Topology.ByBREPString(Dictionary.ValueAtKey(Topology.Dictionary(vertex), "brep"))
|
381
|
+
originA = Topology.Centroid(geom)
|
382
|
+
geom = Topology.Scale(geom, origin=originA, x=scale, y=scale, z=scale)
|
383
|
+
originB = vertex
|
384
|
+
placed = Topology.Place(geom, originA, originB)
|
385
|
+
placed = Topology.Translate(placed, x=xOffset, y=yOffset, z=zOffset)
|
386
|
+
placed_topologies.append(placed)
|
387
|
+
|
388
|
+
return placed_topologies
|
389
|
+
|
topologicpy/Cell.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -850,6 +850,43 @@ class Cell():
|
|
850
850
|
print("Cell.ContainmentStatus - Error: Could not determine containment status. Returning None.")
|
851
851
|
return None
|
852
852
|
|
853
|
+
@staticmethod
|
854
|
+
def Cube(origin = None,
|
855
|
+
size: float = 1,
|
856
|
+
uSides: int = 1, vSides: int = 1, wSides: int = 1,
|
857
|
+
direction: list = [0, 0, 1], placement: str ="center", tolerance: float = 0.0001):
|
858
|
+
"""
|
859
|
+
Creates a cube.
|
860
|
+
|
861
|
+
Parameters
|
862
|
+
----------
|
863
|
+
origin : topologic_core.Vertex , optional
|
864
|
+
The origin location of the cube. The default is None which results in the cube being placed at (0, 0, 0).
|
865
|
+
size : float , optional
|
866
|
+
The size of the cube. The default is 1.
|
867
|
+
uSides : int , optional
|
868
|
+
The number of sides along the width. The default is 1.
|
869
|
+
vSides : int , optional
|
870
|
+
The number of sides along the length. The default is 1.
|
871
|
+
wSides : int , optional
|
872
|
+
The number of sides along the height. The default is 1.
|
873
|
+
direction : list , optional
|
874
|
+
The vector representing the up direction of the cube. The default is [0, 0, 1].
|
875
|
+
placement : str , optional
|
876
|
+
The description of the placement of the origin of the cube. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
|
877
|
+
tolerance : float , optional
|
878
|
+
The desired tolerance. The default is 0.0001.
|
879
|
+
|
880
|
+
Returns
|
881
|
+
-------
|
882
|
+
topologic_core.Cell
|
883
|
+
The created cube.
|
884
|
+
|
885
|
+
"""
|
886
|
+
return Cell.Prism(origin=origin, width=size, length=size, height=size,
|
887
|
+
uSides=uSides, vSides=vSides, wSides=wSides,
|
888
|
+
direction=direction, placement=placement, tolerance=tolerance)
|
889
|
+
|
853
890
|
@staticmethod
|
854
891
|
def Cylinder(origin = None, radius: float = 0.5, height: float = 1, uSides: int = 16, vSides: int = 1, direction: list = [0, 0, 1],
|
855
892
|
placement: str = "center", mantissa: int = 6, tolerance: float = 0.0001):
|
topologicpy/CellComplex.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -450,6 +450,44 @@ class CellComplex():
|
|
450
450
|
_ = cellComplex.Cells(None, cells) # Hook to Core
|
451
451
|
return cells
|
452
452
|
|
453
|
+
@staticmethod
|
454
|
+
def Cube(origin= None,
|
455
|
+
size: float = 1.0,
|
456
|
+
uSides: int = 2, vSides: int = 2, wSides: int = 2,
|
457
|
+
direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
458
|
+
"""
|
459
|
+
Creates a cube with internal cells.
|
460
|
+
|
461
|
+
Parameters
|
462
|
+
----------
|
463
|
+
origin : topologic_core.Vertex , optional
|
464
|
+
The origin location of the cube. The default is None which results in the cube being placed at (0, 0, 0).
|
465
|
+
size : float , optional
|
466
|
+
The size of the cube. The default is 1.
|
467
|
+
uSides : int , optional
|
468
|
+
The number of sides along the width. The default is 1.
|
469
|
+
vSides : int, optional
|
470
|
+
The number of sides along the length. The default is 1.
|
471
|
+
wSides : int , optional
|
472
|
+
The number of sides along the height. The default is 1.
|
473
|
+
direction : list , optional
|
474
|
+
The vector representing the up direction of the cube. The default is [0, 0, 1].
|
475
|
+
placement : str , optional
|
476
|
+
The description of the placement of the origin of the cube. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
|
477
|
+
tolerance : float , optional
|
478
|
+
The desired tolerance. The default is 0.0001.
|
479
|
+
|
480
|
+
Returns
|
481
|
+
-------
|
482
|
+
topologic_core.CellComplex
|
483
|
+
The created cube.
|
484
|
+
|
485
|
+
"""
|
486
|
+
return CellComplex.Prism(origin=origin,
|
487
|
+
width=size, length=size, height=size,
|
488
|
+
uSides=uSides, vSides=vSides, wSides=wSides,
|
489
|
+
direction=direction, placement=placement, tolerance=tolerance)
|
490
|
+
|
453
491
|
@staticmethod
|
454
492
|
def Decompose(cellComplex, tiltAngle: float = 10.0, tolerance: float = 0.0001) -> dict:
|
455
493
|
"""
|
topologicpy/Cluster.py
CHANGED
topologicpy/Color.py
CHANGED
topologicpy/Context.py
CHANGED
topologicpy/DGL.py
CHANGED
topologicpy/Dictionary.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -773,7 +773,7 @@ class Dictionary():
|
|
773
773
|
return None
|
774
774
|
|
775
775
|
@staticmethod
|
776
|
-
def ValueAtKey(dictionary, key, silent=False):
|
776
|
+
def ValueAtKey(dictionary, key, defaultValue=None, silent=False):
|
777
777
|
"""
|
778
778
|
Returns the value of the input key in the input dictionary.
|
779
779
|
|
@@ -783,6 +783,8 @@ class Dictionary():
|
|
783
783
|
The input dictionary.
|
784
784
|
key : string
|
785
785
|
The input key.
|
786
|
+
defaultValue : any , optional
|
787
|
+
The default value to return if the key or value are not found. The default is None.
|
786
788
|
silent : bool , optional
|
787
789
|
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
788
790
|
|
@@ -804,10 +806,10 @@ class Dictionary():
|
|
804
806
|
return None
|
805
807
|
if Topology.IsInstance(dictionary, "Dictionary"):
|
806
808
|
dic = Dictionary.PythonDictionary(dictionary)
|
807
|
-
return dic.get(key,
|
809
|
+
return dic.get(key, defaultValue)
|
808
810
|
elif isinstance(dictionary, dict):
|
809
|
-
return dictionary.get(key,
|
810
|
-
return
|
811
|
+
return dictionary.get(key, defaultValue)
|
812
|
+
return defaultValue
|
811
813
|
|
812
814
|
# if isinstance(dictionary, dict):
|
813
815
|
# attr = dictionary[key]
|
topologicpy/Edge.py
CHANGED
topologicpy/EnergyModel.py
CHANGED
topologicpy/Face.py
CHANGED
topologicpy/Graph.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -4379,12 +4379,17 @@ class Graph:
|
|
4379
4379
|
|
4380
4380
|
@staticmethod
|
4381
4381
|
def Compare(graphA, graphB,
|
4382
|
-
weightAttributes: float =
|
4383
|
-
weightGeometry: float =
|
4384
|
-
|
4385
|
-
|
4386
|
-
|
4387
|
-
|
4382
|
+
weightAttributes: float = 0.0,
|
4383
|
+
weightGeometry: float = 0.0,
|
4384
|
+
weightBetwennessCentrality: float = 0.0,
|
4385
|
+
weightClosenessCentrality: float = 0.0,
|
4386
|
+
weightDegreeCentrality: float = 0.0,
|
4387
|
+
weightDiameter: float = 0.0,
|
4388
|
+
weightGlobalClusteringCoefficient: float = 0.0,
|
4389
|
+
weightPageRank: float = 0.0,
|
4390
|
+
weightStructure: float = 0.0,
|
4391
|
+
weightWeisfeilerLehman: float = 0.0,
|
4392
|
+
weightJaccard: float = 0.0,
|
4388
4393
|
vertexIDKey: str = "id",
|
4389
4394
|
edgeWeightKey: str = None,
|
4390
4395
|
iterations: int = 3,
|
@@ -4402,18 +4407,28 @@ class Graph:
|
|
4402
4407
|
graphB : topologic Graph
|
4403
4408
|
The second input graph.
|
4404
4409
|
weightAttributes : float , optional
|
4405
|
-
The desired weight for attribute similarity (dictionary key overlap at vertices). Default is
|
4410
|
+
The desired weight for attribute similarity (dictionary key overlap at vertices). Default is 0.0.
|
4411
|
+
weightBetwennessCentrality : float , optional
|
4412
|
+
The desired weight for betweenness centrality similarity (graph-level and node-level). Default is 0.0.
|
4413
|
+
weightClosenessCentrality : float , optional
|
4414
|
+
The desired weight for closeness centrality similarity (graph-level and node-level). Default is 0.0.
|
4415
|
+
weightDegreeCentrality : float , optional
|
4416
|
+
The desired weight for degree centrality similarity (graph-level and node-level). Default is 0.0.
|
4417
|
+
weightDiameter : float , optional
|
4418
|
+
The desired weight for diameter similarity (graph-level and node-level). Default is 0.0.
|
4406
4419
|
weightGeometry : float , optional
|
4407
|
-
The desired weight for geometric similarity (vertex positions). Default is
|
4408
|
-
|
4409
|
-
The desired weight for
|
4410
|
-
The compared metrics are: betweenness centrality, closeness centrality, clustering coefficient, degree, diameter, and pagerank.
|
4411
|
-
weightStructure : float , optional
|
4412
|
-
The desired weight for structural similarity (number of vertices and edges). Default is 1.0.
|
4413
|
-
weightWL : float , optional
|
4414
|
-
The desired weight for Weisfeiler-Lehman kernel similarity (iterative label propagation). Default is 1.0.
|
4420
|
+
The desired weight for geometric similarity (vertex positions). Default is 0.0.
|
4421
|
+
weightGlobalClusteringCoefficient : float , optional
|
4422
|
+
The desired weight for global clustering coefficient similarity (graph-level and node-level). Default is 0.0.
|
4415
4423
|
weightJaccard: float , optional
|
4416
|
-
The desired weight for the Weighted Jaccard similarity. Default is
|
4424
|
+
The desired weight for the Weighted Jaccard similarity. Default is 0.0.
|
4425
|
+
weightPageRank : float , optional
|
4426
|
+
The desired weight for PageRank similarity (graph-level and node-level). Default is 0.0.
|
4427
|
+
weightStructure : float , optional
|
4428
|
+
The desired weight for structural similarity (number of vertices and edges). Default is 0.0.
|
4429
|
+
weightWeisfeilerLehman : float , optional
|
4430
|
+
The desired weight for Weisfeiler-Lehman kernel similarity (iterative label propagation). Default is 0.0.
|
4431
|
+
|
4417
4432
|
vertexIDKey: str , optional
|
4418
4433
|
The dictionary key under which to find the unique vertex ID. The default is "id".
|
4419
4434
|
edgeWeightKey: str , optional
|
@@ -4433,12 +4448,16 @@ class Graph:
|
|
4433
4448
|
A dictionary of similarity scores between 0 (completely dissimilar) and 1 (identical), based on weighted components.
|
4434
4449
|
The keys in the dictionary are:
|
4435
4450
|
"attribute"
|
4451
|
+
"betwenness_centrality"
|
4452
|
+
"closeness_centrality"
|
4453
|
+
"degree_centrality"
|
4436
4454
|
"geometry"
|
4437
|
-
"
|
4455
|
+
"global_clustering_coefficient"
|
4456
|
+
"jaccard"
|
4457
|
+
"pagerank"
|
4438
4458
|
"structure"
|
4439
|
-
"
|
4459
|
+
"weisfeiler_lehman"
|
4440
4460
|
"overall"
|
4441
|
-
|
4442
4461
|
"""
|
4443
4462
|
|
4444
4463
|
import hashlib
|
@@ -4551,40 +4570,56 @@ class Graph:
|
|
4551
4570
|
|
4552
4571
|
return numerator / denominator if denominator > 0 else 0.0
|
4553
4572
|
|
4554
|
-
def
|
4555
|
-
# Example using global metrics + mean of node metrics
|
4556
|
-
def safe_mean(lst):
|
4573
|
+
def safe_mean(lst):
|
4557
4574
|
return sum(lst)/len(lst) if lst else 0
|
4558
|
-
|
4559
|
-
|
4560
|
-
|
4561
|
-
|
4562
|
-
|
4563
|
-
|
4564
|
-
|
4565
|
-
|
4566
|
-
|
4567
|
-
|
4568
|
-
|
4569
|
-
|
4570
|
-
|
4571
|
-
|
4572
|
-
|
4573
|
-
|
4574
|
-
|
4575
|
-
|
4576
|
-
|
4577
|
-
|
4578
|
-
|
4579
|
-
|
4580
|
-
|
4581
|
-
|
4582
|
-
|
4583
|
-
|
4584
|
-
|
4585
|
-
|
4586
|
-
|
4587
|
-
|
4575
|
+
|
4576
|
+
def betweenness_centrality_similarity(graphA, graphB, mantissa=6):
|
4577
|
+
v1 = safe_mean(Graph.BetweennessCentrality(graphA))
|
4578
|
+
v2 = safe_mean(Graph.BetweennessCentrality(graphB))
|
4579
|
+
if v1 == 0 and v2 == 0:
|
4580
|
+
return 1
|
4581
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4582
|
+
return round((1 - diff), mantissa)
|
4583
|
+
|
4584
|
+
def closeness_centrality_similarity(graphA, graphB, mantissa=6):
|
4585
|
+
v1 = safe_mean(Graph.ClosenessCentrality(graphA))
|
4586
|
+
v2 = safe_mean(Graph.ClosenessCentrality(graphB))
|
4587
|
+
if v1 == 0 and v2 == 0:
|
4588
|
+
return 1
|
4589
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4590
|
+
return round((1 - diff), mantissa)
|
4591
|
+
|
4592
|
+
def degree_centrality_similarity(graphA, graphB, mantissa=6):
|
4593
|
+
v1 = safe_mean(Graph.DegreeCentrality(graphA))
|
4594
|
+
v2 = safe_mean(Graph.DegreeCentrality(graphB))
|
4595
|
+
if v1 == 0 and v2 == 0:
|
4596
|
+
return 1
|
4597
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4598
|
+
return round((1 - diff), mantissa)
|
4599
|
+
|
4600
|
+
def diameter_similarity(graphA, graphB, mantissa=6):
|
4601
|
+
v1 = Graph.Diameter(graphA)
|
4602
|
+
v2 = Graph.Diameter(graphB)
|
4603
|
+
if v1 == 0 and v2 == 0:
|
4604
|
+
return 1
|
4605
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4606
|
+
return round((1 - diff), mantissa)
|
4607
|
+
|
4608
|
+
def global_clustering_coefficient_similarity(graphA, graphB, mantissa=6):
|
4609
|
+
v1 = Graph.GlobalClusteringCoefficient(graphA)
|
4610
|
+
v2 = Graph.GlobalClusteringCoefficient(graphB)
|
4611
|
+
if v1 == 0 and v2 == 0:
|
4612
|
+
return 1
|
4613
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4614
|
+
return round((1 - diff), mantissa)
|
4615
|
+
|
4616
|
+
def pagerank_similarity(graphA, graphB, mantissa=6):
|
4617
|
+
v1 = safe_mean(Graph.PageRank(graphA))
|
4618
|
+
v2 = safe_mean(Graph.PageRank(graphB))
|
4619
|
+
if v1 == 0 and v2 == 0:
|
4620
|
+
return 1
|
4621
|
+
diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
|
4622
|
+
return round((1 - diff), mantissa)
|
4588
4623
|
|
4589
4624
|
def structure_similarity(graphA, graphB, mantissa=6):
|
4590
4625
|
v1 = Graph.Vertices(graphA)
|
@@ -4640,22 +4675,42 @@ class Graph:
|
|
4640
4675
|
print("Graph.Compare - Error: The graphB input parameter is not a valid topologic graph. Returning None.")
|
4641
4676
|
return
|
4642
4677
|
|
4643
|
-
total_weight = weightAttributes
|
4678
|
+
total_weight = sum([weightAttributes,
|
4679
|
+
weightGeometry,
|
4680
|
+
weightBetwennessCentrality,
|
4681
|
+
weightClosenessCentrality,
|
4682
|
+
weightDegreeCentrality,
|
4683
|
+
weightDiameter,
|
4684
|
+
weightGlobalClusteringCoefficient,
|
4685
|
+
weightPageRank,
|
4686
|
+
weightStructure,
|
4687
|
+
weightWeisfeilerLehman,
|
4688
|
+
weightJaccard])
|
4644
4689
|
|
4645
4690
|
attribute_score = attribute_similarity(graphA, graphB, mantissa=mantissa) if weightAttributes else 0
|
4691
|
+
betweenness_centrality_score = betweenness_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightBetwennessCentrality else 0
|
4692
|
+
closeness_centrality_score = closeness_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightClosenessCentrality else 0
|
4693
|
+
degree_centrality_score = degree_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightDegreeCentrality else 0
|
4694
|
+
diameter_score = diameter_similarity(graphA, graphB, mantissa=mantissa) if weightDiameter else 0
|
4695
|
+
global_clustering_coefficient_score = global_clustering_coefficient_similarity(graphA, graphB, mantissa=mantissa) if weightGlobalClusteringCoefficient else 0
|
4646
4696
|
geometry_score = geometry_similarity(graphA, graphB, mantissa=mantissa) if weightGeometry else 0
|
4647
4697
|
jaccard_score = weighted_jaccard_similarity(graphA, graphB, vertexIDKey=vertexIDKey, edgeWeightKey=edgeWeightKey, mantissa=mantissa) if weightJaccard else 0
|
4648
|
-
|
4698
|
+
pagerank_score = pagerank_similarity(graphA, graphB, mantissa=mantissa) if weightPageRank else 0
|
4649
4699
|
structure_score = structure_similarity(graphA, graphB, mantissa=mantissa) if weightStructure else 0
|
4650
|
-
|
4700
|
+
weisfeiler_lehman_score = weisfeiler_lehman_similarity(graphA, graphB, iterations, mantissa=mantissa) if weightWeisfeilerLehman else 0
|
4651
4701
|
|
4652
4702
|
weighted_sum = (
|
4653
4703
|
attribute_score * weightAttributes +
|
4704
|
+
betweenness_centrality_score * weightBetwennessCentrality +
|
4705
|
+
closeness_centrality_score * weightClosenessCentrality +
|
4706
|
+
degree_centrality_score * weightDegreeCentrality +
|
4707
|
+
diameter_score * weightDiameter +
|
4654
4708
|
geometry_score * weightGeometry +
|
4709
|
+
global_clustering_coefficient_score * weightGlobalClusteringCoefficient +
|
4655
4710
|
jaccard_score * weightJaccard +
|
4656
|
-
|
4711
|
+
pagerank_score * weightPageRank +
|
4657
4712
|
structure_score * weightStructure +
|
4658
|
-
|
4713
|
+
weisfeiler_lehman_score * weightWeisfeilerLehman
|
4659
4714
|
)
|
4660
4715
|
|
4661
4716
|
if total_weight <= 0:
|
@@ -4665,11 +4720,15 @@ class Graph:
|
|
4665
4720
|
|
4666
4721
|
return {
|
4667
4722
|
"attribute": round(attribute_score, mantissa),
|
4723
|
+
"betwenness_centrality": round(betweenness_centrality_score, mantissa),
|
4724
|
+
"closeness_centrality": round(closeness_centrality_score, mantissa),
|
4725
|
+
"degree_centrality": round(degree_centrality_score, mantissa),
|
4668
4726
|
"geometry": round(geometry_score, mantissa),
|
4727
|
+
"global_clustering_coefficient": round(global_clustering_coefficient_score, mantissa),
|
4669
4728
|
"jaccard": round(jaccard_score, mantissa),
|
4670
|
-
"
|
4729
|
+
"pagerank": round(pagerank_score, mantissa),
|
4671
4730
|
"structure": round(structure_score, mantissa),
|
4672
|
-
"
|
4731
|
+
"weisfeiler_lehman": round(weisfeiler_lehman_score, mantissa),
|
4673
4732
|
"overall": round(overall_score, mantissa)
|
4674
4733
|
}
|
4675
4734
|
|
topologicpy/Grid.py
CHANGED
topologicpy/Helper.py
CHANGED
topologicpy/Honeybee.py
CHANGED
topologicpy/Matrix.py
CHANGED
topologicpy/Neo4j.py
CHANGED
topologicpy/Plotly.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -511,7 +511,7 @@ class Plotly:
|
|
511
511
|
borderSizes = []
|
512
512
|
for i in range(len(vertices)):
|
513
513
|
sizes.append(size)
|
514
|
-
labels.append("
|
514
|
+
labels.append("")
|
515
515
|
colors.append(Color.AnyToHex(color))
|
516
516
|
borderColors.append(borderColor)
|
517
517
|
borderSizes.append(size+borderWidth*2)
|
@@ -543,7 +543,7 @@ class Plotly:
|
|
543
543
|
if not temp_color == None:
|
544
544
|
colors[m] = Color.AnyToHex(temp_color)
|
545
545
|
if not labelKey == None:
|
546
|
-
labels[m] =
|
546
|
+
labels[m] = Dictionary.ValueAtKey(d, key=labelKey, defaultValue=" ")
|
547
547
|
if not sizeKey == None:
|
548
548
|
sizes[m] = Dictionary.ValueAtKey(d, key=sizeKey)
|
549
549
|
if sizes[m] == None:
|
topologicpy/Polyskel.py
CHANGED
topologicpy/PyG.py
CHANGED
topologicpy/Shell.py
CHANGED
topologicpy/Speckle.py
CHANGED
topologicpy/Sun.py
CHANGED
topologicpy/Topology.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) 2025
|
2
2
|
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify it under
|
@@ -846,7 +846,7 @@ class Topology():
|
|
846
846
|
return apTopologies
|
847
847
|
|
848
848
|
@staticmethod
|
849
|
-
def Union(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
849
|
+
def Union(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
850
850
|
"""
|
851
851
|
See Topology.Boolean()
|
852
852
|
|
@@ -879,15 +879,15 @@ class Topology():
|
|
879
879
|
else:
|
880
880
|
internal_boundaries.append(eb)
|
881
881
|
return Face.ByWires(external_boundary, internal_boundaries)
|
882
|
-
return Topology.Boolean(topologyA, topologyB, operation="union", tranDict=tranDict, tolerance=tolerance)
|
882
|
+
return Topology.Boolean(topologyA, topologyB, operation="union", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
883
883
|
|
884
884
|
@staticmethod
|
885
|
-
def Difference(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
885
|
+
def Difference(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
886
886
|
"""
|
887
887
|
See Topology.Boolean().
|
888
888
|
|
889
889
|
"""
|
890
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="difference", tranDict=tranDict, tolerance=tolerance)
|
890
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="difference", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
891
891
|
|
892
892
|
@staticmethod
|
893
893
|
def ExternalBoundary(topology):
|
@@ -1006,63 +1006,63 @@ class Topology():
|
|
1006
1006
|
return Topology.SelfMerge(Topology.SelfMerge(Cluster.ByTopologies(results)))
|
1007
1007
|
|
1008
1008
|
@staticmethod
|
1009
|
-
def SymmetricDifference(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1009
|
+
def SymmetricDifference(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1010
1010
|
"""
|
1011
1011
|
See Topology.Boolean().
|
1012
1012
|
|
1013
1013
|
"""
|
1014
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance)
|
1014
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1015
1015
|
|
1016
1016
|
@staticmethod
|
1017
|
-
def SymDif(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1017
|
+
def SymDif(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1018
1018
|
"""
|
1019
1019
|
See Topology.Boolean().
|
1020
1020
|
|
1021
1021
|
"""
|
1022
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance)
|
1022
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1023
1023
|
|
1024
1024
|
@staticmethod
|
1025
|
-
def XOR(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1025
|
+
def XOR(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1026
1026
|
"""
|
1027
1027
|
See Topology.Boolean().
|
1028
1028
|
|
1029
1029
|
"""
|
1030
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance)
|
1030
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="symdif", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1031
1031
|
|
1032
1032
|
@staticmethod
|
1033
|
-
def Merge(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1033
|
+
def Merge(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1034
1034
|
"""
|
1035
1035
|
See Topology.Boolean().
|
1036
1036
|
|
1037
1037
|
"""
|
1038
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="merge", tranDict=tranDict, tolerance=tolerance)
|
1038
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="merge", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1039
1039
|
|
1040
1040
|
@staticmethod
|
1041
|
-
def Slice(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1041
|
+
def Slice(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1042
1042
|
"""
|
1043
1043
|
See Topology.Boolean().
|
1044
1044
|
|
1045
1045
|
"""
|
1046
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="slice", tranDict=tranDict, tolerance=tolerance)
|
1046
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="slice", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1047
1047
|
|
1048
1048
|
@staticmethod
|
1049
|
-
def Impose(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1049
|
+
def Impose(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1050
1050
|
"""
|
1051
1051
|
See Topology.Boolean().
|
1052
1052
|
|
1053
1053
|
"""
|
1054
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="impose", tranDict=tranDict, tolerance=tolerance)
|
1054
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="impose", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1055
1055
|
|
1056
1056
|
@staticmethod
|
1057
|
-
def Imprint(topologyA, topologyB, tranDict=False, tolerance=0.0001):
|
1057
|
+
def Imprint(topologyA, topologyB, tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1058
1058
|
"""
|
1059
1059
|
See Topology.Boolean().
|
1060
1060
|
|
1061
1061
|
"""
|
1062
|
-
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="imprint", tranDict=tranDict, tolerance=tolerance)
|
1062
|
+
return Topology.Boolean(topologyA=topologyA, topologyB=topologyB, operation="imprint", tranDict=tranDict, tolerance=tolerance, silent=silent)
|
1063
1063
|
|
1064
1064
|
@staticmethod
|
1065
|
-
def Boolean(topologyA, topologyB, operation="union", tranDict=False, tolerance=0.0001):
|
1065
|
+
def Boolean(topologyA, topologyB, operation: str = "union", tranDict: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
1066
1066
|
"""
|
1067
1067
|
Execute the input boolean operation type on the input operand topologies and return the result. See https://en.wikipedia.org/wiki/Boolean_operation.
|
1068
1068
|
|
@@ -1078,6 +1078,8 @@ class Topology():
|
|
1078
1078
|
If set to True the dictionaries of the operands are merged and transferred to the result. The default is False.
|
1079
1079
|
tolerance : float , optional
|
1080
1080
|
The desired tolerance. The default is 0.0001.
|
1081
|
+
silent : bool , optional
|
1082
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
1081
1083
|
|
1082
1084
|
Returns
|
1083
1085
|
-------
|
@@ -1087,23 +1089,26 @@ class Topology():
|
|
1087
1089
|
"""
|
1088
1090
|
from topologicpy.Dictionary import Dictionary
|
1089
1091
|
if not Topology.IsInstance(topologyA, "Topology"):
|
1090
|
-
|
1092
|
+
if not silent:
|
1093
|
+
print("Topology.Boolean - Error: the input topologyA parameter is not a valid topology. Returning None.")
|
1091
1094
|
return None
|
1092
1095
|
if not Topology.IsInstance(topologyB, "Topology"):
|
1093
|
-
|
1096
|
+
if not silent:
|
1097
|
+
print("Topology.Boolean - Error: the input topologyB parameter is not a valid topology. Returning None.")
|
1094
1098
|
return None
|
1095
1099
|
if not isinstance(operation, str):
|
1096
|
-
|
1100
|
+
if not silent:
|
1101
|
+
print("Topology.Boolean - Error: the input operation parameter is not a valid string. Returning None.")
|
1097
1102
|
return None
|
1098
1103
|
if not operation.lower() in ["union", "difference", "intersect", "symdif", "merge", "slice", "impose", "imprint"]:
|
1099
|
-
|
1104
|
+
if not silent:
|
1105
|
+
print("Topology.Boolean - Error: the input operation parameter is not a recognized operation. Returning None.")
|
1100
1106
|
return None
|
1101
1107
|
if not isinstance(tranDict, bool):
|
1102
|
-
|
1108
|
+
if not silent:
|
1109
|
+
print("Topology.Boolean - Error: the input tranDict parameter is not a valid boolean. Returning None.")
|
1103
1110
|
return None
|
1104
1111
|
topologyC = None
|
1105
|
-
#topologyC = Topology.Intersect(topologyA, topologyB)
|
1106
|
-
#try:
|
1107
1112
|
if operation.lower() == "union":
|
1108
1113
|
topologyC = topologyA.Union(topologyB, False)
|
1109
1114
|
elif operation.lower() == "difference":
|
topologicpy/Vector.py
CHANGED
topologicpy/Vertex.py
CHANGED
topologicpy/Wire.py
CHANGED
topologicpy/__init__.py
CHANGED
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.23'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.23
|
4
4
|
Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
6
|
License: AGPL v3 License
|
@@ -0,0 +1,37 @@
|
|
1
|
+
topologicpy/ANN.py,sha256=DrNAhNHp-jSvsPc1fb7KVPU46cYmejAvghhknOM430Y,47932
|
2
|
+
topologicpy/Aperture.py,sha256=wNn5miB_IrGCBYuQ18HXQYRva20dUC3id4AJCulL7to,2723
|
3
|
+
topologicpy/BVH.py,sha256=PAezG_P_W5_FUjUGB-HRRb4bzesE9DW89G2Vm-6ChWw,12932
|
4
|
+
topologicpy/CSG.py,sha256=6vawdxs0_r7i9ElnwDO1Mouv_yPOTBr_4IhBnfVsBHk,15680
|
5
|
+
topologicpy/Cell.py,sha256=F8ifMa-3NI5GYRx86J0cokgdoLduBiaw5DIKQFMHtCs,119904
|
6
|
+
topologicpy/CellComplex.py,sha256=5O15NirkK2M1AvNcq9Z8N5lNb-hD9kGNXIJXWJJuj7k,59931
|
7
|
+
topologicpy/Cluster.py,sha256=BSaLcHe4TinFTIwjFo4660rPX2y9Lqly2hv48WCq6fE,58606
|
8
|
+
topologicpy/Color.py,sha256=ZVVQRKGjebY9aOU1gpN_AbssdRRiVKlZV3f8TrsTNgg,20307
|
9
|
+
topologicpy/Context.py,sha256=G3CwMvN8Jw2rnQRwB-n4MaQq_wLS0vPimbXKwsdMJ80,3055
|
10
|
+
topologicpy/DGL.py,sha256=HQXy9iDnrvWGDxaBfe5pRbweQ2zLBvAf6UdjfhKkQYI,139041
|
11
|
+
topologicpy/Dictionary.py,sha256=Lf24WHW8q_RCq0l8VpT3XJTn6UuStY66JI4Lb4W08jI,34126
|
12
|
+
topologicpy/Edge.py,sha256=pu4tZbRbK8qx2oqRbwHAeKuwU2X8JFGPSJjJMTJw8Q0,71418
|
13
|
+
topologicpy/EnergyModel.py,sha256=Pyb28gDDwhzlQIH0xqAygqS0P3SJxWyyV7OWS_AAfRs,53856
|
14
|
+
topologicpy/Face.py,sha256=7K46gB_UIKjKEKyzyY0JqGarqjwjH0ggS-JQTpDtWC4,184847
|
15
|
+
topologicpy/Graph.py,sha256=29oDBceDUoZVbwZ4ajBJWfQD4JIPYGUgDeEqmm7CBX0,527640
|
16
|
+
topologicpy/Grid.py,sha256=qRnFUvs079zMOZ6COWzBX6408niI7HyNz-BM0VRguXY,18245
|
17
|
+
topologicpy/Helper.py,sha256=JdvC30WMrla46mTj5TdwCV_bRv-6y8vK5Bkx0prluy4,29100
|
18
|
+
topologicpy/Honeybee.py,sha256=yctkwfdupKnp7bAOjP1Z4YaYpRrWoMEb4gz9Z5zaWwE,21751
|
19
|
+
topologicpy/Matrix.py,sha256=BHGDRkBn1pf5DkRoY8feAhDGHTF3bjFM4jluiEb_A0w,22779
|
20
|
+
topologicpy/Neo4j.py,sha256=vNMaqTWerwr-3luLjYEXNhf8T97aFee6x5sIKBHY73s,22392
|
21
|
+
topologicpy/Plotly.py,sha256=eHTKT8vOHJDLwH4xypj52atGLR0dGic45d-BiPA55Q8,119219
|
22
|
+
topologicpy/Polyskel.py,sha256=oVfM4lqSMPTjnkHfsRU9VI8Blt6Vf0LVPkD9ebz7Wmw,27082
|
23
|
+
topologicpy/PyG.py,sha256=zvV6jtnol_aFiN6JRoMpYwBVfOU2aFs9gdWSdEo6mtU,109757
|
24
|
+
topologicpy/Shell.py,sha256=3zUSf0VfkAF73ZyTYNWYW21x4-vyfi7JkYu_r5GTVIc,87983
|
25
|
+
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
26
|
+
topologicpy/Sun.py,sha256=_VBBAUIDhvpkp72JBZlv7k9qx9jYubm3yM56UZ1Nc6c,36837
|
27
|
+
topologicpy/Topology.py,sha256=BKiVJ-R5FfwXJ2FYp1V8pjaPoMxRm83MGe2RzBx0_tQ,479205
|
28
|
+
topologicpy/Vector.py,sha256=mx7fgABdioikPWM9HzXKzmqfx3u_XBcU_jlLD4qK2x8,42407
|
29
|
+
topologicpy/Vertex.py,sha256=PIwfbA7_TxK_dSGlSeM5mson97TRr4dYrfZyOLgO150,80913
|
30
|
+
topologicpy/Wire.py,sha256=eRs4PM7h4yU5v6umPh0oBJR4cN8BwsqlVroaFdnvK4w,228499
|
31
|
+
topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
|
32
|
+
topologicpy/version.py,sha256=x1ObPzSnRGxtlZbyDdxO7Th6BX-tC0y4aFEdmCRhvqg,23
|
33
|
+
topologicpy-0.8.23.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
34
|
+
topologicpy-0.8.23.dist-info/METADATA,sha256=vQCjkz3HxMfw9u7K87Q8eiY5cvWggKY1QuZWIgm8fBE,10535
|
35
|
+
topologicpy-0.8.23.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
|
36
|
+
topologicpy-0.8.23.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
37
|
+
topologicpy-0.8.23.dist-info/RECORD,,
|
@@ -1,36 +0,0 @@
|
|
1
|
-
topologicpy/ANN.py,sha256=m_WxD1lgQqDhUpaM20Lia6TmJACDYaAE96wigsi-99U,47932
|
2
|
-
topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
|
3
|
-
topologicpy/BVH.py,sha256=1q2lR5eDs7Wnwv7M-Kr7Cj3GG_iy7d1ddaZqWGHdX-w,12932
|
4
|
-
topologicpy/Cell.py,sha256=BN6hjYpN6Fse0mn7d7oHh65D7c6Mt1Yu7iK3lEp_Cj0,118262
|
5
|
-
topologicpy/CellComplex.py,sha256=udDzbMub3d2QYn1XGMzt3F9Su2VXuAGvn0eoTtOIn3g,58207
|
6
|
-
topologicpy/Cluster.py,sha256=o5jdMRpcGfSGGiXQdFg-e9XcnBF5AqTj3xb1nSpwJWE,58606
|
7
|
-
topologicpy/Color.py,sha256=q9xsGmxFMz7sQKmygwSVS12GaTRB-OT0-_i6t3-cthE,20307
|
8
|
-
topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
|
9
|
-
topologicpy/DGL.py,sha256=M_znFtyPBJJz-iXLYZs2wwBj24fhevIo739dGha0chM,139041
|
10
|
-
topologicpy/Dictionary.py,sha256=7h-Gszgnt2OEOvOSADJ4pa-mTNlhQ9cuIiB5WHEW6aY,33949
|
11
|
-
topologicpy/Edge.py,sha256=yxkCVDYBflJNEYxnjMmlyvbkpg8TNy7y5bSH3yQ4jzs,71418
|
12
|
-
topologicpy/EnergyModel.py,sha256=UoQ9Jm-hYsN383CbcLKw-y6BKitRHj0uyh84yQ-8ACg,53856
|
13
|
-
topologicpy/Face.py,sha256=SlhB8L7BpDjd4a9YZE4UJ3zoGuF1oq9MSpuesEWro_Q,184847
|
14
|
-
topologicpy/Graph.py,sha256=Iq2UI-CdW3usxpgxRi-caxQeUmkFfGhD37c6mPT2Gd8,523908
|
15
|
-
topologicpy/Grid.py,sha256=2s9cSlWldivn1i9EUz4OOokJyANveqmRe_vR93CAndI,18245
|
16
|
-
topologicpy/Helper.py,sha256=4H5KPiv_eiEs489UOOyGLe9RaeoZIfmMh3mk_YCHmXg,29100
|
17
|
-
topologicpy/Honeybee.py,sha256=uDVtDbloydNoaBFcSNukKL_2PLyD6XKkCp1VHz1jtaU,21751
|
18
|
-
topologicpy/Matrix.py,sha256=i22RLP5ebUAMuU7V1tZ__Z4lf1pg9fzq9nENsDZUV74,22779
|
19
|
-
topologicpy/Neo4j.py,sha256=BKOF29fRgXmdpMGkrNzuYbyqgCJ6ElPPMYlfTxXiVbc,22392
|
20
|
-
topologicpy/Plotly.py,sha256=gSe3tWLgF75-rPDjqw7riUIJpv0j_K7hedoxi3-OptE,119244
|
21
|
-
topologicpy/Polyskel.py,sha256=ro5in--VT_uag55r5xymU5ufyAahsovIiJwyiqG_qH8,27082
|
22
|
-
topologicpy/PyG.py,sha256=LU9LCCzjxGPUM31qbaJXZsTvniTtgugxJY7y612t4A4,109757
|
23
|
-
topologicpy/Shell.py,sha256=--dJoSdz6BapxVEyG2DI0W5apO_xwLORj5qmR15yl2Y,87983
|
24
|
-
topologicpy/Speckle.py,sha256=AlsGlSDuKRtX5jhVsPNSSjjbZis079HbUchDH_5RJmE,18187
|
25
|
-
topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
|
26
|
-
topologicpy/Topology.py,sha256=QY195KZ5EostlGRnsPGSFglRIU0tunD2CiwsFPfpOqY,478447
|
27
|
-
topologicpy/Vector.py,sha256=GkGt-aJ591IJ2IPffMAudvITLDPi2qZibZc4UAav6m8,42407
|
28
|
-
topologicpy/Vertex.py,sha256=q99IrWwdNlvVfUXz6iP8icmP8NzP2nsiqtgnF9Jnpx8,80913
|
29
|
-
topologicpy/Wire.py,sha256=IVPzBKsckuxC-rHvwxmvtVF7PpApz2lhPHomtQMo_kg,228499
|
30
|
-
topologicpy/__init__.py,sha256=vlPCanUbxe5NifC4pHcnhSzkmmYcs_UrZrTlVMsxcFs,928
|
31
|
-
topologicpy/version.py,sha256=zZ7tNz8qiJpD43ZZY6gDLsQEo04V3AXFbZKZwwi4Pww,23
|
32
|
-
topologicpy-0.8.21.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
33
|
-
topologicpy-0.8.21.dist-info/METADATA,sha256=uin9-ogEkyhyjro0BGZPrFB4abynjZPuv7G3lTk6XzA,10535
|
34
|
-
topologicpy-0.8.21.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
35
|
-
topologicpy-0.8.21.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
-
topologicpy-0.8.21.dist-info/RECORD,,
|
File without changes
|
File without changes
|