topologicpy 0.8.14__py3-none-any.whl → 0.8.17__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 +1 -1
- topologicpy/Dictionary.py +24 -0
- topologicpy/Face.py +48 -12
- topologicpy/Matrix.py +77 -0
- topologicpy/Polyskel.py +832 -620
- topologicpy/Topology.py +381 -125
- topologicpy/Vertex.py +4 -4
- topologicpy/Wire.py +6 -6
- topologicpy/version.py +1 -1
- {topologicpy-0.8.14.dist-info → topologicpy-0.8.17.dist-info}/METADATA +1 -1
- {topologicpy-0.8.14.dist-info → topologicpy-0.8.17.dist-info}/RECORD +14 -14
- {topologicpy-0.8.14.dist-info → topologicpy-0.8.17.dist-info}/WHEEL +1 -1
- {topologicpy-0.8.14.dist-info → topologicpy-0.8.17.dist-info}/LICENSE +0 -0
- {topologicpy-0.8.14.dist-info → topologicpy-0.8.17.dist-info}/top_level.txt +0 -0
topologicpy/Topology.py
CHANGED
@@ -1498,6 +1498,8 @@ class Topology():
|
|
1498
1498
|
edges = [e for e in edges if e]
|
1499
1499
|
faces = [f for f in faces if f]
|
1500
1500
|
|
1501
|
+
return_topology = None
|
1502
|
+
|
1501
1503
|
if not vertices:
|
1502
1504
|
return None
|
1503
1505
|
|
@@ -1527,7 +1529,7 @@ class Topology():
|
|
1527
1529
|
if topologyType == "wire" and edges:
|
1528
1530
|
topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
|
1529
1531
|
if topEdges:
|
1530
|
-
|
1532
|
+
return_topology = topologyByEdges(topEdges, topologyType)
|
1531
1533
|
elif faces:
|
1532
1534
|
for aFace in faces:
|
1533
1535
|
faceEdges = [Edge.ByVertices([topVerts[aFace[i]], topVerts[aFace[i + 1]]], tolerance=tolerance) for i in range(len(aFace) - 1)]
|
@@ -1545,14 +1547,14 @@ class Topology():
|
|
1545
1547
|
except:
|
1546
1548
|
pass
|
1547
1549
|
if topFaces:
|
1548
|
-
|
1550
|
+
return_topology = topologyByFaces(topFaces, topologyType=topologyType, tolerance=tolerance)
|
1549
1551
|
elif edges:
|
1550
1552
|
topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
|
1551
1553
|
if topEdges:
|
1552
|
-
|
1554
|
+
return_topology = topologyByEdges(topEdges, topologyType)
|
1553
1555
|
else:
|
1554
|
-
|
1555
|
-
return
|
1556
|
+
return_topology = Cluster.ByTopologies(topVerts)
|
1557
|
+
return return_topology
|
1556
1558
|
|
1557
1559
|
@staticmethod
|
1558
1560
|
def ByBIMPath(path, guidKey: str = "guid", colorKey: str = "color", typeKey: str = "type",
|
@@ -3073,6 +3075,118 @@ class Topology():
|
|
3073
3075
|
json_dict = json.loads(string)
|
3074
3076
|
return Topology.ByJSONDictionary(json_dict, tolerance=tolerance)
|
3075
3077
|
|
3078
|
+
@staticmethod
|
3079
|
+
def ByMeshData(dictionary, transferDictionaries: bool = False, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
3080
|
+
"""
|
3081
|
+
Create a cluster by the input python dictionary of vertices, edges, faces, and cells.
|
3082
|
+
|
3083
|
+
Parameters
|
3084
|
+
----------
|
3085
|
+
dictionary : dict
|
3086
|
+
The input python dictionary of vertices, edges, faces, and cells in the form of:
|
3087
|
+
{ 'mode': int, The expected mode of input face data:
|
3088
|
+
0: The faces list is indexed into the vertices list.
|
3089
|
+
1: The faces list is indexesd into the edges list.
|
3090
|
+
'vertices': list, (list of coordinates)
|
3091
|
+
'edges': list, (list of indices into the list of vertices)
|
3092
|
+
'faces': list, (list of indices into the list of edges)
|
3093
|
+
'cells': list, (list of indices into the list of faces)
|
3094
|
+
'vertex_dict': list of dicts,
|
3095
|
+
'edge_dicts': list of dicts,
|
3096
|
+
'face_dicts', list of dicts,
|
3097
|
+
'cell_dicts', list of dicts
|
3098
|
+
}
|
3099
|
+
transferDictionaries : bool , optional
|
3100
|
+
If set to True, the python dictionaries will be transferred to the coorespoding topologies. The default is False.
|
3101
|
+
mantissa : int , optional
|
3102
|
+
The desired length of the mantissa. The default is 6.
|
3103
|
+
tolerance : float , optional
|
3104
|
+
The desired tolerance. The default is 0.0001.
|
3105
|
+
silent : bool , optional
|
3106
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
3107
|
+
|
3108
|
+
Returns
|
3109
|
+
-------
|
3110
|
+
topologic_core.Cluster
|
3111
|
+
The created cluster of vertices, edges, faces, and cells.
|
3112
|
+
|
3113
|
+
"""
|
3114
|
+
from topologicpy.Vertex import Vertex
|
3115
|
+
from topologicpy.Edge import Edge
|
3116
|
+
from topologicpy.Face import Face
|
3117
|
+
from topologicpy.Cell import Cell
|
3118
|
+
from topologicpy.Cluster import Cluster
|
3119
|
+
from topologicpy.Dictionary import Dictionary
|
3120
|
+
from topologicpy.Helper import Helper
|
3121
|
+
|
3122
|
+
if not type(dictionary) == type({}):
|
3123
|
+
if not silent:
|
3124
|
+
print("Topology.ByMeshData - Error: The input dictionary parameter is not a valid dictionary. Returning None.")
|
3125
|
+
return None
|
3126
|
+
|
3127
|
+
vertices = dictionary['vertices']
|
3128
|
+
edges = dictionary['edges']
|
3129
|
+
faces = dictionary['faces']
|
3130
|
+
cells = dictionary['cells']
|
3131
|
+
if not 'mode' in dictionary.keys():
|
3132
|
+
mode = 0
|
3133
|
+
else:
|
3134
|
+
mode = dictionary['mode']
|
3135
|
+
if transferDictionaries == True:
|
3136
|
+
vertex_dicts = dictionary['vertex_dicts']
|
3137
|
+
edge_dicts = dictionary['edge_dicts']
|
3138
|
+
face_dicts = dictionary['face_dicts']
|
3139
|
+
cell_dicts = dictionary['cell_dicts']
|
3140
|
+
else:
|
3141
|
+
vertex_dicts = [{}]*len(vertices)
|
3142
|
+
edge_dicts = [{}]*len(edges)
|
3143
|
+
face_dicts = [{}]*len(faces)
|
3144
|
+
cell_dicts = [{}]*len(cells)
|
3145
|
+
|
3146
|
+
top_verts = []
|
3147
|
+
for i, vertex in enumerate(vertices):
|
3148
|
+
top_vertex = Vertex.ByCoordinates(vertex)
|
3149
|
+
if Topology.IsInstance(top_vertex, "Vertex"):
|
3150
|
+
if transferDictionaries:
|
3151
|
+
d = Dictionary.ByPythonDictionary(vertex_dicts[i])
|
3152
|
+
top_vertex = Topology.SetDictionary(top_vertex, d, silent=True)
|
3153
|
+
top_verts.append(top_vertex)
|
3154
|
+
|
3155
|
+
top_edges = []
|
3156
|
+
for i, edge in enumerate(edges):
|
3157
|
+
top_edge = Edge.ByVertices(top_verts[edge[0]], top_verts[edge[1]], tolerance=tolerance, silent=silent)
|
3158
|
+
if Topology.IsInstance(top_edge, "Edge"):
|
3159
|
+
if transferDictionaries:
|
3160
|
+
d = Dictionary.ByPythonDictionary(edge_dicts[i])
|
3161
|
+
top_edge = Topology.SetDictionary(top_edge, d, silent=True)
|
3162
|
+
top_edges.append(top_edge)
|
3163
|
+
|
3164
|
+
top_faces = []
|
3165
|
+
for i, face in enumerate(faces):
|
3166
|
+
if mode == 0:
|
3167
|
+
face_vertices = [top_verts[v] for v in face]
|
3168
|
+
top_face = Face.ByVertices(face_vertices, tolerance=tolerance, silent=silent)
|
3169
|
+
else:
|
3170
|
+
face_edges = [top_edges[e] for e in face]
|
3171
|
+
top_face = Face.ByEdges(face_edges, tolerance=tolerance, silent=silent)
|
3172
|
+
if Topology.IsInstance(top_face, "Face"):
|
3173
|
+
if transferDictionaries:
|
3174
|
+
d = Dictionary.ByPythonDictionary(face_dicts[i])
|
3175
|
+
top_face = Topology.SetDictionary(top_face, d, silent=True)
|
3176
|
+
top_faces.append(top_face)
|
3177
|
+
|
3178
|
+
top_cells = []
|
3179
|
+
for i, cell in enumerate(cells):
|
3180
|
+
cell_faces = [top_faces[f] for f in cell]
|
3181
|
+
top_cell = Cell.ByFaces(cell_faces, tolerance=tolerance, silent=silent)
|
3182
|
+
if Topology.IsInstance(top_cell, "Cell"):
|
3183
|
+
if transferDictionaries:
|
3184
|
+
d = Dictionary.ByPythonDictionary(cell_dicts[i])
|
3185
|
+
top_cell = Topology.SetDictionary(top_cell, d, silent=True)
|
3186
|
+
top_cells.append(top_cell)
|
3187
|
+
|
3188
|
+
return Cluster.ByTopologies(top_verts+top_edges+top_faces+top_cells)
|
3189
|
+
|
3076
3190
|
@staticmethod
|
3077
3191
|
def ByOBJFile(objFile, mtlFile = None,
|
3078
3192
|
defaultColor: list = [255,255,255],
|
@@ -3301,7 +3415,7 @@ class Topology():
|
|
3301
3415
|
vertex = list(map(float, parts[1:4]))
|
3302
3416
|
vertex = [round(coord, mantissa) for coord in vertex]
|
3303
3417
|
if transposeAxes == True:
|
3304
|
-
vertex = [vertex[0], vertex[2], vertex[1]]
|
3418
|
+
vertex = [vertex[0], -vertex[2], vertex[1]]
|
3305
3419
|
vertices.append(vertex)
|
3306
3420
|
elif parts[0] == 'vt':
|
3307
3421
|
texture = list(map(float, parts[1:3]))
|
@@ -5891,7 +6005,7 @@ class Topology():
|
|
5891
6005
|
return flat_topology
|
5892
6006
|
|
5893
6007
|
@staticmethod
|
5894
|
-
def Geometry(topology, mantissa: int = 6):
|
6008
|
+
def Geometry(topology, transferDictionaries: bool = False, mantissa: int = 6, silent: bool = False):
|
5895
6009
|
"""
|
5896
6010
|
Returns the geometry (mesh data format) of the input topology as a dictionary of vertices, edges, and faces.
|
5897
6011
|
|
@@ -5899,8 +6013,12 @@ class Topology():
|
|
5899
6013
|
----------
|
5900
6014
|
topology : topologic_core.Topology
|
5901
6015
|
The input topology.
|
6016
|
+
transferDictionaries : bool , optional
|
6017
|
+
If set to True, vertex, edge, and face dictionaries will be included in the output. Otherwise, they are not. The default is False.
|
5902
6018
|
mantissa : int , optional
|
5903
6019
|
The desired length of the mantissa. The default is 6.
|
6020
|
+
silent : bool , optional
|
6021
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
5904
6022
|
|
5905
6023
|
Returns
|
5906
6024
|
-------
|
@@ -5911,22 +6029,34 @@ class Topology():
|
|
5911
6029
|
from topologicpy.Vertex import Vertex
|
5912
6030
|
from topologicpy.Edge import Edge
|
5913
6031
|
from topologicpy.Face import Face
|
6032
|
+
from topologicpy.Dictionary import Dictionary
|
5914
6033
|
|
5915
6034
|
vertices = []
|
5916
6035
|
edges = []
|
5917
6036
|
faces = []
|
5918
|
-
|
5919
|
-
|
6037
|
+
vertex_dicts = []
|
6038
|
+
edge_dicts = []
|
6039
|
+
face_dicts = []
|
6040
|
+
if not Topology.IsInstance(topology, "topology"):
|
6041
|
+
if not silent:
|
6042
|
+
print("Topology.Geometry - Error: The input topology parameter is not a valid topology. Retruning None.")
|
6043
|
+
return None
|
5920
6044
|
topVerts = []
|
5921
6045
|
if Topology.Type(topology) == Topology.TypeID("Vertex"): #input is a vertex, just add it and process it
|
5922
6046
|
topVerts.append(topology)
|
5923
6047
|
else:
|
5924
6048
|
topVerts = Topology.Vertices(topology)
|
5925
6049
|
for aVertex in topVerts:
|
6050
|
+
py_dict = {}
|
6051
|
+
if transferDictionaries == True:
|
6052
|
+
d = Topology.Dictionary(aVertex)
|
6053
|
+
if len(Dictionary.Keys(d)) > 0:
|
6054
|
+
py_dict = Dictionary.PythonDictionary(d)
|
5926
6055
|
try:
|
5927
6056
|
vertices.index(Vertex.Coordinates(aVertex, mantissa=mantissa)) # Vertex already in list
|
5928
6057
|
except:
|
5929
6058
|
vertices.append(Vertex.Coordinates(aVertex, mantissa=mantissa)) # Vertex not in list, add it.
|
6059
|
+
vertex_dicts.append(py_dict)
|
5930
6060
|
topEdges = []
|
5931
6061
|
if (Topology.Type(topology) == Topology.TypeID("Edge")): #Input is an Edge, just add it and process it
|
5932
6062
|
topEdges.append(topology)
|
@@ -5949,13 +6079,18 @@ class Topology():
|
|
5949
6079
|
e.append(svIndex)
|
5950
6080
|
e.append(evIndex)
|
5951
6081
|
edges.append(e)
|
6082
|
+
py_dict = {}
|
6083
|
+
if transferDictionaries == True:
|
6084
|
+
d = Topology.Dictionary(anEdge)
|
6085
|
+
if len(Dictionary.Keys(d)) > 0:
|
6086
|
+
py_dict = Dictionary.PythonDictionary(d)
|
6087
|
+
edge_dicts.append(py_dict)
|
5952
6088
|
topFaces = []
|
5953
6089
|
if (Topology.Type(topology) == Topology.TypeID("Face")): # Input is a Face, just add it and process it
|
5954
6090
|
topFaces.append(topology)
|
5955
6091
|
elif (Topology.Type(topology) > Topology.TypeID("Face")):
|
5956
6092
|
_ = topology.Faces(None, topFaces)
|
5957
6093
|
for aFace in topFaces:
|
5958
|
-
f_dir = Face.Normal(aFace)
|
5959
6094
|
ib = []
|
5960
6095
|
_ = aFace.InternalBoundaries(ib)
|
5961
6096
|
if(len(ib) > 0):
|
@@ -5984,7 +6119,13 @@ class Topology():
|
|
5984
6119
|
fVertexIndex = len(vertices)-1
|
5985
6120
|
f.append(fVertexIndex)
|
5986
6121
|
faces.append(f)
|
5987
|
-
|
6122
|
+
py_dict = {}
|
6123
|
+
if transferDictionaries == True:
|
6124
|
+
d = Topology.Dictionary(aFace)
|
6125
|
+
if len(Dictionary.Keys(d)) > 0:
|
6126
|
+
py_dict = Dictionary.PythonDictionary(d)
|
6127
|
+
face_dicts.append(py_dict)
|
6128
|
+
return {"vertices":vertices, "edges":edges, "faces":faces, "vertex_dicts": vertex_dicts, "edge_dicts": edge_dicts, "face_dicts": face_dicts}
|
5988
6129
|
|
5989
6130
|
@staticmethod
|
5990
6131
|
def HighestType(topology):
|
@@ -6264,7 +6405,7 @@ class Topology():
|
|
6264
6405
|
@staticmethod
|
6265
6406
|
def IsSimilar(topologyA, topologyB, removeCoplanarFaces: bool = False, mantissa: int = 6, epsilon: float = 0.1, tolerance: float = 0.0001, silent: bool = False):
|
6266
6407
|
"""
|
6267
|
-
|
6408
|
+
Calculates if the input topologies are similar. See https://en.wikipedia.org/wiki/Similarity_(geometry).
|
6268
6409
|
|
6269
6410
|
Parameters
|
6270
6411
|
----------
|
@@ -6286,7 +6427,8 @@ class Topology():
|
|
6286
6427
|
Returns
|
6287
6428
|
-------
|
6288
6429
|
[bool, list]
|
6289
|
-
True if the input topologies are similar
|
6430
|
+
True if the input topologies are similar, False otherwise and the matrix needed to tranform topologyA to match topologyB.
|
6431
|
+
If the topologies are not similar, the transformation matrix is None.
|
6290
6432
|
|
6291
6433
|
"""
|
6292
6434
|
from topologicpy.Vertex import Vertex
|
@@ -6308,7 +6450,6 @@ class Topology():
|
|
6308
6450
|
if removeCoplanarFaces == True:
|
6309
6451
|
topologyA = Topology.RemoveCoplanarFaces(topologyA, epsilon=epsilon, tolerance=tolerance)
|
6310
6452
|
topologyB = Topology.RemoveCoplanarFaces(topologyB, epsilon=epsilon, tolerance=tolerance)
|
6311
|
-
Topology.Show(topologyA, topologyB)
|
6312
6453
|
len_vertices_a = len(Topology.Vertices(topologyA))
|
6313
6454
|
if len_vertices_a < 1 and not Topology.IsInstance(topologyA, "vertex"):
|
6314
6455
|
if not silent:
|
@@ -6398,90 +6539,58 @@ class Topology():
|
|
6398
6539
|
if len(faces_a) > 0 and len(faces_b) > 0:
|
6399
6540
|
largest_faces_a = Topology.LargestFaces(topologyA)
|
6400
6541
|
largest_faces_b = Topology.LargestFaces(topologyB)
|
6401
|
-
|
6542
|
+
else:
|
6543
|
+
if not silent:
|
6544
|
+
print("Topology.IsSimilar - Error: The topologies do not have faces. Returning None.")
|
6545
|
+
return False, None
|
6402
6546
|
|
6403
6547
|
# Process largest faces
|
6404
|
-
largest_faces_a = Topology.LargestFaces(topologyA)
|
6405
|
-
largest_faces_b = Topology.LargestFaces(topologyB)
|
6406
|
-
face_a_d = Dictionary.ByKeyValue("faceColor", "red")
|
6407
|
-
face_b_d = Dictionary.ByKeyValue("faceColor", "blue")
|
6408
6548
|
for face_a in largest_faces_a:
|
6549
|
+
l_edge_a = Topology.LongestEdges(face_a)[0]
|
6550
|
+
length_a = Edge.Length(l_edge_a)
|
6409
6551
|
centroid_a = Topology.Centroid(face_a)
|
6410
|
-
|
6552
|
+
origin_a = Vertex.Coordinates(centroid_a)
|
6553
|
+
zaxis_a = Face.Normal(face_a)
|
6411
6554
|
third_vertex_a = Face.ThirdVertex(face_a) # Pick a third vertex for orientation
|
6412
|
-
|
6555
|
+
xaxis_a = Vector.Normalize(Vector.ByVertices(centroid_a, third_vertex_a))
|
6556
|
+
yaxis_a = Vector.Cross(xaxis_a, zaxis_a)
|
6557
|
+
# Build Coordinate System matrix. The origin will be (0,0,0) once the trans matrix is applied.
|
6558
|
+
cs_a = [[0,0,0]]+[xaxis_a]+[yaxis_a]+[zaxis_a]
|
6559
|
+
tran_matrix_a = Matrix.ByTranslation(translateX=-origin_a[0], translateY=-origin_a[1], translateZ=-origin_a[2])
|
6413
6560
|
|
6561
|
+
# Check against the faces of B:
|
6414
6562
|
for face_b in largest_faces_b:
|
6415
|
-
|
6563
|
+
l_edge_b = Topology.LongestEdges(face_b)[0]
|
6564
|
+
length_b = Edge.Length(l_edge_b)
|
6565
|
+
scale_factor = length_b/length_a
|
6566
|
+
scale_matrix = Matrix.ByScaling(scaleX=scale_factor, scaleY=scale_factor, scaleZ=scale_factor)
|
6416
6567
|
centroid_b = Topology.Centroid(face_b)
|
6417
|
-
|
6568
|
+
origin_b = Vertex.Coordinates(centroid_b)
|
6569
|
+
zaxis_b = Face.Normal(face_b)
|
6418
6570
|
third_vertex_b = Face.ThirdVertex(face_b)
|
6419
|
-
|
6420
|
-
|
6571
|
+
xaxis_b = Vector.Normalize(Vector.ByVertices(centroid_b, third_vertex_b))
|
6572
|
+
yaxis_b = Vector.Cross(xaxis_b, zaxis_b)
|
6573
|
+
cs_b = [origin_b]+[xaxis_b]+[yaxis_b]+[zaxis_b]
|
6421
6574
|
# Compute transformation matrix
|
6422
|
-
|
6423
|
-
|
6424
|
-
|
6425
|
-
|
6426
|
-
translation_matrix = Matrix.ByTranslation(
|
6427
|
-
Vertex.X(centroid_b) - Vertex.X(centroid_a),
|
6428
|
-
Vertex.Y(centroid_b) - Vertex.Y(centroid_a),
|
6429
|
-
Vertex.Z(centroid_b) - Vertex.Z(centroid_a)
|
6430
|
-
)
|
6431
|
-
combined_matrix = Matrix.Multiply(rotation_matrix, scaling_matrix)
|
6432
|
-
combined_matrix = Matrix.Multiply(translation_matrix, combined_matrix)
|
6433
|
-
|
6434
|
-
transformed_centroid_a = Topology.Transform(centroid_a, combined_matrix)
|
6435
|
-
|
6436
|
-
# One last translation to synchronise the two centroids.
|
6437
|
-
translation_matrix = Matrix.ByTranslation(
|
6438
|
-
Vertex.X(centroid_b) - Vertex.X(transformed_centroid_a),
|
6439
|
-
Vertex.Y(centroid_b) - Vertex.Y(transformed_centroid_a),
|
6440
|
-
Vertex.Z(centroid_b) - Vertex.Z(transformed_centroid_a)
|
6441
|
-
)
|
6442
|
-
combined_matrix = Matrix.Multiply(translation_matrix, combined_matrix)
|
6575
|
+
# translate to origin, scale, then transform coordinate systems
|
6576
|
+
combined_matrix = Matrix.Multiply(scale_matrix, tran_matrix_a)
|
6577
|
+
matching_matrix = Matrix.ByCoordinateSystems(cs_a, cs_b)
|
6578
|
+
combined_matrix = Matrix.Multiply(matching_matrix, combined_matrix)
|
6443
6579
|
# Apply transformation and compare
|
6444
|
-
|
6445
|
-
|
6446
|
-
|
6447
|
-
|
6448
|
-
|
6449
|
-
|
6450
|
-
|
6580
|
+
try:
|
6581
|
+
transformedA = Topology.Transform(topologyA, combined_matrix)
|
6582
|
+
status = Topology.IsVertexCongruent(transformedA, topologyB, mantissa=mantissa, epsilon=epsilon, tolerance=tolerance, silent=silent)
|
6583
|
+
if status:
|
6584
|
+
return True, combined_matrix
|
6585
|
+
except:
|
6586
|
+
pass
|
6451
6587
|
|
6452
6588
|
return False, None
|
6453
|
-
# for l_f_a in largest_faces_a:
|
6454
|
-
# l_e_a = Face.NormalEdge(l_f_a)
|
6455
|
-
# centroid_a = Edge.StartVertex(l_e_a)
|
6456
|
-
# dir_a = Vector.Normalize(Edge.Direction(l_e_a))
|
6457
|
-
# trans_matrix_a = Matrix.ByTranslation(-Vertex.X(centroid_a), -Vertex.Y(centroid_a), -Vertex.Z(centroid_a))
|
6458
|
-
# sf_a = 1/Face.Area(l_f_a)
|
6459
|
-
# scaling_matrix_a = Matrix.ByScaling(sf_a, sf_a, sf_a)
|
6460
|
-
# for l_f_b in largest_faces_b:
|
6461
|
-
# l_e_b = Face.NormalEdge(l_f_b)
|
6462
|
-
# centroid_b = Edge.StartVertex(l_e_b)
|
6463
|
-
# dir_b = Vector.Normalize(Edge.Direction(l_e_b))
|
6464
|
-
# rotation_matrix = Matrix.ByVectors(dir_a, dir_b)
|
6465
|
-
# sf_b = 1/Face.Area(l_f_b)
|
6466
|
-
# scaling_matrix_b = Matrix.ByScaling(sf_b, sf_b, sf_b)
|
6467
|
-
# trans_matrix_b = Matrix.ByTranslation(-Vertex.X(centroid_b), -Vertex.Y(centroid_b), -Vertex.Z(centroid_b))
|
6468
|
-
# combined_matrix_a = Matrix.Multiply(rotation_matrix, scaling_matrix_a)
|
6469
|
-
# combined_matrix_a = Matrix.Multiply(combined_matrix_a, trans_matrix_a)
|
6470
|
-
# combined_matrix_b = Matrix.Multiply(scaling_matrix_b, trans_matrix_b)
|
6471
|
-
# top_a = Topology.Transform(topologyA, combined_matrix_a)
|
6472
|
-
# top_b = Topology.Transform(topologyB, combined_matrix_b)
|
6473
|
-
# Topology.Show(top_a, top_b)
|
6474
|
-
# if Topology.IsVertexCongruent(top_a, top_b, mantissa=mantissa, epsilon=epsilon, tolerance=tolerance, silent=silent):
|
6475
|
-
# Topology.Show(top_a, top_b)
|
6476
|
-
# final_matrix = Matrix.Multiply(Matrix.Invert(combined_matrix_b), combined_matrix_a)
|
6477
|
-
# return True, final_matrix
|
6478
6589
|
|
6479
|
-
return False, None
|
6480
|
-
|
6481
6590
|
@staticmethod
|
6482
6591
|
def IsVertexCongruent(topologyA, topologyB, mantissa: int = 6, epsilon: float = 0.1, tolerance: float = 0.0001, silent : bool = False):
|
6483
6592
|
"""
|
6484
|
-
Returns True if the input topologies are vertex
|
6593
|
+
Returns True if the input topologies are vertex congruent (have same number of vertices and all vertices are congruent within a tolerance). Returns False otherwise.
|
6485
6594
|
|
6486
6595
|
Parameters
|
6487
6596
|
----------
|
@@ -6491,6 +6600,9 @@ class Topology():
|
|
6491
6600
|
The second input topology.
|
6492
6601
|
mantissa : int , optional
|
6493
6602
|
The desired length of the mantissa. The default is 6.
|
6603
|
+
epsilon : float , optional
|
6604
|
+
The desired accepted tolerance for the number of matched number of vertices. For example, an epsilon of 0.1 indicates that
|
6605
|
+
the algorithm will return True even if 10% of the vertices do not match. The default is 0.1.
|
6494
6606
|
tolerance : float , optional
|
6495
6607
|
The desired tolerance. The default is 0.0001.
|
6496
6608
|
silent : bool , optional
|
@@ -6504,46 +6616,27 @@ class Topology():
|
|
6504
6616
|
"""
|
6505
6617
|
from topologicpy.Vertex import Vertex
|
6506
6618
|
|
6507
|
-
|
6619
|
+
|
6620
|
+
def coordinates_unmatched_ratio(list1, list2, mantissa, tolerance):
|
6508
6621
|
"""
|
6509
|
-
|
6510
|
-
coordinate in list2 within a specified tolerance, with each match being unique.
|
6511
|
-
|
6512
|
-
Parameters
|
6513
|
-
----------
|
6514
|
-
list1 : list of list of float
|
6515
|
-
The first list of coordinates, where each coordinate is [x, y, z].
|
6516
|
-
list2 : list of list of float
|
6517
|
-
The second list of coordinates, where each coordinate is [x, y, z].
|
6518
|
-
tolerance : float
|
6519
|
-
The maximum distance within which two coordinates are considered matching.
|
6520
|
-
|
6521
|
-
Returns
|
6522
|
-
-------
|
6523
|
-
float
|
6524
|
-
The percentage of coordinates in list1 that did not find a match in list2.
|
6622
|
+
Optimized version using KDTree for faster nearest-neighbor search.
|
6525
6623
|
"""
|
6526
|
-
|
6527
|
-
|
6528
|
-
|
6529
|
-
|
6624
|
+
from scipy.spatial import KDTree
|
6625
|
+
import numpy as np
|
6626
|
+
rounded_list1 = [np.round(coord, mantissa) for coord in list1]
|
6627
|
+
rounded_list2 = [np.round(coord, mantissa) for coord in list2]
|
6628
|
+
|
6629
|
+
tree = KDTree(rounded_list2)
|
6530
6630
|
unmatched_count = 0
|
6531
|
-
|
6532
|
-
|
6533
|
-
|
6534
|
-
|
6535
|
-
for i, coord2 in enumerate(unmatched):
|
6536
|
-
if distance(coord1, coord2) <= tolerance:
|
6537
|
-
unmatched.pop(i) # Remove matched coordinate
|
6538
|
-
match_found = True
|
6539
|
-
break
|
6540
|
-
if not match_found:
|
6631
|
+
|
6632
|
+
for coord in rounded_list1:
|
6633
|
+
distances, indices = tree.query(coord, k=1)
|
6634
|
+
if distances > tolerance:
|
6541
6635
|
unmatched_count += 1
|
6542
|
-
|
6543
|
-
total_coordinates = len(list1)
|
6544
|
-
unmatched_ratio = (unmatched_count / total_coordinates)
|
6545
6636
|
|
6546
|
-
|
6637
|
+
total_coordinates = len(list1)
|
6638
|
+
unmatched_ratio = unmatched_count / total_coordinates
|
6639
|
+
return round(unmatched_ratio, mantissa)
|
6547
6640
|
|
6548
6641
|
if not Topology.IsInstance(topologyA, "topology"):
|
6549
6642
|
if not silent:
|
@@ -6568,11 +6661,12 @@ class Topology():
|
|
6568
6661
|
return None
|
6569
6662
|
# Number of vertices
|
6570
6663
|
max_len = max([len_vertices_a, len_vertices_b])
|
6571
|
-
|
6664
|
+
ratio = round(float(abs(len_vertices_a - len_vertices_b))/float(max_len), mantissa)
|
6665
|
+
if ratio > epsilon:
|
6572
6666
|
return False
|
6573
6667
|
coords_a = [Vertex.Coordinates(v, mantissa=mantissa) for v in vertices_a]
|
6574
6668
|
coords_b = [Vertex.Coordinates(v, mantissa=mantissa) for v in vertices_b]
|
6575
|
-
unmatched_ratio = coordinates_unmatched_ratio(coords_a, coords_b, tolerance=tolerance)
|
6669
|
+
unmatched_ratio = coordinates_unmatched_ratio(coords_a, coords_b, mantissa=mantissa, tolerance=tolerance)
|
6576
6670
|
if unmatched_ratio <= epsilon:
|
6577
6671
|
return True
|
6578
6672
|
return False
|
@@ -6706,6 +6800,161 @@ class Topology():
|
|
6706
6800
|
return None
|
6707
6801
|
return Topology.SelfMerge(Cluster.ByTopologies(topologyList), tolerance=tolerance)
|
6708
6802
|
|
6803
|
+
@staticmethod
|
6804
|
+
def MeshData(topology, mode: int = 1, transferDictionaries: bool = False, mantissa: int = 6, silent: bool = False):
|
6805
|
+
"""
|
6806
|
+
Creates a mesh data python dictionary from the input topology.
|
6807
|
+
|
6808
|
+
Parameters
|
6809
|
+
----------
|
6810
|
+
topology : topologic_core.Topology
|
6811
|
+
The input topology.
|
6812
|
+
mode : int , optional
|
6813
|
+
The desired mode of conversion:
|
6814
|
+
0: The faces list indexes into the vertices list.
|
6815
|
+
1: The faces list indexes into the edges list.
|
6816
|
+
The default is 1.
|
6817
|
+
transferDictionaries : bool , optional
|
6818
|
+
If set to True, the python dictionaries will be transferred to the coorespoding topologies. The default is False.
|
6819
|
+
mantissa : int , optional
|
6820
|
+
The desired length of the mantissa. The default is 6.
|
6821
|
+
tolerance : float , optional
|
6822
|
+
The desired tolerance. The default is 0.0001.
|
6823
|
+
silent : bool , optional
|
6824
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
6825
|
+
|
6826
|
+
Returns
|
6827
|
+
-------
|
6828
|
+
dict
|
6829
|
+
The created mesh data python dictionary of vertices, edges, faces, and cells in the form of:
|
6830
|
+
{ 'mode' : int (the mode of the face data)
|
6831
|
+
'vertices': list, (list of coordinates)
|
6832
|
+
'edges': list, (list of indices into the list of vertices)
|
6833
|
+
'faces': list, (list of indices into the list of edges or list of vertices based on mode)
|
6834
|
+
'cells': list, (list of indices into the list of faces)
|
6835
|
+
'vertex_dict': list of dicts,
|
6836
|
+
'edge_dicts': list of dicts,
|
6837
|
+
'face_dicts', list of dicts,
|
6838
|
+
'cell_dicts', list of dicts
|
6839
|
+
}
|
6840
|
+
|
6841
|
+
"""
|
6842
|
+
from topologicpy.Vertex import Vertex
|
6843
|
+
from topologicpy.Dictionary import Dictionary
|
6844
|
+
|
6845
|
+
vertex_dicts = []
|
6846
|
+
edge_dicts = []
|
6847
|
+
face_dicts = []
|
6848
|
+
cell_dicts = []
|
6849
|
+
top = Topology.Copy(topology)
|
6850
|
+
top = Topology.Triangulate(top, transferDictionaries=transferDictionaries)
|
6851
|
+
vertices = Topology.Vertices(top)
|
6852
|
+
edges = Topology.Edges(top)
|
6853
|
+
faces = Topology.Faces(top)
|
6854
|
+
if Topology.IsInstance(top, "Vertex"):
|
6855
|
+
vertices = [top]
|
6856
|
+
edges = []
|
6857
|
+
faces = []
|
6858
|
+
cells = []
|
6859
|
+
elif Topology.IsInstance(top, "Edge"):
|
6860
|
+
vertices = Topology.Vertices(top)
|
6861
|
+
edges = [top]
|
6862
|
+
faces = []
|
6863
|
+
cells = []
|
6864
|
+
elif Topology.IsInstance(top, "Wire"):
|
6865
|
+
vertices = Topology.Vertices(top)
|
6866
|
+
edges = Topology.Edges(top)
|
6867
|
+
faces = []
|
6868
|
+
cells = []
|
6869
|
+
elif Topology.IsInstance(top, "Face"):
|
6870
|
+
vertices = Topology.Vertices(top)
|
6871
|
+
edges = Topology.Edges(top)
|
6872
|
+
faces = [top]
|
6873
|
+
cells = []
|
6874
|
+
elif Topology.IsInstance(top, "Shell"):
|
6875
|
+
vertices = Topology.Vertices(top)
|
6876
|
+
edges = Topology.Edges(top)
|
6877
|
+
faces = Topology.Faces(top)
|
6878
|
+
cells = []
|
6879
|
+
elif Topology.IsInstance(top, "Cell"):
|
6880
|
+
vertices = Topology.Vertices(top)
|
6881
|
+
edges = Topology.Edges(top)
|
6882
|
+
faces = Topology.Faces(top)
|
6883
|
+
cells = [top]
|
6884
|
+
elif Topology.IsInstance(top, "CellComplex"):
|
6885
|
+
vertices = Topology.Vertices(top)
|
6886
|
+
edges = Topology.Edges(top)
|
6887
|
+
faces = Topology.Faces(top)
|
6888
|
+
cells = Topology.Cells(top)
|
6889
|
+
elif Topology.IsInstance(top, "Cluster"):
|
6890
|
+
vertices = Topology.Vertices(top)
|
6891
|
+
edges = Topology.Edges(top)
|
6892
|
+
faces = Topology.Faces(top)
|
6893
|
+
cells = Topology.Cells(top)
|
6894
|
+
else:
|
6895
|
+
if not silent:
|
6896
|
+
print("Topology.MeshData - Error: The input topology parameter is not a valid topology. Returning None.")
|
6897
|
+
return None
|
6898
|
+
|
6899
|
+
m_verts = []
|
6900
|
+
m_edges = []
|
6901
|
+
m_faces = []
|
6902
|
+
m_cells = []
|
6903
|
+
key = "_n_"
|
6904
|
+
|
6905
|
+
for i, v in enumerate(vertices):
|
6906
|
+
d = Topology.Dictionary(v)
|
6907
|
+
v = Topology.SetDictionary(v, Dictionary.ByKeyValue(key, i))
|
6908
|
+
m_verts.append(Vertex.Coordinates(v, mantissa=mantissa))
|
6909
|
+
vertex_dicts.append(Dictionary.PythonDictionary(d))
|
6910
|
+
|
6911
|
+
for i, e in enumerate(edges):
|
6912
|
+
d = Topology.Dictionary(e)
|
6913
|
+
e = Topology.SetDictionary(e, Dictionary.ByKeyValue(key, i), silent=True)
|
6914
|
+
sv, ev = Topology.Vertices(e)
|
6915
|
+
sv_n = Dictionary.ValueAtKey(Topology.Dictionary(sv), key)
|
6916
|
+
ev_n = Dictionary.ValueAtKey(Topology.Dictionary(ev), key)
|
6917
|
+
m_edges.append([sv_n, ev_n])
|
6918
|
+
edge_dicts.append(Dictionary.PythonDictionary(d))
|
6919
|
+
|
6920
|
+
for i, f in enumerate(faces):
|
6921
|
+
d = Topology.Dictionary(f)
|
6922
|
+
f = Topology.SetDictionary(f, Dictionary.ByKeyValue(key, i), silent=True)
|
6923
|
+
if mode == 1:
|
6924
|
+
f_edges = Topology.Edges(f)
|
6925
|
+
edge_indices = []
|
6926
|
+
for f_edge in f_edges:
|
6927
|
+
edge_indices.append(Dictionary.ValueAtKey(Topology.Dictionary(f_edge), key))
|
6928
|
+
m_faces.append(edge_indices)
|
6929
|
+
else:
|
6930
|
+
f_vertices = Topology.Vertices(f)
|
6931
|
+
vertex_indices = []
|
6932
|
+
for f_vertex in f_vertices:
|
6933
|
+
vertex_indices.append(Dictionary.ValueAtKey(Topology.Dictionary(f_vertex), key))
|
6934
|
+
m_faces.append(vertex_indices)
|
6935
|
+
face_dicts.append(Dictionary.PythonDictionary(d))
|
6936
|
+
|
6937
|
+
for i, c in enumerate(cells):
|
6938
|
+
d = Topology.Dictionary(c)
|
6939
|
+
c = Topology.SetDictionary(c, Dictionary.ByKeyValue(key, i), silent=True)
|
6940
|
+
c_faces = Topology.Faces(c)
|
6941
|
+
face_indices = []
|
6942
|
+
for c_face in c_faces:
|
6943
|
+
face_indices.append(Dictionary.ValueAtKey(Topology.Dictionary(c_face), key))
|
6944
|
+
m_cells.append(face_indices)
|
6945
|
+
cell_dicts.append(Dictionary.PythonDictionary(d))
|
6946
|
+
|
6947
|
+
return {"mode": mode,
|
6948
|
+
"vertices": m_verts,
|
6949
|
+
"edges": m_edges,
|
6950
|
+
"faces": m_faces,
|
6951
|
+
"cells": m_cells,
|
6952
|
+
"vertex_dicts": vertex_dicts,
|
6953
|
+
"edge_dicts": edge_dicts,
|
6954
|
+
"face_dicts": face_dicts,
|
6955
|
+
"cell_dicts": cell_dicts
|
6956
|
+
}
|
6957
|
+
|
6709
6958
|
@staticmethod
|
6710
6959
|
def Move(topology, x=0, y=0, z=0):
|
6711
6960
|
"""
|
@@ -9791,7 +10040,7 @@ class Topology():
|
|
9791
10040
|
|
9792
10041
|
|
9793
10042
|
@staticmethod
|
9794
|
-
def Triangulate(topology, transferDictionaries: bool = False, mode: int = 0, meshSize: float = None, tolerance: float = 0.0001):
|
10043
|
+
def Triangulate(topology, transferDictionaries: bool = False, mode: int = 0, meshSize: float = None, tolerance: float = 0.0001, silent: bool = False):
|
9795
10044
|
"""
|
9796
10045
|
Triangulates the input topology.
|
9797
10046
|
|
@@ -9818,6 +10067,8 @@ class Topology():
|
|
9818
10067
|
calculated automatically and set to 10% of the overall size of the face.
|
9819
10068
|
tolerance : float , optional
|
9820
10069
|
The desired tolerance. The default is 0.0001.
|
10070
|
+
silent : bool , optional
|
10071
|
+
If set to True, no warnings or errors will be printed. The default is False.
|
9821
10072
|
|
9822
10073
|
Returns
|
9823
10074
|
-------
|
@@ -9832,28 +10083,33 @@ class Topology():
|
|
9832
10083
|
from topologicpy.Cluster import Cluster
|
9833
10084
|
|
9834
10085
|
if not Topology.IsInstance(topology, "Topology"):
|
9835
|
-
|
10086
|
+
if not silent:
|
10087
|
+
print("Topology.Triangulate - Error: The input parameter is not a valid topology. Returning None.")
|
9836
10088
|
return None
|
9837
10089
|
t = Topology.Type(topology)
|
9838
10090
|
if (t == Topology.TypeID("Vertex")) or (t == Topology.TypeID("Edge")) or (t == Topology.TypeID("Wire")):
|
10091
|
+
if not silent:
|
10092
|
+
print("Topology.Triangulate - Warning: The input topology parameter contains no faces. Returning the original topology.")
|
9839
10093
|
return topology
|
9840
10094
|
elif t == Topology.TypeID("Cluster"):
|
9841
10095
|
temp_topologies = []
|
9842
10096
|
cellComplexes = Topology.SubTopologies(topology, subTopologyType="cellcomplex") or []
|
9843
10097
|
for cc in cellComplexes:
|
9844
|
-
temp_topologies.append(Topology.Triangulate(cc, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance))
|
10098
|
+
temp_topologies.append(Topology.Triangulate(cc, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance, silent=silent))
|
9845
10099
|
cells = Cluster.FreeCells(topology, tolerance=tolerance) or []
|
9846
10100
|
for c in cells:
|
9847
|
-
temp_topologies.append(Topology.Triangulate(c, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance))
|
10101
|
+
temp_topologies.append(Topology.Triangulate(c, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance, silent=silent))
|
9848
10102
|
shells = Cluster.FreeShells(topology, tolerance=tolerance) or []
|
9849
10103
|
for s in shells:
|
9850
|
-
temp_topologies.append(Topology.Triangulate(s, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance))
|
10104
|
+
temp_topologies.append(Topology.Triangulate(s, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance, silent=silent))
|
9851
10105
|
faces = Cluster.FreeFaces(topology, tolerance=tolerance) or []
|
9852
10106
|
for f in faces:
|
9853
|
-
temp_topologies.append(Topology.Triangulate(f, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance))
|
10107
|
+
temp_topologies.append(Topology.Triangulate(f, transferDictionaries=transferDictionaries, mode=mode, meshSize=meshSize, tolerance=tolerance, silent=silent))
|
9854
10108
|
if len(temp_topologies) > 0:
|
9855
10109
|
return Cluster.ByTopologies(temp_topologies)
|
9856
10110
|
else:
|
10111
|
+
if not silent:
|
10112
|
+
print("Topology.Triangulate - Warning: The input topology parameter contains no faces. Returning the original topology.")
|
9857
10113
|
return topology
|
9858
10114
|
topologyFaces = []
|
9859
10115
|
_ = topology.Faces(None, topologyFaces)
|
@@ -9866,7 +10122,7 @@ class Topology():
|
|
9866
10122
|
triFaces = [aFace]
|
9867
10123
|
for triFace in triFaces:
|
9868
10124
|
if transferDictionaries:
|
9869
|
-
selectors.append(Topology.SetDictionary(
|
10125
|
+
selectors.append(Topology.SetDictionary(Topology.Centroid(triFace), Topology.Dictionary(aFace), silent=True))
|
9870
10126
|
faceTriangles.append(triFace)
|
9871
10127
|
return_topology = None
|
9872
10128
|
if t == Topology.TypeID("Face") or t == Topology.TypeID("Shell"): # Face or Shell
|