topologicpy 0.8.28__py3-none-any.whl → 0.8.29__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/Plotly.py +9 -5
- topologicpy/ShapeGrammar.py +492 -0
- topologicpy/Topology.py +0 -2
- topologicpy/version.py +1 -1
- {topologicpy-0.8.28.dist-info → topologicpy-0.8.29.dist-info}/METADATA +1 -1
- {topologicpy-0.8.28.dist-info → topologicpy-0.8.29.dist-info}/RECORD +9 -8
- {topologicpy-0.8.28.dist-info → topologicpy-0.8.29.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.28.dist-info → topologicpy-0.8.29.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.28.dist-info → topologicpy-0.8.29.dist-info}/top_level.txt +0 -0
topologicpy/Plotly.py
CHANGED
@@ -592,6 +592,7 @@ class Plotly:
|
|
592
592
|
mode = "markers+text"
|
593
593
|
else:
|
594
594
|
mode = "markers"
|
595
|
+
|
595
596
|
vData2 = go.Scatter3d(x=x,
|
596
597
|
y=y,
|
597
598
|
z=z,
|
@@ -603,11 +604,13 @@ class Plotly:
|
|
603
604
|
opacity=1,
|
604
605
|
sizemode="diameter"),
|
605
606
|
mode=mode,
|
607
|
+
customdata = labels,
|
606
608
|
legendgroup=legendGroup,
|
607
609
|
legendrank=legendRank,
|
608
610
|
text=labels,
|
609
611
|
hoverinfo='text',
|
610
|
-
hovertext=labels
|
612
|
+
hovertext=labels,
|
613
|
+
hovertemplate=["Click "+label for label in labels]
|
611
614
|
)
|
612
615
|
if borderWidth > 0 or borderWidthKey:
|
613
616
|
vData1 = go.Scatter3d(x=x,
|
@@ -676,14 +679,13 @@ class Plotly:
|
|
676
679
|
labels = []
|
677
680
|
for j, elements_cluster in enumerate(elements_clusters):
|
678
681
|
d_color = color
|
679
|
-
labels.append("Edge_"+str(j+1).zfill(n))
|
680
682
|
d = dict_clusters[j][0] # All dicitonaries have same values in dictionaries, so take first one.
|
681
683
|
if d:
|
682
684
|
if not colorKey == None:
|
683
685
|
d_color = Dictionary.ValueAtKey(d, key=colorKey) or color
|
684
686
|
d_color = Color.AnyToHex(d_color)
|
685
687
|
if not labelKey == None:
|
686
|
-
|
688
|
+
labels.append(str(Dictionary.ValueAtKey(d, labelKey, "")))
|
687
689
|
if not widthKey == None:
|
688
690
|
e_width = Dictionary.ValueAtKey(d, key=widthKey)
|
689
691
|
if not e_width == None:
|
@@ -727,8 +729,10 @@ class Plotly:
|
|
727
729
|
line=dict(color=d_color, width=width),
|
728
730
|
legendgroup=legendGroup,
|
729
731
|
legendrank=legendRank,
|
730
|
-
text=
|
731
|
-
|
732
|
+
text=labels,
|
733
|
+
customdata=labels,
|
734
|
+
hoverinfo='text',
|
735
|
+
hovertext=labels)
|
732
736
|
traces.append(trace)
|
733
737
|
else:
|
734
738
|
x = []
|
@@ -0,0 +1,492 @@
|
|
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
|
+
import topologic_core as topologic
|
18
|
+
|
19
|
+
class ShapeGrammar:
|
20
|
+
def __init__(self):
|
21
|
+
self.title = "Untitled" # Stores the title of the topology grammar.
|
22
|
+
self.description = "" # Stores the description of the grammar.
|
23
|
+
self.rules = [] # Stores transformation rules of the topology grammar.
|
24
|
+
# Operations
|
25
|
+
# Replace
|
26
|
+
replace = {"title": "Replace",
|
27
|
+
"description": "Replaces the input topology with the output topology.",
|
28
|
+
"uSides": None,
|
29
|
+
"vSides": None,
|
30
|
+
"wSides": None}
|
31
|
+
# Transform
|
32
|
+
transform = {"title": "Transform",
|
33
|
+
"description": "Transforms the input topology using the specified matrix.",
|
34
|
+
"uSides": None,
|
35
|
+
"vSides": None,
|
36
|
+
"wSides": None}
|
37
|
+
# Union
|
38
|
+
union = {"title": "Union",
|
39
|
+
"description": "Unions the input topology and the output topology.",
|
40
|
+
"uSides": None,
|
41
|
+
"vSides": None,
|
42
|
+
"wSides": None}
|
43
|
+
# Difference
|
44
|
+
difference = {"title": "Difference",
|
45
|
+
"description": "Subtracts the output topology from the input topology.",
|
46
|
+
"uSides": None,
|
47
|
+
"vSides": None,
|
48
|
+
"wSides": None}
|
49
|
+
# Difference
|
50
|
+
symdif = {"title": "Symmetric Difference",
|
51
|
+
"description": "Calculates the symmetrical difference of the input topology and the output topology.",
|
52
|
+
"uSides": None,
|
53
|
+
"vSides": None,
|
54
|
+
"wSides": None}
|
55
|
+
# Intersect
|
56
|
+
intersect = {"title": "Intersect",
|
57
|
+
"description": "Intersects the input topology and the output topology.",
|
58
|
+
"uSides": None,
|
59
|
+
"vSides": None,
|
60
|
+
"wSides": None}
|
61
|
+
# Merge
|
62
|
+
merge = {"title": "Merge",
|
63
|
+
"description": "Merges the input topology and the output topology.",
|
64
|
+
"uSides": None,
|
65
|
+
"vSides": None,
|
66
|
+
"wSides": None}
|
67
|
+
# Slice
|
68
|
+
slice = {"title": "Slice",
|
69
|
+
"description": "Slices the input topology using the output topology.",
|
70
|
+
"uSides": None,
|
71
|
+
"vSides": None,
|
72
|
+
"wSides": None}
|
73
|
+
# Impose
|
74
|
+
impose = {"title": "Impose",
|
75
|
+
"description": "Imposes the output topology on the input topology.",
|
76
|
+
"uSides": None,
|
77
|
+
"vSides": None,
|
78
|
+
"wSides": None}
|
79
|
+
# Imprint
|
80
|
+
imprint = {"title": "Imprint",
|
81
|
+
"description": "Imposes the output topology on the input topology.",
|
82
|
+
"uSides": None,
|
83
|
+
"vSides": None,
|
84
|
+
"wSides": None}
|
85
|
+
# Divide
|
86
|
+
divide = {"title": "Divide",
|
87
|
+
"description": "Divides the input topology along the x, y, and z axes using the specified number of sides (uSides, vSides, wSides)",
|
88
|
+
"uSides": 2,
|
89
|
+
"vSides": 2,
|
90
|
+
"wSides": 2}
|
91
|
+
self.operations = [replace, transform, union, difference, symdif, intersect, merge, slice, impose, imprint, divide]
|
92
|
+
|
93
|
+
def OperationTitles(self):
|
94
|
+
"""
|
95
|
+
Returns the list of available operation titles.
|
96
|
+
|
97
|
+
Parameters
|
98
|
+
----------
|
99
|
+
|
100
|
+
Returns
|
101
|
+
-------
|
102
|
+
list
|
103
|
+
The requested list of operation titles
|
104
|
+
"""
|
105
|
+
return [op["title"] for op in self.operations]
|
106
|
+
|
107
|
+
def OperationByTitle(self, title):
|
108
|
+
"""
|
109
|
+
Returns the operation given the input title string
|
110
|
+
|
111
|
+
Parameters
|
112
|
+
----------
|
113
|
+
title : str
|
114
|
+
The input operation str. See OperationTitles for list of operations.
|
115
|
+
|
116
|
+
Returns
|
117
|
+
-------
|
118
|
+
ShapeGrammar.Operation
|
119
|
+
The requested operation
|
120
|
+
"""
|
121
|
+
for op in self.operations:
|
122
|
+
op_title = op["title"]
|
123
|
+
if title.lower() in op_title.lower():
|
124
|
+
return op
|
125
|
+
return None
|
126
|
+
|
127
|
+
def AddRule(self,
|
128
|
+
input,
|
129
|
+
output,
|
130
|
+
title : str = "Untitled Rule",
|
131
|
+
description: str = "",
|
132
|
+
operation : dict = None,
|
133
|
+
matrix: list = None,
|
134
|
+
silent: bool = False):
|
135
|
+
"""
|
136
|
+
Adds a rule to the topology grammar.
|
137
|
+
|
138
|
+
Parameters
|
139
|
+
----------
|
140
|
+
input : topologic_core.Topology
|
141
|
+
The linput topology of the rule.
|
142
|
+
output : topologic_core.Topology
|
143
|
+
The output topology of the rule.
|
144
|
+
title : str , optional
|
145
|
+
The title of the rule. The default is "Untitled Rule"
|
146
|
+
description : str, optional
|
147
|
+
The description of the rule. The default is "".
|
148
|
+
operation : dict , optional
|
149
|
+
The desired rule operation. See Rule Operations. If set to None, the replacement rule is applied. The default is None.
|
150
|
+
matrix : list
|
151
|
+
The 4x4 transformation matrix that tranforms the output topology to the input topology. If set to None, no transformation is applied. The default is None.
|
152
|
+
silent : bool, optional
|
153
|
+
If True, suppresses error/warning messages. Default is False.
|
154
|
+
|
155
|
+
Returns
|
156
|
+
-------
|
157
|
+
None
|
158
|
+
This method does not return a value.
|
159
|
+
"""
|
160
|
+
from topologicpy.Topology import Topology
|
161
|
+
|
162
|
+
def is_4x4_matrix(matrix):
|
163
|
+
return (
|
164
|
+
isinstance(matrix, list) and
|
165
|
+
len(matrix) == 4 and
|
166
|
+
all(isinstance(row, list) and len(row) == 4 for row in matrix)
|
167
|
+
)
|
168
|
+
|
169
|
+
if not Topology.IsInstance(input, "Topology"):
|
170
|
+
if not silent:
|
171
|
+
print("ShapeGrammar.AddRule - Error: The input input parameter is not a valid topology. Returning None.")
|
172
|
+
return None
|
173
|
+
if not output == None:
|
174
|
+
if not Topology.IsInstance(output, "Topology"):
|
175
|
+
if not silent:
|
176
|
+
print("ShapeGrammar.AddRule - Error: The input output parameter is not a valid topology. Returning None.")
|
177
|
+
return None
|
178
|
+
if not operation == None:
|
179
|
+
if not operation in self.operations:
|
180
|
+
if not silent:
|
181
|
+
print("ShapeGrammar.AddRule - Error: The input operation parameter is not a valid operation. Returning None.")
|
182
|
+
return None
|
183
|
+
if not matrix == None:
|
184
|
+
if not is_4x4_matrix(matrix):
|
185
|
+
if not silent:
|
186
|
+
print("ShapeGrammar.AddRule - Error: The input matrix parameter is not a valid matrix. Returning None.")
|
187
|
+
return None
|
188
|
+
|
189
|
+
self.rules.append({"input":input,
|
190
|
+
"output": output,
|
191
|
+
"title": title,
|
192
|
+
"description": description,
|
193
|
+
"operation": operation,
|
194
|
+
"matrix": matrix
|
195
|
+
})
|
196
|
+
|
197
|
+
def ApplicableRules(self, topology, keys: list = None, silent: bool = False):
|
198
|
+
"""
|
199
|
+
Returns rules applicable to the input topology.
|
200
|
+
|
201
|
+
Parameters
|
202
|
+
----------
|
203
|
+
topology : topologic_core.Topology
|
204
|
+
The input topology
|
205
|
+
keys : list , optional
|
206
|
+
The list of dictionary keys to semantically match the rules. The default is None which means dictionaries are not considered.
|
207
|
+
silent : bool, optional
|
208
|
+
If True, suppresses error/warning messages. Default is False.
|
209
|
+
|
210
|
+
Returns
|
211
|
+
-------
|
212
|
+
list
|
213
|
+
The list of applicable rules.
|
214
|
+
"""
|
215
|
+
from topologicpy.Topology import Topology
|
216
|
+
from topologicpy.Dictionary import Dictionary
|
217
|
+
|
218
|
+
if not Topology.IsInstance(topology, "Topology"):
|
219
|
+
if not silent:
|
220
|
+
print("ShapeGrammar.ApplicableRules - Error: The input topology parameter is not a valid topology. Returning None.")
|
221
|
+
return None
|
222
|
+
|
223
|
+
ap_rules = []
|
224
|
+
ap_trans = []
|
225
|
+
d = Topology.Dictionary(topology)
|
226
|
+
for i, rule in enumerate(self.rules):
|
227
|
+
dict_status = True
|
228
|
+
input = rule["input"]
|
229
|
+
# If there is a list of keys specified, check that the values match
|
230
|
+
if isinstance(keys, list):
|
231
|
+
d_input = Topology.Dictionary(input)
|
232
|
+
for j, key in enumerate(keys):
|
233
|
+
if not Dictionary.ValueAtKey(d, key, None) == Dictionary.ValueAtKey(d_input, key, None):
|
234
|
+
dict_status = False
|
235
|
+
break
|
236
|
+
#If it passed the dictionary key test, then check topology similarity
|
237
|
+
if dict_status:
|
238
|
+
topology_status, mat = Topology.IsSimilar(rule["input"], topology)
|
239
|
+
if topology_status:
|
240
|
+
ap_rules.append(rule)
|
241
|
+
ap_trans.append(mat)
|
242
|
+
return ap_rules, ap_trans
|
243
|
+
|
244
|
+
def ApplyRule(self, topology, rule: dict = None, matrix: list = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
245
|
+
"""
|
246
|
+
Returns rules applicable to the input topology.
|
247
|
+
|
248
|
+
Parameters
|
249
|
+
----------
|
250
|
+
topology : topologic_core.Topology
|
251
|
+
The input topology
|
252
|
+
rule : dict , optional
|
253
|
+
The desired rule to apply. The default is None.
|
254
|
+
matrix : list
|
255
|
+
The 4x4 transformation matrix that tranforms the output topology to the input topology. If set to None, no transformation is applied. The default is None.
|
256
|
+
mantissa : int, optional
|
257
|
+
Decimal precision. Default is 6.
|
258
|
+
tolerance : float, optional
|
259
|
+
The desired Tolerance. Not used here but included for API compatibility. Default is 0.0001.
|
260
|
+
silent : bool, optional
|
261
|
+
If True, suppresses error/warning messages. Default is False.
|
262
|
+
|
263
|
+
Returns
|
264
|
+
-------
|
265
|
+
topologic_core.Topology
|
266
|
+
The transformed topology
|
267
|
+
"""
|
268
|
+
|
269
|
+
from topologicpy.Topology import Topology
|
270
|
+
from topologicpy.Cluster import Cluster
|
271
|
+
from topologicpy.Face import Face
|
272
|
+
from topologicpy.Vertex import Vertex
|
273
|
+
|
274
|
+
def is_4x4_matrix(matrix):
|
275
|
+
return (
|
276
|
+
isinstance(matrix, list) and
|
277
|
+
len(matrix) == 4 and
|
278
|
+
all(isinstance(row, list) and len(row) == 4 for row in matrix)
|
279
|
+
)
|
280
|
+
|
281
|
+
def bb(topology):
|
282
|
+
vertices = Topology.Vertices(topology)
|
283
|
+
x = []
|
284
|
+
y = []
|
285
|
+
z = []
|
286
|
+
for aVertex in vertices:
|
287
|
+
x.append(Vertex.X(aVertex, mantissa=mantissa))
|
288
|
+
y.append(Vertex.Y(aVertex, mantissa=mantissa))
|
289
|
+
z.append(Vertex.Z(aVertex, mantissa=mantissa))
|
290
|
+
x_min = min(x)
|
291
|
+
y_min = min(y)
|
292
|
+
z_min = min(z)
|
293
|
+
maxX = max(x)
|
294
|
+
maxY = max(y)
|
295
|
+
maxZ = max(z)
|
296
|
+
return [x_min, y_min, z_min, maxX, maxY, maxZ]
|
297
|
+
|
298
|
+
def slice(topology, uSides, vSides, wSides):
|
299
|
+
x_min, y_min, z_min, maxX, maxY, maxZ = bb(topology)
|
300
|
+
centroid = Vertex.ByCoordinates(x_min+(maxX-x_min)*0.5, y_min+(maxY-y_min)*0.5, z_min+(maxZ-z_min)*0.5)
|
301
|
+
wOrigin = Vertex.ByCoordinates(Vertex.X(centroid, mantissa=mantissa), Vertex.Y(centroid, mantissa=mantissa), z_min)
|
302
|
+
wFace = Face.Rectangle(origin=wOrigin, width=(maxX-x_min)*1.1, length=(maxY-y_min)*1.1)
|
303
|
+
wFaces = []
|
304
|
+
wOffset = (maxZ-z_min)/wSides
|
305
|
+
for i in range(wSides-1):
|
306
|
+
wFaces.append(Topology.Translate(wFace, 0,0,wOffset*(i+1)))
|
307
|
+
uOrigin = Vertex.ByCoordinates(x_min, Vertex.Y(centroid, mantissa=mantissa), Vertex.Z(centroid, mantissa=mantissa))
|
308
|
+
uFace = Face.Rectangle(origin=uOrigin, width=(maxZ-z_min)*1.1, length=(maxY-y_min)*1.1, direction=[1,0,0])
|
309
|
+
uFaces = []
|
310
|
+
uOffset = (maxX-x_min)/uSides
|
311
|
+
for i in range(uSides-1):
|
312
|
+
uFaces.append(Topology.Translate(uFace, uOffset*(i+1),0,0))
|
313
|
+
vOrigin = Vertex.ByCoordinates(Vertex.X(centroid, mantissa=mantissa), y_min, Vertex.Z(centroid, mantissa=mantissa))
|
314
|
+
vFace = Face.Rectangle(origin=vOrigin, width=(maxX-x_min)*1.1, length=(maxZ-z_min)*1.1, direction=[0,1,0])
|
315
|
+
vFaces = []
|
316
|
+
vOffset = (maxY-y_min)/vSides
|
317
|
+
for i in range(vSides-1):
|
318
|
+
vFaces.append(Topology.Translate(vFace, 0,vOffset*(i+1),0))
|
319
|
+
all_faces = uFaces+vFaces+wFaces
|
320
|
+
if len(all_faces) > 0:
|
321
|
+
f_clus = Cluster.ByTopologies(uFaces+vFaces+wFaces)
|
322
|
+
return Topology.Slice(topology, f_clus, tolerance=tolerance)
|
323
|
+
else:
|
324
|
+
return topology
|
325
|
+
|
326
|
+
if not Topology.IsInstance(topology, "Topology"):
|
327
|
+
if not silent:
|
328
|
+
print("ShapeGrammar.ApplyRule - Error: The input topology parameter is not a valid topology. Returning None.")
|
329
|
+
return None
|
330
|
+
if not matrix == None:
|
331
|
+
if not is_4x4_matrix(matrix):
|
332
|
+
if not silent:
|
333
|
+
print("ShapeGrammar.ApplyRule - Error: The input matrix parameter is not a valid matrix. Returning None.")
|
334
|
+
return None
|
335
|
+
|
336
|
+
if not rule == None:
|
337
|
+
input = rule["input"]
|
338
|
+
output = rule["output"]
|
339
|
+
r_matrix = rule["matrix"]
|
340
|
+
operation = rule["operation"]
|
341
|
+
if not operation == None:
|
342
|
+
op_title = operation["title"]
|
343
|
+
else:
|
344
|
+
op_title = "None"
|
345
|
+
|
346
|
+
result_output = topology
|
347
|
+
temp_output = None
|
348
|
+
if not output == None:
|
349
|
+
temp_output = output
|
350
|
+
# Transform the output topology to the input topology to prepare it for final transformation
|
351
|
+
if not r_matrix == None and not output == None:
|
352
|
+
temp_output = Topology.Transform(output, r_matrix)
|
353
|
+
|
354
|
+
if "replace" in op_title.lower():
|
355
|
+
result_output = temp_output
|
356
|
+
elif "transform" in op_title.lower():
|
357
|
+
result_output = Topology.Transform(topology, r_matrix)
|
358
|
+
elif "union" in op_title.lower():
|
359
|
+
result_output = Topology.Union(input, temp_output)
|
360
|
+
elif "difference" in op_title.lower():
|
361
|
+
result_output = Topology.Difference(input, temp_output)
|
362
|
+
elif "symmetric difference" in op_title.lower():
|
363
|
+
result_output = Topology.SymmetricDifference(input, temp_output)
|
364
|
+
elif "intersect" in op_title.lower():
|
365
|
+
result_output = Topology.Intersect(input, temp_output)
|
366
|
+
elif "merge" in op_title.lower():
|
367
|
+
result_output = Topology.Merge(input, temp_output)
|
368
|
+
elif "slice" in op_title.lower():
|
369
|
+
result_output = Topology.Slice(input, temp_output)
|
370
|
+
elif "impose" in op_title.lower():
|
371
|
+
result_output = Topology.Impose(input, temp_output)
|
372
|
+
elif "imprint" in op_title.lower():
|
373
|
+
result_output = Topology.Imprint(input, temp_output)
|
374
|
+
elif "divide" in op_title.lower():
|
375
|
+
uSides = operation["uSides"]
|
376
|
+
vSides = operation["vSides"]
|
377
|
+
wSides = operation["wSides"]
|
378
|
+
if not uSides == None and not vSides == None and not wSides == None:
|
379
|
+
result_output = slice(input, uSides, vSides, wSides)
|
380
|
+
|
381
|
+
# Finally, transform the result to the input topology
|
382
|
+
if not matrix == None:
|
383
|
+
result_output = Topology.Transform(result_output, matrix)
|
384
|
+
|
385
|
+
return result_output
|
386
|
+
|
387
|
+
def FigureByInputOutput(self, input, output, silent: bool = False):
|
388
|
+
"""
|
389
|
+
Returns the Plotly figure of the input and output topologies as a rule.
|
390
|
+
|
391
|
+
Parameters
|
392
|
+
----------
|
393
|
+
input : topologic_core.Topology
|
394
|
+
The input topology
|
395
|
+
output : topologic_core.Topology
|
396
|
+
The output topology
|
397
|
+
silent : bool, optional
|
398
|
+
If True, suppresses error/warning messages. Default is False.
|
399
|
+
|
400
|
+
Returns
|
401
|
+
-------
|
402
|
+
This function does not return a value
|
403
|
+
"""
|
404
|
+
|
405
|
+
from topologicpy.Vertex import Vertex
|
406
|
+
from topologicpy.Cell import Cell
|
407
|
+
from topologicpy.Topology import Topology
|
408
|
+
from topologicpy.Dictionary import Dictionary
|
409
|
+
from topologicpy.Cluster import Cluster
|
410
|
+
from topologicpy.Plotly import Plotly
|
411
|
+
|
412
|
+
if not Topology.IsInstance(input, "Topology"):
|
413
|
+
if not silent:
|
414
|
+
print("ShapeGrammar.DrawInputOutput - Error: The input topology parameter is not a valid topology. Returning None.")
|
415
|
+
return None
|
416
|
+
if not Topology.IsInstance(output, "Topology"):
|
417
|
+
if not silent:
|
418
|
+
print("ShapeGrammar.DrawInputOutput - Error: The output topology parameter is not a valid topology. Returning None.")
|
419
|
+
return None
|
420
|
+
|
421
|
+
input_bb = Topology.BoundingBox(input)
|
422
|
+
input_centroid = Topology.Centroid(input_bb)
|
423
|
+
input_d = Topology.Dictionary(input_bb)
|
424
|
+
xmin = Dictionary.ValueAtKey(input_d, "xmin")
|
425
|
+
ymin = Dictionary.ValueAtKey(input_d, "ymin")
|
426
|
+
zmin = Dictionary.ValueAtKey(input_d, "zmin")
|
427
|
+
xmax = Dictionary.ValueAtKey(input_d, "xmax")
|
428
|
+
ymax = Dictionary.ValueAtKey(input_d, "ymax")
|
429
|
+
zmax = Dictionary.ValueAtKey(input_d, "zmax")
|
430
|
+
input_width = xmax-xmin
|
431
|
+
input_length = ymax-ymin
|
432
|
+
input_height = zmax-zmin
|
433
|
+
input_max = max(input_width, input_length, input_height)
|
434
|
+
sf = 1/input_max
|
435
|
+
temp_input = Topology.Translate(input, -Vertex.X(input_centroid), -Vertex.Y(input_centroid), -Vertex.Z(input_centroid))
|
436
|
+
temp_input = Topology.Scale(temp_input, x=sf, y=sf, z=sf)
|
437
|
+
temp_input = Topology.Translate(temp_input, 0.5, 0, 0)
|
438
|
+
|
439
|
+
output_bb = Topology.BoundingBox(output)
|
440
|
+
output_centroid = Topology.Centroid(output_bb)
|
441
|
+
output_d = Topology.Dictionary(output_bb)
|
442
|
+
xmin = Dictionary.ValueAtKey(output_d, "xmin")
|
443
|
+
ymin = Dictionary.ValueAtKey(output_d, "ymin")
|
444
|
+
zmin = Dictionary.ValueAtKey(output_d, "zmin")
|
445
|
+
xmax = Dictionary.ValueAtKey(output_d, "xmax")
|
446
|
+
ymax = Dictionary.ValueAtKey(output_d, "ymax")
|
447
|
+
zmax = Dictionary.ValueAtKey(output_d, "zmax")
|
448
|
+
output_width = xmax-xmin
|
449
|
+
output_length = ymax-ymin
|
450
|
+
output_height = zmax-zmin
|
451
|
+
output_max = max(output_width, output_length, output_height)
|
452
|
+
sf = 1/output_max
|
453
|
+
temp_output = Topology.Translate(output, -Vertex.X(output_centroid), -Vertex.Y(output_centroid), -Vertex.Z(output_centroid))
|
454
|
+
temp_output = Topology.Scale(temp_output, x=sf, y=sf, z=sf)
|
455
|
+
temp_output = Topology.Translate(temp_output, 2.5, 0, 0)
|
456
|
+
|
457
|
+
cyl = Cell.Cylinder(radius=0.04, height=0.4, placement="bottom")
|
458
|
+
cyl=Topology.Rotate(cyl, axis=[0,1,0], angle=90)
|
459
|
+
cyl = Topology.Translate(cyl, 1.25, 0, 0)
|
460
|
+
|
461
|
+
cone = Cell.Cone(baseRadius=0.1, topRadius=0, height=0.15, placement="bottom")
|
462
|
+
cone=Topology.Rotate(cone, axis=[0,1,0], angle=90)
|
463
|
+
cone = Topology.Translate(cone, 1.65, 0, 0)
|
464
|
+
cluster = Cluster.ByTopologies([temp_input, temp_output, cyl, cone])
|
465
|
+
cluster = Topology.Place(cluster, originA=Topology.Centroid(cluster), originB=Vertex.Origin())
|
466
|
+
data = Plotly.DataByTopology(cluster)
|
467
|
+
fig = Plotly.FigureByData(data)
|
468
|
+
return fig
|
469
|
+
|
470
|
+
def FigureByRule(self, rule, silent: bool = False):
|
471
|
+
"""
|
472
|
+
Returns the Plotly figure of the input rule.
|
473
|
+
|
474
|
+
Parameters
|
475
|
+
----------
|
476
|
+
rule : dict
|
477
|
+
The input rule
|
478
|
+
silent : bool, optional
|
479
|
+
If True, suppresses error/warning messages. Default is False.
|
480
|
+
|
481
|
+
Returns
|
482
|
+
-------
|
483
|
+
This function does not return a value
|
484
|
+
"""
|
485
|
+
from topologicpy.Topology import Topology
|
486
|
+
if not isinstance(rule, dict):
|
487
|
+
if not silent:
|
488
|
+
print("ShapeGrammar.DrawRule - Error: The input rule parameter is not a valid rule. Returning None.")
|
489
|
+
return None
|
490
|
+
input = rule["input"]
|
491
|
+
output = self.ApplyRule(input, rule)
|
492
|
+
return self.FigureByInputOutput(input, output)
|
topologicpy/Topology.py
CHANGED
@@ -9949,7 +9949,6 @@ class Topology():
|
|
9949
9949
|
|
9950
9950
|
# Extract translation (last column of the matrix)
|
9951
9951
|
translation = [m[3] for m in matrix[:3]]
|
9952
|
-
print("translation", translation)
|
9953
9952
|
x_translate, y_translate, z_translate = translation
|
9954
9953
|
|
9955
9954
|
# Extract rotation (top-left 3x3 part of the matrix)
|
@@ -9957,7 +9956,6 @@ class Topology():
|
|
9957
9956
|
|
9958
9957
|
# Extract scaling (diagonal of the matrix)
|
9959
9958
|
scaling_factors = [matrix[m][m] for m in [0,1,2]] # scaling is stored in the diagonal of the rotation matrix
|
9960
|
-
print(scaling_factors)
|
9961
9959
|
x_scale, y_scale, z_scale = scaling_factors
|
9962
9960
|
|
9963
9961
|
# Step 1: Apply Scaling
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.29'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.29
|
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
|
@@ -18,20 +18,21 @@ topologicpy/Helper.py,sha256=JdvC30WMrla46mTj5TdwCV_bRv-6y8vK5Bkx0prluy4,29100
|
|
18
18
|
topologicpy/Honeybee.py,sha256=yctkwfdupKnp7bAOjP1Z4YaYpRrWoMEb4gz9Z5zaWwE,21751
|
19
19
|
topologicpy/Matrix.py,sha256=BHGDRkBn1pf5DkRoY8feAhDGHTF3bjFM4jluiEb_A0w,22779
|
20
20
|
topologicpy/Neo4j.py,sha256=vNMaqTWerwr-3luLjYEXNhf8T97aFee6x5sIKBHY73s,22392
|
21
|
-
topologicpy/Plotly.py,sha256=
|
21
|
+
topologicpy/Plotly.py,sha256=FIFahDnWhvbQ--VJjy3lQGl5735w8hDzZNrVkCkpZFE,119455
|
22
22
|
topologicpy/Polyskel.py,sha256=oVfM4lqSMPTjnkHfsRU9VI8Blt6Vf0LVPkD9ebz7Wmw,27082
|
23
23
|
topologicpy/PyG.py,sha256=zvV6jtnol_aFiN6JRoMpYwBVfOU2aFs9gdWSdEo6mtU,109757
|
24
|
+
topologicpy/ShapeGrammar.py,sha256=JwE__VcKum5X3r33WwToEWtpJdFuhzZYyNhU2ob15ss,21194
|
24
25
|
topologicpy/Shell.py,sha256=h8S2nP1e0JtMxeOdAFZVhOYTJWTW8vlZRM5lxK0gu2o,89577
|
25
26
|
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
26
27
|
topologicpy/Sun.py,sha256=_VBBAUIDhvpkp72JBZlv7k9qx9jYubm3yM56UZ1Nc6c,36837
|
27
|
-
topologicpy/Topology.py,sha256=
|
28
|
+
topologicpy/Topology.py,sha256=UN1BnwS4G0DN5oLb6rLFUHEPxTj7PR6KzH-AnJQ0NHQ,478331
|
28
29
|
topologicpy/Vector.py,sha256=mx7fgABdioikPWM9HzXKzmqfx3u_XBcU_jlLD4qK2x8,42407
|
29
30
|
topologicpy/Vertex.py,sha256=UMDhERrLH6b4WOu4pl0UgYzcfp9-NvmASLtKXwetO_4,84687
|
30
31
|
topologicpy/Wire.py,sha256=eRs4PM7h4yU5v6umPh0oBJR4cN8BwsqlVroaFdnvK4w,228499
|
31
32
|
topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
|
32
|
-
topologicpy/version.py,sha256=
|
33
|
-
topologicpy-0.8.
|
34
|
-
topologicpy-0.8.
|
35
|
-
topologicpy-0.8.
|
36
|
-
topologicpy-0.8.
|
37
|
-
topologicpy-0.8.
|
33
|
+
topologicpy/version.py,sha256=c72Y0CCfU5Qgxq7demxoD7bRlDWidTBPnLUByhWGtHU,23
|
34
|
+
topologicpy-0.8.29.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
35
|
+
topologicpy-0.8.29.dist-info/METADATA,sha256=ahE6eaRHVYotJtOLSidVqD3l81GOrkKbBhlSnJauDsk,10535
|
36
|
+
topologicpy-0.8.29.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
37
|
+
topologicpy-0.8.29.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
38
|
+
topologicpy-0.8.29.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|