topologicpy 0.4.94__py3-none-any.whl → 0.4.96__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 +42 -136
- topologicpy/CellComplex.py +4 -20
- topologicpy/Cluster.py +46 -3
- topologicpy/Edge.py +43 -27
- topologicpy/Face.py +42 -288
- topologicpy/Graph.py +237 -74
- topologicpy/Plotly.py +41 -34
- topologicpy/Shell.py +32 -115
- topologicpy/Topology.py +340 -161
- topologicpy/Vector.py +243 -6
- topologicpy/Vertex.py +216 -30
- topologicpy/Wire.py +118 -210
- topologicpy/__init__.py +1 -1
- {topologicpy-0.4.94.dist-info → topologicpy-0.4.96.dist-info}/METADATA +1 -1
- {topologicpy-0.4.94.dist-info → topologicpy-0.4.96.dist-info}/RECORD +18 -18
- {topologicpy-0.4.94.dist-info → topologicpy-0.4.96.dist-info}/LICENSE +0 -0
- {topologicpy-0.4.94.dist-info → topologicpy-0.4.96.dist-info}/WHEEL +0 -0
- {topologicpy-0.4.94.dist-info → topologicpy-0.4.96.dist-info}/top_level.txt +0 -0
topologicpy/Vector.py
CHANGED
@@ -147,6 +147,48 @@ class Vector(list):
|
|
147
147
|
altitude = round(altitude, mantissa)
|
148
148
|
return {"azimuth":azimuth, "altitude":altitude}
|
149
149
|
|
150
|
+
@staticmethod
|
151
|
+
def Bisect(vectorA, vectorB):
|
152
|
+
"""
|
153
|
+
Compute the bisecting vector of two input vectors.
|
154
|
+
|
155
|
+
Parameters
|
156
|
+
----------
|
157
|
+
vectorA : list
|
158
|
+
The first input vector.
|
159
|
+
vectorB : list
|
160
|
+
The second input vector.
|
161
|
+
|
162
|
+
Returns
|
163
|
+
-------
|
164
|
+
dict
|
165
|
+
The bisecting vector.
|
166
|
+
|
167
|
+
"""
|
168
|
+
import numpy as np
|
169
|
+
|
170
|
+
|
171
|
+
# Ensure vectors are numpy arrays
|
172
|
+
vector1 = np.array(vectorA)
|
173
|
+
vector2 = np.array(vectorB)
|
174
|
+
|
175
|
+
# Normalize input vectors
|
176
|
+
vector1_norm = vector1 / np.linalg.norm(vector1)
|
177
|
+
vector2_norm = vector2 / np.linalg.norm(vector2)
|
178
|
+
|
179
|
+
# Check if the angle between vectors is either 0 or 180 degrees
|
180
|
+
dot_product = np.dot(vector1_norm, vector2_norm)
|
181
|
+
if np.isclose(dot_product, 1.0) or np.isclose(dot_product, -1.0):
|
182
|
+
print("Vector.Bisect - Warning: The two vectors are collinear and thus the bisecting vector is not well-defined.")
|
183
|
+
# Angle is either 0 or 180 degrees, return any perpendicular vector
|
184
|
+
bisecting_vector = np.array([vector1[1] - vector1[2], vector1[2] - vector1[0], vector1[0] - vector1[1]])
|
185
|
+
bisecting_vector /= np.linalg.norm(bisecting_vector)
|
186
|
+
else:
|
187
|
+
# Compute bisecting vector
|
188
|
+
bisecting_vector = (vector1_norm + vector2_norm) / np.linalg.norm(vector1_norm + vector2_norm)
|
189
|
+
|
190
|
+
return bisecting_vector
|
191
|
+
|
150
192
|
@staticmethod
|
151
193
|
def ByAzimuthAltitude(azimuth, altitude, north=0, reverse=False, tolerance=0.0001):
|
152
194
|
"""
|
@@ -375,27 +417,153 @@ class Vector(list):
|
|
375
417
|
return [1,0,0]
|
376
418
|
|
377
419
|
@staticmethod
|
378
|
-
def
|
420
|
+
def IsAntiParallel(vectorA, vectorB):
|
421
|
+
"""
|
422
|
+
Returns True if the input vectors are anti-parallel. Returns False otherwise.
|
423
|
+
|
424
|
+
Parameters
|
425
|
+
----------
|
426
|
+
vectorA : list
|
427
|
+
The first input vector.
|
428
|
+
vectorB : list
|
429
|
+
The second input vector.
|
430
|
+
|
431
|
+
Returns
|
432
|
+
-------
|
433
|
+
bool
|
434
|
+
True if the input vectors are anti-parallel. False otherwise.
|
435
|
+
|
379
436
|
"""
|
380
|
-
|
437
|
+
import numpy as np
|
381
438
|
|
439
|
+
|
440
|
+
# Ensure vectors are numpy arrays
|
441
|
+
vector1 = np.array(vectorA)
|
442
|
+
vector2 = np.array(vectorB)
|
443
|
+
|
444
|
+
# Normalize input vectors
|
445
|
+
vector1_norm = vector1 / np.linalg.norm(vector1)
|
446
|
+
vector2_norm = vector2 / np.linalg.norm(vector2)
|
447
|
+
|
448
|
+
# Check if the angle between vectors is either 0 or 180 degrees
|
449
|
+
dot_product = np.dot(vector1_norm, vector2_norm)
|
450
|
+
if np.isclose(dot_product, -1.0):
|
451
|
+
return True
|
452
|
+
else:
|
453
|
+
# Compute bisecting vector
|
454
|
+
return False
|
455
|
+
|
456
|
+
@staticmethod
|
457
|
+
def IsParallel(vectorA, vectorB):
|
458
|
+
"""
|
459
|
+
Returns True if the input vectors are parallel. Returns False otherwise.
|
460
|
+
|
382
461
|
Parameters
|
383
462
|
----------
|
384
463
|
vectorA : list
|
385
464
|
The first input vector.
|
386
465
|
vectorB : list
|
387
466
|
The second input vector.
|
388
|
-
|
389
|
-
|
467
|
+
|
468
|
+
Returns
|
469
|
+
-------
|
470
|
+
bool
|
471
|
+
True if the input vectors are parallel. False otherwise.
|
472
|
+
|
473
|
+
"""
|
474
|
+
import numpy as np
|
390
475
|
|
476
|
+
|
477
|
+
# Ensure vectors are numpy arrays
|
478
|
+
vector1 = np.array(vectorA)
|
479
|
+
vector2 = np.array(vectorB)
|
480
|
+
|
481
|
+
# Normalize input vectors
|
482
|
+
vector1_norm = vector1 / np.linalg.norm(vector1)
|
483
|
+
vector2_norm = vector2 / np.linalg.norm(vector2)
|
484
|
+
|
485
|
+
# Check if the angle between vectors is either 0 or 180 degrees
|
486
|
+
dot_product = np.dot(vector1_norm, vector2_norm)
|
487
|
+
if np.isclose(dot_product, 1.0):
|
488
|
+
return True
|
489
|
+
else:
|
490
|
+
# Compute bisecting vector
|
491
|
+
return False
|
492
|
+
|
493
|
+
@staticmethod
|
494
|
+
def IsCollinear(vectorA, vectorB):
|
495
|
+
"""
|
496
|
+
Returns True if the input vectors are collinear (parallel or anti-parallel). Returns False otherwise.
|
497
|
+
|
498
|
+
Parameters
|
499
|
+
----------
|
500
|
+
vectorA : list
|
501
|
+
The first input vector.
|
502
|
+
vectorB : list
|
503
|
+
The second input vector.
|
504
|
+
|
391
505
|
Returns
|
392
506
|
-------
|
393
507
|
bool
|
394
|
-
|
508
|
+
True if the input vectors are collinear (parallel or anti-parallel). False otherwise.
|
509
|
+
|
395
510
|
"""
|
511
|
+
import numpy as np
|
396
512
|
|
397
|
-
return Vector.Angle(vectorA, vectorB) < angTolerance
|
398
513
|
|
514
|
+
# Ensure vectors are numpy arrays
|
515
|
+
vector1 = np.array(vectorA)
|
516
|
+
vector2 = np.array(vectorB)
|
517
|
+
|
518
|
+
# Normalize input vectors
|
519
|
+
vector1_norm = vector1 / np.linalg.norm(vector1)
|
520
|
+
vector2_norm = vector2 / np.linalg.norm(vector2)
|
521
|
+
|
522
|
+
# Check if the angle between vectors is either 0 or 180 degrees
|
523
|
+
dot_product = np.dot(vector1_norm, vector2_norm)
|
524
|
+
if np.isclose(dot_product, 1.0) or np.isclose(dot_product, -1.0):
|
525
|
+
return True
|
526
|
+
else:
|
527
|
+
# Compute bisecting vector
|
528
|
+
return False
|
529
|
+
|
530
|
+
@staticmethod
|
531
|
+
def IsParallel(vectorA, vectorB):
|
532
|
+
"""
|
533
|
+
Returns True if the input vectors are parallel. Returns False otherwise.
|
534
|
+
|
535
|
+
Parameters
|
536
|
+
----------
|
537
|
+
vectorA : list
|
538
|
+
The first input vector.
|
539
|
+
vectorB : list
|
540
|
+
The second input vector.
|
541
|
+
|
542
|
+
Returns
|
543
|
+
-------
|
544
|
+
bool
|
545
|
+
True if the input vectors are parallel. False otherwise.
|
546
|
+
|
547
|
+
"""
|
548
|
+
import numpy as np
|
549
|
+
|
550
|
+
|
551
|
+
# Ensure vectors are numpy arrays
|
552
|
+
vector1 = np.array(vectorA)
|
553
|
+
vector2 = np.array(vectorB)
|
554
|
+
|
555
|
+
# Normalize input vectors
|
556
|
+
vector1_norm = vector1 / np.linalg.norm(vector1)
|
557
|
+
vector2_norm = vector2 / np.linalg.norm(vector2)
|
558
|
+
|
559
|
+
# Check if the angle between vectors is either 0 or 180 degrees
|
560
|
+
dot_product = np.dot(vector1_norm, vector2_norm)
|
561
|
+
if np.isclose(dot_product, 1.0):
|
562
|
+
return True
|
563
|
+
else:
|
564
|
+
# Compute bisecting vector
|
565
|
+
return False
|
566
|
+
|
399
567
|
@staticmethod
|
400
568
|
def Magnitude(vector, mantissa: int = 6):
|
401
569
|
"""
|
@@ -606,6 +774,75 @@ class Vector(list):
|
|
606
774
|
|
607
775
|
return sum_dimensions
|
608
776
|
|
777
|
+
@staticmethod
|
778
|
+
def TransformationMatrix(vectorA, vectorB):
|
779
|
+
"""
|
780
|
+
Returns the transformation matrix needed to align vectorA with vectorB.
|
781
|
+
|
782
|
+
Parameters
|
783
|
+
----------
|
784
|
+
vectorA : list
|
785
|
+
The input vector to be transformed.
|
786
|
+
vectorB : list
|
787
|
+
The desired vector with which to align vectorA.
|
788
|
+
|
789
|
+
Returns
|
790
|
+
-------
|
791
|
+
list
|
792
|
+
Transformation matrix that follows the Blender software convention (nested list)
|
793
|
+
"""
|
794
|
+
import numpy as np
|
795
|
+
from topologicpy.Matrix import Matrix
|
796
|
+
|
797
|
+
import numpy as np
|
798
|
+
|
799
|
+
def transformation_matrix(vec1, vec2, translation_vector=None):
|
800
|
+
"""
|
801
|
+
Compute a 4x4 transformation matrix that aligns vec1 to vec2.
|
802
|
+
|
803
|
+
:param vec1: A 3D "source" vector
|
804
|
+
:param vec2: A 3D "destination" vector
|
805
|
+
:param translation_vector: Optional translation vector (default is None)
|
806
|
+
:return: The 4x4 transformation matrix
|
807
|
+
"""
|
808
|
+
vec1 = vec1 / np.linalg.norm(vec1)
|
809
|
+
vec2 = vec2 / np.linalg.norm(vec2)
|
810
|
+
dot_product = np.dot(vec1, vec2)
|
811
|
+
|
812
|
+
if np.isclose(dot_product, 1.0):
|
813
|
+
# Vectors are parallel; return the identity matrix
|
814
|
+
return np.eye(4)
|
815
|
+
elif np.isclose(dot_product, -1.0):
|
816
|
+
# Vectors are antiparallel; reflect one of the vectors about the origin
|
817
|
+
reflection_matrix = np.eye(4)
|
818
|
+
reflection_matrix[2, 2] = -1
|
819
|
+
return reflection_matrix
|
820
|
+
|
821
|
+
cross_product = np.cross(vec1, vec2)
|
822
|
+
|
823
|
+
skew_symmetric_matrix = np.array([[0, -cross_product[2], cross_product[1], 0],
|
824
|
+
[cross_product[2], 0, -cross_product[0], 0],
|
825
|
+
[-cross_product[1], cross_product[0], 0, 0],
|
826
|
+
[0, 0, 0, 1]])
|
827
|
+
|
828
|
+
rotation_matrix = np.eye(4) + skew_symmetric_matrix + \
|
829
|
+
np.dot(skew_symmetric_matrix, skew_symmetric_matrix) * \
|
830
|
+
(1 / (1 + dot_product))
|
831
|
+
|
832
|
+
if translation_vector is not None:
|
833
|
+
translation_matrix = np.eye(4)
|
834
|
+
translation_matrix[:3, 3] = translation_vector
|
835
|
+
transformation_matrix = np.dot(translation_matrix, rotation_matrix)
|
836
|
+
else:
|
837
|
+
transformation_matrix = rotation_matrix
|
838
|
+
|
839
|
+
return transformation_matrix
|
840
|
+
|
841
|
+
|
842
|
+
tran_mat = transformation_matrix(vectorA, vectorB)
|
843
|
+
|
844
|
+
return [list(tran_mat[0]), list(tran_mat[1]), list(tran_mat[2]), list(tran_mat[3])]
|
845
|
+
|
609
846
|
@staticmethod
|
610
847
|
def Up():
|
611
848
|
"""
|
topologicpy/Vertex.py
CHANGED
@@ -78,7 +78,7 @@ class Vertex(Topology):
|
|
78
78
|
return None
|
79
79
|
if len(vertexList) < 3:
|
80
80
|
return True # Any two vertices can form a line!
|
81
|
-
cluster = Topology.SelfMerge(Cluster.ByTopologies(vertexList))
|
81
|
+
cluster = Topology.SelfMerge(Cluster.ByTopologies(vertexList), tolerance=tolerance)
|
82
82
|
vertexList = Topology.Vertices(cluster)
|
83
83
|
slices = []
|
84
84
|
for i in range(2,len(vertexList)):
|
@@ -537,7 +537,7 @@ class Vertex(Topology):
|
|
537
537
|
|
538
538
|
def distance_to_face(vertex, face, includeCentroid):
|
539
539
|
v_proj = Vertex.Project(vertex, face, mantissa=mantissa)
|
540
|
-
if not
|
540
|
+
if not Vertex.IsInternal(v_proj, face):
|
541
541
|
vertices = Topology.Vertices(topology)
|
542
542
|
distances = [distance_to_vertex(vertex, v) for v in vertices]
|
543
543
|
edges = Topology.Edges(topology)
|
@@ -867,15 +867,70 @@ class Vertex(Topology):
|
|
867
867
|
return vertex
|
868
868
|
|
869
869
|
@staticmethod
|
870
|
-
def
|
870
|
+
def IsCoincident(vertexA: topologic.Vertex, vertexB: topologic.Vertex, tolerance: float = 0.0001, silent: bool = False) -> bool:
|
871
871
|
"""
|
872
|
-
|
872
|
+
Returns True if the input vertexA is coincident with the input vertexB. Returns False otherwise.
|
873
|
+
|
874
|
+
Parameters
|
875
|
+
----------
|
876
|
+
vertexA : topologic.Vertex
|
877
|
+
The first input vertex.
|
878
|
+
vertexB : topologic.Vertex
|
879
|
+
The second input vertex.
|
880
|
+
tolerance : float , optional
|
881
|
+
The tolerance for computing if the input vertexA is coincident with the input vertexB. The default is 0.0001.
|
882
|
+
|
883
|
+
Returns
|
884
|
+
-------
|
885
|
+
bool
|
886
|
+
True if the input vertexA is coincident with the input vertexB. False otherwise.
|
887
|
+
|
873
888
|
"""
|
874
|
-
|
875
|
-
|
889
|
+
if not isinstance(vertexA, topologic.Vertex):
|
890
|
+
if not silent:
|
891
|
+
print("Vertex.IsCoincident - Error: The input vertexA parameter is not a valid vertex. Returning None.")
|
892
|
+
return None
|
893
|
+
if not isinstance(vertexB, topologic.Vertex):
|
894
|
+
if not silent:
|
895
|
+
print("Vertex.IsICoincident - Error: The input vertexB parameter is not a valid vertex. Returning None.")
|
896
|
+
return None
|
897
|
+
return Vertex.IsInternal(vertexA, vertexB, tolerance=tolerance, silent=silent)
|
876
898
|
|
877
899
|
@staticmethod
|
878
|
-
def
|
900
|
+
def IsExternal(vertex: topologic.Vertex, topology: topologic.Topology, tolerance: float = 0.0001, silent: bool = False) -> bool:
|
901
|
+
"""
|
902
|
+
Returns True if the input vertex is external to the input topology. Returns False otherwise.
|
903
|
+
|
904
|
+
Parameters
|
905
|
+
----------
|
906
|
+
vertex : topologic.Vertex
|
907
|
+
The input vertex.
|
908
|
+
topology : topologic.Topology
|
909
|
+
The input topology.
|
910
|
+
tolerance : float , optional
|
911
|
+
The tolerance for computing if the input vertex is external to the input topology. The default is 0.0001.
|
912
|
+
silent : bool , optional
|
913
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
914
|
+
|
915
|
+
Returns
|
916
|
+
-------
|
917
|
+
bool
|
918
|
+
True if the input vertex is external to the input topology. False otherwise.
|
919
|
+
|
920
|
+
"""
|
921
|
+
|
922
|
+
if not isinstance(vertex, topologic.Vertex):
|
923
|
+
if not silent:
|
924
|
+
print("Vertex.IsExternal - Error: The input vertex parameter is not a valid vertex. Returning None.")
|
925
|
+
return None
|
926
|
+
if not isinstance(topology, topologic.Topology):
|
927
|
+
if not silent:
|
928
|
+
print("Vertex.IsExternal - Error: The input topology parameter is not a valid topology. Returning None.")
|
929
|
+
return None
|
930
|
+
return not (Vertex.IsPeripheral(vertex, topology, tolerance=tolerance, silent=silent) or Vertex.IsInternal(vertex, topology, tolerance=tolerance, silent=silent))
|
931
|
+
|
932
|
+
@staticmethod
|
933
|
+
def IsInternal(vertex: topologic.Vertex, topology: topologic.Topology, tolerance: float = 0.0001, silent: bool = False) -> bool:
|
879
934
|
"""
|
880
935
|
Returns True if the input vertex is inside the input topology. Returns False otherwise.
|
881
936
|
|
@@ -886,14 +941,17 @@ class Vertex(Topology):
|
|
886
941
|
topology : topologic.Topology
|
887
942
|
The input topology.
|
888
943
|
tolerance : float , optional
|
889
|
-
The tolerance for computing if the input vertex is
|
944
|
+
The tolerance for computing if the input vertex is internal to the input topology. The default is 0.0001.
|
945
|
+
silent : bool , optional
|
946
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
890
947
|
|
891
948
|
Returns
|
892
949
|
-------
|
893
950
|
bool
|
894
|
-
True if the input vertex is
|
951
|
+
True if the input vertex is internal to the input topology. False otherwise.
|
895
952
|
|
896
953
|
"""
|
954
|
+
from topologicpy.Edge import Edge
|
897
955
|
from topologicpy.Wire import Wire
|
898
956
|
from topologicpy.Face import Face
|
899
957
|
from topologicpy.Shell import Shell
|
@@ -901,8 +959,12 @@ class Vertex(Topology):
|
|
901
959
|
from topologicpy.Cluster import Cluster
|
902
960
|
from topologicpy.Topology import Topology
|
903
961
|
if not isinstance(vertex, topologic.Vertex):
|
962
|
+
if not silent:
|
963
|
+
print("Vertex.IsInternal - Error: The input vertex parameter is not a valid vertex. Returning None.")
|
904
964
|
return None
|
905
965
|
if not isinstance(topology, topologic.Topology):
|
966
|
+
if not silent:
|
967
|
+
print("Vertex.IsInternal - Error: The input topology parameter is not a valid topology. Returning None.")
|
906
968
|
return None
|
907
969
|
|
908
970
|
if isinstance(topology, topologic.Vertex):
|
@@ -914,39 +976,163 @@ class Vertex(Topology):
|
|
914
976
|
parameter = 400 #aribtrary large number greater than 1
|
915
977
|
return 0 <= parameter <= 1
|
916
978
|
elif isinstance(topology, topologic.Wire):
|
979
|
+
vertices = [v for v in Topology.Vertices(topology) if Vertex.Degree(v, topology) > 1]
|
917
980
|
edges = Wire.Edges(topology)
|
918
|
-
|
919
|
-
|
981
|
+
sub_list = vertices + edges
|
982
|
+
for sub in sub_list:
|
983
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
920
984
|
return True
|
921
985
|
return False
|
922
986
|
elif isinstance(topology, topologic.Face):
|
923
|
-
|
987
|
+
# Test the distance first
|
988
|
+
if Vertex.PerpendicularDistance(vertex, topology) > tolerance:
|
989
|
+
return False
|
990
|
+
if Vertex.IsPeripheral(vertex, topology):
|
991
|
+
return False
|
992
|
+
normal = Face.Normal(topology)
|
993
|
+
proj_v = Vertex.Project(vertex, topology)
|
994
|
+
v1 = Topology.TranslateByDirectionDistance(proj_v, normal, 1)
|
995
|
+
v2 = Topology.TranslateByDirectionDistance(proj_v, normal, -1)
|
996
|
+
edge = Edge.ByVertices(v1, v2)
|
997
|
+
intersect = edge.Intersect(topology)
|
998
|
+
if intersect == None:
|
999
|
+
return False
|
1000
|
+
return True
|
924
1001
|
elif isinstance(topology, topologic.Shell):
|
925
|
-
|
926
|
-
|
927
|
-
|
1002
|
+
if Vertex.IsPeripheral(vertex, topology, tolerance=tolerance, silent=silent):
|
1003
|
+
return False
|
1004
|
+
else:
|
1005
|
+
edges = Topology.Edges(topology)
|
1006
|
+
for edge in edges:
|
1007
|
+
if Vertex.IsInternal(vertex, edge, tolerance=tolerance, silent=silent):
|
1008
|
+
return True
|
1009
|
+
faces = Topology.Faces(topology)
|
1010
|
+
for face in faces:
|
1011
|
+
if Vertex.IsInternal(vertex, face, tolerance=tolerance, silent=silent):
|
1012
|
+
return True
|
1013
|
+
return False
|
1014
|
+
elif isinstance(topology, topologic.Cell):
|
1015
|
+
return topologic.CellUtility.Contains(topology, vertex, tolerance) == 0
|
1016
|
+
elif isinstance(topology, topologic.CellComplex):
|
1017
|
+
ext_boundary = CellComplex.ExternalBoundary(topology)
|
1018
|
+
return Vertex.IsInternal(vertex, ext_boundary, tolerance=tolerance, silent=silent)
|
1019
|
+
elif isinstance(topology, topologic.Cluster):
|
1020
|
+
sub_list = Cluster.FreeTopologies(topology)
|
1021
|
+
for sub in sub_list:
|
1022
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
1023
|
+
return True
|
1024
|
+
return False
|
1025
|
+
return False
|
1026
|
+
|
1027
|
+
|
1028
|
+
@staticmethod
|
1029
|
+
def IsPeripheral(vertex: topologic.Vertex, topology: topologic.Topology, tolerance: float = 0.0001, silent: bool = False) -> bool:
|
1030
|
+
"""
|
1031
|
+
Returns True if the input vertex is peripheral to the input topology. Returns False otherwise.
|
1032
|
+
A vertex is said to be peripheral to the input topology if:
|
1033
|
+
01. Vertex: If it is internal to it (i.e. coincident with it).
|
1034
|
+
02. Edge: If it is internal to its start or end vertices.
|
1035
|
+
03. Manifold open wire: If it is internal to its start or end vertices.
|
1036
|
+
04. Manifold closed wire: If it is internal to any of its vertices.
|
1037
|
+
05. Non-manifold wire: If it is internal to any of its vertices that has a vertex degree of 1.
|
1038
|
+
06. Face: If it is internal to any of its edges or vertices.
|
1039
|
+
07. Shell: If it is internal to external boundary
|
1040
|
+
08. Cell: If it is internal to any of its faces, edges, or vertices.
|
1041
|
+
09. CellComplex: If it is peripheral to its external boundary.
|
1042
|
+
10. Cluster: If it is peripheral to any of its free topologies. (See Cluster.FreeTopologies)
|
1043
|
+
|
1044
|
+
Parameters
|
1045
|
+
----------
|
1046
|
+
vertex : topologic.Vertex
|
1047
|
+
The input vertex.
|
1048
|
+
topology : topologic.Topology
|
1049
|
+
The input topology.
|
1050
|
+
tolerance : float , optional
|
1051
|
+
The tolerance for computing if the input vertex is peripheral to the input topology. The default is 0.0001.
|
1052
|
+
silent : bool , optional
|
1053
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
1054
|
+
|
1055
|
+
Returns
|
1056
|
+
-------
|
1057
|
+
bool
|
1058
|
+
True if the input vertex is peripheral to the input topology. False otherwise.
|
1059
|
+
|
1060
|
+
"""
|
1061
|
+
from topologicpy.Edge import Edge
|
1062
|
+
from topologicpy.Wire import Wire
|
1063
|
+
from topologicpy.Face import Face
|
1064
|
+
from topologicpy.Shell import Shell
|
1065
|
+
from topologicpy.CellComplex import CellComplex
|
1066
|
+
from topologicpy.Cluster import Cluster
|
1067
|
+
from topologicpy.Topology import Topology
|
1068
|
+
|
1069
|
+
if not isinstance(vertex, topologic.Vertex):
|
1070
|
+
if not silent:
|
1071
|
+
print("Vertex.IsPeripheral - Error: The input vertex parameter is not a valid vertex. Returning None.")
|
1072
|
+
return None
|
1073
|
+
if not isinstance(topology, topologic.Topology):
|
1074
|
+
if not silent:
|
1075
|
+
print("Vertex.IsPeripheral - Error: The input topology parameter is not a valid topology. Returning None.")
|
1076
|
+
return None
|
1077
|
+
|
1078
|
+
if isinstance(topology, topologic.Vertex):
|
1079
|
+
return Vertex.IsInternal(vertex, topology, tolerance=tolerance, silent=silent)
|
1080
|
+
elif isinstance(topology, topologic.Edge):
|
1081
|
+
sv = Edge.StartVertex(topology)
|
1082
|
+
ev = Edge.EndVertex(topology)
|
1083
|
+
f1 = Vertex.IsInternal(vertex, sv, tolerance=tolerance, silent=silent)
|
1084
|
+
f2 = Vertex.IsInternal(vertex, ev, tolerance=tolerance, silent=silent)
|
1085
|
+
return f1 or f2
|
1086
|
+
elif isinstance(topology, topologic.Wire):
|
1087
|
+
if Wire.IsManifold(topology):
|
1088
|
+
if not Wire.IsClosed(topology):
|
1089
|
+
sv = Wire.StartVertex(topology)
|
1090
|
+
ev = Wire.EndVertex(topology)
|
1091
|
+
f1 = Vertex.IsInternal(vertex, sv, tolerance=tolerance, silent=silent)
|
1092
|
+
f2 = Vertex.IsInternal(vertex, ev, tolerance=tolerance, silent=silent)
|
1093
|
+
return f1 or f2
|
1094
|
+
else:
|
1095
|
+
sub_list = [v for v in Topology.Vertices(topology)]
|
1096
|
+
for sub in sub_list:
|
1097
|
+
if Vertex.IsPeripheral(vertex, sub, tolerance=tolerance, silent=silent):
|
1098
|
+
return True
|
1099
|
+
return False
|
1100
|
+
else:
|
1101
|
+
sub_list = [v for v in Topology.Vertices(topology) if Vertex.Degree(v, topology) == 1]
|
1102
|
+
for sub in sub_list:
|
1103
|
+
if Vertex.IsPeripheral(vertex, sub, tolerance=tolerance, silent=silent):
|
1104
|
+
return True
|
1105
|
+
return False
|
1106
|
+
elif isinstance(topology, topologic.Face):
|
1107
|
+
sub_list = Topology.Vertices(topology) + Topology.Edges(topology)
|
1108
|
+
for sub in sub_list:
|
1109
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
1110
|
+
return True
|
1111
|
+
return False
|
1112
|
+
elif isinstance(topology, topologic.Shell):
|
1113
|
+
ext_boundary = Shell.ExternalBoundary(topology)
|
1114
|
+
sub_list = Topology.Vertices(ext_boundary) + Topology.Edges(ext_boundary)
|
1115
|
+
for sub in sub_list:
|
1116
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
928
1117
|
return True
|
929
1118
|
return False
|
930
1119
|
elif isinstance(topology, topologic.Cell):
|
931
|
-
|
1120
|
+
sub_list = Topology.Vertices(topology) + Topology.Edges(topology) + Topology.Faces(topology)
|
1121
|
+
for sub in sub_list:
|
1122
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
1123
|
+
return True
|
1124
|
+
return False
|
932
1125
|
elif isinstance(topology, topologic.CellComplex):
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
subtopologies = cells + faces + edges + vertices
|
938
|
-
for subtopology in subtopologies:
|
939
|
-
if Vertex.IsInternal(vertex, subtopology, tolerance):
|
1126
|
+
ext_boundary = CellComplex.ExternalBoundary(topology)
|
1127
|
+
sub_list = Topology.Vertices(ext_boundary) + Topology.Edges(ext_boundary) + Topology.Faces(ext_boundary)
|
1128
|
+
for sub in sub_list:
|
1129
|
+
if Vertex.IsInternal(vertex, sub, tolerance=tolerance, silent=silent):
|
940
1130
|
return True
|
941
1131
|
return False
|
942
1132
|
elif isinstance(topology, topologic.Cluster):
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
vertices = Cluster.Vertices(topology)
|
947
|
-
subtopologies = cells + faces + edges + vertices
|
948
|
-
for subtopology in subtopologies:
|
949
|
-
if Vertex.IsInternal(vertex, subtopology, tolerance):
|
1133
|
+
sub_list = Cluster.FreeTopologies(topology)
|
1134
|
+
for sub in sub_list:
|
1135
|
+
if Vertex.IsPeripheral(vertex, sub, tolerance=tolerance, silent=silent):
|
950
1136
|
return True
|
951
1137
|
return False
|
952
1138
|
return False
|