topologicpy 0.8.40__py3-none-any.whl → 0.8.42__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/Cell.py +9 -6
- topologicpy/CellComplex.py +7 -3
- topologicpy/Edge.py +54 -22
- topologicpy/Face.py +37 -11
- topologicpy/Graph.py +164 -0
- topologicpy/Plotly.py +85 -10
- topologicpy/Topology.py +21 -7
- topologicpy/Vertex.py +38 -31
- topologicpy/Wire.py +3 -28
- topologicpy/version.py +1 -1
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.42.dist-info}/METADATA +1 -1
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.42.dist-info}/RECORD +15 -15
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.42.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.42.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.40.dist-info → topologicpy-0.8.42.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
@@ -2762,7 +2762,7 @@ class Cell():
|
|
2762
2762
|
return prism
|
2763
2763
|
|
2764
2764
|
@staticmethod
|
2765
|
-
def RemoveCollinearEdges(cell, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
2765
|
+
def RemoveCollinearEdges(cell, angTolerance: float = 0.1, tolerance: float = 0.0001, silent: bool = False):
|
2766
2766
|
"""
|
2767
2767
|
Removes any collinear edges in the input cell.
|
2768
2768
|
|
@@ -2774,6 +2774,8 @@ class Cell():
|
|
2774
2774
|
The desired angular tolerance. The default is 0.1.
|
2775
2775
|
tolerance : float , optional
|
2776
2776
|
The desired tolerance. The default is 0.0001.
|
2777
|
+
silent : bool , optional
|
2778
|
+
If set to True, error and warning messages are suppressed. The default is False.
|
2777
2779
|
|
2778
2780
|
Returns
|
2779
2781
|
-------
|
@@ -2786,15 +2788,16 @@ class Cell():
|
|
2786
2788
|
import inspect
|
2787
2789
|
|
2788
2790
|
if not Topology.IsInstance(cell, "Cell"):
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2791
|
+
if not silent:
|
2792
|
+
print("Cell.RemoveCollinearEdges - Error: The input cell parameter is not a valid cell. Returning None.")
|
2793
|
+
curframe = inspect.currentframe()
|
2794
|
+
calframe = inspect.getouterframes(curframe, 2)
|
2795
|
+
print('caller name:', calframe[1][3])
|
2793
2796
|
return None
|
2794
2797
|
faces = Cell.Faces(cell)
|
2795
2798
|
clean_faces = []
|
2796
2799
|
for face in faces:
|
2797
|
-
clean_faces.append(Face.RemoveCollinearEdges(face, angTolerance=angTolerance, tolerance=tolerance))
|
2800
|
+
clean_faces.append(Face.RemoveCollinearEdges(face, angTolerance=angTolerance, tolerance=tolerance, silent=silent))
|
2798
2801
|
return Cell.ByFaces(clean_faces, tolerance=tolerance)
|
2799
2802
|
|
2800
2803
|
@staticmethod
|
topologicpy/CellComplex.py
CHANGED
@@ -104,7 +104,7 @@ class CellComplex():
|
|
104
104
|
tolerance : float , optional
|
105
105
|
The desired tolerance. The default is 0.0001.
|
106
106
|
silent : bool , optional
|
107
|
-
|
107
|
+
If set to True, error and warning messages are suppressed. The default is False.
|
108
108
|
|
109
109
|
Returns
|
110
110
|
-------
|
@@ -990,7 +990,7 @@ class CellComplex():
|
|
990
990
|
return None
|
991
991
|
|
992
992
|
@staticmethod
|
993
|
-
def RemoveCollinearEdges(cellComplex, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
993
|
+
def RemoveCollinearEdges(cellComplex, angTolerance: float = 0.1, tolerance: float = 0.0001, silent: bool = True):
|
994
994
|
"""
|
995
995
|
Removes any collinear edges in the input cellComplex.
|
996
996
|
|
@@ -1002,6 +1002,8 @@ class CellComplex():
|
|
1002
1002
|
The desired angular tolerance. The default is 0.1.
|
1003
1003
|
tolerance : float , optional
|
1004
1004
|
The desired tolerance. The default is 0.0001.
|
1005
|
+
silent : bool , optional
|
1006
|
+
If set to True, error and warning messages are suppressed. The default is False.
|
1005
1007
|
|
1006
1008
|
Returns
|
1007
1009
|
-------
|
@@ -1023,7 +1025,7 @@ class CellComplex():
|
|
1023
1025
|
cells = CellComplex.Cells(cellComplex)
|
1024
1026
|
clean_cells = []
|
1025
1027
|
for cell in cells:
|
1026
|
-
clean_cells.append(Cell.RemoveCollinearEdges(cell, angTolerance=angTolerance, tolerance=tolerance))
|
1028
|
+
clean_cells.append(Cell.RemoveCollinearEdges(cell, angTolerance=angTolerance, tolerance=tolerance, silent=silent))
|
1027
1029
|
return CellComplex.ByCells(clean_cells, tolerance=tolerance)
|
1028
1030
|
|
1029
1031
|
@staticmethod
|
@@ -1098,6 +1100,8 @@ class CellComplex():
|
|
1098
1100
|
The desired length of the mantissa. The default is 6.
|
1099
1101
|
tolerance : float , optional
|
1100
1102
|
The desired tolerance. The default is 0.0001.
|
1103
|
+
silent : bool , optional
|
1104
|
+
If set to True, error and warning messages are suppressed. The default is False.
|
1101
1105
|
|
1102
1106
|
Returns
|
1103
1107
|
-------
|
topologicpy/Edge.py
CHANGED
@@ -256,31 +256,63 @@ class Edge():
|
|
256
256
|
@staticmethod
|
257
257
|
def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001):
|
258
258
|
"""
|
259
|
-
Creates
|
260
|
-
|
261
|
-
Parameters
|
262
|
-
----------
|
263
|
-
edge : topologic_core.Edge
|
264
|
-
The input edge.
|
265
|
-
offset : float , optional
|
266
|
-
The desired offset. The default is 1.
|
267
|
-
tolerance : float , optional
|
268
|
-
The desired tolerance. The default is 0.0001.
|
269
|
-
|
270
|
-
Returns
|
271
|
-
-------
|
272
|
-
topologic_core.Edge
|
273
|
-
An edge offset from the input edge.
|
274
|
-
|
259
|
+
Creates an edge offset from the input edge in the XY plane.
|
275
260
|
"""
|
276
261
|
from topologicpy.Topology import Topology
|
277
|
-
from topologicpy.
|
262
|
+
from topologicpy.Vertex import Vertex
|
263
|
+
from topologicpy.Edge import Edge
|
278
264
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
265
|
+
sv = Edge.StartVertex(edge)
|
266
|
+
ev = Edge.EndVertex(edge)
|
267
|
+
|
268
|
+
x1, y1, _ = Vertex.Coordinates(sv)
|
269
|
+
x2, y2, _ = Vertex.Coordinates(ev)
|
270
|
+
|
271
|
+
dx = x2 - x1
|
272
|
+
dy = y2 - y1
|
273
|
+
length = (dx**2 + dy**2)**0.5
|
274
|
+
if length < tolerance:
|
275
|
+
return None
|
276
|
+
|
277
|
+
# Perpendicular vector to the left
|
278
|
+
nx = -dy / length
|
279
|
+
ny = dx / length
|
280
|
+
|
281
|
+
ox = nx * offset
|
282
|
+
oy = ny * offset
|
283
|
+
|
284
|
+
new_sv = Vertex.ByCoordinates(x1 + ox, y1 + oy, 0)
|
285
|
+
new_ev = Vertex.ByCoordinates(x2 + ox, y2 + oy, 0)
|
286
|
+
|
287
|
+
return Edge.ByVertices(new_sv, new_ev)
|
288
|
+
# @staticmethod
|
289
|
+
# def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001):
|
290
|
+
# """
|
291
|
+
# Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane.
|
292
|
+
|
293
|
+
# Parameters
|
294
|
+
# ----------
|
295
|
+
# edge : topologic_core.Edge
|
296
|
+
# The input edge.
|
297
|
+
# offset : float , optional
|
298
|
+
# The desired offset. The default is 1.
|
299
|
+
# tolerance : float , optional
|
300
|
+
# The desired tolerance. The default is 0.0001.
|
301
|
+
|
302
|
+
# Returns
|
303
|
+
# -------
|
304
|
+
# topologic_core.Edge
|
305
|
+
# An edge offset from the input edge.
|
306
|
+
|
307
|
+
# """
|
308
|
+
# from topologicpy.Topology import Topology
|
309
|
+
# from topologicpy.Vector import Vector
|
310
|
+
|
311
|
+
# n = Edge.Normal(edge)
|
312
|
+
# n = Vector.Normalize(n)
|
313
|
+
# n = Vector.Multiply(n, offset, tolerance=tolerance)
|
314
|
+
# edge = Topology.Translate(edge, n[0], n[1], n[2])
|
315
|
+
# return edge
|
284
316
|
|
285
317
|
@staticmethod
|
286
318
|
def ByStartVertexEndVertex(vertexA, vertexB, tolerance: float = 0.0001, silent=False):
|
topologicpy/Face.py
CHANGED
@@ -827,7 +827,7 @@ class Face():
|
|
827
827
|
return Face.ByVertices(vertices, tolerance=tolerance)
|
828
828
|
|
829
829
|
@staticmethod
|
830
|
-
def ByWire(wire, tolerance: float = 0.0001, silent=False):
|
830
|
+
def ByWire(wire, tolerance: float = 0.0001, silent: bool = False):
|
831
831
|
"""
|
832
832
|
Creates a face from the input closed wire.
|
833
833
|
|
@@ -942,14 +942,21 @@ class Face():
|
|
942
942
|
"""
|
943
943
|
from topologicpy.Wire import Wire
|
944
944
|
from topologicpy.Topology import Topology
|
945
|
+
import inspect
|
945
946
|
|
946
947
|
if not Topology.IsInstance(externalBoundary, "Wire"):
|
947
948
|
if not silent:
|
948
949
|
print("Face.ByWires - Error: The input externalBoundary parameter is not a valid topologic wire. Returning None.")
|
950
|
+
curframe = inspect.currentframe()
|
951
|
+
calframe = inspect.getouterframes(curframe, 2)
|
952
|
+
print('caller name:', calframe[1][3])
|
949
953
|
return None
|
950
954
|
if not Wire.IsClosed(externalBoundary):
|
951
955
|
if not silent:
|
952
956
|
print("Face.ByWires - Error: The input externalBoundary parameter is not a closed topologic wire. Returning None.")
|
957
|
+
curframe = inspect.currentframe()
|
958
|
+
calframe = inspect.getouterframes(curframe, 2)
|
959
|
+
print('caller name:', calframe[1][3])
|
953
960
|
return None
|
954
961
|
ibList = [x for x in internalBoundaries if Topology.IsInstance(x, "Wire") and Wire.IsClosed(x)]
|
955
962
|
face = None
|
@@ -958,6 +965,9 @@ class Face():
|
|
958
965
|
except:
|
959
966
|
if not silent:
|
960
967
|
print("Face.ByWires - Error: The operation failed. Returning None.")
|
968
|
+
curframe = inspect.currentframe()
|
969
|
+
calframe = inspect.getouterframes(curframe, 2)
|
970
|
+
print('caller name:', calframe[1][3])
|
961
971
|
face = None
|
962
972
|
return face
|
963
973
|
|
@@ -3404,7 +3414,7 @@ class Face():
|
|
3404
3414
|
return None
|
3405
3415
|
eb = Wire.RemoveCollinearEdges(Face.Wire(face), angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
3406
3416
|
ib = [Wire.RemoveCollinearEdges(w, angTolerance=angTolerance, tolerance=tolerance, silent=silent) for w in Face.InternalBoundaries(face)]
|
3407
|
-
return Face.ByWires(eb, ib)
|
3417
|
+
return Face.ByWires(eb, ib, silent=silent)
|
3408
3418
|
|
3409
3419
|
@staticmethod
|
3410
3420
|
def RHS(origin= None, width: float = 1.0, length: float = 1.0, thickness: float = 0.25, outerFillet: float = 0.0, innerFillet: float = 0.0, sides: int = 16, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001, silent: bool = False):
|
@@ -3602,35 +3612,51 @@ class Face():
|
|
3602
3612
|
return Face.RHS(origin = origin, width = size, length = size, thickness = thickness, outerFillet = outerFillet, innerFillet = innerFillet, sides = sides, direction = direction, placement = placement, tolerance = tolerance, silent = silent)
|
3603
3613
|
|
3604
3614
|
@staticmethod
|
3605
|
-
def Simplify(face, tolerance=0.0001):
|
3615
|
+
def Simplify(face, method='douglas-peucker', tolerance=0.0001, silent=False):
|
3606
3616
|
"""
|
3607
|
-
Simplifies the input
|
3608
|
-
Part of this code was contributed by gaoxipeng. See https://github.com/wassimj/topologicpy/issues/35
|
3617
|
+
Simplifies the input wire edges based on the selected algorithm: Douglas-Peucker or Visvalingam–Whyatt.
|
3609
3618
|
|
3610
3619
|
Parameters
|
3611
3620
|
----------
|
3612
3621
|
face : topologic_core.Face
|
3613
3622
|
The input face.
|
3623
|
+
method : str, optional
|
3624
|
+
The simplification method to use: 'douglas-peucker' or 'visvalingam-whyatt' or 'reumann-witkam'.
|
3625
|
+
The default is 'douglas-peucker'.
|
3614
3626
|
tolerance : float , optional
|
3615
|
-
The desired tolerance.
|
3616
|
-
|
3627
|
+
The desired tolerance.
|
3628
|
+
If using the douglas-peucker method, edge lengths shorter than this amount will be removed.
|
3629
|
+
If using the visvalingam-whyatt method, triangulare areas less than is amount will be removed.
|
3630
|
+
If using the Reumann-Witkam method, the tolerance specifies the maximum perpendicular distance allowed
|
3631
|
+
between any point and the current line segment; points falling within this distance are discarded.
|
3632
|
+
The default is 0.0001.
|
3633
|
+
silent : bool , optional
|
3634
|
+
If set to True, error and warning messages are suppressed. The default is False.
|
3635
|
+
|
3617
3636
|
Returns
|
3618
3637
|
-------
|
3619
3638
|
topologic_core.Face
|
3620
3639
|
The simplified face.
|
3640
|
+
|
3621
3641
|
"""
|
3622
3642
|
from topologicpy.Wire import Wire
|
3623
3643
|
from topologicpy.Topology import Topology
|
3624
3644
|
|
3625
3645
|
if not Topology.IsInstance(face, "Face"):
|
3626
|
-
|
3646
|
+
if not silent:
|
3647
|
+
print("Face.Simplify - Error: The input face parameter is not a valid face. Returning None.")
|
3627
3648
|
return None
|
3628
3649
|
|
3629
3650
|
eb = Face.ExternalBoundary(face)
|
3630
|
-
eb = Wire.Simplify(eb, tolerance=tolerance)
|
3651
|
+
eb = Wire.Simplify(eb, method=method, tolerance=tolerance, silent=silent)
|
3631
3652
|
ibList = Face.InternalBoundaries(face)
|
3632
|
-
ibList = [Wire.Simplify(ib) for ib in ibList]
|
3633
|
-
|
3653
|
+
ibList = [Wire.Simplify(ib, method=method, tolerance=tolerance, silent=silent) for ib in ibList]
|
3654
|
+
return_face = Face.ByWires(eb, ibList, tolerance=tolerance, silent=silent)
|
3655
|
+
if not Topology.IsInstance(return_face, "Face"):
|
3656
|
+
if not silent:
|
3657
|
+
print("Face.Simplify - Error: Could not simplify the face. Returning the original input face.")
|
3658
|
+
return face
|
3659
|
+
return return_face
|
3634
3660
|
|
3635
3661
|
@staticmethod
|
3636
3662
|
def Skeleton(face, boundary: bool = True, tolerance: float = 0.001):
|
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']
|
@@ -685,13 +743,16 @@ class Plotly:
|
|
685
743
|
labels = []
|
686
744
|
for j, elements_cluster in enumerate(elements_clusters):
|
687
745
|
d_color = color
|
746
|
+
d_arrowSize = arrowSize
|
747
|
+
d_dash = dash
|
688
748
|
d = dict_clusters[j][0] # All dicitonaries have same values in dictionaries, so take first one.
|
689
749
|
if d:
|
690
750
|
if not colorKey == None:
|
691
|
-
d_color = Dictionary.ValueAtKey(d, key=colorKey
|
692
|
-
d_color = Color.AnyToHex(d_color)
|
751
|
+
d_color = Color.AnyToHex(Dictionary.ValueAtKey(d, key=colorKey, default=color))
|
693
752
|
if not dashKey == None:
|
694
|
-
d_dash = Dictionary.ValueAtKey(d, key=dashKey
|
753
|
+
d_dash = Dictionary.ValueAtKey(d, key=dashKey, default=dash)
|
754
|
+
if not arrowSizeKey == None:
|
755
|
+
d_arrowSize = Dictionary.ValueAtKey(d, key=arrowSizeKey, default=arrowSize)
|
695
756
|
if not labelKey == None:
|
696
757
|
labels.append(str(Dictionary.ValueAtKey(d, labelKey, "")))
|
697
758
|
if not widthKey == None:
|
@@ -727,7 +788,7 @@ class Plotly:
|
|
727
788
|
marker_width = width[0]*0.25
|
728
789
|
else:
|
729
790
|
marker_width = width*0.25
|
730
|
-
if
|
791
|
+
if d_dash:
|
731
792
|
dot = "dot"
|
732
793
|
else:
|
733
794
|
dot = "solid"
|
@@ -744,6 +805,9 @@ class Plotly:
|
|
744
805
|
text=labels,
|
745
806
|
hoverinfo='text',
|
746
807
|
hovertext=labels)
|
808
|
+
if directed:
|
809
|
+
arrow_traces = create_arrowheads(x, y, z, arrowSize=d_arrowSize)
|
810
|
+
traces += arrow_traces
|
747
811
|
traces.append(trace)
|
748
812
|
else:
|
749
813
|
x = []
|
@@ -775,6 +839,9 @@ class Plotly:
|
|
775
839
|
legendrank=legendRank,
|
776
840
|
text=label,
|
777
841
|
hoverinfo='text')
|
842
|
+
if directed:
|
843
|
+
arrow_traces = create_arrowheads(x, y, z, arrowSize=arrowSize)
|
844
|
+
traces += arrow_traces
|
778
845
|
traces.append(trace)
|
779
846
|
return traces
|
780
847
|
|
@@ -799,6 +866,9 @@ class Plotly:
|
|
799
866
|
vertexLegendLabel="Topology Vertices",
|
800
867
|
vertexLegendRank=1,
|
801
868
|
vertexLegendGroup=1,
|
869
|
+
directed=False,
|
870
|
+
arrowSize=0.1,
|
871
|
+
arrowSizeKey=None,
|
802
872
|
showEdges=True,
|
803
873
|
edgeWidth=1,
|
804
874
|
edgeWidthKey=None,
|
@@ -884,7 +954,12 @@ class Plotly:
|
|
884
954
|
The legend rank order of the vertices of this topology. The default is 1.
|
885
955
|
vertexLegendGroup : int , optional
|
886
956
|
The number of the vertex legend group to which the vertices of this topology belong. The default is 1.
|
887
|
-
|
957
|
+
directed : bool , optional
|
958
|
+
If set to True, arrowheads are drawn to show direction. The default is False.
|
959
|
+
arrowSize : int, optional
|
960
|
+
The desired size of arrowheads for directed graphs. The default is 0.1.
|
961
|
+
arrowSizeKey: str , optional
|
962
|
+
The edge dictionary key under which to find the arrowhead size. The default is None.
|
888
963
|
showEdges : bool , optional
|
889
964
|
If set to True the edges will be drawn. Otherwise, they will not be drawn. The default is True.
|
890
965
|
edgeWidth : float , optional
|
@@ -1194,7 +1269,7 @@ class Plotly:
|
|
1194
1269
|
vertices = geo['vertices']
|
1195
1270
|
edges = geo['edges']
|
1196
1271
|
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))
|
1272
|
+
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
1273
|
|
1199
1274
|
if showFaces and Topology.Type(topology) >= Topology.TypeID("Face"):
|
1200
1275
|
if not faceColorKey == None:
|
topologicpy/Topology.py
CHANGED
@@ -6992,16 +6992,16 @@ class Topology():
|
|
6992
6992
|
return_topology = Wire.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
6993
6993
|
return return_topology
|
6994
6994
|
elif Topology.IsInstance(topology, "Face"):
|
6995
|
-
return_topology = Face.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
6995
|
+
return_topology = Face.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
6996
6996
|
return return_topology
|
6997
6997
|
elif Topology.IsInstance(topology, "Shell"):
|
6998
|
-
return_topology = Shell.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
6998
|
+
return_topology = Shell.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
6999
6999
|
return return_topology
|
7000
7000
|
elif Topology.IsInstance(topology, "Cell"):
|
7001
|
-
return_topology = Cell.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
7001
|
+
return_topology = Cell.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
7002
7002
|
return return_topology
|
7003
7003
|
elif Topology.IsInstance(topology, "CellComplex"):
|
7004
|
-
return_topology = CellComplex.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance)
|
7004
|
+
return_topology = CellComplex.RemoveCollinearEdges(topology, angTolerance=angTolerance, tolerance=tolerance, silent=silent)
|
7005
7005
|
return return_topology
|
7006
7006
|
elif Topology.IsInstance(topology, "Cluster"):
|
7007
7007
|
topologies = []
|
@@ -7009,7 +7009,7 @@ class Topology():
|
|
7009
7009
|
topologies += Cluster.FreeEdges(topology)
|
7010
7010
|
faces = Topology.Faces(topology)
|
7011
7011
|
for face in faces:
|
7012
|
-
topologies.append(Face.RemoveCollinearEdges(face, angTolerance=angTolerance, tolerance=tolerance))
|
7012
|
+
topologies.append(Face.RemoveCollinearEdges(face, angTolerance=angTolerance, tolerance=tolerance, silent=silent))
|
7013
7013
|
return_topology = Topology.SelfMerge(Cluster.ByTopologies(topologies), tolerance=tolerance)
|
7014
7014
|
return return_topology
|
7015
7015
|
|
@@ -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/Wire.py
CHANGED
@@ -465,15 +465,13 @@ class Wire():
|
|
465
465
|
from topologicpy.Cluster import Cluster
|
466
466
|
from topologicpy.Topology import Topology
|
467
467
|
from topologicpy.Vector import Vector
|
468
|
-
from topologicpy.Helper import Helper
|
468
|
+
from topologicpy.Helper import Helper
|
469
469
|
|
470
470
|
if not Topology.IsInstance(wire, "Wire"):
|
471
471
|
if not silent:
|
472
472
|
print("Wire.ByOffset - Error: The input wire parameter is not a valid wire. Returning None.")
|
473
473
|
return None
|
474
474
|
|
475
|
-
#temp_face = Face.ByWire(wire)
|
476
|
-
#original_area = Face.Area(temp_face)
|
477
475
|
if reverse == True:
|
478
476
|
fac = -1
|
479
477
|
else:
|
@@ -481,13 +479,10 @@ class Wire():
|
|
481
479
|
origin = Topology.Centroid(wire)
|
482
480
|
temp_vertices = [Topology.Vertices(wire)[0], Topology.Vertices(wire)[1], Topology.Centroid(wire)]
|
483
481
|
temp_face = Face.ByWire(Wire.ByVertices(temp_vertices, close=True, tolerance=tolerance), silent=silent)
|
484
|
-
temp_normal = Face.Normal(temp_face)
|
485
|
-
flat_wire = Topology.Flatten(wire, direction=temp_normal, origin=origin)
|
486
482
|
normal = Face.Normal(temp_face)
|
487
483
|
flat_wire = Topology.Flatten(wire, direction=normal, origin=origin)
|
488
484
|
original_edges = Topology.Edges(wire)
|
489
485
|
edges = Topology.Edges(flat_wire)
|
490
|
-
original_edges = Topology.Edges(wire)
|
491
486
|
offsets = []
|
492
487
|
offset_edges = []
|
493
488
|
final_vertices = []
|
@@ -495,9 +490,7 @@ class Wire():
|
|
495
490
|
edge_dictionaries = []
|
496
491
|
for i, edge in enumerate(edges):
|
497
492
|
d = Topology.Dictionary(original_edges[i])
|
498
|
-
d_offset = Dictionary.ValueAtKey(d, offsetKey)
|
499
|
-
if d_offset == None:
|
500
|
-
d_offset = offset
|
493
|
+
d_offset = Dictionary.ValueAtKey(d, key=offsetKey, defaultValue=offset)
|
501
494
|
d_offset = d_offset*fac
|
502
495
|
offsets.append(d_offset)
|
503
496
|
offset_edge = Edge.ByOffset2D(edge, d_offset)
|
@@ -595,23 +588,7 @@ class Wire():
|
|
595
588
|
v1 = Topology.SetDictionary(v1, Topology.Dictionary(v_a), silent=True)
|
596
589
|
if bisectors == True:
|
597
590
|
bisectors_list.append(Edge.ByVertices(v_a, v1))
|
598
|
-
|
599
|
-
|
600
|
-
# wire_edges = []
|
601
|
-
# for i in range(len(final_vertices)-1):
|
602
|
-
# v1 = final_vertices[i]
|
603
|
-
# v2 = final_vertices[i+1]
|
604
|
-
# w_e = Edge.ByVertices(v1,v2)
|
605
|
-
# #w_e = Edge.SetLength(w_e, Edge.Length(w_e)+(2*epsilon), bothSides = True)
|
606
|
-
# wire_edges.append(w_e)
|
607
|
-
# if Wire.IsClosed(wire):
|
608
|
-
# v1 = final_vertices[-1]
|
609
|
-
# v2 = final_vertices[0]
|
610
|
-
# #w_e = Edge.SetLength(w_e, Edge.Length(w_e)+(2*epsilon), bothSides = True)
|
611
|
-
# wire_edges.append(w_e)
|
612
|
-
|
613
591
|
return_wire = Wire.ByVertices(final_vertices, close=Wire.IsClosed(wire), tolerance=tolerance, silent=silent)
|
614
|
-
#wire_edges = Topology.Edges(wire_edges)
|
615
592
|
wire_edges = [Edge.SetLength(w_e, Edge.Length(w_e)+(2*epsilon), bothSides=True) for w_e in Topology.Edges(return_wire)]
|
616
593
|
return_wire_edges = Topology.Edges(return_wire)
|
617
594
|
if transferDictionaries == True:
|
@@ -651,7 +628,6 @@ class Wire():
|
|
651
628
|
print("Wire.ByOffset - Warning: The resulting wire is non-manifold, please check your offsets.")
|
652
629
|
print("Wire.ByOffset - Warning: Pursuing a workaround, but it might take longer to complete.")
|
653
630
|
|
654
|
-
#cycles = Wire.Cycles(return_wire, maxVertices = len(final_vertices))
|
655
631
|
temp_wire = Topology.SelfMerge(Cluster.ByTopologies(wire_edges))
|
656
632
|
cycles = Wire.Cycles(temp_wire, maxVertices = len(final_vertices))
|
657
633
|
if len(cycles) > 0:
|
@@ -679,7 +655,6 @@ class Wire():
|
|
679
655
|
return_cycle = Topology.TransferDictionariesBySelectors(return_cycle, Topology.Vertices(return_wire), tranVertices=True, tolerance=tolerance, numWorkers=numWorkers)
|
680
656
|
return_cycle = Topology.TransferDictionariesBySelectors(return_cycle, sel_edges, tranEdges=True, tolerance=tolerance, numWorkers=numWorkers)
|
681
657
|
return_wire = return_cycle
|
682
|
-
|
683
658
|
return_wire = Topology.Unflatten(return_wire, direction=normal, origin=origin)
|
684
659
|
if transferDictionaries == True:
|
685
660
|
return_wire = Topology.SetDictionary(return_wire, Topology.Dictionary(wire), silent=True)
|
@@ -3728,7 +3703,7 @@ class Wire():
|
|
3728
3703
|
return None
|
3729
3704
|
|
3730
3705
|
new_wire = cleanup(wire)
|
3731
|
-
wires = Wire.Split(new_wire) if not Wire.IsManifold(new_wire) else [new_wire]
|
3706
|
+
wires = Wire.Split(new_wire) if not Wire.IsManifold(new_wire, silent=silent) else [new_wire]
|
3732
3707
|
|
3733
3708
|
processed_wires = [remove_collinear_vertices(w) for w in wires]
|
3734
3709
|
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.42'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.42
|
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
|
@@ -2,37 +2,37 @@ topologicpy/ANN.py,sha256=DrNAhNHp-jSvsPc1fb7KVPU46cYmejAvghhknOM430Y,47932
|
|
2
2
|
topologicpy/Aperture.py,sha256=wNn5miB_IrGCBYuQ18HXQYRva20dUC3id4AJCulL7to,2723
|
3
3
|
topologicpy/BVH.py,sha256=Iwp_8VDG8ETE4330k7ifWxdI4jmWmv9h8e8IIIZZFGY,13043
|
4
4
|
topologicpy/CSG.py,sha256=uDkOSmc8m1V_k7T3UCerODhOSyYNO4FRDzoOqt0kEt8,15590
|
5
|
-
topologicpy/Cell.py,sha256=
|
6
|
-
topologicpy/CellComplex.py,sha256=
|
5
|
+
topologicpy/Cell.py,sha256=M4Xv4gabSgtKYYA-Wh0lgYEbRNRVF9zr4DYejOXJc-4,176278
|
6
|
+
topologicpy/CellComplex.py,sha256=c2B3mF1c3iwOfT-V0JWt9qNcFdd6DPR0aBOE2UnZTn4,61165
|
7
7
|
topologicpy/Cluster.py,sha256=wvfMAx6aPrSAt5nQ4--KnqD4EK9MGjch6Dg985WF7JQ,58748
|
8
8
|
topologicpy/Color.py,sha256=FcR0-__giyGQqvgiOrG8GkA65arHbiS33Si-QbUADPI,23362
|
9
9
|
topologicpy/Context.py,sha256=G3CwMvN8Jw2rnQRwB-n4MaQq_wLS0vPimbXKwsdMJ80,3055
|
10
10
|
topologicpy/DGL.py,sha256=HQXy9iDnrvWGDxaBfe5pRbweQ2zLBvAf6UdjfhKkQYI,139041
|
11
11
|
topologicpy/Dictionary.py,sha256=2Sxm8twR1W4ksZho0YXQB_EltK2qbZWK4UHskP3jvFQ,40846
|
12
|
-
topologicpy/Edge.py,sha256=
|
12
|
+
topologicpy/Edge.py,sha256=dLoAPuRKbjVg_dzloTgjRnQyv_05U9nfrtLO3tqyuys,74167
|
13
13
|
topologicpy/EnergyModel.py,sha256=Pyb28gDDwhzlQIH0xqAygqS0P3SJxWyyV7OWS_AAfRs,53856
|
14
|
-
topologicpy/Face.py,sha256=
|
15
|
-
topologicpy/Graph.py,sha256=
|
14
|
+
topologicpy/Face.py,sha256=pN1fssyDLYWf1vU0NOBRx69DaUL958wRSxT-7VBCuCg,203184
|
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=SqoQOFqchfDY52_mTGyBOqE_OPEfBI48YI3OyuJ7JQw,123758
|
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=FnDunqk4uq0iAqtOiQtjNArETXflx6cRBHMYv7NJqC8,467594
|
29
29
|
topologicpy/Vector.py,sha256=X12eqskn28bdB7sLY1EZhq3noPYzPbNEgHPb4a959ss,42302
|
30
|
-
topologicpy/Vertex.py,sha256=
|
31
|
-
topologicpy/Wire.py,sha256=
|
30
|
+
topologicpy/Vertex.py,sha256=RlGQnxQSb_kAus3tJgXd-v-Ptubtt09PQPA9IMwfXmI,84835
|
31
|
+
topologicpy/Wire.py,sha256=sJE8qwqYOomvN3snMWmj2P2-Sq25ul_OQ95YFz6DFUw,230553
|
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=zx8I7AqRXGv-YmSUcQeFeKLCO2nWXVogDC-GQVEnTsI,23
|
34
|
+
topologicpy-0.8.42.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
35
|
+
topologicpy-0.8.42.dist-info/METADATA,sha256=YEn71WRNeRaM0zD1L8Uh4HSmaxe_JJPkC5lBpaawXcc,10535
|
36
|
+
topologicpy-0.8.42.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
37
|
+
topologicpy-0.8.42.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
38
|
+
topologicpy-0.8.42.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|