topologicpy 0.7.11__py3-none-any.whl → 0.7.14__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 +16 -14
- topologicpy/CellComplex.py +24 -1
- topologicpy/Edge.py +205 -95
- topologicpy/Face.py +43 -15
- topologicpy/Grid.py +1 -1
- topologicpy/Polyskel.py +157 -12
- topologicpy/Shell.py +3 -4
- topologicpy/Sun.py +6 -6
- topologicpy/Topology.py +632 -8
- topologicpy/Vector.py +109 -2
- topologicpy/Vertex.py +106 -3
- topologicpy/Wire.py +59 -35
- topologicpy/version.py +1 -1
- {topologicpy-0.7.11.dist-info → topologicpy-0.7.14.dist-info}/METADATA +6 -5
- topologicpy-0.7.14.dist-info/RECORD +33 -0
- topologicpy-0.7.11.dist-info/RECORD +0 -33
- {topologicpy-0.7.11.dist-info → topologicpy-0.7.14.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.11.dist-info → topologicpy-0.7.14.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.11.dist-info → topologicpy-0.7.14.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
@@ -566,7 +566,7 @@ class Cell():
|
|
566
566
|
from topologicpy.Topology import Topology
|
567
567
|
from topologicpy.Cell import Cell
|
568
568
|
from topologicpy.Vertex import Vertex
|
569
|
-
if not origin:
|
569
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
570
570
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
571
571
|
if not Topology.IsInstance(origin, "Vertex"):
|
572
572
|
print("Cell.Capsule - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -652,8 +652,10 @@ class Cell():
|
|
652
652
|
The radius of the top circle of the cone. The default is 0.
|
653
653
|
height : float , optional
|
654
654
|
The height of the cone. The default is 1.
|
655
|
-
|
656
|
-
The number of
|
655
|
+
uSides : int , optional
|
656
|
+
The number of circle segments of the cylinder. The default is 16.
|
657
|
+
vSides : int , optional
|
658
|
+
The number of vertical segments of the cylinder. The default is 1.
|
657
659
|
direction : list , optional
|
658
660
|
The vector representing the up direction of the cone. The default is [0, 0, 1].
|
659
661
|
placement : str , optional
|
@@ -697,7 +699,7 @@ class Cell():
|
|
697
699
|
f = Face.ByWire(w, tolerance=tolerance)
|
698
700
|
faces.append(f)
|
699
701
|
return Cell.ByFaces(faces, tolerance=tolerance)
|
700
|
-
if not origin:
|
702
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
701
703
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
702
704
|
if not Topology.IsInstance(origin, "Vertex"):
|
703
705
|
print("Cell.Cone - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -839,7 +841,7 @@ class Cell():
|
|
839
841
|
from topologicpy.CellComplex import CellComplex
|
840
842
|
from topologicpy.Cluster import Cluster
|
841
843
|
from topologicpy.Topology import Topology
|
842
|
-
if not origin:
|
844
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
843
845
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
844
846
|
if not Topology.IsInstance(origin, "Vertex"):
|
845
847
|
print("Cell.Cylinder - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1014,7 +1016,7 @@ class Cell():
|
|
1014
1016
|
from topologicpy.Cluster import Cluster
|
1015
1017
|
from topologicpy.Topology import Topology
|
1016
1018
|
|
1017
|
-
if not origin:
|
1019
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1018
1020
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1019
1021
|
if not Topology.IsInstance(origin, "Vertex"):
|
1020
1022
|
print("Cell.Dodecahedron - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1113,7 +1115,7 @@ class Cell():
|
|
1113
1115
|
from topologicpy.Topology import Topology
|
1114
1116
|
from topologicpy.Dictionary import Dictionary
|
1115
1117
|
|
1116
|
-
if not origin:
|
1118
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1117
1119
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1118
1120
|
if not Topology.IsInstance(origin, "Vertex"):
|
1119
1121
|
print("Cell.Sphere - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1280,7 +1282,7 @@ class Cell():
|
|
1280
1282
|
returnTopology = Cluster.ByTopologies(faces)
|
1281
1283
|
return returnTopology
|
1282
1284
|
|
1283
|
-
if not origin:
|
1285
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1284
1286
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1285
1287
|
if not Topology.IsInstance(origin, "Vertex"):
|
1286
1288
|
print("Cell.Hyperboloid - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1352,7 +1354,7 @@ class Cell():
|
|
1352
1354
|
from topologicpy.Topology import Topology
|
1353
1355
|
import math
|
1354
1356
|
|
1355
|
-
if not origin:
|
1357
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1356
1358
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1357
1359
|
if not Topology.IsInstance(origin, "Vertex"):
|
1358
1360
|
print("Cell.Dodecahedron - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1520,7 +1522,7 @@ class Cell():
|
|
1520
1522
|
from topologicpy.Face import Face
|
1521
1523
|
from topologicpy.Topology import Topology
|
1522
1524
|
|
1523
|
-
if not origin:
|
1525
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1524
1526
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1525
1527
|
if not Topology.IsInstance(origin, "Vertex"):
|
1526
1528
|
print("Cell.Octahedron - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1751,7 +1753,7 @@ class Cell():
|
|
1751
1753
|
from topologicpy.Face import Face
|
1752
1754
|
from topologicpy.Topology import Topology
|
1753
1755
|
|
1754
|
-
if not origin:
|
1756
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1755
1757
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1756
1758
|
if not Topology.IsInstance(origin, "Vertex"):
|
1757
1759
|
print("Cell.Prism - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1965,7 +1967,7 @@ class Cell():
|
|
1965
1967
|
from topologicpy.Wire import Wire
|
1966
1968
|
from topologicpy.Topology import Topology
|
1967
1969
|
|
1968
|
-
if not origin:
|
1970
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1969
1971
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
1970
1972
|
if not Topology.IsInstance(origin, "Vertex"):
|
1971
1973
|
print("Cell.Sphere - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -2039,7 +2041,7 @@ class Cell():
|
|
2039
2041
|
from topologicpy.Topology import Topology
|
2040
2042
|
import math
|
2041
2043
|
|
2042
|
-
if not origin:
|
2044
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2043
2045
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
2044
2046
|
if not Topology.IsInstance(origin, "Vertex"):
|
2045
2047
|
print("Cell.Tetrahedron - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -2100,7 +2102,7 @@ class Cell():
|
|
2100
2102
|
from topologicpy.Wire import Wire
|
2101
2103
|
from topologicpy.Topology import Topology
|
2102
2104
|
|
2103
|
-
if not origin:
|
2105
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2104
2106
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
2105
2107
|
if not Topology.IsInstance(origin, "Vertex"):
|
2106
2108
|
print("Cell.Torus - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
topologicpy/CellComplex.py
CHANGED
@@ -678,6 +678,29 @@ class CellComplex():
|
|
678
678
|
"""
|
679
679
|
return cellComplex.ExternalBoundary()
|
680
680
|
|
681
|
+
@staticmethod
|
682
|
+
def ExternalBoundary(cellComplex):
|
683
|
+
"""
|
684
|
+
Returns the external boundary (cell) of the input cellComplex.
|
685
|
+
|
686
|
+
Parameters
|
687
|
+
----------
|
688
|
+
cellComplex : topologic_core.CellComplex
|
689
|
+
The input cellComplex.
|
690
|
+
|
691
|
+
Returns
|
692
|
+
-------
|
693
|
+
topologic_core.Cell
|
694
|
+
The external boundary of the input cellComplex.
|
695
|
+
|
696
|
+
"""
|
697
|
+
from topologicpy.Topology import Topology
|
698
|
+
|
699
|
+
if not Topology.IsInstance(cellComplex, "CellComplex"):
|
700
|
+
print("CellComplex.ExternalBoundary - Error: The input cellComplex parameter is not a valid cellComplex. Returning None.")
|
701
|
+
return None
|
702
|
+
return cellComplex.ExternalBoundary()
|
703
|
+
|
681
704
|
@staticmethod
|
682
705
|
def ExternalFaces(cellComplex) -> list:
|
683
706
|
"""
|
@@ -795,7 +818,7 @@ class CellComplex():
|
|
795
818
|
from topologicpy.Face import Face
|
796
819
|
from topologicpy.Topology import Topology
|
797
820
|
|
798
|
-
if not origin:
|
821
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
799
822
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
800
823
|
if not Topology.IsInstance(origin, "Vertex"):
|
801
824
|
print("CellComplex.Octahedron - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
topologicpy/Edge.py
CHANGED
@@ -444,50 +444,98 @@ class Edge():
|
|
444
444
|
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
445
445
|
|
446
446
|
@staticmethod
|
447
|
-
def
|
447
|
+
def ExtendToEdge(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
448
448
|
"""
|
449
|
-
Extends the first input edge to meet the second input edge.
|
449
|
+
Extends the first input edge to meet the second input edge.
|
450
450
|
|
451
451
|
Parameters
|
452
452
|
----------
|
453
453
|
edgeA : topologic_core.Edge
|
454
|
-
The first input edge.
|
454
|
+
The first input edge. This edge will be extended to meet edgeB.
|
455
455
|
edgeB : topologic_core.Edge
|
456
|
-
The second input edge.
|
456
|
+
The second input edge. This edge will be used to extend edgeA.
|
457
457
|
tolerance : float , optional
|
458
458
|
The desired tolerance. The default is 0.0001.
|
459
|
+
silent : bool , optional
|
460
|
+
If set to True, not error or warning messages are printed. Otherwise, they are. The default is False.
|
459
461
|
|
460
462
|
Returns
|
461
463
|
-------
|
462
464
|
topologic_core.Edge
|
463
|
-
The
|
465
|
+
The trimmed edge.
|
464
466
|
|
465
467
|
"""
|
466
|
-
|
467
468
|
from topologicpy.Vertex import Vertex
|
469
|
+
from topologicpy.Vector import Vector
|
468
470
|
from topologicpy.Topology import Topology
|
469
471
|
|
470
472
|
if not Topology.IsInstance(edgeA, "Edge"):
|
471
|
-
|
473
|
+
if not silent:
|
474
|
+
print("Edge.ExtendToEdge - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
472
475
|
return None
|
473
476
|
if not Topology.IsInstance(edgeB, "Edge"):
|
474
|
-
|
477
|
+
if not silent:
|
478
|
+
print("Edge.ExtendToEdge - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
475
479
|
return None
|
480
|
+
if not Edge.IsCoplanar(edgeA, edgeB, mantissa=mantissa, tolerance=tolerance):
|
481
|
+
if not silent:
|
482
|
+
print("Edge.ExtendToEdge - Error: The input edges are not coplanar. Returning the original edge.")
|
483
|
+
return edgeA
|
484
|
+
if not Edge.IsParallel(edgeA, edgeB, tolerance=tolerance):
|
485
|
+
if not silent:
|
486
|
+
print("Edge.ExtendToEdge - Error: The input edges are parallel. Returning the original edge.")
|
487
|
+
return edgeA
|
488
|
+
|
476
489
|
sva = Edge.StartVertex(edgeA)
|
477
490
|
eva = Edge.EndVertex(edgeA)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
491
|
+
d1 = Vertex.Distance(sva, edgeB)
|
492
|
+
d2 = Vertex.Distance(eva, edgeB)
|
493
|
+
edge_direction = Edge.Direction(edgeA)
|
494
|
+
if d1 < d2:
|
495
|
+
v1 = eva
|
496
|
+
v2 = sva
|
497
|
+
edge_direction = Vector.Reverse(edge_direction)
|
498
|
+
else:
|
499
|
+
v1 = sva
|
500
|
+
v2 = eva
|
501
|
+
|
502
|
+
d = max(d1, d2)*2
|
503
|
+
v2 = Topology.TranslateByDirectionDistance(v2, direction=edge_direction, distance=d)
|
504
|
+
new_edge = Edge.ByVertices(v1, v2)
|
505
|
+
|
506
|
+
svb = Edge.StartVertex(edgeB)
|
507
|
+
evb = Edge.EndVertex(edgeB)
|
508
|
+
|
509
|
+
intVertex = Topology.Intersect(new_edge, edgeB, tolerance=tolerance)
|
510
|
+
if intVertex:
|
511
|
+
return Edge.ByVertices([v1, intVertex], tolerance=tolerance, silent=True)
|
512
|
+
print("Edge.ExtendToEdge - Error: The operation failed. Returning None.")
|
489
513
|
return None
|
490
514
|
|
515
|
+
@staticmethod
|
516
|
+
def ExternalBoundary(edge):
|
517
|
+
"""
|
518
|
+
Returns the external boundary (cluster of end vertices) of the input edge.
|
519
|
+
|
520
|
+
Parameters
|
521
|
+
----------
|
522
|
+
edge : topologic_core.Edge
|
523
|
+
The input edge.
|
524
|
+
|
525
|
+
Returns
|
526
|
+
-------
|
527
|
+
topologic_core.Cluster
|
528
|
+
The external boundary of the input edge. This is a cluster of the edge's end vertices.
|
529
|
+
|
530
|
+
"""
|
531
|
+
from topologicpy.Topology import Topology
|
532
|
+
from topologicpy.Cluster import Cluster
|
533
|
+
|
534
|
+
if not Topology.IsInstance(edge, "Edge"):
|
535
|
+
print("Edge.ExternalBoundary - Error: The input edge parameter is not a valid edge. Returning None.")
|
536
|
+
return None
|
537
|
+
return Cluster.ByTopologies([Edge.StartVertex(edge), Edge.EndVertex(edge)])
|
538
|
+
|
491
539
|
@staticmethod
|
492
540
|
def Index(edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int:
|
493
541
|
"""
|
@@ -542,67 +590,6 @@ class Edge():
|
|
542
590
|
return i
|
543
591
|
return None
|
544
592
|
|
545
|
-
@staticmethod
|
546
|
-
def Intersect2D(edgeA, edgeB, mantissa: int = 6, silent: bool = False):
|
547
|
-
"""
|
548
|
-
Returns the intersection of the two input edges as a topologic_core.Vertex. This works only in the XY plane. Z coordinates are ignored.
|
549
|
-
|
550
|
-
Parameters
|
551
|
-
----------
|
552
|
-
edgeA : topologic_core.Edge
|
553
|
-
The first input edge.
|
554
|
-
edgeB : topologic_core.Edge
|
555
|
-
The second input edge.
|
556
|
-
mantissa : int , optional
|
557
|
-
The desired length of the mantissa. The default is 6.
|
558
|
-
silent : bool , optional
|
559
|
-
If set to False, error and warning messages are displayed. Otherwise they are not. The default is False.
|
560
|
-
|
561
|
-
Returns
|
562
|
-
-------
|
563
|
-
topologic_core.Vertex
|
564
|
-
The intersection of the two input edges.
|
565
|
-
|
566
|
-
"""
|
567
|
-
from topologicpy.Vertex import Vertex
|
568
|
-
from topologicpy.Topology import Topology
|
569
|
-
|
570
|
-
if not Topology.IsInstance(edgeA, "Edge"):
|
571
|
-
if not silent:
|
572
|
-
print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
573
|
-
return None
|
574
|
-
if not Topology.IsInstance(edgeB, "Edge"):
|
575
|
-
if not silent:
|
576
|
-
print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
577
|
-
return None
|
578
|
-
sva = Edge.StartVertex(edgeA)
|
579
|
-
eva = Edge.EndVertex(edgeA)
|
580
|
-
svb = Edge.StartVertex(edgeB)
|
581
|
-
evb = Edge.EndVertex(edgeB)
|
582
|
-
# Line AB represented as a1x + b1y = c1
|
583
|
-
a1 = Vertex.Y(eva, mantissa=mantissa) - Vertex.Y(sva, mantissa=mantissa)
|
584
|
-
b1 = Vertex.X(sva, mantissa=mantissa) - Vertex.X(eva, mantissa=mantissa)
|
585
|
-
c1 = a1*(Vertex.X(sva, mantissa=mantissa)) + b1*(Vertex.Y(sva, mantissa=mantissa))
|
586
|
-
|
587
|
-
# Line CD represented as a2x + b2y = c2
|
588
|
-
a2 = Vertex.Y(evb, mantissa=mantissa) - Vertex.Y(svb, mantissa=mantissa)
|
589
|
-
b2 = Vertex.X(svb, mantissa=mantissa) - Vertex.X(evb, mantissa=mantissa)
|
590
|
-
c2 = a2*(Vertex.X(svb, mantissa=mantissa)) + b2*(Vertex.Y(svb, mantissa=mantissa))
|
591
|
-
|
592
|
-
determinant = a1*b2 - a2*b1
|
593
|
-
|
594
|
-
if (determinant == 0):
|
595
|
-
# The lines are parallel. This is simplified
|
596
|
-
# by returning a pair of FLT_MAX
|
597
|
-
if not silent:
|
598
|
-
print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.")
|
599
|
-
return None
|
600
|
-
else:
|
601
|
-
x = (b2*c1 - b1*c2)/determinant
|
602
|
-
y = (a1*c2 - a2*c1)/determinant
|
603
|
-
return Vertex.ByCoordinates(x,y,0)
|
604
|
-
|
605
|
-
|
606
593
|
@staticmethod
|
607
594
|
def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
|
608
595
|
"""
|
@@ -686,7 +673,65 @@ class Edge():
|
|
686
673
|
return bool(distance_start < tolerance) and bool(distance_end < tolerance)
|
687
674
|
|
688
675
|
@staticmethod
|
689
|
-
def
|
676
|
+
def IsCoplanar(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001):
|
677
|
+
"""
|
678
|
+
Return True if the two input edges are coplanar. Returns False otherwise.
|
679
|
+
|
680
|
+
Parameters
|
681
|
+
----------
|
682
|
+
edgeA : topologic_core.Edge
|
683
|
+
The first input edge.
|
684
|
+
edgeB : topologic_core.Edge
|
685
|
+
The second input edge.
|
686
|
+
mantissa : int , optional
|
687
|
+
The desired length of the mantissa. The default is 6.
|
688
|
+
tolerance : float , optional
|
689
|
+
The desired tolerance. The default is 0.0001.
|
690
|
+
|
691
|
+
Returns
|
692
|
+
-------
|
693
|
+
bool
|
694
|
+
True if the two edges are coplanar. False otherwise.
|
695
|
+
|
696
|
+
"""
|
697
|
+
import numpy as np
|
698
|
+
from topologicpy.Vertex import Vertex
|
699
|
+
from topologicpy.Topology import Topology
|
700
|
+
|
701
|
+
if not Topology.IsInstance(edgeA, "Edge"):
|
702
|
+
print("Edge.IsCoplanar - Error: The input parameter edgeA is not a valid edge. Returning None")
|
703
|
+
return None
|
704
|
+
if not Topology.IsInstance(edgeB, "Edge"):
|
705
|
+
print("Edge.IsCoplanar - Error: The input parameter edgeB is not a valid edge. Returning None")
|
706
|
+
return None
|
707
|
+
if Edge.Length(edgeA) < tolerance:
|
708
|
+
print("Edge.IsCoplanar - Error: The length of edgeA is less than the tolerance. Returning None")
|
709
|
+
return None
|
710
|
+
if Edge.Length(edgeB) < tolerance:
|
711
|
+
print("Edge.IsCoplanar - Error: The length of edgeB is less than the tolerance. Returning None")
|
712
|
+
return None
|
713
|
+
|
714
|
+
# Extract points
|
715
|
+
sva, eva = [Topology.Vertices(edgeA)[0], Topology.Vertices(edgeA)[-1]]
|
716
|
+
p1 = Vertex.Coordinates(sva, mantissa=mantissa)
|
717
|
+
p2 = Vertex.Coordinates(eva, mantissa=mantissa)
|
718
|
+
svb, evb = [Topology.Vertices(edgeB)[0], Topology.Vertices(edgeB)[-1]]
|
719
|
+
p3 = Vertex.Coordinates(svb, mantissa=mantissa)
|
720
|
+
p4 = Vertex.Coordinates(evb, mantissa=mantissa)
|
721
|
+
|
722
|
+
# Create vectors
|
723
|
+
v1 = np.subtract(p2, p1)
|
724
|
+
v2 = np.subtract(p4, p3)
|
725
|
+
v3 = np.subtract(p3, p1)
|
726
|
+
|
727
|
+
# Calculate the scalar triple product
|
728
|
+
scalar_triple_product = np.dot(np.cross(v1, v2), v3)
|
729
|
+
|
730
|
+
# Check for coplanarity
|
731
|
+
return np.isclose(scalar_triple_product, 0, atol=tolerance)
|
732
|
+
|
733
|
+
@staticmethod
|
734
|
+
def IsParallel(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
|
690
735
|
"""
|
691
736
|
Return True if the two input edges are parallel. Returns False otherwise.
|
692
737
|
|
@@ -707,7 +752,9 @@ class Edge():
|
|
707
752
|
True if the two edges are collinear. False otherwise.
|
708
753
|
|
709
754
|
"""
|
755
|
+
from topologicpy.Vertex import Vertex
|
710
756
|
from topologicpy.Topology import Topology
|
757
|
+
import numpy as np
|
711
758
|
|
712
759
|
if not Topology.IsInstance(edgeA, "Edge"):
|
713
760
|
print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
@@ -715,10 +762,38 @@ class Edge():
|
|
715
762
|
if not Topology.IsInstance(edgeB, "Edge"):
|
716
763
|
print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
717
764
|
return None
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
765
|
+
|
766
|
+
def are_lines_parallel(line1, line2, tolerance=0.0001):
|
767
|
+
"""
|
768
|
+
Determines if two lines in 3D space are parallel.
|
769
|
+
|
770
|
+
Parameters:
|
771
|
+
line1 (tuple): A tuple of two points defining the first line. Each point is a tuple of (x, y, z).
|
772
|
+
line2 (tuple): A tuple of two points defining the second line. Each point is a tuple of (x, y, z).
|
773
|
+
|
774
|
+
Returns:
|
775
|
+
bool: True if the lines are parallel, False otherwise.
|
776
|
+
"""
|
777
|
+
def vector_from_points(p1, p2):
|
778
|
+
return np.array([p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]])
|
779
|
+
|
780
|
+
# Get direction vectors for both lines
|
781
|
+
vec1 = vector_from_points(line1[0], line1[1])
|
782
|
+
vec2 = vector_from_points(line2[0], line2[1])
|
783
|
+
|
784
|
+
# Compute the cross product of the direction vectors
|
785
|
+
cross_product = np.cross(vec1, vec2)
|
786
|
+
|
787
|
+
# Two vectors are parallel if their cross product is a zero vector
|
788
|
+
return np.allclose(cross_product, 0, atol=tolerance)
|
789
|
+
|
790
|
+
x1, y1, z1 = Vertex.Coordinates(Edge.StartVertex(edgeA), mantissa=mantissa)
|
791
|
+
x2, y2, z2 = Vertex.Coordinates(Edge.EndVertex(edgeA), mantissa=mantissa)
|
792
|
+
x3, y3, z3 = Vertex.Coordinates(Edge.StartVertex(edgeA), mantissa=mantissa)
|
793
|
+
x4, y4, z4 = Vertex.Coordinates(Edge.EndVertex(edgeA), mantissa=mantissa)
|
794
|
+
line1 = ((x1, y1, z1), (x2, y2, z2))
|
795
|
+
line2 = ((x3, y3, z3), (x4, y4, z4))
|
796
|
+
return are_lines_parallel(line1, line2, tolerance=tolerance)
|
722
797
|
|
723
798
|
@staticmethod
|
724
799
|
def Length(edge, mantissa: int = 6) -> float:
|
@@ -770,7 +845,7 @@ class Edge():
|
|
770
845
|
1. "center" which places the center of the edge at the origin.
|
771
846
|
2. "start" which places the start of the edge at the origin.
|
772
847
|
3. "end" which places the end of the edge at the origin.
|
773
|
-
The default is "center".
|
848
|
+
The default is "center". It is case insensitive.
|
774
849
|
tolerance : float , optional
|
775
850
|
The desired tolerance. The default is 0.0001.
|
776
851
|
Returns
|
@@ -783,7 +858,7 @@ class Edge():
|
|
783
858
|
from topologicpy.Vector import Vector
|
784
859
|
from topologicpy.Topology import Topology
|
785
860
|
|
786
|
-
if origin
|
861
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
787
862
|
origin = Vertex.Origin()
|
788
863
|
if not Topology.IsInstance(origin, "Vertex"):
|
789
864
|
print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -1126,18 +1201,22 @@ class Edge():
|
|
1126
1201
|
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
1127
1202
|
|
1128
1203
|
@staticmethod
|
1129
|
-
def
|
1204
|
+
def TrimByEdge(edgeA, edgeB, reverse: bool = False, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
1130
1205
|
"""
|
1131
|
-
Trims the first input edge by the second input edge.
|
1206
|
+
Trims the first input edge by the second input edge.
|
1132
1207
|
|
1133
1208
|
Parameters
|
1134
1209
|
----------
|
1135
1210
|
edgeA : topologic_core.Edge
|
1136
|
-
The first input edge.
|
1211
|
+
The first input edge. This edge will be trimmed by edgeB.
|
1137
1212
|
edgeB : topologic_core.Edge
|
1138
|
-
The second input edge.
|
1213
|
+
The second input edge. This edge will be used to trim edgeA.
|
1214
|
+
reverse : bool , optional
|
1215
|
+
If set to True, which segment is preserved is reversed. Otherwise, it is not. The default is False.
|
1139
1216
|
tolerance : float , optional
|
1140
1217
|
The desired tolerance. The default is 0.0001.
|
1218
|
+
silent : bool , optional
|
1219
|
+
If set to True, not error or warning messages are printed. Otherwise, they are. The default is False.
|
1141
1220
|
|
1142
1221
|
Returns
|
1143
1222
|
-------
|
@@ -1149,14 +1228,45 @@ class Edge():
|
|
1149
1228
|
from topologicpy.Topology import Topology
|
1150
1229
|
|
1151
1230
|
if not Topology.IsInstance(edgeA, "Edge"):
|
1152
|
-
|
1231
|
+
if not silent:
|
1232
|
+
print("Edge.TrimByEdge - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
1153
1233
|
return None
|
1154
1234
|
if not Topology.IsInstance(edgeB, "Edge"):
|
1155
|
-
|
1235
|
+
if not silent:
|
1236
|
+
print("Edge.TrimByEdge - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
1156
1237
|
return None
|
1238
|
+
if not Edge.IsCoplanar(edgeA, edgeB, mantissa=mantissa, tolerance=tolerance):
|
1239
|
+
if not silent:
|
1240
|
+
print("Edge.TrimByEdge - Error: The input edges are not coplanar. Returning the original edge.")
|
1241
|
+
return edgeA
|
1242
|
+
if not Edge.IsParallel(edgeA, edgeB, tolerance=tolerance):
|
1243
|
+
if not silent:
|
1244
|
+
print("Edge.TrimByEdge - Error: The input edges are parallel. Returning the original edge.")
|
1245
|
+
return edgeA
|
1246
|
+
|
1247
|
+
sva = Edge.StartVertex(edgeA)
|
1248
|
+
eva = Edge.EndVertex(edgeA)
|
1249
|
+
svb = Edge.StartVertex(edgeB)
|
1250
|
+
evb = Edge.EndVertex(edgeB)
|
1251
|
+
intVertex = None
|
1252
|
+
if Edge.IsCollinear(edgeA, edgeB):
|
1253
|
+
if Vertex.IsInternal(svb, edgeA):
|
1254
|
+
intVertex = svb
|
1255
|
+
elif Vertex.IsInternal(evb, edgeA):
|
1256
|
+
intVertex = evb
|
1257
|
+
else:
|
1258
|
+
intVertex = None
|
1259
|
+
if intVertex:
|
1260
|
+
if reverse:
|
1261
|
+
return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
1262
|
+
else:
|
1263
|
+
return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
|
1264
|
+
else:
|
1265
|
+
return None
|
1266
|
+
|
1157
1267
|
sva = Edge.StartVertex(edgeA)
|
1158
1268
|
eva = Edge.EndVertex(edgeA)
|
1159
|
-
intVertex =
|
1269
|
+
intVertex = Topology.Intersect(edgeA, edgeB)
|
1160
1270
|
if intVertex and (Vertex.IsInternal(intVertex, edgeA)):
|
1161
1271
|
if reverse:
|
1162
1272
|
return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
@@ -1195,7 +1305,7 @@ class Edge():
|
|
1195
1305
|
if not Topology.IsInstance(edge, "Edge"):
|
1196
1306
|
print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1197
1307
|
return None
|
1198
|
-
if not origin:
|
1308
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1199
1309
|
origin = edge.StartVertex()
|
1200
1310
|
if not Topology.IsInstance(origin, "Vertex"):
|
1201
1311
|
print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
topologicpy/Face.py
CHANGED
@@ -341,7 +341,7 @@ class Face():
|
|
341
341
|
print("Face.ByShell - Error: The input shell parameter is not a valid toplogic shell. Returning None.")
|
342
342
|
return None
|
343
343
|
|
344
|
-
if origin
|
344
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
345
345
|
origin = Topology.Centroid(shell)
|
346
346
|
if not Topology.IsInstance(origin, "Vertex"):
|
347
347
|
print("Face.ByShell - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
@@ -683,7 +683,7 @@ class Face():
|
|
683
683
|
"""
|
684
684
|
from topologicpy.Topology import Topology
|
685
685
|
from topologicpy.Vertex import Vertex
|
686
|
-
if not origin:
|
686
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
687
687
|
origin = Vertex.Origin()
|
688
688
|
|
689
689
|
c = Face.Circle(origin=origin, radius=radius, sides=sides, direction=[0, 0, 1], placement="center", tolerance=tolerance)
|
@@ -780,7 +780,7 @@ class Face():
|
|
780
780
|
return round(compactness, mantissa)
|
781
781
|
|
782
782
|
@staticmethod
|
783
|
-
def CompassAngle(face, north: list = None, mantissa: int = 6) -> float:
|
783
|
+
def CompassAngle(face, north: list = None, mantissa: int = 6, tolerance: float = 0.0001) -> float:
|
784
784
|
"""
|
785
785
|
Returns the horizontal compass angle in degrees between the normal vector of the input face and the input vector. The angle is measured in counter-clockwise fashion. Only the first two elements of the vectors are considered.
|
786
786
|
|
@@ -809,7 +809,7 @@ class Face():
|
|
809
809
|
if not north:
|
810
810
|
north = Vector.North()
|
811
811
|
dirA = Face.NormalAtParameters(face,mantissa=mantissa)
|
812
|
-
return Vector.CompassAngle(vectorA=dirA, vectorB=north, mantissa=mantissa)
|
812
|
+
return Vector.CompassAngle(vectorA=dirA, vectorB=north, mantissa=mantissa, tolerance=tolerance)
|
813
813
|
|
814
814
|
@staticmethod
|
815
815
|
def Edges(face) -> list:
|
@@ -1216,7 +1216,7 @@ class Face():
|
|
1216
1216
|
return inverted_face
|
1217
1217
|
|
1218
1218
|
@staticmethod
|
1219
|
-
def IsCoplanar(faceA, faceB, tolerance: float = 0.0001) -> bool:
|
1219
|
+
def IsCoplanar(faceA, faceB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
|
1220
1220
|
"""
|
1221
1221
|
Returns True if the two input faces are coplanar. Returns False otherwise.
|
1222
1222
|
|
@@ -1226,13 +1226,10 @@ class Face():
|
|
1226
1226
|
The first input face.
|
1227
1227
|
faceB : topologic_core.Face
|
1228
1228
|
The second input face
|
1229
|
+
mantissa : int , optional
|
1230
|
+
The length of the desired mantissa. The default is 6.
|
1229
1231
|
tolerance : float , optional
|
1230
|
-
The desired tolerance. The
|
1231
|
-
|
1232
|
-
Raises
|
1233
|
-
------
|
1234
|
-
Exception
|
1235
|
-
Raises an exception if the angle between the two input faces cannot be determined.
|
1232
|
+
The desired tolerance. The default is 0.0001.
|
1236
1233
|
|
1237
1234
|
Returns
|
1238
1235
|
-------
|
@@ -1240,8 +1237,23 @@ class Face():
|
|
1240
1237
|
True if the two input faces are coplanar. False otherwise.
|
1241
1238
|
|
1242
1239
|
"""
|
1243
|
-
from topologicpy.Vector import Vector
|
1244
1240
|
from topologicpy.Topology import Topology
|
1241
|
+
import warnings
|
1242
|
+
|
1243
|
+
try:
|
1244
|
+
import numpy as np
|
1245
|
+
except:
|
1246
|
+
print("Face.IsCoplanar - Information: Installing required numpy library.")
|
1247
|
+
try:
|
1248
|
+
os.system("pip install numpy")
|
1249
|
+
except:
|
1250
|
+
os.system("pip install numpy --user")
|
1251
|
+
try:
|
1252
|
+
import numpy as np
|
1253
|
+
print("Face.IsCoplanar - Information: numpy library installed successfully.")
|
1254
|
+
except:
|
1255
|
+
warnings.warn("Face.IsCoplanar - Error:: Could not import numpy. Please install the numpy library manually. Returning None.")
|
1256
|
+
return None
|
1245
1257
|
|
1246
1258
|
if not Topology.IsInstance(faceA, "Face"):
|
1247
1259
|
print("Face.IsInide - Error: The input faceA parameter is not a valid topologic face. Returning None.")
|
@@ -1249,9 +1261,25 @@ class Face():
|
|
1249
1261
|
if not Topology.IsInstance(faceB, "Face"):
|
1250
1262
|
print("Face.IsInide - Error: The input faceB parameter is not a valid topologic face. Returning None.")
|
1251
1263
|
return None
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1264
|
+
|
1265
|
+
def normalize_plane_coefficients(plane):
|
1266
|
+
norm = np.linalg.norm(plane[:3]) # Normalize using the first three coefficients (a, b, c)
|
1267
|
+
if norm == 0:
|
1268
|
+
return plane
|
1269
|
+
return [coef / norm for coef in plane]
|
1270
|
+
|
1271
|
+
def are_planes_coplanar(plane1, plane2, tolerance):
|
1272
|
+
normalized_plane1 = normalize_plane_coefficients(plane1)
|
1273
|
+
normalized_plane2 = normalize_plane_coefficients(plane2)
|
1274
|
+
return np.allclose(normalized_plane1, normalized_plane2, atol=tolerance)
|
1275
|
+
|
1276
|
+
eq_a = Face.PlaneEquation(faceA, mantissa=mantissa)
|
1277
|
+
plane_a = [eq_a['a'], eq_a['b'], eq_a['c'], eq_a['d']]
|
1278
|
+
plane_a = normalize_plane_coefficients(plane_a)
|
1279
|
+
eq_b = Face.PlaneEquation(faceB, mantissa=mantissa)
|
1280
|
+
plane_b = [eq_b['a'], eq_b['b'], eq_b['c'], eq_b['d']]
|
1281
|
+
plane_b = normalize_plane_coefficients(plane_b)
|
1282
|
+
return are_planes_coplanar(plane_a, plane_b, tolerance=tolerance)
|
1255
1283
|
|
1256
1284
|
@staticmethod
|
1257
1285
|
def Isovist(face, vertex, obstacles: list = [], direction: list = [0,1,0], fov: float = 360, mantissa: int = 6, tolerance: float = 0.0001):
|