topologicpy 0.8.40__py3-none-any.whl → 0.8.41__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/Graph.py CHANGED
@@ -7751,6 +7751,34 @@ class Graph:
7751
7751
  edge = Topology.SetDictionary(edge, d)
7752
7752
  return graph
7753
7753
 
7754
+ @staticmethod
7755
+ def IsEmpty(graph, silent: bool = False):
7756
+ """
7757
+ Tests if the input graph is empty (Has no vertices).
7758
+
7759
+ Parameters
7760
+ ----------
7761
+ graph : topologic_core.Graph
7762
+ The input graph.
7763
+ silent : bool , optional
7764
+ If set to True, error and warning messages are suppressed. The default is False.
7765
+
7766
+ Returns
7767
+ -------
7768
+ bool
7769
+ True if the two input graphs are isomorphic. False otherwise
7770
+
7771
+ """
7772
+
7773
+ from topologicpy.Topology import Topology
7774
+
7775
+ if not Topology.IsInstance(graph, "Graph"):
7776
+ if not silent:
7777
+ print("Graph.IsEmpty - Error: The input graph parameter is not a valid graph. Returning None.")
7778
+ return None
7779
+
7780
+ return (len(Graph.Vertices(graph)) == 0)
7781
+
7754
7782
  @staticmethod
7755
7783
  def IsIsomorphic(graphA, graphB, maxIterations=10, silent=False):
7756
7784
  """
@@ -9192,6 +9220,142 @@ class Graph:
9192
9220
  return None
9193
9221
  return graph.GetGUID()
9194
9222
 
9223
+ @staticmethod
9224
+ def HasseDiagram(topology, types=["vertex", "edge", "wire", "face", "shell", "cell", "cellComplex"], topDown: bool = False, minDistance: float=0.1, vertexLabelKey: str="label", vertexTypeKey: str="type", vertexColorKey: str="color", colorScale: str="viridis", storeBREP: bool = False, tolerance: float=0.0001, silent: bool=False):
9225
+ """
9226
+ Constructs a Hasse diagram from the input topology as a directed graph. See: https://en.wikipedia.org/wiki/Hasse_diagram
9227
+ Vertices represent topologies (vertices, edges, wires, faces, shells, cells, cellComplexes).
9228
+ Edges represent inclusion (e.g. vertex ⊂ edge, edge ⊂ wire).
9229
+
9230
+ Parameters
9231
+ ----------
9232
+ topology : topologic_core.Topology
9233
+ The input topology
9234
+ types : optional, list
9235
+ The list of topology types that you wish to encode in the Hasse diagram.
9236
+ This list must be ordered according to topologic_core's class hierarchy.
9237
+ If you are not interested in representing some topology types. These can be omitted.
9238
+ The default is:
9239
+ ["vertex", "edge", "wire", "face", "shell", "cell", "cellComplex"].
9240
+ topDown : bool , optional
9241
+ If set to True, the graph edges are directed from topologies to their subtopologies.
9242
+ Otherwise, they are directed from topologies to their supertopologies. The default is False.
9243
+ minDistance : float , optional
9244
+ The desired minimum distance between the vertices of the graph. The default is 0.1.
9245
+ vertexLabelKey: str , optional
9246
+ The desired vertex dictionary key under which to store a unique label (of the form Type_Index). The default is "label".
9247
+ vertexTypeKey: str , optional
9248
+ The desired vertex dictionary key under which to store the topology type (e.g. "vertex", "edge", "wire"). The default is "type".
9249
+ vertexColorKey: str , optional
9250
+ The desired vertex dictionary key under which to store the topology color. The default is "color".
9251
+ colorScale : str , optional
9252
+ The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
9253
+ In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
9254
+ storeBREP : bool , optional
9255
+ If set to True, store the BRep of the topology in its representative vertex. The default is False.
9256
+ tolerance : float
9257
+ The desired tolerance. The default is 0.0001.
9258
+ silent : bool , optional
9259
+ If set to True, error and warning messages are suppressed. The default is False.
9260
+
9261
+ Returns
9262
+ -------
9263
+ topologic_core.Graph
9264
+ The created Hesse diagram graph.
9265
+
9266
+ """
9267
+ from topologicpy.Vertex import Vertex
9268
+ from topologicpy.Edge import Edge
9269
+ from topologicpy.Dictionary import Dictionary
9270
+ from topologicpy.Color import Color
9271
+ from topologicpy.Topology import Topology
9272
+
9273
+ def label(topo, index):
9274
+ cls = Topology.TypeAsString(topo)
9275
+ return f"{cls}_{index}"
9276
+
9277
+ def collect_topologies(topology, topo_types):
9278
+ """
9279
+ Returns a dict of all sub-topologies by dimension.
9280
+ """
9281
+ topo_by_type = {}
9282
+ for sub_type in topo_types:
9283
+ topo_by_type[sub_type] = Topology.SubTopologies(topology, subTopologyType=sub_type)
9284
+ return topo_by_type
9285
+
9286
+ if not Topology.IsInstance(topology, "topology"):
9287
+ if not silent:
9288
+ print("Graph.HasseDiagram - Error: The input topology parameter is not a valid topology. Returning None.")
9289
+ return None
9290
+ if minDistance <= tolerance:
9291
+ if not silent:
9292
+ print("Graph.HasseDiagram - Error: The input minDistance parameter cannot be less than the input tolerance parameter. Returning None.")
9293
+ return None
9294
+ types = [t.lower() for t in types]
9295
+ for type in types:
9296
+ if type not in ["vertex", "edge", "wire", "face", "shell", "cell", "cellcomplex"]:
9297
+ if not silent:
9298
+ print("Graph.HasseDiagram - Error: Unknown type found in the types input parameter. Returning None.")
9299
+ return None
9300
+
9301
+ topology_type = Topology.TypeAsString(topology).lower()
9302
+ try:
9303
+ sub_types = types[:types.index(topology_type)]
9304
+ except:
9305
+ sub_types = types
9306
+ topo_by_type = collect_topologies(topology, sub_types)
9307
+ all_topos = []
9308
+ topo_ids = {}
9309
+ index = 0
9310
+
9311
+ # Flatten and assign unique labels
9312
+ for sub_type in sub_types:
9313
+ color = Color.AnyToHex(Color.ByValueInRange(float(types.index(sub_type)), minValue=0, maxValue=6, colorScale=colorScale))
9314
+ lbl_index = 1
9315
+ for t in topo_by_type[sub_type]:
9316
+ lbl = label(t, lbl_index)
9317
+ d = Topology.Dictionary(t)
9318
+ d = Dictionary.SetValuesAtKeys(d, [vertexLabelKey, vertexTypeKey, vertexColorKey], [lbl, sub_type, color])
9319
+ t = Topology.SetDictionary(t, d)
9320
+ all_topos.append(t)
9321
+ topo_ids[lbl] = index
9322
+ index += 1
9323
+ lbl_index += 1
9324
+
9325
+ # Create graph vertices
9326
+ graph_vertices = [Topology.Centroid(_) for _ in all_topos]
9327
+
9328
+ # Add dictionaries to each vertex
9329
+ for i, t in enumerate(all_topos):
9330
+ d = Topology.Dictionary(t)
9331
+ if storeBREP == True:
9332
+ d = Dictionary.SetValueAtKey(d,"brep", Topology.BREPString(t))
9333
+ graph_vertices[i] = Topology.SetDictionary(graph_vertices[i], d)
9334
+
9335
+ graph_vertices = Vertex.Separate(graph_vertices, minDistance= minDistance, tolerance=tolerance)
9336
+ # Build edges of Hasse diagram
9337
+ graph_edges = []
9338
+ for parent_type in sub_types[1:]:
9339
+ for parent in topo_by_type[parent_type]:
9340
+ parent_label = Dictionary.ValueAtKey(Topology.Dictionary(parent), vertexLabelKey)
9341
+ children = Topology.SubTopologies(parent, subTopologyType=types[types.index(parent_type) - 1])
9342
+ for child in children:
9343
+ child_label = Dictionary.ValueAtKey(Topology.Dictionary(child), vertexLabelKey)
9344
+ child_id = topo_ids.get(child_label)
9345
+ parent_id = topo_ids.get(parent_label)
9346
+ if child_id is not None and parent_id is not None:
9347
+ if topDown:
9348
+ sv = graph_vertices[parent_id]
9349
+ ev = graph_vertices[child_id]
9350
+ else:
9351
+ sv = graph_vertices[child_id]
9352
+ ev = graph_vertices[parent_id]
9353
+ graph_edges.append(Edge.ByVertices(sv, ev, tolerance=tolerance, silent=silent))
9354
+
9355
+ return_graph = Graph.ByVerticesEdges(graph_vertices, graph_edges)
9356
+ return_graph = Graph.SetDictionary(return_graph, Topology.Dictionary(topology))
9357
+ return return_graph
9358
+
9195
9359
  @staticmethod
9196
9360
  def IncomingEdges(graph, vertex, directed: bool = False, tolerance: float = 0.0001) -> list:
9197
9361
  """
topologicpy/Plotly.py CHANGED
@@ -277,6 +277,9 @@ class Plotly:
277
277
  absolute: bool = False,
278
278
  sides: int = 8,
279
279
  angle: float = 0,
280
+ directed: bool = False,
281
+ arrowSize: int = 0.1,
282
+ arrowSizeKey: str = None,
280
283
  vertexColor: str = "black",
281
284
  vertexColorKey: str = None,
282
285
  vertexSize: float = 10,
@@ -330,6 +333,12 @@ class Plotly:
330
333
  For example, if the length of the edge is 10, the sagitta is set to 0.5, and absolute is set to False, the sagitta length will be 5. The default is True.
331
334
  sides : int , optional
332
335
  The number of sides of the arc. The default is 8.
336
+ directed : bool , optional
337
+ If set to True, arrowheads are drawn to show direction. The default is False.
338
+ arrowSize : int, optional
339
+ The desired size of arrowheads for directed graphs. The default is 0.1.
340
+ arrowSizeKey: str , optional
341
+ The edge dictionary key under which to find the arrowhead size. The default is None.
333
342
  vertexColor : str , optional
334
343
  The desired color of the output vertices. This can be any plotly color string and may be specified as:
335
344
  - A hex string (e.g. '#ff0000')
@@ -479,7 +488,7 @@ class Plotly:
479
488
  geo = Topology.Geometry(e_cluster, mantissa=mantissa)
480
489
  vertices = geo['vertices']
481
490
  edges = geo['edges']
482
- data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, dash=edgeDash, dashKey=edgeDashKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
491
+ data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, dash=edgeDash, dashKey=edgeDashKey, directed=directed, arrowSize=arrowSize, arrowSizeKey=arrowSizeKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
483
492
  return data
484
493
 
485
494
  @staticmethod
@@ -638,11 +647,60 @@ class Plotly:
638
647
  return return_value
639
648
 
640
649
  @staticmethod
641
- def edgeData(vertices, edges, dictionaries=None, color="black", colorKey=None, width=1, widthKey=None, dash=False, dashKey=None, labelKey=None, showEdgeLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
650
+ def edgeData(vertices, edges, dictionaries=None, color="black", colorKey=None, width=1, widthKey=None, dash=False, dashKey=None, directed=False, arrowSize=0.1, arrowSizeKey=None, labelKey=None, showEdgeLabel = False, groupKey=None, minGroup=None, maxGroup=None, groups=[], legendLabel="Topology Edges", legendGroup=2, legendRank=2, showLegend=True, colorScale="Viridis"):
642
651
 
643
652
  from topologicpy.Color import Color
644
653
  from topologicpy.Dictionary import Dictionary
645
654
  from topologicpy.Helper import Helper
655
+
656
+ def create_arrowheads(x, y, z, arrowSize=4):
657
+ import plotly.graph_objects as go
658
+ import numpy as np
659
+
660
+ arrow_traces = []
661
+
662
+ # Compute segment directions
663
+ cone_x, cone_y, cone_z = [], [], []
664
+ cone_u, cone_v, cone_w = [], [], []
665
+
666
+ for i in range(len(x) - 1):
667
+ if x[i] == None or x[i+1] == None:
668
+ continue
669
+ u = x[i+1] - x[i]
670
+ v = y[i+1] - y[i]
671
+ w = z[i+1] - z[i]
672
+
673
+ norm = np.linalg.norm([u, v, w])
674
+ if norm > 0:
675
+ u /= norm
676
+ v /= norm
677
+ w /= norm
678
+ cone_x.append(x[i+1])
679
+ cone_y.append(y[i+1])
680
+ cone_z.append(z[i+1])
681
+ cone_u.append(u)
682
+ cone_v.append(v)
683
+ cone_w.append(w)
684
+
685
+ cone_trace = go.Cone(
686
+ x=cone_x,
687
+ y=cone_y,
688
+ z=cone_z,
689
+ u=cone_u,
690
+ v=cone_v,
691
+ w=cone_w,
692
+ sizemode="raw",
693
+ sizeref=arrowSize,
694
+ showscale=False,
695
+ colorscale=[[0, color], [1, color]],
696
+ anchor="tip",
697
+ name="", # Hide legend
698
+ hoverinfo="skip",
699
+ showlegend=False
700
+ )
701
+ arrow_traces.append(cone_trace)
702
+
703
+ return arrow_traces
646
704
  traces = []
647
705
  x = []
648
706
  y = []
@@ -676,8 +734,8 @@ class Plotly:
676
734
  maxGroup = 1
677
735
 
678
736
 
679
- if colorKey or widthKey or labelKey or groupKey or dashKey:
680
- keys = [x for x in [colorKey, widthKey, labelKey, groupKey, dashKey] if not x == None]
737
+ if colorKey or widthKey or labelKey or groupKey or dashKey or arrowSizeKey:
738
+ keys = [x for x in [colorKey, widthKey, labelKey, groupKey, dashKey, arrowSizeKey] if not x == None]
681
739
  temp_dict = Helper.ClusterByKeys(edges, dictionaries, keys, silent=False)
682
740
  dict_clusters = temp_dict["dictionaries"]
683
741
  elements_clusters = temp_dict['elements']
@@ -692,6 +750,8 @@ class Plotly:
692
750
  d_color = Color.AnyToHex(d_color)
693
751
  if not dashKey == None:
694
752
  d_dash = Dictionary.ValueAtKey(d, key=dashKey) or dash
753
+ if not arrowSizeKey == None:
754
+ d_arrowSize = Dictionary.ValueAtKey(d, key=arrowSizeKey) or arrowSize
695
755
  if not labelKey == None:
696
756
  labels.append(str(Dictionary.ValueAtKey(d, labelKey, "")))
697
757
  if not widthKey == None:
@@ -744,6 +804,9 @@ class Plotly:
744
804
  text=labels,
745
805
  hoverinfo='text',
746
806
  hovertext=labels)
807
+ if directed:
808
+ arrow_traces = create_arrowheads(x, y, z, arrowSize=d_arrowSize)
809
+ traces += arrow_traces
747
810
  traces.append(trace)
748
811
  else:
749
812
  x = []
@@ -775,6 +838,9 @@ class Plotly:
775
838
  legendrank=legendRank,
776
839
  text=label,
777
840
  hoverinfo='text')
841
+ if directed:
842
+ arrow_traces = create_arrowheads(x, y, z, arrowSize=arrowSize)
843
+ traces += arrow_traces
778
844
  traces.append(trace)
779
845
  return traces
780
846
 
@@ -799,6 +865,9 @@ class Plotly:
799
865
  vertexLegendLabel="Topology Vertices",
800
866
  vertexLegendRank=1,
801
867
  vertexLegendGroup=1,
868
+ directed=False,
869
+ arrowSize=0.1,
870
+ arrowSizeKey=None,
802
871
  showEdges=True,
803
872
  edgeWidth=1,
804
873
  edgeWidthKey=None,
@@ -884,7 +953,12 @@ class Plotly:
884
953
  The legend rank order of the vertices of this topology. The default is 1.
885
954
  vertexLegendGroup : int , optional
886
955
  The number of the vertex legend group to which the vertices of this topology belong. The default is 1.
887
-
956
+ directed : bool , optional
957
+ If set to True, arrowheads are drawn to show direction. The default is False.
958
+ arrowSize : int, optional
959
+ The desired size of arrowheads for directed graphs. The default is 0.1.
960
+ arrowSizeKey: str , optional
961
+ The edge dictionary key under which to find the arrowhead size. The default is None.
888
962
  showEdges : bool , optional
889
963
  If set to True the edges will be drawn. Otherwise, they will not be drawn. The default is True.
890
964
  edgeWidth : float , optional
@@ -1194,7 +1268,7 @@ class Plotly:
1194
1268
  vertices = geo['vertices']
1195
1269
  edges = geo['edges']
1196
1270
  if len(edges) > 0:
1197
- data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
1271
+ data.extend(Plotly.edgeData(vertices, edges, dictionaries=e_dictionaries, color=edgeColor, colorKey=edgeColorKey, width=edgeWidth, widthKey=edgeWidthKey, directed=directed, arrowSize=arrowSize, arrowSizeKey=arrowSizeKey, labelKey=edgeLabelKey, showEdgeLabel=showEdgeLabel, groupKey=edgeGroupKey, minGroup=edgeMinGroup, maxGroup=edgeMaxGroup, groups=edgeGroups, legendLabel=edgeLegendLabel, legendGroup=edgeLegendGroup, legendRank=edgeLegendRank, showLegend=showEdgeLegend, colorScale=colorScale))
1198
1272
 
1199
1273
  if showFaces and Topology.Type(topology) >= Topology.TypeID("Face"):
1200
1274
  if not faceColorKey == None:
topologicpy/Topology.py CHANGED
@@ -8162,7 +8162,10 @@ class Topology():
8162
8162
  vertexMaxGroup=None,
8163
8163
  showVertexLegend=False,
8164
8164
  vertexLegendLabel="Vertices",
8165
-
8165
+
8166
+ directed=False,
8167
+ arrowSize=0.1,
8168
+ arrowSizeKey=None,
8166
8169
  showEdges=True,
8167
8170
  edgeWidth=None,
8168
8171
  edgeWidthKey=None,
@@ -8281,7 +8284,12 @@ class Topology():
8281
8284
  If set to True, the legend for the vertices of this topology is shown. Otherwise, it isn't. The default is False.
8282
8285
  vertexLegendLabel : str , optional
8283
8286
  The legend label string used to identify vertices. The default is "Topology Vertices".
8284
-
8287
+ directed : bool , optional
8288
+ If set to True, arrowheads are drawn to show direction. The default is False.
8289
+ arrowSize : int, optional
8290
+ The desired size of arrowheads for directed graphs. The default is 0.1.
8291
+ arrowSizeKey: str , optional
8292
+ The edge dictionary key under which to find the arrowhead size. The default is None.
8285
8293
  showEdges : bool , optional
8286
8294
  If set to True the edges will be drawn. Otherwise, they will not be drawn. The default is True.
8287
8295
  edgeWidth : float , optional
@@ -8470,6 +8478,9 @@ class Topology():
8470
8478
  absolute=absolute,
8471
8479
  sides=sides,
8472
8480
  angle=angle,
8481
+ directed=directed,
8482
+ arrowSize=arrowSize,
8483
+ arrowSizeKey=arrowSizeKey,
8473
8484
  vertexColor=vertexColor,
8474
8485
  vertexColorKey=vertexColorKey,
8475
8486
  vertexSize=vSize,
@@ -8543,6 +8554,9 @@ class Topology():
8543
8554
  vertexLegendLabel=str(i+1)+": "+name+" ("+vertexLegendLabel+")",
8544
8555
  vertexLegendRank=topology_counter+1,
8545
8556
  vertexLegendGroup=topology_counter+1,
8557
+ directed=directed,
8558
+ arrowSize=arrowSize,
8559
+ arrowSizeKey=arrowSizeKey,
8546
8560
  showEdges=showEdges,
8547
8561
  edgeWidth=eWidth,
8548
8562
  edgeWidthKey=edgeWidthKey,
topologicpy/Vertex.py CHANGED
@@ -1819,7 +1819,7 @@ class Vertex():
1819
1819
  return Vertex.ByCoordinates(pt[0], pt[1], pt[2])
1820
1820
 
1821
1821
  @staticmethod
1822
- def Separate(*vertices, minDistance: float = 0.0001, silent: bool = False):
1822
+ def Separate(*vertices, minDistance: float = 0.0001, iterations: int = 100, strength: float = 0.1, tolerance: float = 0.0001, silent: bool = False):
1823
1823
  """
1824
1824
  Separates the input vertices such that no two vertices are within the input minimum distance.
1825
1825
 
@@ -1829,6 +1829,12 @@ class Vertex():
1829
1829
  One or more instances of a topologic vertex to be processed.
1830
1830
  minDistance : float , optional
1831
1831
  The desired minimum distance. The default is 0.0001.
1832
+ iterations : int
1833
+ The number of iterations to run the repulsion simulation. The default is 100.
1834
+ strength : float
1835
+ The force multiplier controlling how strongly vertices repel each other. The default is 0.1.
1836
+ tolerance : float
1837
+ The desired tolerance. The default is 0.0001.
1832
1838
  silent : bool , optional
1833
1839
  If set to True, error and warning messages are suppressed. The default is False.
1834
1840
 
@@ -1840,10 +1846,7 @@ class Vertex():
1840
1846
  """
1841
1847
  from topologicpy.Topology import Topology
1842
1848
  from topologicpy.Helper import Helper
1843
- from topologicpy.Dictionary import Dictionary
1844
- from math import sqrt
1845
- from scipy.spatial import KDTree
1846
- import numpy as np
1849
+ import math
1847
1850
 
1848
1851
  if len(vertices) == 0:
1849
1852
  if not silent:
@@ -1873,33 +1876,37 @@ class Vertex():
1873
1876
  if not silent:
1874
1877
  print("Vertex.Separate - Error: The input parameters do not contain any valid vertices. Returning None.")
1875
1878
  return None
1876
-
1877
- coords = np.array([[v.X(), v.Y(), v.Z()] for v in vertexList]) # Extract coordinates
1878
- tree = KDTree(coords) # Build k-d tree for efficient neighbor search
1879
+
1880
+ minDistance = minDistance + tolerance # Add a bit of a safety factor
1881
+
1882
+ # Convert to mutable coordinates
1883
+ coords = [[v.X(), v.Y(), v.Z()] for v in vertices]
1884
+
1885
+ for _ in range(iterations):
1886
+ for i in range(len(coords)):
1887
+ for j in range(i + 1, len(coords)):
1888
+ dx = coords[j][0] - coords[i][0]
1889
+ dy = coords[j][1] - coords[i][1]
1890
+ dz = coords[j][2] - coords[i][2]
1891
+ dist = math.sqrt(dx*dx + dy*dy + dz*dz)
1892
+
1893
+ if dist < minDistance and dist > 1e-9:
1894
+ # Calculate repulsion vector
1895
+ repel = (minDistance - dist) / dist * strength
1896
+ shift = [dx * repel * 0.5, dy * repel * 0.5, dz * repel * 0.5]
1897
+ coords[i][0] -= shift[0]
1898
+ coords[i][1] -= shift[1]
1899
+ coords[i][2] -= shift[2]
1900
+ coords[j][0] += shift[0]
1901
+ coords[j][1] += shift[1]
1902
+ coords[j][2] += shift[2]
1879
1903
 
1880
- for i, vertex in enumerate(coords):
1881
- neighbors = tree.query_ball_point(vertex, minDistance)
1882
- for neighbor_index in neighbors:
1883
- if neighbor_index != i: # Avoid self-comparison
1884
- direction = coords[neighbor_index] - vertex
1885
- distance = np.linalg.norm(direction)
1886
- if distance < minDistance:
1887
- # Move current vertex away from its neighbor
1888
- adjustment = (minDistance - distance) / 2
1889
- unit_vector = direction / distance if distance != 0 else np.random.rand(3)
1890
- coords[i] -= unit_vector * adjustment
1891
- coords[neighbor_index] += unit_vector * adjustment
1892
-
1893
- # Rebuild the k-d tree after adjustment
1894
- tree = KDTree(coords)
1895
-
1896
- # Convert adjusted coordinates back to Vertex objects
1897
- separated_vertices = [Vertex.ByCoordinates(x, y, z) for x, y, z in coords]
1898
- for i, vertex in enumerate(vertexList):
1899
- d = Topology.Dictionary(vertex)
1900
- if len(Dictionary.Keys(d)) > 0:
1901
- separated_vertices[i] = Topology.SetDictionary(separated_vertices[i], d)
1902
- return separated_vertices
1904
+ # Reconstruct TopologicPy Vertex objects
1905
+ new_vertices = [Vertex.ByCoordinates(x, y, z) for x, y, z in coords]
1906
+ # Transfer the dictionaries
1907
+ for i, v in enumerate(new_vertices):
1908
+ v = Topology.SetDictionary(v, Topology.Dictionary(vertices[i]))
1909
+ return new_vertices
1903
1910
 
1904
1911
  @staticmethod
1905
1912
  def Transform(vertex, matrix, mantissa: int = 6, silent: bool = False):
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.8.40'
1
+ __version__ = '0.8.41'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topologicpy
3
- Version: 0.8.40
3
+ Version: 0.8.41
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
@@ -12,27 +12,27 @@ topologicpy/Dictionary.py,sha256=2Sxm8twR1W4ksZho0YXQB_EltK2qbZWK4UHskP3jvFQ,408
12
12
  topologicpy/Edge.py,sha256=CPdQKaE7ft6zgh0vxekkfGRRUY_yEqkEJ14NvjSgJOA,73190
13
13
  topologicpy/EnergyModel.py,sha256=Pyb28gDDwhzlQIH0xqAygqS0P3SJxWyyV7OWS_AAfRs,53856
14
14
  topologicpy/Face.py,sha256=BT_5ymb7-s-Wb1tuaBtkopJpeNg-RbooTUk_-KInQ6c,201618
15
- topologicpy/Graph.py,sha256=z_9TeMkmwFXlCfVDW9Z56PX0sHxGj8iVKlCdJLreMo0,639785
15
+ topologicpy/Graph.py,sha256=GykBbB8KKcy2oPV2Dsnz_vkyWGgczxLi0puVx5NJUYU,648088
16
16
  topologicpy/Grid.py,sha256=EbI2NcYhQDpD5mItd7A1Lpr8Puuf87vZPWuoh7_gChQ,18483
17
17
  topologicpy/Helper.py,sha256=qEsE4yaboEGW94q9lFCff0I_JwwTTQnDAFXw006yHaQ,31203
18
18
  topologicpy/Honeybee.py,sha256=yctkwfdupKnp7bAOjP1Z4YaYpRrWoMEb4gz9Z5zaWwE,21751
19
19
  topologicpy/Matrix.py,sha256=LqVckk2qTwKwEo79eyNsOrHVSHdO82JCREcfy6WIk4I,22716
20
20
  topologicpy/Neo4j.py,sha256=ELKmON7R16j1kQD8xRHDGGCvzjIM2HGHNekdaXDUw6w,22371
21
- topologicpy/Plotly.py,sha256=Dmy9i9puSfvB42mrBUip3v0TCXIzHpAETWDUCDxfqNA,120556
21
+ topologicpy/Plotly.py,sha256=3jTy-bFNS_zFsfqpY_WdhHlt9kdexDq_Jvp5jxR16tQ,123710
22
22
  topologicpy/Polyskel.py,sha256=oVfM4lqSMPTjnkHfsRU9VI8Blt6Vf0LVPkD9ebz7Wmw,27082
23
23
  topologicpy/PyG.py,sha256=zvV6jtnol_aFiN6JRoMpYwBVfOU2aFs9gdWSdEo6mtU,109757
24
24
  topologicpy/ShapeGrammar.py,sha256=UVb8VPwVKd6V3zDTNzpBecQPgYo1EjSsS10XJ8k5YcI,23364
25
25
  topologicpy/Shell.py,sha256=fx0WTndC8blkvWe38nKsJsI_AmklOA0qsjU0gbZp4b4,90501
26
26
  topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
27
27
  topologicpy/Sun.py,sha256=_VBBAUIDhvpkp72JBZlv7k9qx9jYubm3yM56UZ1Nc6c,36837
28
- topologicpy/Topology.py,sha256=G6KtKRKabV1gNUKCZ3rzZJkCogGkOJDnCl-_S7DuHKc,466648
28
+ topologicpy/Topology.py,sha256=hGjePUb2-1MmyMva9nNtPiWr4CAWMa__BGX17mIOHfA,467519
29
29
  topologicpy/Vector.py,sha256=X12eqskn28bdB7sLY1EZhq3noPYzPbNEgHPb4a959ss,42302
30
- topologicpy/Vertex.py,sha256=epBfbD7fm87T-TZ0WuwrioXdYqg9NgRlHn_qUFtVbkc,84562
30
+ topologicpy/Vertex.py,sha256=RlGQnxQSb_kAus3tJgXd-v-Ptubtt09PQPA9IMwfXmI,84835
31
31
  topologicpy/Wire.py,sha256=vE6IoObVucOZVTFMPiHuNN4DDezRHHyFbwhF5WRBm3s,231547
32
32
  topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
33
- topologicpy/version.py,sha256=9UtSkYQrOL8TXxQBwLoy5jvQKNWp84nSX32fmM7V0Ac,23
34
- topologicpy-0.8.40.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
- topologicpy-0.8.40.dist-info/METADATA,sha256=8YuR3I1XDjArnIbbajaveZEDc7Q8eVk4aBOvtaLhULA,10535
36
- topologicpy-0.8.40.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- topologicpy-0.8.40.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
- topologicpy-0.8.40.dist-info/RECORD,,
33
+ topologicpy/version.py,sha256=tObOvnnCfxEdJFf4I6CjFR-B5fIFs3s0EygfFnJZgQM,23
34
+ topologicpy-0.8.41.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
35
+ topologicpy-0.8.41.dist-info/METADATA,sha256=Fqkthwxq-nQkwkhyhz3ZvFA9C4tU6vPVwo2i3Q9QVmU,10535
36
+ topologicpy-0.8.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ topologicpy-0.8.41.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
38
+ topologicpy-0.8.41.dist-info/RECORD,,