topologicpy 0.7.56__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 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
- print("Graph.AddEdge - Error: The input graph is not a valid graph. Returning None.")
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
- print("Graph.AddEdge - Error: The input edge is not a valid edge. Returning None.")
562
- return None
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
- print("Graph.AddVertex - Error: The input graph is not a valid graph. Returning None.")
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
- print("Graph.AddVertex - Error: The input vertex is not a valid vertex. Returning None.")
608
- return None
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
- print("Graph.AddVertices - Error: The input graph is not a valid graph. Returning None.")
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
- print("Graph.AddVertices - Error: The input list of vertices is not a valid list. Returning None.")
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
- print("Graph.AddVertices - Error: Could not find any valid vertices in the input list of vertices. Returning None.")
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
- print("Graph.AdjacentVertices - Error: The input graph is not a valid graph. Returning None.")
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
- print("Graph.AdjacentVertices - Error: The input vertex is not a valid vertex. Returning None.")
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
- print("Graph.AllPaths - Error: The input graph is not a valid graph. Returning None.")
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
- print("Graph.AllPaths - Error: The input vertexA is not a valid vertex. Returning None.")
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
- print("Graph.AllPaths - Error: The input vertexB is not a valid vertex. Returning None.")
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
- print("Graph.LocalClusteringCoefficient - Error: The input graph parameter is not a valid graph. Returning None.")
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
- print("Graph.LocalClusteringCoefficient - Error: The input graph parameter is a NULL graph. Returning None.")
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
@@ -2607,7 +2631,7 @@ class Graph:
2607
2631
  if len(apList) > 0:
2608
2632
  apTopList = []
2609
2633
  for ap in apList:
2610
- apTopList.append(ap.Topology())
2634
+ apTopList.append(ap)
2611
2635
  apertureExists = True
2612
2636
  break
2613
2637
  if apertureExists:
@@ -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
- # Normalize categories to a range between 0 and 1 for the color scale
401
- min_category = 0
402
- max_category = max(len(vertexGroups), 1)
403
- normalized_categories = [(cat - min_category) / (max_category - min_category) for cat in v_groupList]
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.56'
1
+ __version__ = '0.7.58'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: topologicpy
3
- Version: 0.7.56
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=Ik8NNzV8W8wdMJwxSV1Y6yb1GUZhRHWwVnQZ6s9UcUw,407624
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=xkBzK4TDGBpZ97aFbWWFQpoqENyLbcwESd1oD9EDIx0,106387
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=jTff8K144q4sccF93u8lrLqsH5r5ar5w40zPcmKgm0I,396181
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=bs_JMVwzGP1kPVGNECzwn5u1VxWd2PW2ue9xoYfFrwI,23
31
- topologicpy-0.7.56.dist-info/LICENSE,sha256=BRNw73R2WdDBICtwhI3wm3cxsaVqLTAGuRwrTltcfxs,1068
32
- topologicpy-0.7.56.dist-info/METADATA,sha256=SeEGO2zEhrn9PjaETXnqaLhzvp1Og-t96SIGM7weBqo,10918
33
- topologicpy-0.7.56.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
34
- topologicpy-0.7.56.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
35
- topologicpy-0.7.56.dist-info/RECORD,,
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,,