topologicpy 0.7.57__py3-none-any.whl → 0.7.58__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/BVH.py +296 -0
- topologicpy/Graph.py +46 -23
- topologicpy/Plotly.py +6 -4
- topologicpy/Topology.py +16 -0
- topologicpy/version.py +1 -1
- {topologicpy-0.7.57.dist-info → topologicpy-0.7.58.dist-info}/METADATA +1 -1
- {topologicpy-0.7.57.dist-info → topologicpy-0.7.58.dist-info}/RECORD +10 -9
- {topologicpy-0.7.57.dist-info → topologicpy-0.7.58.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.57.dist-info → topologicpy-0.7.58.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.57.dist-info → topologicpy-0.7.58.dist-info}/top_level.txt +0 -0
topologicpy/BVH.py
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# Copyright (C) 2024
|
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
|
+
import warnings
|
19
|
+
|
20
|
+
try:
|
21
|
+
import numpy as np
|
22
|
+
except:
|
23
|
+
print("BVH - Installing required numpy library.")
|
24
|
+
try:
|
25
|
+
os.system("pip install numpy")
|
26
|
+
except:
|
27
|
+
os.system("pip install numpy --user")
|
28
|
+
try:
|
29
|
+
import numpy as np
|
30
|
+
print("BVH - numpy library installed correctly.")
|
31
|
+
except:
|
32
|
+
warnings.warn("ANN - Error: Could not import numpy.")
|
33
|
+
|
34
|
+
class BVH:
|
35
|
+
# A class for Axis-Aligned Bounding Box (AABB)
|
36
|
+
class AABB:
|
37
|
+
def __init__(self, min_point, max_point):
|
38
|
+
self.min_point = np.array(min_point)
|
39
|
+
self.max_point = np.array(max_point)
|
40
|
+
self.centroid = (self.min_point + self.max_point) / 2.0
|
41
|
+
|
42
|
+
def intersects(self, other):
|
43
|
+
# Check if this AABB intersects with another AABB
|
44
|
+
return np.all(self.min_point <= other.max_point) and np.all(self.max_point >= other.min_point)
|
45
|
+
|
46
|
+
def contains(self, point):
|
47
|
+
# Check if a point is contained within the AABB
|
48
|
+
return np.all(self.min_point <= point) and np.all(self.max_point >= point)
|
49
|
+
|
50
|
+
# MeshObject class that stores a reference to the Topologic object
|
51
|
+
class MeshObject:
|
52
|
+
def __init__(self, vertices, topologic_object):
|
53
|
+
self.vertices = np.array(vertices)
|
54
|
+
self.aabb = BVH.AABB(np.min(vertices, axis=0), np.max(vertices, axis=0))
|
55
|
+
self.centroid = np.mean(vertices, axis=0)
|
56
|
+
self.topologic_object = topologic_object # Store the Topologic object reference
|
57
|
+
|
58
|
+
# BVH Node class
|
59
|
+
class BVHNode:
|
60
|
+
def __init__(self, aabb, left=None, right=None, objects=None):
|
61
|
+
self.aabb = aabb
|
62
|
+
self.left = left
|
63
|
+
self.right = right
|
64
|
+
self.objects = objects if objects else []
|
65
|
+
|
66
|
+
@staticmethod
|
67
|
+
def ByTopologies(*topologies, silent: bool = False):
|
68
|
+
"""
|
69
|
+
Creates a BVH Tree from the input list of topologies. The input can be individual topologies each as an input argument or a list of topologies stored in one input argument.
|
70
|
+
|
71
|
+
Parameters
|
72
|
+
----------
|
73
|
+
topologies : list
|
74
|
+
The list of topologies.
|
75
|
+
silent : bool , optional
|
76
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
77
|
+
|
78
|
+
Returns
|
79
|
+
-------
|
80
|
+
BVH tree
|
81
|
+
The created BVH tree.
|
82
|
+
|
83
|
+
"""
|
84
|
+
from topologicpy.Vertex import Vertex
|
85
|
+
from topologicpy.Topology import Topology
|
86
|
+
from topologicpy.Helper import Helper
|
87
|
+
|
88
|
+
if len(topologies) == 0:
|
89
|
+
print("BVH.ByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
90
|
+
return None
|
91
|
+
if len(topologies) == 1:
|
92
|
+
topologyList = topologies[0]
|
93
|
+
if isinstance(topologyList, list):
|
94
|
+
if len(topologyList) == 0:
|
95
|
+
if not silent:
|
96
|
+
print("BVH.ByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
97
|
+
return None
|
98
|
+
else:
|
99
|
+
topologyList = [x for x in topologyList if Topology.IsInstance(x, "Topology")]
|
100
|
+
if len(topologyList) == 0:
|
101
|
+
if not silent:
|
102
|
+
print("BVH.ByTopologies - Error: The input topologies parameter does not contain any valid topologies. Returning None.")
|
103
|
+
return None
|
104
|
+
else:
|
105
|
+
if not silent:
|
106
|
+
print("BVH.ByTopologies - Warning: The input topologies parameter contains only one topology. Returning the same topology.")
|
107
|
+
return topologies
|
108
|
+
else:
|
109
|
+
topologyList = Helper.Flatten(list(topologies))
|
110
|
+
topologyList = [x for x in topologyList if Topology.IsInstance(x, "Topology")]
|
111
|
+
if len(topologyList) == 0:
|
112
|
+
if not silent:
|
113
|
+
print("BVH.ByTopologies - Error: The input parameters do not contain any valid topologies. Returning None.")
|
114
|
+
return None
|
115
|
+
# Recursive BVH construction
|
116
|
+
def build_bvh(objects, depth=0):
|
117
|
+
if len(objects) == 1:
|
118
|
+
return BVH.BVHNode(objects[0].aabb, objects=objects)
|
119
|
+
|
120
|
+
# Split objects along the median axis based on their centroids
|
121
|
+
axis = depth % 3
|
122
|
+
objects.sort(key=lambda obj: obj.centroid[axis])
|
123
|
+
|
124
|
+
mid = len(objects) // 2
|
125
|
+
left_bvh = build_bvh(objects[:mid], depth + 1)
|
126
|
+
right_bvh = build_bvh(objects[mid:], depth + 1)
|
127
|
+
|
128
|
+
# Merge left and right bounding boxes
|
129
|
+
combined_aabb = BVH.AABB(
|
130
|
+
np.minimum(left_bvh.aabb.min_point, right_bvh.aabb.min_point),
|
131
|
+
np.maximum(left_bvh.aabb.max_point, right_bvh.aabb.max_point)
|
132
|
+
)
|
133
|
+
|
134
|
+
return BVH.BVHNode(combined_aabb, left_bvh, right_bvh)
|
135
|
+
|
136
|
+
mesh_objects = []
|
137
|
+
for topology in topologyList:
|
138
|
+
vertices = [(Vertex.X(v), Vertex.Y(v), Vertex.Z(v)) for v in Topology.Vertices(topology)]
|
139
|
+
mesh_objects.append(BVH.MeshObject(vertices, topology))
|
140
|
+
|
141
|
+
return build_bvh(mesh_objects)
|
142
|
+
|
143
|
+
@staticmethod
|
144
|
+
def QueryByTopologies(*topologies, silent: bool = False):
|
145
|
+
"""
|
146
|
+
Creates a BVH Query from the input list of topologies. The input can be individual topologies each as an input argument or a list of topologies stored in one input argument.
|
147
|
+
|
148
|
+
Parameters
|
149
|
+
----------
|
150
|
+
topologies : list
|
151
|
+
The list of topologies.
|
152
|
+
silent : bool , optional
|
153
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
154
|
+
|
155
|
+
Returns
|
156
|
+
-------
|
157
|
+
BVH query
|
158
|
+
The created BVH query.
|
159
|
+
|
160
|
+
"""
|
161
|
+
from topologicpy.Vertex import Vertex
|
162
|
+
from topologicpy.Cluster import Cluster
|
163
|
+
from topologicpy.Topology import Topology
|
164
|
+
from topologicpy.Dictionary import Dictionary
|
165
|
+
from topologicpy.Helper import Helper
|
166
|
+
|
167
|
+
if len(topologies) == 0:
|
168
|
+
print("BVH.QueryByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
169
|
+
return None
|
170
|
+
if len(topologies) == 1:
|
171
|
+
topologyList = topologies[0]
|
172
|
+
if isinstance(topologyList, list):
|
173
|
+
if len(topologyList) == 0:
|
174
|
+
if not silent:
|
175
|
+
print("BVH.QueryByTopologies - Error: The input topologies parameter is an empty list. Returning None.")
|
176
|
+
return None
|
177
|
+
else:
|
178
|
+
topologyList = [x for x in topologyList if Topology.IsInstance(x, "Topology")]
|
179
|
+
if len(topologyList) == 0:
|
180
|
+
if not silent:
|
181
|
+
print("BVH.QueryByTopologies - Error: The input topologies parameter does not contain any valid topologies. Returning None.")
|
182
|
+
return None
|
183
|
+
else:
|
184
|
+
if not silent:
|
185
|
+
print("BVH.QueryByTopologies - Warning: The input topologies parameter contains only one topology. Returning the same topology.")
|
186
|
+
return topologies
|
187
|
+
else:
|
188
|
+
topologyList = Helper.Flatten(list(topologies))
|
189
|
+
topologyList = [x for x in topologyList if Topology.IsInstance(x, "Topology")]
|
190
|
+
if len(topologyList) == 0:
|
191
|
+
if not silent:
|
192
|
+
print("BVH.ByTopologies - Error: The input parameters do not contain any valid topologies. Returning None.")
|
193
|
+
return None
|
194
|
+
vertices = []
|
195
|
+
for topology in topologyList:
|
196
|
+
if Topology.IsInstance(topology, "Vertex"):
|
197
|
+
vertices.append(topology)
|
198
|
+
else:
|
199
|
+
vertices.extend(Topology.Vertices(topology))
|
200
|
+
cluster = Cluster.ByTopologies(vertices)
|
201
|
+
bb = Topology.BoundingBox(cluster)
|
202
|
+
d = Topology.Dictionary(bb)
|
203
|
+
min_x = Dictionary.ValueAtKey(d, "minx")
|
204
|
+
min_y = Dictionary.ValueAtKey(d, "miny")
|
205
|
+
min_z = Dictionary.ValueAtKey(d, "minz")
|
206
|
+
max_x = Dictionary.ValueAtKey(d, "maxx")
|
207
|
+
max_y = Dictionary.ValueAtKey(d, "maxy")
|
208
|
+
max_z = Dictionary.ValueAtKey(d, "maxz")
|
209
|
+
query_aabb = BVH.AABB(min_point=(min_x, min_y, min_z), max_point=(max_x,max_y,max_z))
|
210
|
+
return query_aabb
|
211
|
+
|
212
|
+
def Clashes(bvh, query):
|
213
|
+
"""
|
214
|
+
Returns a list of topologies in the input bvh tree that clashes (broad phase) with the list of topologies in the input query.
|
215
|
+
|
216
|
+
Parameters
|
217
|
+
----------
|
218
|
+
topologies : list
|
219
|
+
The list of topologies.
|
220
|
+
silent : bool , optional
|
221
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
222
|
+
|
223
|
+
Returns
|
224
|
+
-------
|
225
|
+
list
|
226
|
+
The list of clashing topologies (based on their axis-aligned bounding box (AABB))
|
227
|
+
|
228
|
+
"""
|
229
|
+
# Function to perform clash detection (broad-phase) and return Topologic objects
|
230
|
+
def clash_detection(bvh_node, query_aabb, clashing_objects=None):
|
231
|
+
if clashing_objects is None:
|
232
|
+
clashing_objects = []
|
233
|
+
|
234
|
+
# Check if the query AABB intersects with the current node's AABB
|
235
|
+
if not bvh_node.aabb.intersects(query_aabb):
|
236
|
+
return clashing_objects
|
237
|
+
|
238
|
+
# If this is a leaf node, check each object in the node
|
239
|
+
if bvh_node.objects:
|
240
|
+
for obj in bvh_node.objects:
|
241
|
+
if obj.aabb.intersects(query_aabb):
|
242
|
+
clashing_objects.append(obj.topologic_object) # Return the Topologic object
|
243
|
+
return clashing_objects
|
244
|
+
|
245
|
+
# Recursively check the left and right child nodes
|
246
|
+
clash_detection(bvh_node.left, query_aabb, clashing_objects)
|
247
|
+
clash_detection(bvh_node.right, query_aabb, clashing_objects)
|
248
|
+
|
249
|
+
return clashing_objects
|
250
|
+
return clash_detection(bvh, query)
|
251
|
+
|
252
|
+
# Function to recursively add nodes and edges to the TopologicPy Graph
|
253
|
+
def Graph(bvh, tolerance=0.0001):
|
254
|
+
"""
|
255
|
+
Creates a graph from the input bvh tree.
|
256
|
+
|
257
|
+
Parameters
|
258
|
+
----------
|
259
|
+
bvh : BVH Tree
|
260
|
+
The input BVH Tree.
|
261
|
+
tolerance : float , optional
|
262
|
+
The desired tolerance. The default is 0.0001.
|
263
|
+
|
264
|
+
Returns
|
265
|
+
-------
|
266
|
+
topologic_core.Graph
|
267
|
+
The created graph.
|
268
|
+
|
269
|
+
"""
|
270
|
+
from topologicpy.Vertex import Vertex
|
271
|
+
from topologicpy.Edge import Edge
|
272
|
+
from topologicpy.Graph import Graph
|
273
|
+
from topologicpy.Topology import Topology
|
274
|
+
import random
|
275
|
+
def add_bvh_to_graph(bvh_node, graph, parent_vertex=None, tolerance=0.0001):
|
276
|
+
# Create a vertex for the current node's AABB centroid
|
277
|
+
centroid = bvh_node.aabb.centroid
|
278
|
+
current_vertex = Vertex.ByCoordinates(x=centroid[0], y=centroid[1], z=centroid[2])
|
279
|
+
|
280
|
+
# Add an edge from the parent to this vertex (if a parent exists)
|
281
|
+
if parent_vertex is not None:
|
282
|
+
d = Vertex.Distance(parent_vertex, current_vertex)
|
283
|
+
if d < tolerance:
|
284
|
+
current_vertex = Topology.Translate(current_vertex, tolerance*random.uniform(2,50), tolerance*random.uniform(2,50), tolerance*random.uniform(2,50))
|
285
|
+
edge = Edge.ByVertices(parent_vertex, current_vertex, tolerance=tolerance)
|
286
|
+
graph = Graph.AddEdge(graph, edge, silent=True)
|
287
|
+
|
288
|
+
# Recursively add child nodes
|
289
|
+
if bvh_node.left:
|
290
|
+
graph = add_bvh_to_graph(bvh_node.left, graph, parent_vertex=current_vertex, tolerance=tolerance)
|
291
|
+
if bvh_node.right:
|
292
|
+
graph = add_bvh_to_graph(bvh_node.right, graph, parent_vertex=current_vertex, tolerance=tolerance)
|
293
|
+
|
294
|
+
return graph
|
295
|
+
graph = Graph.ByVerticesEdges([Vertex.Origin()], [])
|
296
|
+
return add_bvh_to_graph(bvh, graph, parent_vertex = None, tolerance=tolerance)
|
topologicpy/Graph.py
CHANGED
@@ -500,7 +500,7 @@ class Graph:
|
|
500
500
|
return adjList
|
501
501
|
|
502
502
|
@staticmethod
|
503
|
-
def AddEdge(graph, edge, transferVertexDictionaries=False, transferEdgeDictionaries=False, tolerance=0.0001):
|
503
|
+
def AddEdge(graph, edge, transferVertexDictionaries: bool = False, transferEdgeDictionaries: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
504
504
|
"""
|
505
505
|
Adds the input edge to the input Graph.
|
506
506
|
|
@@ -516,6 +516,8 @@ class Graph:
|
|
516
516
|
If set to True, the dictionaries of the edges are transferred to the graph.
|
517
517
|
tolerance : float , optional
|
518
518
|
The desired tolerance. The default is 0.0001.
|
519
|
+
silent : bool , optional
|
520
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
519
521
|
|
520
522
|
Returns
|
521
523
|
-------
|
@@ -555,11 +557,13 @@ class Graph:
|
|
555
557
|
return [graph_vertices, returnVertex]
|
556
558
|
|
557
559
|
if not Topology.IsInstance(graph, "Graph"):
|
558
|
-
|
560
|
+
if not silent:
|
561
|
+
print("Graph.AddEdge - Error: The input graph is not a valid graph. Returning None.")
|
559
562
|
return None
|
560
563
|
if not Topology.IsInstance(edge, "Edge"):
|
561
|
-
|
562
|
-
|
564
|
+
if not silent:
|
565
|
+
print("Graph.AddEdge - Error: The input edge is not a valid edge. Returning the input graph.")
|
566
|
+
return graph
|
563
567
|
graph_vertices = Graph.Vertices(graph)
|
564
568
|
graph_edges = Graph.Edges(graph, graph_vertices, tolerance)
|
565
569
|
vertices = Edge.Vertices(edge)
|
@@ -579,7 +583,7 @@ class Graph:
|
|
579
583
|
return new_graph
|
580
584
|
|
581
585
|
@staticmethod
|
582
|
-
def AddVertex(graph, vertex, tolerance=0.0001):
|
586
|
+
def AddVertex(graph, vertex, tolerance: float = 0.0001, silent: bool = False):
|
583
587
|
"""
|
584
588
|
Adds the input vertex to the input graph.
|
585
589
|
|
@@ -591,6 +595,8 @@ class Graph:
|
|
591
595
|
The input vertex.
|
592
596
|
tolerance : float , optional
|
593
597
|
The desired tolerance. The default is 0.0001.
|
598
|
+
silent : bool , optional
|
599
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
594
600
|
|
595
601
|
Returns
|
596
602
|
-------
|
@@ -601,16 +607,18 @@ class Graph:
|
|
601
607
|
from topologicpy.Topology import Topology
|
602
608
|
|
603
609
|
if not Topology.IsInstance(graph, "Graph"):
|
604
|
-
|
610
|
+
if not silent:
|
611
|
+
print("Graph.AddVertex - Error: The input graph is not a valid graph. Returning None.")
|
605
612
|
return None
|
606
613
|
if not Topology.IsInstance(vertex, "Vertex"):
|
607
|
-
|
608
|
-
|
614
|
+
if not silent:
|
615
|
+
print("Graph.AddVertex - Error: The input vertex is not a valid vertex. Returning the input graph.")
|
616
|
+
return graph
|
609
617
|
_ = graph.AddVertices([vertex], tolerance)
|
610
618
|
return graph
|
611
619
|
|
612
620
|
@staticmethod
|
613
|
-
def AddVertices(graph, vertices, tolerance=0.0001):
|
621
|
+
def AddVertices(graph, vertices, tolerance: float = 0.0001, silent: bool = False):
|
614
622
|
"""
|
615
623
|
Adds the input vertex to the input graph.
|
616
624
|
|
@@ -622,6 +630,8 @@ class Graph:
|
|
622
630
|
The input list of vertices.
|
623
631
|
tolerance : float , optional
|
624
632
|
The desired tolerance. The default is 0.0001.
|
633
|
+
silent : bool , optional
|
634
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
625
635
|
|
626
636
|
Returns
|
627
637
|
-------
|
@@ -632,20 +642,23 @@ class Graph:
|
|
632
642
|
from topologicpy.Topology import Topology
|
633
643
|
|
634
644
|
if not Topology.IsInstance(graph, "Graph"):
|
635
|
-
|
645
|
+
if not silent:
|
646
|
+
print("Graph.AddVertices - Error: The input graph is not a valid graph. Returning None.")
|
636
647
|
return None
|
637
648
|
if not isinstance(vertices, list):
|
638
|
-
|
649
|
+
if not silent:
|
650
|
+
print("Graph.AddVertices - Error: The input list of vertices is not a valid list. Returning None.")
|
639
651
|
return None
|
640
652
|
vertices = [v for v in vertices if Topology.IsInstance(v, "Vertex")]
|
641
653
|
if len(vertices) < 1:
|
642
|
-
|
654
|
+
if not silent:
|
655
|
+
print("Graph.AddVertices - Error: Could not find any valid vertices in the input list of vertices. Returning None.")
|
643
656
|
return None
|
644
657
|
_ = graph.AddVertices(vertices, tolerance)
|
645
658
|
return graph
|
646
659
|
|
647
660
|
@staticmethod
|
648
|
-
def AdjacentVertices(graph, vertex):
|
661
|
+
def AdjacentVertices(graph, vertex, silent: bool = False):
|
649
662
|
"""
|
650
663
|
Returns the list of vertices connected to the input vertex.
|
651
664
|
|
@@ -655,6 +668,8 @@ class Graph:
|
|
655
668
|
The input graph.
|
656
669
|
vertex : topologic_core.Vertex
|
657
670
|
the input vertex.
|
671
|
+
silent : bool , optional
|
672
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
658
673
|
|
659
674
|
Returns
|
660
675
|
-------
|
@@ -665,17 +680,19 @@ class Graph:
|
|
665
680
|
from topologicpy.Topology import Topology
|
666
681
|
|
667
682
|
if not Topology.IsInstance(graph, "Graph"):
|
668
|
-
|
683
|
+
if not silent:
|
684
|
+
print("Graph.AdjacentVertices - Error: The input graph is not a valid graph. Returning None.")
|
669
685
|
return None
|
670
686
|
if not Topology.IsInstance(vertex, "Vertex"):
|
671
|
-
|
687
|
+
if not silent:
|
688
|
+
print("Graph.AdjacentVertices - Error: The input vertex is not a valid vertex. Returning None.")
|
672
689
|
return None
|
673
690
|
vertices = []
|
674
691
|
_ = graph.AdjacentVertices(vertex, vertices)
|
675
692
|
return list(vertices)
|
676
693
|
|
677
694
|
@staticmethod
|
678
|
-
def AllPaths(graph, vertexA, vertexB, timeLimit=10):
|
695
|
+
def AllPaths(graph, vertexA, vertexB, timeLimit=10, silent: bool = False):
|
679
696
|
"""
|
680
697
|
Returns all the paths that connect the input vertices within the allowed time limit in seconds.
|
681
698
|
|
@@ -689,6 +706,8 @@ class Graph:
|
|
689
706
|
The second input vertex.
|
690
707
|
timeLimit : int , optional
|
691
708
|
The time limit in second. The default is 10 seconds.
|
709
|
+
silent : bool , optional
|
710
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
692
711
|
|
693
712
|
Returns
|
694
713
|
-------
|
@@ -699,20 +718,23 @@ class Graph:
|
|
699
718
|
from topologicpy.Topology import Topology
|
700
719
|
|
701
720
|
if not Topology.IsInstance(graph, "Graph"):
|
702
|
-
|
721
|
+
if not silent:
|
722
|
+
print("Graph.AllPaths - Error: The input graph is not a valid graph. Returning None.")
|
703
723
|
return None
|
704
724
|
if not Topology.IsInstance(vertexA, "Vertex"):
|
705
|
-
|
725
|
+
if not silent:
|
726
|
+
print("Graph.AllPaths - Error: The input vertexA is not a valid vertex. Returning None.")
|
706
727
|
return None
|
707
728
|
if not Topology.IsInstance(vertexB, "Vertex"):
|
708
|
-
|
729
|
+
if not silent:
|
730
|
+
print("Graph.AllPaths - Error: The input vertexB is not a valid vertex. Returning None.")
|
709
731
|
return None
|
710
732
|
paths = []
|
711
733
|
_ = graph.AllPaths(vertexA, vertexB, True, timeLimit, paths)
|
712
734
|
return paths
|
713
735
|
|
714
736
|
@staticmethod
|
715
|
-
def AverageClusteringCoefficient(graph, mantissa: int = 6):
|
737
|
+
def AverageClusteringCoefficient(graph, mantissa: int = 6, silent: bool = False):
|
716
738
|
"""
|
717
739
|
Returns the average clustering coefficient of the input graph. See https://en.wikipedia.org/wiki/Clustering_coefficient.
|
718
740
|
|
@@ -732,11 +754,13 @@ class Graph:
|
|
732
754
|
from topologicpy.Topology import Topology
|
733
755
|
|
734
756
|
if not Topology.IsInstance(graph, "Graph"):
|
735
|
-
|
757
|
+
if not silent:
|
758
|
+
print("Graph.LocalClusteringCoefficient - Error: The input graph parameter is not a valid graph. Returning None.")
|
736
759
|
return None
|
737
760
|
vertices = Graph.Vertices(graph)
|
738
761
|
if len(vertices) < 1:
|
739
|
-
|
762
|
+
if not silent:
|
763
|
+
print("Graph.LocalClusteringCoefficient - Error: The input graph parameter is a NULL graph. Returning None.")
|
740
764
|
return None
|
741
765
|
if len(vertices) == 1:
|
742
766
|
return 0.0
|
@@ -5988,7 +6012,6 @@ class Graph:
|
|
5988
6012
|
flat_list = Helper.Flatten(edge_list)
|
5989
6013
|
flat_list = [x for x in flat_list if not x == None]
|
5990
6014
|
num_nodes = max(flat_list) + 1
|
5991
|
-
print("Number of Nodes:", num_nodes)
|
5992
6015
|
|
5993
6016
|
# Create an adjacency matrix.
|
5994
6017
|
adjacency_matrix = np.zeros((num_nodes, num_nodes))
|
topologicpy/Plotly.py
CHANGED
@@ -397,10 +397,12 @@ class Plotly:
|
|
397
397
|
mode = "markers+text"
|
398
398
|
else:
|
399
399
|
mode = "markers"
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
400
|
+
normalized_categories = vertexColor # Start with the default vertexColor
|
401
|
+
if len(vertexGroups) > 0:
|
402
|
+
# Normalize categories to a range between 0 and 1 for the color scale
|
403
|
+
min_category = 0
|
404
|
+
max_category = max(len(vertexGroups), 1)
|
405
|
+
normalized_categories = [(cat - min_category) / (max_category - min_category) for cat in v_groupList]
|
404
406
|
v_trace=go.Scatter3d(x=Xn,
|
405
407
|
y=Yn,
|
406
408
|
z=Zn,
|
topologicpy/Topology.py
CHANGED
@@ -1344,7 +1344,23 @@ class Topology():
|
|
1344
1344
|
if not x_flag and not y_flag and not z_flag:
|
1345
1345
|
print("Topology.BoundingBox - Error: the input axes parameter is not a recognized string. Returning None.")
|
1346
1346
|
return None
|
1347
|
+
if Topology.IsInstance(topology, "Vertex"):
|
1348
|
+
minX = Vertex.X(topology)
|
1349
|
+
minY = Vertex.Y(topology)
|
1350
|
+
minZ = Vertex.Z(topology)
|
1351
|
+
dictionary = Dictionary.ByKeysValues(["xrot","yrot","zrot", "minx", "miny", "minz", "maxx", "maxy", "maxz", "width", "length", "height"], [0, 0, 0, minX, minY, minZ, minX, minY, minZ, 0, 0, 0])
|
1352
|
+
box = Vertex.ByCoordinates(minX, minY, minZ)
|
1353
|
+
box = Topology.SetDictionary(box, dictionary)
|
1354
|
+
return box
|
1347
1355
|
vertices = Topology.SubTopologies(topology, subTopologyType="vertex")
|
1356
|
+
if len(vertices) == 1: # A Cluster made of one vertex. Rare, but can happen!
|
1357
|
+
minX = Vertex.X(vertices[0])
|
1358
|
+
minY = Vertex.Y(vertices[0])
|
1359
|
+
minZ = Vertex.Z(vertices[0])
|
1360
|
+
dictionary = Dictionary.ByKeysValues(["xrot","yrot","zrot", "minx", "miny", "minz", "maxx", "maxy", "maxz", "width", "length", "height"], [0, 0, 0, minX, minY, minZ, minX, minY, minZ, 0, 0, 0])
|
1361
|
+
box = Vertex.ByCoordinates(minX, minY, minZ)
|
1362
|
+
box = Topology.SetDictionary(box, dictionary)
|
1363
|
+
return box
|
1348
1364
|
topology = Cluster.ByTopologies(vertices)
|
1349
1365
|
boundingBox = bb(topology)
|
1350
1366
|
minX = boundingBox[0]
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.58'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.58
|
4
4
|
Summary: An Advanced Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
6
|
License: MIT License
|
@@ -1,5 +1,6 @@
|
|
1
1
|
topologicpy/ANN.py,sha256=XAuUjNvDRK1hhXfo82S-zXmnAPZGEdHJMRdfpu0aJ8I,47901
|
2
2
|
topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
|
3
|
+
topologicpy/BVH.py,sha256=dfVQyn5OPN1_50nusS0AxAcmUfqTzpl0vWT7RBEz-WM,12870
|
3
4
|
topologicpy/Cell.py,sha256=_vEYx1kNc3JZJUCCS8nhLM_j8EV4SyZYt3DjNHNRoDw,107707
|
4
5
|
topologicpy/CellComplex.py,sha256=YNmNkH6IUplM9f7agZQd6IL2xnHf5ds3JkGQk4jiSXQ,48029
|
5
6
|
topologicpy/Cluster.py,sha256=TZXuxzdaUr6OHSWnjWpjCOMlVj6YHBH8aUVbDVsncVA,54999
|
@@ -10,26 +11,26 @@ topologicpy/Dictionary.py,sha256=cURg452wwk2WeSxWY46ncgAUo5XD1c2c5EtO6ESZHaY,273
|
|
10
11
|
topologicpy/Edge.py,sha256=vhYHkobSLGSWV-oe2oJFFDobqFToDyb7s71yQ840AAA,65166
|
11
12
|
topologicpy/EnergyModel.py,sha256=NM3_nAdY9_YDtbp9CaEZ0x0xVsetTqVDzm_VSjmq_mI,53746
|
12
13
|
topologicpy/Face.py,sha256=YjU6TxxW2Mf5InumMvzXUXVVRdtjxyRGauRIhGXzkao,116411
|
13
|
-
topologicpy/Graph.py,sha256=
|
14
|
+
topologicpy/Graph.py,sha256=6jeS8ViWSdSoieISY0iZnZN19f6Ow0WRtF68SoA6s3E,408932
|
14
15
|
topologicpy/Grid.py,sha256=3-sn7CHWGcXk18XCnHjsUttNJTWwmN63g_Insj__p04,18218
|
15
16
|
topologicpy/Helper.py,sha256=i-AfI29NMsZXBaymjilfvxQbuS3wpYbpPw4RWu1YCHs,16358
|
16
17
|
topologicpy/Honeybee.py,sha256=Oc8mfGBNSjs6wxkPzCKmEw1ZPQPbp9XtiYWaAF62oSk,21893
|
17
18
|
topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
|
18
19
|
topologicpy/Neo4j.py,sha256=BezQ-sdpU8B0W4X_kaF7alZrlN0-h4779HFrB3Fsn-w,22033
|
19
|
-
topologicpy/Plotly.py,sha256=
|
20
|
+
topologicpy/Plotly.py,sha256=_cgTZmMhp2EOWNazA-GGBgPy5tx_vdl-6hVl0xjhp90,106526
|
20
21
|
topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
|
21
22
|
topologicpy/PyG.py,sha256=LU9LCCzjxGPUM31qbaJXZsTvniTtgugxJY7y612t4A4,109757
|
22
23
|
topologicpy/Shell.py,sha256=joahFtpRQTWJpQOmi3qU4Xe0Sx2XXeayHlXTNx8CzMk,87610
|
23
24
|
topologicpy/Speckle.py,sha256=rUS6PCaxIjEF5_fUruxvMH47FMKg-ohcoU0qAUb-yNM,14267
|
24
25
|
topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
|
25
|
-
topologicpy/Topology.py,sha256=
|
26
|
+
topologicpy/Topology.py,sha256=cFYSb93kxqcsdGLdeVcdE9td-KZ9X967sEn98NQAYfM,397243
|
26
27
|
topologicpy/Vector.py,sha256=WQQUbwrg7VKImtxuBUi2i-FRiPT77WlrzLP05gdXKM8,33079
|
27
28
|
topologicpy/Vertex.py,sha256=bLY60YWoMsgCgHk7F7k9F93Sq2FJ6AzUcTfJ83NZfHA,71107
|
28
29
|
topologicpy/Wire.py,sha256=OoPb7SJl0VpZDZpGL0-VkYJ35zPANS7gHDt9tixOSxc,157629
|
29
30
|
topologicpy/__init__.py,sha256=D7ky87CAQMiS2KE6YLvcTLkTgA2PY7rASe6Z23pjp9k,872
|
30
|
-
topologicpy/version.py,sha256=
|
31
|
-
topologicpy-0.7.
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
34
|
-
topologicpy-0.7.
|
35
|
-
topologicpy-0.7.
|
31
|
+
topologicpy/version.py,sha256=_LZYqF4sncRmxYtm8gZrX2loMxAZar5Q6FHbJDatzH0,23
|
32
|
+
topologicpy-0.7.58.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
|
33
|
+
topologicpy-0.7.58.dist-info/METADATA,sha256=XLAiGFSE_Wlh15I97O2XsTqjKkgBWhqoi4iHYCwr1HQ,10918
|
34
|
+
topologicpy-0.7.58.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
35
|
+
topologicpy-0.7.58.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
+
topologicpy-0.7.58.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|