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 +164 -0
- topologicpy/Plotly.py +80 -6
- topologicpy/Topology.py +16 -2
- topologicpy/Vertex.py +38 -31
- topologicpy/version.py +1 -1
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.41.dist-info}/METADATA +1 -1
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.41.dist-info}/RECORD +10 -10
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.41.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.41.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.41.dist-info}/top_level.txt +0 -0
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
|
-
|
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
|
-
|
1878
|
-
|
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
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
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.
|
1
|
+
__version__ = '0.8.41'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
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=
|
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=
|
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=
|
28
|
+
topologicpy/Topology.py,sha256=hGjePUb2-1MmyMva9nNtPiWr4CAWMa__BGX17mIOHfA,467519
|
29
29
|
topologicpy/Vector.py,sha256=X12eqskn28bdB7sLY1EZhq3noPYzPbNEgHPb4a959ss,42302
|
30
|
-
topologicpy/Vertex.py,sha256=
|
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=
|
34
|
-
topologicpy-0.8.
|
35
|
-
topologicpy-0.8.
|
36
|
-
topologicpy-0.8.
|
37
|
-
topologicpy-0.8.
|
38
|
-
topologicpy-0.8.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|