topologicpy 0.6.2__py3-none-any.whl → 0.7.0__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/Aperture.py +12 -13
- topologicpy/Cell.py +234 -210
- topologicpy/CellComplex.py +130 -118
- topologicpy/Cluster.py +108 -91
- topologicpy/Context.py +11 -7
- topologicpy/DGL.py +1 -1
- topologicpy/Dictionary.py +55 -65
- topologicpy/Edge.py +185 -148
- topologicpy/EnergyModel.py +23 -24
- topologicpy/Face.py +512 -313
- topologicpy/Graph.py +439 -351
- topologicpy/Grid.py +40 -43
- topologicpy/Honeybee.py +1 -1
- topologicpy/Matrix.py +28 -27
- topologicpy/Neo4j.py +5 -5
- topologicpy/Plotly.py +169 -53
- topologicpy/Shell.py +160 -145
- topologicpy/Sun.py +17 -13
- topologicpy/Topology.py +534 -766
- topologicpy/Vector.py +4 -3
- topologicpy/Vertex.py +145 -126
- topologicpy/Wire.py +542 -325
- topologicpy/version.py +1 -1
- {topologicpy-0.6.2.dist-info → topologicpy-0.7.0.dist-info}/METADATA +1 -1
- topologicpy-0.7.0.dist-info/RECORD +33 -0
- topologicpy-0.6.2.dist-info/RECORD +0 -33
- {topologicpy-0.6.2.dist-info → topologicpy-0.7.0.dist-info}/LICENSE +0 -0
- {topologicpy-0.6.2.dist-info → topologicpy-0.7.0.dist-info}/WHEEL +0 -0
- {topologicpy-0.6.2.dist-info → topologicpy-0.7.0.dist-info}/top_level.txt +0 -0
topologicpy/Wire.py
CHANGED
@@ -23,20 +23,20 @@ import itertools
|
|
23
23
|
|
24
24
|
class Wire(Topology):
|
25
25
|
@staticmethod
|
26
|
-
def Arc(startVertex
|
26
|
+
def Arc(startVertex, middleVertex, endVertex, sides: int = 16, close: bool = True, tolerance: float = 0.0001):
|
27
27
|
"""
|
28
28
|
Creates an arc. The base chord will be parallel to the x-axis and the height will point in the positive y-axis direction.
|
29
29
|
|
30
30
|
Parameters
|
31
31
|
----------
|
32
|
-
startVertex :
|
32
|
+
startVertex : topologic_core.Vertex
|
33
33
|
The location of the start vertex of the arc.
|
34
|
-
middleVertex :
|
34
|
+
middleVertex : topologic_core.Vertex
|
35
35
|
The location of the middle vertex (apex) of the arc.
|
36
|
-
endVertex :
|
36
|
+
endVertex : topologic_core.Vertex
|
37
37
|
The location of the end vertex of the arc.
|
38
38
|
sides : int , optional
|
39
|
-
The number of sides of the
|
39
|
+
The number of sides of the arc. The default is 16.
|
40
40
|
close : bool , optional
|
41
41
|
If set to True, the arc will be closed by connecting the last vertex to the first vertex. Otherwise, it will be left open.
|
42
42
|
tolerance : float , optional
|
@@ -44,7 +44,7 @@ class Wire(Topology):
|
|
44
44
|
|
45
45
|
Returns
|
46
46
|
-------
|
47
|
-
|
47
|
+
topologic_core.Wire
|
48
48
|
The created arc.
|
49
49
|
|
50
50
|
"""
|
@@ -97,11 +97,11 @@ class Wire(Topology):
|
|
97
97
|
|
98
98
|
# Determine the direction of the arc based on the angle between points 1 and 3
|
99
99
|
if angle13 < math.pi:
|
100
|
-
start_angle = angle1
|
101
|
-
end_angle = angle3
|
102
|
-
else:
|
103
100
|
start_angle = angle3
|
104
101
|
end_angle = angle1
|
102
|
+
else:
|
103
|
+
start_angle = angle1
|
104
|
+
end_angle = angle3
|
105
105
|
|
106
106
|
# Calculate the angle increment
|
107
107
|
angle_increment = (end_angle - start_angle) / sides
|
@@ -115,19 +115,19 @@ class Wire(Topology):
|
|
115
115
|
arc_points.append([x, y])
|
116
116
|
|
117
117
|
return arc_points
|
118
|
-
if not
|
118
|
+
if not Topology.IsInstance(startVertex, "Vertex"):
|
119
119
|
print("Wire.Arc - Error: The startVertex parameter is not a valid vertex. Returning None.")
|
120
120
|
return None
|
121
|
-
if not
|
121
|
+
if not Topology.IsInstance(middleVertex, "Vertex"):
|
122
122
|
print("Wire.Arc - Error: The middleVertex parameter is not a valid vertex. Returning None.")
|
123
123
|
return None
|
124
|
-
if not
|
124
|
+
if not Topology.IsInstance(endVertex, "Vertex"):
|
125
125
|
print("Wire.Arc - Error: The endVertex parameter is not a valid vertex. Returning None.")
|
126
126
|
return None
|
127
127
|
if Vertex.AreCollinear([startVertex, middleVertex, endVertex], tolerance = tolerance):
|
128
128
|
return Wire.ByVertices([startVertex, middleVertex, endVertex], close=False)
|
129
129
|
|
130
|
-
w = Wire.ByVertices([startVertex, middleVertex, endVertex], close=
|
130
|
+
w = Wire.ByVertices([startVertex, middleVertex, endVertex], close=True)
|
131
131
|
f = Face.ByWire(w, tolerance=tolerance)
|
132
132
|
normal = Face.Normal(f)
|
133
133
|
flat_w = Topology.Flatten(w, origin=startVertex, direction=normal)
|
@@ -143,13 +143,13 @@ class Wire(Topology):
|
|
143
143
|
return arc
|
144
144
|
|
145
145
|
@staticmethod
|
146
|
-
def BoundingRectangle(topology
|
146
|
+
def BoundingRectangle(topology, optimize: int = 0, tolerance=0.0001):
|
147
147
|
"""
|
148
148
|
Returns a wire representing a bounding rectangle of the input topology. The returned wire contains a dictionary with key "zrot" that represents rotations around the Z axis. If applied the resulting wire will become axis-aligned.
|
149
149
|
|
150
150
|
Parameters
|
151
151
|
----------
|
152
|
-
topology :
|
152
|
+
topology : topologic_core.Topology
|
153
153
|
The input topology.
|
154
154
|
optimize : int , optional
|
155
155
|
If set to an integer from 1 (low optimization) to 10 (high optimization), the method will attempt to optimize the bounding rectangle so that it reduces its surface area. The default is 0 which will result in an axis-aligned bounding rectangle. The default is 0.
|
@@ -158,7 +158,7 @@ class Wire(Topology):
|
|
158
158
|
|
159
159
|
Returns
|
160
160
|
-------
|
161
|
-
|
161
|
+
topologic_core.Wire
|
162
162
|
The bounding rectangle of the input topology.
|
163
163
|
|
164
164
|
"""
|
@@ -185,7 +185,7 @@ class Wire(Topology):
|
|
185
185
|
maxY = max(y)
|
186
186
|
return [minX, minY, maxX, maxY]
|
187
187
|
|
188
|
-
if not
|
188
|
+
if not Topology.IsInstance(topology, "Topology"):
|
189
189
|
return None
|
190
190
|
|
191
191
|
world_origin = Vertex.Origin()
|
@@ -253,10 +253,10 @@ class Wire(Topology):
|
|
253
253
|
best_br = boundingRectangle
|
254
254
|
|
255
255
|
minX, minY, maxX, maxY = best_br
|
256
|
-
vb1 =
|
257
|
-
vb2 =
|
258
|
-
vb3 =
|
259
|
-
vb4 =
|
256
|
+
vb1 = Vertex.ByCoordinates(minX, minY, 0)
|
257
|
+
vb2 = Vertex.ByCoordinates(maxX, minY, 0)
|
258
|
+
vb3 = Vertex.ByCoordinates(maxX, maxY, 0)
|
259
|
+
vb4 = Vertex.ByCoordinates(minX, maxY, 0)
|
260
260
|
|
261
261
|
boundingRectangle = Wire.ByVertices([vb1, vb2, vb3, vb4], close=True)
|
262
262
|
boundingRectangle = Topology.Rotate(boundingRectangle, origin=origin, axis=[0, 0, 1], angle=-best_z)
|
@@ -266,7 +266,7 @@ class Wire(Topology):
|
|
266
266
|
return boundingRectangle
|
267
267
|
|
268
268
|
@staticmethod
|
269
|
-
def ByEdges(edges: list, tolerance: float = 0.0001)
|
269
|
+
def ByEdges(edges: list, orient: bool = False, tolerance: float = 0.0001):
|
270
270
|
"""
|
271
271
|
Creates a wire from the input list of edges.
|
272
272
|
|
@@ -274,53 +274,57 @@ class Wire(Topology):
|
|
274
274
|
----------
|
275
275
|
edges : list
|
276
276
|
The input list of edges.
|
277
|
+
orient : bool , optional
|
278
|
+
If set to True the edges are oriented head to tail. Otherwise, they are not. The default is False.
|
277
279
|
tolerance : float , optional
|
278
280
|
The desired tolerance. The default is 0.0001
|
279
281
|
|
280
282
|
Returns
|
281
283
|
-------
|
282
|
-
|
284
|
+
topologic_core.Wire
|
283
285
|
The created wire.
|
284
286
|
|
285
287
|
"""
|
286
288
|
from topologicpy.Cluster import Cluster
|
287
289
|
from topologicpy.Topology import Topology
|
290
|
+
|
288
291
|
if not isinstance(edges, list):
|
289
292
|
return None
|
290
|
-
edgeList = [x for x in edges if
|
293
|
+
edgeList = [x for x in edges if Topology.IsInstance(x, "Edge")]
|
291
294
|
if len(edgeList) == 0:
|
292
295
|
print("Wire.ByEdges - Error: The input edges list does not contain any valid edges. Returning None.")
|
293
296
|
return None
|
294
297
|
if len(edgeList) == 1:
|
295
|
-
wire = topologic.Wire.ByEdges(edgeList)
|
298
|
+
wire = topologic.Wire.ByEdges(edgeList) # Hook to Core
|
296
299
|
else:
|
297
300
|
wire = Topology.SelfMerge(Cluster.ByTopologies(edgeList), tolerance=tolerance)
|
298
|
-
if not
|
301
|
+
if not Topology.IsInstance(wire, "Wire"):
|
299
302
|
print("Wire.ByEdges - Error: The operation failed. Returning None.")
|
300
303
|
wire = None
|
301
304
|
if Wire.IsManifold(wire):
|
302
|
-
|
305
|
+
if orient == True:
|
306
|
+
wire = Wire.OrientEdges(wire, Wire.StartVertex(wire), tolerance=tolerance)
|
303
307
|
return wire
|
304
308
|
|
305
309
|
@staticmethod
|
306
|
-
def ByEdgesCluster(cluster
|
310
|
+
def ByEdgesCluster(cluster, tolerance: float = 0.0001):
|
307
311
|
"""
|
308
312
|
Creates a wire from the input cluster of edges.
|
309
313
|
|
310
314
|
Parameters
|
311
315
|
----------
|
312
|
-
cluster :
|
316
|
+
cluster : topologic_core.Cluster
|
313
317
|
The input cluster of edges.
|
314
318
|
tolerance : float , optional
|
315
319
|
The desired tolerance. The default is 0.0001.
|
316
320
|
|
317
321
|
Returns
|
318
322
|
-------
|
319
|
-
|
323
|
+
topologic_core.Wire
|
320
324
|
The created wire.
|
321
325
|
|
322
326
|
"""
|
323
|
-
if not
|
327
|
+
if not Topology.IsInstance(cluster, "Cluster"):
|
324
328
|
print("Wire.ByEdges - Error: The input cluster parameter is not a valid topologic cluster. Returning None.")
|
325
329
|
return None
|
326
330
|
edges = []
|
@@ -328,16 +332,16 @@ class Wire(Topology):
|
|
328
332
|
return Wire.ByEdges(edges, tolerance=tolerance)
|
329
333
|
|
330
334
|
@staticmethod
|
331
|
-
def ByOffset(wire
|
335
|
+
def ByOffset(wire, offset: float = 1.0,
|
332
336
|
miter: bool = False, miterThreshold: float = None,
|
333
337
|
offsetKey: str = None, miterThresholdKey: str = None,
|
334
|
-
step: bool = True, angTolerance: float = 0.1, tolerance: float = 0.0001)
|
338
|
+
step: bool = True, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
335
339
|
"""
|
336
340
|
Creates an offset wire from the input wire.
|
337
341
|
|
338
342
|
Parameters
|
339
343
|
----------
|
340
|
-
wire :
|
344
|
+
wire : topologic_core.Wire
|
341
345
|
The input wire.
|
342
346
|
offset : float , optional
|
343
347
|
The desired offset distance. The default is 1.0.
|
@@ -346,9 +350,9 @@ class Wire(Topology):
|
|
346
350
|
miterThreshold : float , optional
|
347
351
|
The distance beyond which a miter should be added. The default is None which means the miter threshold is set to the offset distance multiplied by the square root of 2.
|
348
352
|
offsetKey : str , optional
|
349
|
-
If specified, the dictionary of the edges will be queried for this key to
|
353
|
+
If specified, the dictionary of the edges will be queried for this key to specify the desired offset. The default is None.
|
350
354
|
miterThresholdKey : str , optional
|
351
|
-
If specified, the dictionary of the vertices will be queried for this key to
|
355
|
+
If specified, the dictionary of the vertices will be queried for this key to specify the desired miter threshold distance. The default is None.
|
352
356
|
step : bool , optional
|
353
357
|
If set to True, The transition between collinear edges with different offsets will be a step. Otherwise, it will be a continous edge. The default is True.
|
354
358
|
angTolerance : float , optional
|
@@ -358,7 +362,7 @@ class Wire(Topology):
|
|
358
362
|
|
359
363
|
Returns
|
360
364
|
-------
|
361
|
-
|
365
|
+
topologic_core.Wire
|
362
366
|
The created wire.
|
363
367
|
|
364
368
|
"""
|
@@ -371,7 +375,7 @@ class Wire(Topology):
|
|
371
375
|
|
372
376
|
from random import randrange, sample
|
373
377
|
|
374
|
-
if not
|
378
|
+
if not Topology.IsInstance(wire, "Wire"):
|
375
379
|
return None
|
376
380
|
if not miterThreshold:
|
377
381
|
miterThreshold = offset*math.sqrt(2)
|
@@ -524,7 +528,7 @@ class Wire(Topology):
|
|
524
528
|
return newWire
|
525
529
|
|
526
530
|
@staticmethod
|
527
|
-
def ByVertices(vertices: list, close: bool = True, tolerance: float = 0.0001)
|
531
|
+
def ByVertices(vertices: list, close: bool = True, tolerance: float = 0.0001):
|
528
532
|
"""
|
529
533
|
Creates a wire from the input list of vertices.
|
530
534
|
|
@@ -539,17 +543,17 @@ class Wire(Topology):
|
|
539
543
|
|
540
544
|
Returns
|
541
545
|
-------
|
542
|
-
|
546
|
+
topologic_core.Wire
|
543
547
|
The created wire.
|
544
548
|
|
545
549
|
"""
|
546
|
-
from topologicpy.Vertex import Vertex
|
547
550
|
from topologicpy.Edge import Edge
|
548
551
|
from topologicpy.Cluster import Cluster
|
549
552
|
from topologicpy.Topology import Topology
|
553
|
+
|
550
554
|
if not isinstance(vertices, list):
|
551
555
|
return None
|
552
|
-
vertexList = [x for x in vertices if
|
556
|
+
vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")]
|
553
557
|
if len(vertexList) < 2:
|
554
558
|
print("Wire.ByVertices - Error: The number of vertices is less than 2. Returning None.")
|
555
559
|
return None
|
@@ -558,55 +562,55 @@ class Wire(Topology):
|
|
558
562
|
v1 = vertexList[i]
|
559
563
|
v2 = vertexList[i+1]
|
560
564
|
e = Edge.ByStartVertexEndVertex(v1, v2, tolerance=tolerance, silent=True)
|
561
|
-
if
|
565
|
+
if Topology.IsInstance(e, "Edge"):
|
562
566
|
edges.append(e)
|
563
567
|
if close:
|
564
568
|
v1 = vertexList[-1]
|
565
569
|
v2 = vertexList[0]
|
566
570
|
e = Edge.ByStartVertexEndVertex(v1, v2, tolerance=tolerance, silent=True)
|
567
|
-
if
|
571
|
+
if Topology.IsInstance(e, "Edge"):
|
568
572
|
edges.append(e)
|
569
573
|
if len(edges) < 1:
|
570
574
|
print("Wire.ByVertices - Error: The number of edges is less than 1. Returning None.")
|
571
575
|
return None
|
572
576
|
elif len(edges) == 1:
|
573
|
-
wire =
|
577
|
+
wire = Wire.ByEdges(edges, orient=False)
|
574
578
|
else:
|
575
579
|
wire = Topology.SelfMerge(Cluster.ByTopologies(edges), tolerance=tolerance)
|
576
580
|
return wire
|
577
581
|
|
578
582
|
@staticmethod
|
579
|
-
def ByVerticesCluster(cluster
|
583
|
+
def ByVerticesCluster(cluster, close: bool = True):
|
580
584
|
"""
|
581
585
|
Creates a wire from the input cluster of vertices.
|
582
586
|
|
583
587
|
Parameters
|
584
588
|
----------
|
585
|
-
cluster :
|
589
|
+
cluster : topologic_core.cluster
|
586
590
|
the input cluster of vertices.
|
587
591
|
close : bool , optional
|
588
592
|
If True the last vertex will be connected to the first vertex to close the wire. The default is True.
|
589
593
|
|
590
594
|
Returns
|
591
595
|
-------
|
592
|
-
|
596
|
+
topologic_core.Wire
|
593
597
|
The created wire.
|
594
598
|
|
595
599
|
"""
|
596
|
-
if not
|
600
|
+
if not Topology.IsInstance(cluster, "Cluster"):
|
597
601
|
return None
|
598
602
|
vertices = []
|
599
603
|
_ = cluster.Vertices(None, vertices)
|
600
604
|
return Wire.ByVertices(vertices, close)
|
601
605
|
|
602
606
|
@staticmethod
|
603
|
-
def Circle(origin
|
607
|
+
def Circle(origin= None, radius: float = 0.5, sides: int = 16, fromAngle: float = 0.0, toAngle: float = 360.0, close: bool = True, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
604
608
|
"""
|
605
609
|
Creates a circle.
|
606
610
|
|
607
611
|
Parameters
|
608
612
|
----------
|
609
|
-
origin :
|
613
|
+
origin : topologic_core.Vertex , optional
|
610
614
|
The location of the origin of the circle. The default is None which results in the circle being placed at (0, 0, 0).
|
611
615
|
radius : float , optional
|
612
616
|
The radius of the circle. The default is 0.5.
|
@@ -627,7 +631,7 @@ class Wire(Topology):
|
|
627
631
|
|
628
632
|
Returns
|
629
633
|
-------
|
630
|
-
|
634
|
+
topologic_core.Wire
|
631
635
|
The created circle.
|
632
636
|
|
633
637
|
"""
|
@@ -635,10 +639,12 @@ class Wire(Topology):
|
|
635
639
|
from topologicpy.Topology import Topology
|
636
640
|
|
637
641
|
if not origin:
|
638
|
-
origin =
|
639
|
-
if not
|
642
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
643
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
644
|
+
print("Wire.Circle - Error: The input origin parameter is not a valid Vertex. Retruning None.")
|
640
645
|
return None
|
641
646
|
if not placement.lower() in ["center", "lowerleft", "upperleft", "lowerright", "upperright"]:
|
647
|
+
print("Wire.Circle - Error: The input placement parameter is not a recognised string. Retruning None.")
|
642
648
|
return None
|
643
649
|
radius = abs(radius)
|
644
650
|
if radius < tolerance:
|
@@ -691,7 +697,7 @@ class Wire(Topology):
|
|
691
697
|
|
692
698
|
Parameters
|
693
699
|
----------
|
694
|
-
wire :
|
700
|
+
wire : topologic_core.Wire
|
695
701
|
The input wire.
|
696
702
|
mantissa : int , optional
|
697
703
|
The desired length of the mantissa. The default is 6.
|
@@ -700,7 +706,7 @@ class Wire(Topology):
|
|
700
706
|
|
701
707
|
Returns
|
702
708
|
-------
|
703
|
-
|
709
|
+
topologic_core.Wire
|
704
710
|
The closed version of the input wire.
|
705
711
|
|
706
712
|
"""
|
@@ -717,7 +723,7 @@ class Wire(Topology):
|
|
717
723
|
new_vertices = Helper.Sort(vertices, distances)
|
718
724
|
return new_vertices[1] #The first item is the same vertex, so return the next nearest vertex.
|
719
725
|
|
720
|
-
if not
|
726
|
+
if not Topology.IsInstance(wire, "Wire"):
|
721
727
|
print("Wire.Close - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
722
728
|
return None
|
723
729
|
if Wire.IsClosed(wire):
|
@@ -757,14 +763,14 @@ class Wire(Topology):
|
|
757
763
|
|
758
764
|
Parameters
|
759
765
|
----------
|
760
|
-
topology :
|
766
|
+
topology : topologic_core.Topology
|
761
767
|
The input topology.
|
762
768
|
tolerance : float , optional
|
763
769
|
The desired tolerance. The default is 0.0001.
|
764
770
|
|
765
771
|
Returns
|
766
772
|
-------
|
767
|
-
|
773
|
+
topologic_core.Wire
|
768
774
|
The convex hull of the input topology.
|
769
775
|
|
770
776
|
"""
|
@@ -863,7 +869,7 @@ class Wire(Topology):
|
|
863
869
|
|
864
870
|
f = None
|
865
871
|
# Create a sample face and flatten
|
866
|
-
while not
|
872
|
+
while not Topology.IsInstance(f, "Face"):
|
867
873
|
vertices = Topology.SubTopologies(topology=topology, subTopologyType="vertex")
|
868
874
|
v = sample(vertices, 3)
|
869
875
|
w = Wire.ByVertices(v)
|
@@ -885,13 +891,13 @@ class Wire(Topology):
|
|
885
891
|
return ch
|
886
892
|
|
887
893
|
@staticmethod
|
888
|
-
def Cycles(wire
|
894
|
+
def Cycles(wire, maxVertices: int = 4, tolerance: float = 0.0001) -> list:
|
889
895
|
"""
|
890
896
|
Returns the closed circuits of wires found within the input wire.
|
891
897
|
|
892
898
|
Parameters
|
893
899
|
----------
|
894
|
-
wire :
|
900
|
+
wire : topologic_core.Wire
|
895
901
|
The input wire.
|
896
902
|
maxVertices : int , optional
|
897
903
|
The maximum number of vertices of the circuits to be searched. The default is 4.
|
@@ -1003,13 +1009,13 @@ class Wire(Topology):
|
|
1003
1009
|
return resultWires
|
1004
1010
|
|
1005
1011
|
@staticmethod
|
1006
|
-
def Edges(wire
|
1012
|
+
def Edges(wire) -> list:
|
1007
1013
|
"""
|
1008
1014
|
Returns the edges of the input wire.
|
1009
1015
|
|
1010
1016
|
Parameters
|
1011
1017
|
----------
|
1012
|
-
wire :
|
1018
|
+
wire : topologic_core.Wire
|
1013
1019
|
The input wire.
|
1014
1020
|
|
1015
1021
|
Returns
|
@@ -1018,20 +1024,20 @@ class Wire(Topology):
|
|
1018
1024
|
The list of edges.
|
1019
1025
|
|
1020
1026
|
"""
|
1021
|
-
if not
|
1027
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1022
1028
|
return None
|
1023
1029
|
edges = []
|
1024
1030
|
_ = wire.Edges(None, edges)
|
1025
1031
|
return edges
|
1026
1032
|
|
1027
1033
|
@staticmethod
|
1028
|
-
def Einstein(origin
|
1034
|
+
def Einstein(origin= None, radius: float = 0.5, direction: list = [0, 0, 1], placement: str = "center"):
|
1029
1035
|
"""
|
1030
1036
|
Creates an aperiodic monotile, also called an 'einstein' tile (meaning one tile in German, not the name of the famous physist). See https://arxiv.org/abs/2303.10798
|
1031
1037
|
|
1032
1038
|
Parameters
|
1033
1039
|
----------
|
1034
|
-
origin :
|
1040
|
+
origin : topologic_core.Vertex , optional
|
1035
1041
|
The location of the origin of the tile. The default is None which results in the tiles first vertex being placed at (0, 0, 0).
|
1036
1042
|
radius : float , optional
|
1037
1043
|
The radius of the hexagon determining the size of the tile. The default is 0.5.
|
@@ -1077,13 +1083,13 @@ class Wire(Topology):
|
|
1077
1083
|
return einstein
|
1078
1084
|
|
1079
1085
|
@staticmethod
|
1080
|
-
def Ellipse(origin
|
1086
|
+
def Ellipse(origin= None, inputMode: int = 1, width: float = 2.0, length: float = 1.0, focalLength: float = 0.866025, eccentricity: float = 0.866025, majorAxisLength: float = 1.0, minorAxisLength: float = 0.5, sides: float = 32, fromAngle: float = 0.0, toAngle: float = 360.0, close: bool = True, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
1081
1087
|
"""
|
1082
1088
|
Creates an ellipse and returns all its geometry and parameters.
|
1083
1089
|
|
1084
1090
|
Parameters
|
1085
1091
|
----------
|
1086
|
-
origin :
|
1092
|
+
origin : topologic_core.Vertex , optional
|
1087
1093
|
The location of the origin of the ellipse. The default is None which results in the ellipse being placed at (0, 0, 0).
|
1088
1094
|
inputMode : int , optional
|
1089
1095
|
The method by wich the ellipse is defined. The default is 1.
|
@@ -1121,7 +1127,7 @@ class Wire(Topology):
|
|
1121
1127
|
|
1122
1128
|
Returns
|
1123
1129
|
-------
|
1124
|
-
|
1130
|
+
topologic_core.Wire
|
1125
1131
|
The created ellipse
|
1126
1132
|
|
1127
1133
|
"""
|
@@ -1129,13 +1135,13 @@ class Wire(Topology):
|
|
1129
1135
|
return ellipseAll["ellipse"]
|
1130
1136
|
|
1131
1137
|
@staticmethod
|
1132
|
-
def EllipseAll(origin
|
1138
|
+
def EllipseAll(origin= None, inputMode: int = 1, width: float = 2.0, length: float = 1.0, focalLength: float = 0.866025, eccentricity: float = 0.866025, majorAxisLength: float = 1.0, minorAxisLength: float = 0.5, sides: int = 32, fromAngle: float = 0.0, toAngle: float = 360.0, close: bool = True, direction: list = [0, 0, 1], placement: str ="center", tolerance: float = 0.0001):
|
1133
1139
|
"""
|
1134
1140
|
Creates an ellipse and returns all its geometry and parameters.
|
1135
1141
|
|
1136
1142
|
Parameters
|
1137
1143
|
----------
|
1138
|
-
origin :
|
1144
|
+
origin : topologic_core.Vertex , optional
|
1139
1145
|
The location of the origin of the ellipse. The default is None which results in the ellipse being placed at (0, 0, 0).
|
1140
1146
|
inputMode : int , optional
|
1141
1147
|
The method by wich the ellipse is defined. The default is 1.
|
@@ -1175,8 +1181,8 @@ class Wire(Topology):
|
|
1175
1181
|
-------
|
1176
1182
|
dictionary
|
1177
1183
|
A dictionary with the following keys and values:
|
1178
|
-
1. "ellipse" : The ellipse (
|
1179
|
-
2. "foci" : The two focal points (
|
1184
|
+
1. "ellipse" : The ellipse (topologic_core.Wire)
|
1185
|
+
2. "foci" : The two focal points (topologic_core.Cluster containing two vertices)
|
1180
1186
|
3. "a" : The major axis length
|
1181
1187
|
4. "b" : The minor axis length
|
1182
1188
|
5. "c" : The focal length
|
@@ -1185,11 +1191,13 @@ class Wire(Topology):
|
|
1185
1191
|
8. "length" : The length
|
1186
1192
|
|
1187
1193
|
"""
|
1194
|
+
from topologicpy.Vertex import Vertex
|
1195
|
+
from topologicpy.Cluster import Cluster
|
1188
1196
|
from topologicpy.Topology import Topology
|
1189
1197
|
|
1190
1198
|
if not origin:
|
1191
|
-
origin =
|
1192
|
-
if not
|
1199
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
1200
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1193
1201
|
return None
|
1194
1202
|
if inputMode not in [1, 2, 3, 4]:
|
1195
1203
|
return None
|
@@ -1256,7 +1264,7 @@ class Wire(Topology):
|
|
1256
1264
|
z = origin.Z()
|
1257
1265
|
xList.append(x)
|
1258
1266
|
yList.append(y)
|
1259
|
-
baseV.append(
|
1267
|
+
baseV.append(Vertex.ByCoordinates(x, y, z))
|
1260
1268
|
|
1261
1269
|
if angleRange == 360:
|
1262
1270
|
baseWire = Wire.ByVertices(baseV[::-1], close=False) #reversing the list so that the normal points up in Blender
|
@@ -1267,9 +1275,9 @@ class Wire(Topology):
|
|
1267
1275
|
baseWire = Topology.Translate(baseWire, a, b, 0)
|
1268
1276
|
baseWire = Topology.Orient(baseWire, origin=origin, dirA=[0, 0, 1], dirB=direction)
|
1269
1277
|
# Create a Cluster of the two foci
|
1270
|
-
v1 =
|
1271
|
-
v2 =
|
1272
|
-
foci =
|
1278
|
+
v1 = Vertex.ByCoordinates(c+origin.X(), 0+origin.Y(), 0)
|
1279
|
+
v2 = Vertex.ByCoordinates(-c+origin.X(), 0+origin.Y(), 0)
|
1280
|
+
foci = Cluster.ByTopologies([v1, v2])
|
1273
1281
|
if placement.lower() == "lowerleft":
|
1274
1282
|
foci = Topology.Translate(foci, a, b, 0)
|
1275
1283
|
foci = Topology.Orient(foci, origin=origin, dirA=[0, 0, 1], dirB=direction)
|
@@ -1285,7 +1293,7 @@ class Wire(Topology):
|
|
1285
1293
|
return d
|
1286
1294
|
|
1287
1295
|
@staticmethod
|
1288
|
-
def EndVertex(wire
|
1296
|
+
def EndVertex(wire):
|
1289
1297
|
"""
|
1290
1298
|
Returns the end vertex of the input wire. The wire must be manifold and open.
|
1291
1299
|
|
@@ -1294,13 +1302,13 @@ class Wire(Topology):
|
|
1294
1302
|
return ev
|
1295
1303
|
|
1296
1304
|
@staticmethod
|
1297
|
-
def ExteriorAngles(wire
|
1305
|
+
def ExteriorAngles(wire, tolerance: float = 0.0001, mantissa: int = 6) -> list:
|
1298
1306
|
"""
|
1299
1307
|
Returns the exterior angles of the input wire in degrees. The wire must be planar, manifold, and closed.
|
1300
1308
|
|
1301
1309
|
Parameters
|
1302
1310
|
----------
|
1303
|
-
wire :
|
1311
|
+
wire : topologic_core.Wire
|
1304
1312
|
The input wire.
|
1305
1313
|
tolerance : float , optional
|
1306
1314
|
The desired tolerance. The default is 0.0001.
|
@@ -1313,7 +1321,7 @@ class Wire(Topology):
|
|
1313
1321
|
The list of exterior angles.
|
1314
1322
|
"""
|
1315
1323
|
|
1316
|
-
if not
|
1324
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1317
1325
|
print("Wire.InteriorAngles - Error: The input wire parameter is not a valid wire. Returning None")
|
1318
1326
|
return None
|
1319
1327
|
if not Wire.IsManifold(wire):
|
@@ -1328,13 +1336,146 @@ class Wire(Topology):
|
|
1328
1336
|
return exterior_angles
|
1329
1337
|
|
1330
1338
|
@staticmethod
|
1331
|
-
def
|
1339
|
+
def Fillet(wire, radius: float = 0, radiusKey: str = None, tolerance: float = 0.0001, silent: bool = False):
|
1340
|
+
"""
|
1341
|
+
Fillets (rounds) the interior and exterior corners of the input wire given the input radius. See https://en.wikipedia.org/wiki/Fillet_(mechanics)
|
1342
|
+
|
1343
|
+
Parameters
|
1344
|
+
----------
|
1345
|
+
wire : topologic_core.Wire
|
1346
|
+
The input wire.
|
1347
|
+
radius : float
|
1348
|
+
The desired radius of the fillet.
|
1349
|
+
radiusKey : str , optional
|
1350
|
+
If specified, the dictionary of the vertices will be queried for this key to specify the desired fillet radius. The default is None.
|
1351
|
+
tolerance : float , optional
|
1352
|
+
The desired tolerance. The default is 0.0001.
|
1353
|
+
silent : bool , optional
|
1354
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
1355
|
+
|
1356
|
+
Returns
|
1357
|
+
-------
|
1358
|
+
topologic_core.Wire
|
1359
|
+
The filleted wire.
|
1360
|
+
|
1361
|
+
"""
|
1362
|
+
def start_from(edge, v):
|
1363
|
+
sv = Edge.StartVertex(edge)
|
1364
|
+
ev = Edge.EndVertex(edge)
|
1365
|
+
if Vertex.Distance(v, ev) < Vertex.Distance(v, sv):
|
1366
|
+
return Edge.Reverse(edge)
|
1367
|
+
return edge
|
1368
|
+
|
1369
|
+
def compute_kite_edges(alpha, r):
|
1370
|
+
# Convert angle to radians
|
1371
|
+
alpha = math.radians(alpha) *0.5
|
1372
|
+
h = r/math.cos(alpha)
|
1373
|
+
a = math.sqrt(h*h - r*r)
|
1374
|
+
return [a,h]
|
1375
|
+
|
1376
|
+
import math
|
1377
|
+
from topologicpy.Vertex import Vertex
|
1378
|
+
from topologicpy.Edge import Edge
|
1379
|
+
from topologicpy.Wire import Wire
|
1380
|
+
from topologicpy.Face import Face
|
1381
|
+
from topologicpy.Cluster import Cluster
|
1382
|
+
from topologicpy.Topology import Topology
|
1383
|
+
from topologicpy.Vector import Vector
|
1384
|
+
from topologicpy.Dictionary import Dictionary
|
1385
|
+
|
1386
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1387
|
+
if not silent:
|
1388
|
+
print("Wire.Fillet - Error: The input wire parameter is not a valid wire. Returning None.")
|
1389
|
+
return None
|
1390
|
+
if not Wire.IsManifold(wire):
|
1391
|
+
if not silent:
|
1392
|
+
print("Wire.Fillet - Error: The input wire parameter is not manifold. Returning None.")
|
1393
|
+
return None
|
1394
|
+
if not Topology.IsPlanar(wire):
|
1395
|
+
if not silent:
|
1396
|
+
print("Wire.Fillet - Error: The input wire parameter is not planar. Returning None.")
|
1397
|
+
return None
|
1398
|
+
|
1399
|
+
orig_radius = radius
|
1400
|
+
f = Face.BoundingRectangle(wire, tolerance=tolerance)
|
1401
|
+
normal = Face.Normal(f)
|
1402
|
+
flat_wire = Topology.Flatten(wire, origin=Vertex.Origin(), direction=normal)
|
1403
|
+
vertices = Topology.Vertices(flat_wire)
|
1404
|
+
final_vertices = []
|
1405
|
+
fillets = []
|
1406
|
+
for v in vertices:
|
1407
|
+
radius = orig_radius
|
1408
|
+
edges = Topology.SuperTopologies(v, flat_wire, topologyType="edge")
|
1409
|
+
if len(edges) == 2:
|
1410
|
+
for edge in edges:
|
1411
|
+
ev = Edge.EndVertex(edge)
|
1412
|
+
if Vertex.Distance(v, ev) < tolerance:
|
1413
|
+
edge0 = edge
|
1414
|
+
else:
|
1415
|
+
edge1 = edge
|
1416
|
+
ang = Edge.Angle(edge0, edge1)
|
1417
|
+
e1 = start_from(edge0, v)
|
1418
|
+
e2 = start_from(edge1, v)
|
1419
|
+
|
1420
|
+
dir1 = Edge.Direction(e1)
|
1421
|
+
dir2 = Edge.Direction(e2)
|
1422
|
+
if Vector.IsParallel(dir1, dir2) or Vector.IsAntiParallel(dir1, dir2):
|
1423
|
+
pass
|
1424
|
+
else:
|
1425
|
+
if isinstance(radiusKey, str):
|
1426
|
+
d = Topology.Dictionary(v)
|
1427
|
+
if Topology.IsInstance(d, "Dictionary"):
|
1428
|
+
v_radius = Dictionary.ValueAtKey(d, radiusKey)
|
1429
|
+
if isinstance(v_radius, float) or isinstance(v_radius, int):
|
1430
|
+
if v_radius >= 0:
|
1431
|
+
radius = v_radius
|
1432
|
+
if radius > 0:
|
1433
|
+
dir_bisector = Vector.Bisect(dir1,dir2)
|
1434
|
+
a, h = compute_kite_edges(ang, radius)
|
1435
|
+
if a <= Edge.Length(e1) and a <= Edge.Length(e2):
|
1436
|
+
v1 = Topology.TranslateByDirectionDistance(v, dir1, a)
|
1437
|
+
center = Topology.TranslateByDirectionDistance(v, dir_bisector, h)
|
1438
|
+
v2 = Topology.TranslateByDirectionDistance(v, dir2, a)
|
1439
|
+
r1 = Edge.ByVertices(center, v1)
|
1440
|
+
dir1 = Edge.Direction(r1)
|
1441
|
+
r2 = Edge.ByVertices(center, v2)
|
1442
|
+
dir2 = Edge.Direction(r2)
|
1443
|
+
compass1 = Vector.CompassAngle(Vector.East(), dir1)*-1
|
1444
|
+
compass2 = Vector.CompassAngle(Vector.East(), dir2)*-1
|
1445
|
+
if compass2 < compass1:
|
1446
|
+
temp = compass2
|
1447
|
+
compass2 = compass1
|
1448
|
+
compass1 = temp
|
1449
|
+
w1 = Wire.Circle(origin=center, radius=radius, fromAngle=compass1, toAngle=compass2, close=False)
|
1450
|
+
w2 = Wire.Circle(origin=center, radius=radius, fromAngle=compass2, toAngle=compass1, close=False)
|
1451
|
+
if Wire.Length(w1) < Wire.Length(w2):
|
1452
|
+
fillet = w1
|
1453
|
+
else:
|
1454
|
+
fillet = w2
|
1455
|
+
f_sv = Wire.StartVertex(fillet)
|
1456
|
+
if Vertex.Distance(f_sv, edge1) < Vertex.Distance(f_sv, edge0):
|
1457
|
+
fillet = Wire.Reverse(fillet)
|
1458
|
+
final_vertices += Topology.Vertices(fillet)
|
1459
|
+
else:
|
1460
|
+
if not silent:
|
1461
|
+
print("Wire.Fillet - Error: The specified fillet radius is too large to be applied. Skipping.")
|
1462
|
+
else:
|
1463
|
+
final_vertices.append(v)
|
1464
|
+
else:
|
1465
|
+
final_vertices.append(v)
|
1466
|
+
flat_wire = Wire.ByVertices(final_vertices, close=Wire.IsClosed(wire))
|
1467
|
+
# Unflatten the wire
|
1468
|
+
return_wire = Topology.Unflatten(flat_wire, origin=Vertex.Origin(), direction=normal)
|
1469
|
+
return return_wire
|
1470
|
+
|
1471
|
+
@staticmethod
|
1472
|
+
def InteriorAngles(wire, tolerance: float = 0.0001, mantissa: int = 6) -> list:
|
1332
1473
|
"""
|
1333
1474
|
Returns the interior angles of the input wire in degrees. The wire must be planar, manifold, and closed.
|
1334
1475
|
|
1335
1476
|
Parameters
|
1336
1477
|
----------
|
1337
|
-
wire :
|
1478
|
+
wire : topologic_core.Wire
|
1338
1479
|
The input wire.
|
1339
1480
|
tolerance : float , optional
|
1340
1481
|
The desired tolerance. The default is 0.0001.
|
@@ -1353,7 +1494,7 @@ class Wire(Topology):
|
|
1353
1494
|
from topologicpy.Vector import Vector
|
1354
1495
|
from topologicpy.Dictionary import Dictionary
|
1355
1496
|
|
1356
|
-
if not
|
1497
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1357
1498
|
print("Wire.InteriorAngles - Error: The input wire parameter is not a valid wire. Returning None")
|
1358
1499
|
return None
|
1359
1500
|
if not Wire.IsManifold(wire):
|
@@ -1381,15 +1522,15 @@ class Wire(Topology):
|
|
1381
1522
|
return angles
|
1382
1523
|
|
1383
1524
|
@staticmethod
|
1384
|
-
def Interpolate(wires: list, n: int = 5, outputType: str = "default", mapping: str = "default", tolerance: float = 0.0001)
|
1525
|
+
def Interpolate(wires: list, n: int = 5, outputType: str = "default", mapping: str = "default", tolerance: float = 0.0001):
|
1385
1526
|
"""
|
1386
1527
|
Creates *n* number of wires that interpolate between wireA and wireB.
|
1387
1528
|
|
1388
1529
|
Parameters
|
1389
1530
|
----------
|
1390
|
-
wireA :
|
1531
|
+
wireA : topologic_core.Wire
|
1391
1532
|
The first input wire.
|
1392
|
-
wireB :
|
1533
|
+
wireB : topologic_core.Wire
|
1393
1534
|
The second input wire.
|
1394
1535
|
n : int , optional
|
1395
1536
|
The number of intermediate wires to create. The default is 5.
|
@@ -1407,8 +1548,8 @@ class Wire(Topology):
|
|
1407
1548
|
|
1408
1549
|
Returns
|
1409
1550
|
-------
|
1410
|
-
|
1411
|
-
The created interpolated wires as well as the input wires. The return type can be a
|
1551
|
+
tTopology
|
1552
|
+
The created interpolated wires as well as the input wires. The return type can be a topologic_core.Cluster or a topologic_core.Wire based on options.
|
1412
1553
|
|
1413
1554
|
"""
|
1414
1555
|
|
@@ -1502,35 +1643,35 @@ class Wire(Topology):
|
|
1502
1643
|
return Topology.SelfMerge(Cluster.ByTopologies(finalWires+ridges), tolerance=tolerance)
|
1503
1644
|
|
1504
1645
|
@staticmethod
|
1505
|
-
def Invert(wire
|
1646
|
+
def Invert(wire):
|
1506
1647
|
"""
|
1507
1648
|
Creates a wire that is an inverse (mirror) of the input wire.
|
1508
1649
|
|
1509
1650
|
Parameters
|
1510
1651
|
----------
|
1511
|
-
wire :
|
1652
|
+
wire : topologic_core.Wire
|
1512
1653
|
The input wire.
|
1513
1654
|
|
1514
1655
|
Returns
|
1515
1656
|
-------
|
1516
|
-
|
1657
|
+
topologic_core.Wire
|
1517
1658
|
The inverted wire.
|
1518
1659
|
|
1519
1660
|
"""
|
1520
|
-
if not
|
1661
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1521
1662
|
return None
|
1522
1663
|
vertices = Wire.Vertices(wire)
|
1523
1664
|
reversed_vertices = vertices[::-1]
|
1524
1665
|
return Wire.ByVertices(reversed_vertices)
|
1525
1666
|
|
1526
1667
|
@staticmethod
|
1527
|
-
def IsClosed(wire
|
1668
|
+
def IsClosed(wire) -> bool:
|
1528
1669
|
"""
|
1529
1670
|
Returns True if the input wire is closed. Returns False otherwise.
|
1530
1671
|
|
1531
1672
|
Parameters
|
1532
1673
|
----------
|
1533
|
-
wire :
|
1674
|
+
wire : topologic_core.Wire
|
1534
1675
|
The input wire.
|
1535
1676
|
|
1536
1677
|
Returns
|
@@ -1541,18 +1682,18 @@ class Wire(Topology):
|
|
1541
1682
|
"""
|
1542
1683
|
status = None
|
1543
1684
|
if wire:
|
1544
|
-
if
|
1685
|
+
if Topology.IsInstance(wire, "Wire"):
|
1545
1686
|
status = wire.IsClosed()
|
1546
1687
|
return status
|
1547
1688
|
|
1548
1689
|
@staticmethod
|
1549
|
-
def IsManifold(wire
|
1690
|
+
def IsManifold(wire) -> bool:
|
1550
1691
|
"""
|
1551
1692
|
Returns True if the input wire is manifold. Returns False otherwise. A manifold wire is one where its vertices have a degree of 1 or 2.
|
1552
1693
|
|
1553
1694
|
Parameters
|
1554
1695
|
----------
|
1555
|
-
wire :
|
1696
|
+
wire : topologic_core.Wire
|
1556
1697
|
The input wire.
|
1557
1698
|
|
1558
1699
|
Returns
|
@@ -1562,7 +1703,7 @@ class Wire(Topology):
|
|
1562
1703
|
"""
|
1563
1704
|
|
1564
1705
|
from topologicpy.Vertex import Vertex
|
1565
|
-
if not
|
1706
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1566
1707
|
print("Wire.IsManifold - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
1567
1708
|
return None
|
1568
1709
|
|
@@ -1571,131 +1712,17 @@ class Wire(Topology):
|
|
1571
1712
|
if Vertex.Degree(v, hostTopology=wire) > 2:
|
1572
1713
|
return False
|
1573
1714
|
return True
|
1574
|
-
|
1575
|
-
@staticmethod
|
1576
|
-
def Isovist(wire: topologic.Wire, viewPoint: topologic.Vertex, obstaclesCluster: topologic.Cluster, tolerance: float = 0.0001) -> list:
|
1577
|
-
"""
|
1578
|
-
Returns a list of faces representing the isovist projection from the input viewpoint.
|
1579
|
-
|
1580
|
-
Parameters
|
1581
|
-
----------
|
1582
|
-
wire : topologic.Wire
|
1583
|
-
The wire representing the external boundary (border) of the isovist.
|
1584
|
-
viewPoint : topologic.Vertex
|
1585
|
-
The vertex representing the location of the viewpoint of the isovist.
|
1586
|
-
obstaclesCluster : topologic.Cluster
|
1587
|
-
A cluster of wires representing the obstacles within the externalBoundary.
|
1588
|
-
tolerance : float , optional:
|
1589
|
-
The desired tolerance. The default is 0.0001.
|
1590
|
-
|
1591
|
-
Returns
|
1592
|
-
-------
|
1593
|
-
list
|
1594
|
-
A list of faces representing the isovist projection from the input viewpoint.
|
1595
|
-
|
1596
|
-
"""
|
1597
|
-
from topologicpy.Vertex import Vertex
|
1598
|
-
from topologicpy.Edge import Edge
|
1599
|
-
from topologicpy.Cluster import Cluster
|
1600
|
-
from topologicpy.Topology import Topology
|
1601
|
-
|
1602
|
-
|
1603
|
-
def vertexPartofFace(vertex, face, tolerance):
|
1604
|
-
vertices = []
|
1605
|
-
_ = face.Vertices(None, vertices)
|
1606
|
-
for v in vertices:
|
1607
|
-
if Vertex.Distance(vertex, v) < tolerance:
|
1608
|
-
return True
|
1609
|
-
return False
|
1610
|
-
|
1611
|
-
internalBoundaries = []
|
1612
|
-
_ = obstaclesCluster.Wires(None, internalBoundaries)
|
1613
|
-
internalVertices = []
|
1614
|
-
_ = obstaclesCluster.Vertices(None, internalVertices)
|
1615
|
-
# 1. Create a Face with external and internal boundaries
|
1616
|
-
face = topologic.Face.ByExternalInternalBoundaries(wire, internalBoundaries, False)
|
1617
|
-
# 2. Draw Rays from viewpoint through each Vertex of the obstacles extending to the External Boundary
|
1618
|
-
# 2.1 Get the Edges and Vertices of the External Boundary
|
1619
|
-
exBoundaryEdges = []
|
1620
|
-
_ = wire.Edges(None, exBoundaryEdges)
|
1621
|
-
exBoundaryVertices = []
|
1622
|
-
_ = wire.Vertices(None, exBoundaryVertices)
|
1623
|
-
testTopologies = exBoundaryEdges+exBoundaryVertices
|
1624
|
-
# 1.2 Find the maximum distance from the viewpoint to the edges and vertices of the external boundary
|
1625
|
-
distances = []
|
1626
|
-
for x in testTopologies:
|
1627
|
-
distances.append(Vertex.Distance(viewPoint, x))
|
1628
|
-
maxDistance = max(distances)*1.5
|
1629
|
-
# 1.3 Shoot rays and intersect with the external boundary
|
1630
|
-
rays = []
|
1631
|
-
for aVertex in (internalVertices+exBoundaryVertices):
|
1632
|
-
d = Vertex.Distance(viewPoint, aVertex)
|
1633
|
-
if d > tolerance:
|
1634
|
-
scaleFactor = maxDistance/d
|
1635
|
-
newV = Topology.Scale(aVertex, viewPoint, scaleFactor, scaleFactor, scaleFactor)
|
1636
|
-
try:
|
1637
|
-
ray = Edge.ByStartVertexEndVertex(viewPoint, newV, tolerance=tolerance, silent=True)
|
1638
|
-
topologyC = ray.Intersect(wire, False)
|
1639
|
-
vertices = []
|
1640
|
-
_ = topologyC.Vertices(None, vertices)
|
1641
|
-
if topologyC:
|
1642
|
-
try:
|
1643
|
-
rays.append(Edge.ByStartVertexEndVertex(viewPoint, vertices[0], tolerance=tolerance, silent=True))
|
1644
|
-
except:
|
1645
|
-
pass
|
1646
|
-
try:
|
1647
|
-
rays.append(Edge.ByStartVertexEndVertex(viewPoint, aVertex, tolerance=tolerance, silent=True))
|
1648
|
-
except:
|
1649
|
-
pass
|
1650
|
-
except:
|
1651
|
-
pass
|
1652
|
-
rayEdges = []
|
1653
|
-
for r in rays:
|
1654
|
-
a = r.Difference(obstaclesCluster, False)
|
1655
|
-
if a:
|
1656
|
-
edges = []
|
1657
|
-
_ = a.Edges(None, edges)
|
1658
|
-
w = None
|
1659
|
-
try:
|
1660
|
-
w = Wire.ByEdges(edges, tolerance=tolerance)
|
1661
|
-
rayEdges = rayEdges + edges
|
1662
|
-
except:
|
1663
|
-
c = Cluster.ByTopologies(edges)
|
1664
|
-
c = Topology.SelfMerge(c, tolerance=tolerance)
|
1665
|
-
wires = []
|
1666
|
-
_ = c.Wires(None, wires)
|
1667
|
-
if len(wires) > 0:
|
1668
|
-
edges = []
|
1669
|
-
_ = wires[0].Edges(None, edges)
|
1670
|
-
rayEdges = rayEdges + edges
|
1671
|
-
else:
|
1672
|
-
for e in edges:
|
1673
|
-
vertices = []
|
1674
|
-
e.Vertices(None, vertices)
|
1675
|
-
for v in vertices:
|
1676
|
-
if Vertex.Distance(viewPoint, v) < tolerance:
|
1677
|
-
rayEdges.append(e)
|
1678
|
-
rayCluster = Cluster.ByTopologies(rayEdges)
|
1679
|
-
#return rayCluster
|
1680
|
-
shell = face.Slice(rayCluster, False)
|
1681
|
-
faces = []
|
1682
|
-
_ = shell.Faces(None, faces)
|
1683
|
-
finalFaces = []
|
1684
|
-
for aFace in faces:
|
1685
|
-
if vertexPartofFace(viewPoint, aFace, 0.001):
|
1686
|
-
finalFaces.append(aFace)
|
1687
|
-
return finalFaces
|
1688
1715
|
|
1689
1716
|
@staticmethod
|
1690
|
-
def IsSimilar(wireA
|
1717
|
+
def IsSimilar(wireA, wireB, angTolerance: float = 0.1, tolerance: float = 0.0001) -> bool:
|
1691
1718
|
"""
|
1692
1719
|
Returns True if the input wires are similar. Returns False otherwise. The wires must be closed.
|
1693
1720
|
|
1694
1721
|
Parameters
|
1695
1722
|
----------
|
1696
|
-
wireA :
|
1723
|
+
wireA : topologic_core.Wire
|
1697
1724
|
The first input wire.
|
1698
|
-
wireB :
|
1725
|
+
wireB : topologic_core.Wire
|
1699
1726
|
The second input wire.
|
1700
1727
|
angTolerance : float , optional
|
1701
1728
|
The desired angular tolerance. The default is 0.1.
|
@@ -1708,6 +1735,8 @@ class Wire(Topology):
|
|
1708
1735
|
True if the two input wires are similar. False otherwise.
|
1709
1736
|
|
1710
1737
|
"""
|
1738
|
+
from topologicpy.Vertex import Vertex
|
1739
|
+
from topologicpy.Edge import Edge
|
1711
1740
|
|
1712
1741
|
def isCyclicallyEquivalent(u, v, lengthTolerance, angleTolerance):
|
1713
1742
|
n, i, j = len(u), 0, 0
|
@@ -1733,7 +1762,7 @@ class Wire(Topology):
|
|
1733
1762
|
a = e1.EndVertex().X() - e1.StartVertex().X()
|
1734
1763
|
b = e1.EndVertex().Y() - e1.StartVertex().Y()
|
1735
1764
|
c = e1.EndVertex().Z() - e1.StartVertex().Z()
|
1736
|
-
d =
|
1765
|
+
d = Vertex.Distance(e1.EndVertex(), e2.StartVertex())
|
1737
1766
|
if d <= tolerance:
|
1738
1767
|
d = e2.StartVertex().X() - e2.EndVertex().X()
|
1739
1768
|
e = e2.StartVertex().Y() - e2.EndVertex().Y()
|
@@ -1760,7 +1789,7 @@ class Wire(Topology):
|
|
1760
1789
|
angles = getInteriorAngles(edges, tolerance)
|
1761
1790
|
lengths = []
|
1762
1791
|
for anEdge in edges:
|
1763
|
-
lengths.append(
|
1792
|
+
lengths.append(Edge.Length(anEdge))
|
1764
1793
|
minLength = min(lengths)
|
1765
1794
|
normalisedLengths = []
|
1766
1795
|
for aLength in lengths:
|
@@ -1786,13 +1815,13 @@ class Wire(Topology):
|
|
1786
1815
|
return False
|
1787
1816
|
|
1788
1817
|
@staticmethod
|
1789
|
-
def Length(wire
|
1818
|
+
def Length(wire, mantissa: int = 6) -> float:
|
1790
1819
|
"""
|
1791
1820
|
Returns the length of the input wire.
|
1792
1821
|
|
1793
1822
|
Parameters
|
1794
1823
|
----------
|
1795
|
-
wire :
|
1824
|
+
wire : topologic_core.Wire
|
1796
1825
|
The input wire.
|
1797
1826
|
mantissa : int , optional
|
1798
1827
|
The desired length of the mantissa. The default is 6.
|
@@ -1803,9 +1832,10 @@ class Wire(Topology):
|
|
1803
1832
|
The length of the input wire. Test
|
1804
1833
|
|
1805
1834
|
"""
|
1835
|
+
from topologicpy.Edge import Edge
|
1806
1836
|
if not wire:
|
1807
1837
|
return None
|
1808
|
-
if not
|
1838
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1809
1839
|
return None
|
1810
1840
|
totalLength = None
|
1811
1841
|
try:
|
@@ -1813,20 +1843,20 @@ class Wire(Topology):
|
|
1813
1843
|
_ = wire.Edges(None, edges)
|
1814
1844
|
totalLength = 0
|
1815
1845
|
for anEdge in edges:
|
1816
|
-
totalLength = totalLength +
|
1846
|
+
totalLength = totalLength + Edge.Length(anEdge)
|
1817
1847
|
totalLength = round(totalLength, mantissa)
|
1818
1848
|
except:
|
1819
1849
|
totalLength = None
|
1820
1850
|
return totalLength
|
1821
1851
|
|
1822
1852
|
@staticmethod
|
1823
|
-
def Line(origin
|
1853
|
+
def Line(origin= None, length: float = 1, direction: list = [1, 0, 0], sides: int = 2, placement: str ="center"):
|
1824
1854
|
"""
|
1825
1855
|
Creates a straight line wire using the input parameters.
|
1826
1856
|
|
1827
1857
|
Parameters
|
1828
1858
|
----------
|
1829
|
-
origin :
|
1859
|
+
origin : topologic_core.Vertex , optional
|
1830
1860
|
The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0).
|
1831
1861
|
length : float , optional
|
1832
1862
|
The desired length of the edge. The default is 1.0.
|
@@ -1843,7 +1873,7 @@ class Wire(Topology):
|
|
1843
1873
|
|
1844
1874
|
Returns
|
1845
1875
|
-------
|
1846
|
-
|
1876
|
+
topologic_core.Edge
|
1847
1877
|
The created edge
|
1848
1878
|
"""
|
1849
1879
|
|
@@ -1854,7 +1884,7 @@ class Wire(Topology):
|
|
1854
1884
|
|
1855
1885
|
if origin == None:
|
1856
1886
|
origin = Vertex.Origin()
|
1857
|
-
if not
|
1887
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1858
1888
|
print("Wire.Line - Error: The input origin is not a valid vertex. Returning None.")
|
1859
1889
|
return None
|
1860
1890
|
if length <= 0:
|
@@ -1884,26 +1914,26 @@ class Wire(Topology):
|
|
1884
1914
|
|
1885
1915
|
Parameters
|
1886
1916
|
----------
|
1887
|
-
wire :
|
1917
|
+
wire : topologic_core.Wire
|
1888
1918
|
The input wire.
|
1889
|
-
vertexA :
|
1919
|
+
vertexA : topologic_core.Vertex
|
1890
1920
|
The desired start vertex of the wire.
|
1891
1921
|
tolerance : float, optional
|
1892
1922
|
The desired tolerance. The default is 0.0001.
|
1893
1923
|
|
1894
1924
|
Returns
|
1895
1925
|
-------
|
1896
|
-
|
1926
|
+
topologic_core.Wire
|
1897
1927
|
The oriented wire.
|
1898
1928
|
|
1899
1929
|
"""
|
1900
1930
|
from topologicpy.Vertex import Vertex
|
1901
1931
|
from topologicpy.Edge import Edge
|
1902
1932
|
|
1903
|
-
if not
|
1933
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1904
1934
|
print("Wire.OrientEdges - Error: The input wire parameter is not a valid wire. Returning None.")
|
1905
1935
|
return None
|
1906
|
-
if not
|
1936
|
+
if not Topology.IsInstance(vertexA, "Vertex"):
|
1907
1937
|
print("Wire.OrientEdges - Error: The input vertexA parameter is not a valid vertex. Returning None.")
|
1908
1938
|
return None
|
1909
1939
|
if not Wire.IsManifold(wire):
|
@@ -1911,7 +1941,6 @@ class Wire(Topology):
|
|
1911
1941
|
return None
|
1912
1942
|
oriented_edges = []
|
1913
1943
|
remaining_edges = Topology.Edges(wire)
|
1914
|
-
|
1915
1944
|
current_vertex = vertexA
|
1916
1945
|
while remaining_edges:
|
1917
1946
|
next_edge = None
|
@@ -1937,24 +1966,24 @@ class Wire(Topology):
|
|
1937
1966
|
return Wire.ByVertices(vertices, close=Wire.IsClosed(wire))
|
1938
1967
|
|
1939
1968
|
@staticmethod
|
1940
|
-
def Planarize(wire
|
1969
|
+
def Planarize(wire, origin= None, mantissa: int = 6, tolerance: float = 0.0001):
|
1941
1970
|
"""
|
1942
1971
|
Returns a planarized version of the input wire.
|
1943
1972
|
|
1944
1973
|
Parameters
|
1945
1974
|
----------
|
1946
|
-
wire :
|
1975
|
+
wire : topologic_core.Wire
|
1947
1976
|
The input wire.
|
1948
1977
|
tolerance : float, optional
|
1949
1978
|
The desired tolerance. The default is 0.0001.
|
1950
|
-
origin :
|
1979
|
+
origin : topologic_core.Vertex , optional
|
1951
1980
|
The desired origin of the plane unto which the planar wire will be projected. If set to None, the centroid of the input wire will be chosen. The default is None.
|
1952
1981
|
mantissa : int , optional
|
1953
1982
|
The desired length of the mantissa. The default is 6.
|
1954
1983
|
|
1955
1984
|
Returns
|
1956
1985
|
-------
|
1957
|
-
|
1986
|
+
topologic_core.Wire
|
1958
1987
|
The planarized wire.
|
1959
1988
|
|
1960
1989
|
"""
|
@@ -1964,12 +1993,12 @@ class Wire(Topology):
|
|
1964
1993
|
from topologicpy.Cluster import Cluster
|
1965
1994
|
from topologicpy.Topology import Topology
|
1966
1995
|
|
1967
|
-
if not
|
1996
|
+
if not Topology.IsInstance(wire, "Wire"):
|
1968
1997
|
print("Wire.Planarize - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
1969
1998
|
return None
|
1970
1999
|
if origin == None:
|
1971
2000
|
origin = Vertex.Origin()
|
1972
|
-
if not
|
2001
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
1973
2002
|
print("Wire.Planarize - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
1974
2003
|
return None
|
1975
2004
|
|
@@ -1995,15 +2024,15 @@ class Wire(Topology):
|
|
1995
2024
|
return Topology.SelfMerge(Cluster.ByTopologies(new_edges), tolerance=tolerance)
|
1996
2025
|
|
1997
2026
|
@staticmethod
|
1998
|
-
def Project(wire
|
2027
|
+
def Project(wire, face, direction: list = None, mantissa: int = 6, tolerance: float = 0.0001):
|
1999
2028
|
"""
|
2000
2029
|
Creates a projection of the input wire unto the input face.
|
2001
2030
|
|
2002
2031
|
Parameters
|
2003
2032
|
----------
|
2004
|
-
wire :
|
2033
|
+
wire : topologic_core.Wire
|
2005
2034
|
The input wire.
|
2006
|
-
face :
|
2035
|
+
face : topologic_core.Face
|
2007
2036
|
The face unto which to project the input wire.
|
2008
2037
|
direction : list, optional
|
2009
2038
|
The vector representing the direction of the projection. If None, the reverse vector of the receiving face normal will be used. The default is None.
|
@@ -2014,20 +2043,21 @@ class Wire(Topology):
|
|
2014
2043
|
|
2015
2044
|
Returns
|
2016
2045
|
-------
|
2017
|
-
|
2046
|
+
topologic_core.Wire
|
2018
2047
|
The projected wire.
|
2019
2048
|
|
2020
2049
|
"""
|
2021
2050
|
from topologicpy.Vertex import Vertex
|
2022
2051
|
from topologicpy.Edge import Edge
|
2023
2052
|
from topologicpy.Face import Face
|
2053
|
+
from topologicpy.Topology import Topology
|
2024
2054
|
if not wire:
|
2025
2055
|
return None
|
2026
|
-
if not
|
2056
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2027
2057
|
return None
|
2028
2058
|
if not face:
|
2029
2059
|
return None
|
2030
|
-
if not
|
2060
|
+
if not Topology.IsInstance(face, "Face"):
|
2031
2061
|
return None
|
2032
2062
|
if not direction:
|
2033
2063
|
direction = -1*Face.NormalAtParameters(face, 0.5, 0.5, "XYZ", mantissa)
|
@@ -2037,10 +2067,10 @@ class Wire(Topology):
|
|
2037
2067
|
projected_edges = []
|
2038
2068
|
|
2039
2069
|
if large_face:
|
2040
|
-
if (
|
2070
|
+
if (Topology.Type(large_face) == Topology.TypeID("Face")):
|
2041
2071
|
for edge in edges:
|
2042
2072
|
if edge:
|
2043
|
-
if (
|
2073
|
+
if (Topology.Type(edge) == Topology.TypeID("Edge")):
|
2044
2074
|
sv = edge.StartVertex()
|
2045
2075
|
ev = edge.EndVertex()
|
2046
2076
|
|
@@ -2056,13 +2086,13 @@ class Wire(Topology):
|
|
2056
2086
|
return w
|
2057
2087
|
|
2058
2088
|
@staticmethod
|
2059
|
-
def Rectangle(origin
|
2089
|
+
def Rectangle(origin= None, width: float = 1.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", angTolerance: float = 0.1, tolerance: float = 0.0001):
|
2060
2090
|
"""
|
2061
2091
|
Creates a rectangle.
|
2062
2092
|
|
2063
2093
|
Parameters
|
2064
2094
|
----------
|
2065
|
-
origin :
|
2095
|
+
origin : topologic_core.Vertex , optional
|
2066
2096
|
The location of the origin of the rectangle. The default is None which results in the rectangle being placed at (0, 0, 0).
|
2067
2097
|
width : float , optional
|
2068
2098
|
The width of the rectangle. The default is 1.0.
|
@@ -2079,7 +2109,7 @@ class Wire(Topology):
|
|
2079
2109
|
|
2080
2110
|
Returns
|
2081
2111
|
-------
|
2082
|
-
|
2112
|
+
topologic_core.Wire
|
2083
2113
|
The created rectangle.
|
2084
2114
|
|
2085
2115
|
"""
|
@@ -2087,7 +2117,7 @@ class Wire(Topology):
|
|
2087
2117
|
from topologicpy.Topology import Topology
|
2088
2118
|
if not origin:
|
2089
2119
|
origin = Vertex.ByCoordinates(0, 0, 0)
|
2090
|
-
if not
|
2120
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2091
2121
|
print("Wire.Rectangle - Error: specified origin is not a topologic vertex. Retruning None.")
|
2092
2122
|
return None
|
2093
2123
|
if not placement.lower() in ["center", "lowerleft", "upperleft", "lowerright", "upperright"]:
|
@@ -2127,13 +2157,13 @@ class Wire(Topology):
|
|
2127
2157
|
return baseWire
|
2128
2158
|
|
2129
2159
|
@staticmethod
|
2130
|
-
def RemoveCollinearEdges(wire
|
2160
|
+
def RemoveCollinearEdges(wire, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
2131
2161
|
"""
|
2132
2162
|
Removes any collinear edges in the input wire.
|
2133
2163
|
|
2134
2164
|
Parameters
|
2135
2165
|
----------
|
2136
|
-
wire :
|
2166
|
+
wire : topologic_core.Wire
|
2137
2167
|
The input wire.
|
2138
2168
|
angTolerance : float , optional
|
2139
2169
|
The desired angular tolerance. The default is 0.1.
|
@@ -2142,7 +2172,7 @@ class Wire(Topology):
|
|
2142
2172
|
|
2143
2173
|
Returns
|
2144
2174
|
-------
|
2145
|
-
|
2175
|
+
topologic_core.Wire
|
2146
2176
|
The created wire without any collinear edges.
|
2147
2177
|
|
2148
2178
|
"""
|
@@ -2167,7 +2197,7 @@ class Wire(Topology):
|
|
2167
2197
|
return new_wire
|
2168
2198
|
|
2169
2199
|
def rce(wire, angTolerance=0.1):
|
2170
|
-
if not
|
2200
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2171
2201
|
return wire
|
2172
2202
|
final_wire = None
|
2173
2203
|
vertices = []
|
@@ -2194,55 +2224,56 @@ class Wire(Topology):
|
|
2194
2224
|
return final_wire
|
2195
2225
|
|
2196
2226
|
new_wire = cleanup(wire, tolerance=tolerance)
|
2197
|
-
if not
|
2227
|
+
if not Wire.IsManifold(new_wire):
|
2198
2228
|
wires = Wire.Split(new_wire)
|
2199
2229
|
else:
|
2200
2230
|
wires = [new_wire]
|
2201
2231
|
returnWires = []
|
2202
2232
|
for aWire in wires:
|
2203
|
-
if not
|
2233
|
+
if not Topology.IsInstance(aWire, "Wire"):
|
2204
2234
|
returnWires.append(aWire)
|
2205
2235
|
else:
|
2206
2236
|
returnWires.append(rce(aWire, angTolerance=angTolerance))
|
2207
2237
|
if len(returnWires) == 1:
|
2208
2238
|
returnWire = returnWires[0]
|
2209
|
-
if
|
2239
|
+
if Topology.IsInstance(returnWire, "Edge"):
|
2210
2240
|
return Wire.ByEdges([returnWire], tolerance=tolerance)
|
2211
|
-
elif
|
2241
|
+
elif Topology.IsInstance(returnWire, "Wire"):
|
2212
2242
|
return returnWire
|
2213
2243
|
else:
|
2214
2244
|
return wire
|
2215
2245
|
elif len(returnWires) > 1:
|
2216
|
-
returnWire =
|
2217
|
-
if
|
2246
|
+
returnWire = Topology.SelfMerge(Cluster.ByTopologies(returnWires))
|
2247
|
+
if Topology.IsInstance(returnWire, "Edge"):
|
2218
2248
|
return Wire.ByEdges([returnWire], tolerance=tolerance)
|
2219
|
-
elif
|
2249
|
+
elif Topology.IsInstance(returnWire, "Wire"):
|
2220
2250
|
return returnWire
|
2221
2251
|
else:
|
2222
2252
|
return wire
|
2223
2253
|
else:
|
2224
2254
|
return wire
|
2225
|
-
|
2255
|
+
|
2256
|
+
@staticmethod
|
2226
2257
|
def Reverse(wire, tolerance: float = 0.0001):
|
2227
2258
|
"""
|
2228
2259
|
Creates a wire that has the reverse direction of the input wire.
|
2229
2260
|
|
2230
2261
|
Parameters
|
2231
2262
|
----------
|
2232
|
-
wire :
|
2263
|
+
wire : topologic_core.Wire
|
2233
2264
|
The input wire.
|
2234
2265
|
tolerance : float , optional
|
2235
2266
|
The desired tolerance. The default is 0.0001.
|
2236
2267
|
|
2237
2268
|
Returns
|
2238
2269
|
-------
|
2239
|
-
|
2270
|
+
topologic_core.Wire
|
2240
2271
|
The reversed wire.
|
2241
2272
|
|
2242
2273
|
"""
|
2243
2274
|
from topologicpy.Topology import Topology
|
2244
2275
|
|
2245
|
-
if not
|
2276
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2246
2277
|
print("Wire.Reverse - Error: The input wire parameter is not a valid wire. Returning None.")
|
2247
2278
|
return None
|
2248
2279
|
if not Wire.IsManifold(wire):
|
@@ -2254,6 +2285,7 @@ class Wire(Topology):
|
|
2254
2285
|
new_wire = Wire.ByVertices(vertices, close=Wire.IsClosed(wire), tolerance=tolerance)
|
2255
2286
|
return new_wire
|
2256
2287
|
|
2288
|
+
@staticmethod
|
2257
2289
|
def Roof(face, angle: float = 45, tolerance: float = 0.001):
|
2258
2290
|
"""
|
2259
2291
|
Creates a hipped roof through a straight skeleton. This method is contributed by 高熙鹏 xipeng gao <gaoxipeng1998@gmail.com>
|
@@ -2261,7 +2293,7 @@ class Wire(Topology):
|
|
2261
2293
|
|
2262
2294
|
Parameters
|
2263
2295
|
----------
|
2264
|
-
face :
|
2296
|
+
face : topologic_core.Face
|
2265
2297
|
The input face.
|
2266
2298
|
angle : float , optioal
|
2267
2299
|
The desired angle in degrees of the roof. The default is 45.
|
@@ -2270,7 +2302,7 @@ class Wire(Topology):
|
|
2270
2302
|
|
2271
2303
|
Returns
|
2272
2304
|
-------
|
2273
|
-
|
2305
|
+
topologic_core.Wire
|
2274
2306
|
The created roof. This method returns the roof as a set of edges. No faces are created.
|
2275
2307
|
|
2276
2308
|
"""
|
@@ -2348,7 +2380,7 @@ class Wire(Topology):
|
|
2348
2380
|
roofTopology = Topology.SelfMerge(Cluster.ByTopologies(roofEdges), tolerance=tolerance)
|
2349
2381
|
return roofTopology
|
2350
2382
|
|
2351
|
-
if not
|
2383
|
+
if not Topology.IsInstance(face, "Face"):
|
2352
2384
|
return None
|
2353
2385
|
angle = abs(angle)
|
2354
2386
|
if angle >= 90-tolerance:
|
@@ -2363,6 +2395,98 @@ class Wire(Topology):
|
|
2363
2395
|
roof = Topology.Unflatten(roof, origin=origin, direction=normal)
|
2364
2396
|
return roof
|
2365
2397
|
|
2398
|
+
@staticmethod
|
2399
|
+
def Simplify(wire, tolerance=0.0001):
|
2400
|
+
"""
|
2401
|
+
Simplifies the input wire edges based on the Douglas Peucker algorthim. See https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
|
2402
|
+
Part of this code was contributed by gaoxipeng. See https://github.com/wassimj/topologicpy/issues/35
|
2403
|
+
|
2404
|
+
Parameters
|
2405
|
+
----------
|
2406
|
+
wire : topologic_core.Wire
|
2407
|
+
The input wire.
|
2408
|
+
tolerance : float , optional
|
2409
|
+
The desired tolerance. The default is 0.0001. Edges shorter than this length will be removed.
|
2410
|
+
|
2411
|
+
Returns
|
2412
|
+
-------
|
2413
|
+
topologic_core.Wire
|
2414
|
+
The simplified wire.
|
2415
|
+
"""
|
2416
|
+
|
2417
|
+
from topologicpy.Vertex import Vertex
|
2418
|
+
from topologicpy.Edge import Edge
|
2419
|
+
from topologicpy.Cluster import Cluster
|
2420
|
+
from topologicpy.Topology import Topology
|
2421
|
+
|
2422
|
+
def perpendicular_distance(point, line_start, line_end):
|
2423
|
+
# Calculate the perpendicular distance from a point to a line segment
|
2424
|
+
x0 = point.X()
|
2425
|
+
y0 = point.Y()
|
2426
|
+
x1 = line_start.X()
|
2427
|
+
y1 = line_start.Y()
|
2428
|
+
x2 = line_end.X()
|
2429
|
+
y2 = line_end.Y()
|
2430
|
+
|
2431
|
+
numerator = abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1)
|
2432
|
+
denominator = Vertex.Distance(line_start, line_end)
|
2433
|
+
|
2434
|
+
return numerator / denominator
|
2435
|
+
|
2436
|
+
def douglas_peucker(wire, tolerance):
|
2437
|
+
if isinstance(wire, list):
|
2438
|
+
points = wire
|
2439
|
+
else:
|
2440
|
+
points = Wire.Vertices(wire)
|
2441
|
+
# points.insert(0, points.pop())
|
2442
|
+
if len(points) <= 2:
|
2443
|
+
return points
|
2444
|
+
|
2445
|
+
# Use the first and last points in the list as the starting and ending points
|
2446
|
+
start_point = points[0]
|
2447
|
+
end_point = points[-1]
|
2448
|
+
|
2449
|
+
# Find the point with the maximum distance
|
2450
|
+
max_distance = 0
|
2451
|
+
max_index = 0
|
2452
|
+
|
2453
|
+
for i in range(1, len(points) - 1):
|
2454
|
+
d = perpendicular_distance(points[i], start_point, end_point)
|
2455
|
+
if d > max_distance:
|
2456
|
+
max_distance = d
|
2457
|
+
max_index = i
|
2458
|
+
|
2459
|
+
# If the maximum distance is less than the tolerance, no further simplification is needed
|
2460
|
+
if max_distance <= tolerance:
|
2461
|
+
return [start_point, end_point]
|
2462
|
+
|
2463
|
+
# Recursively simplify
|
2464
|
+
first_segment = douglas_peucker(points[:max_index + 1], tolerance)
|
2465
|
+
second_segment = douglas_peucker(points[max_index:], tolerance)
|
2466
|
+
|
2467
|
+
# Merge the two simplified segments
|
2468
|
+
return first_segment[:-1] + second_segment
|
2469
|
+
|
2470
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2471
|
+
print("Wire.Simplify = Error: The input wire parameter is not a Wire. Returning None.")
|
2472
|
+
return None
|
2473
|
+
if not Wire.IsManifold(wire):
|
2474
|
+
wires = Wire.Split(wire)
|
2475
|
+
new_wires = []
|
2476
|
+
for w in wires:
|
2477
|
+
if Topology.IsInstance(w, "Edge"):
|
2478
|
+
if Edge.Length(w) > tolerance:
|
2479
|
+
new_wires.append(w)
|
2480
|
+
elif Topology.IsInstance(w, "Wire"):
|
2481
|
+
new_wires.append(Wire.Simplify(w, tolerance=tolerance))
|
2482
|
+
return_wire = Topology.SelfMerge(Cluster.ByTopologies(new_wires))
|
2483
|
+
return return_wire
|
2484
|
+
|
2485
|
+
new_vertices = douglas_peucker(wire, tolerance=tolerance)
|
2486
|
+
new_wire = Wire.ByVertices(new_vertices, close=Wire.IsClosed(wire))
|
2487
|
+
return new_wire
|
2488
|
+
|
2489
|
+
@staticmethod
|
2366
2490
|
def Skeleton(face, tolerance=0.001):
|
2367
2491
|
"""
|
2368
2492
|
Creates a straight skeleton. This method is contributed by 高熙鹏 xipeng gao <gaoxipeng1998@gmail.com>
|
@@ -2371,7 +2495,7 @@ class Wire(Topology):
|
|
2371
2495
|
|
2372
2496
|
Parameters
|
2373
2497
|
----------
|
2374
|
-
face :
|
2498
|
+
face : topologic_core.Face
|
2375
2499
|
The input face.
|
2376
2500
|
|
2377
2501
|
tolerance : float , optional
|
@@ -2379,22 +2503,22 @@ class Wire(Topology):
|
|
2379
2503
|
|
2380
2504
|
Returns
|
2381
2505
|
-------
|
2382
|
-
|
2506
|
+
topologic_core.Wire
|
2383
2507
|
The created straight skeleton.
|
2384
2508
|
|
2385
2509
|
"""
|
2386
|
-
if not
|
2510
|
+
if not Topology.IsInstance(face, "Face"):
|
2387
2511
|
return None
|
2388
2512
|
return Wire.Roof(face, angle=0, tolerance=tolerance)
|
2389
2513
|
|
2390
2514
|
@staticmethod
|
2391
|
-
def Spiral(origin
|
2515
|
+
def Spiral(origin = None, radiusA : float = 0.05, radiusB : float = 0.5, height : float = 1, turns : int = 10, sides : int = 36, clockwise : bool = False, reverse : bool = False, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
2392
2516
|
"""
|
2393
2517
|
Creates a spiral.
|
2394
2518
|
|
2395
2519
|
Parameters
|
2396
2520
|
----------
|
2397
|
-
origin :
|
2521
|
+
origin : topologic_core.Vertex , optional
|
2398
2522
|
The location of the origin of the spiral. The default is None which results in the spiral being placed at (0, 0, 0).
|
2399
2523
|
radiusA : float , optional
|
2400
2524
|
The initial radius of the spiral. The default is 0.05.
|
@@ -2417,7 +2541,7 @@ class Wire(Topology):
|
|
2417
2541
|
|
2418
2542
|
Returns
|
2419
2543
|
-------
|
2420
|
-
|
2544
|
+
topologic_core.Wire
|
2421
2545
|
The created spiral.
|
2422
2546
|
|
2423
2547
|
"""
|
@@ -2426,8 +2550,8 @@ class Wire(Topology):
|
|
2426
2550
|
import math
|
2427
2551
|
|
2428
2552
|
if not origin:
|
2429
|
-
origin =
|
2430
|
-
if not
|
2553
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
2554
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2431
2555
|
print("Wire.Spiral - Error: the input origin is not a valid topologic Vertex. Returning None.")
|
2432
2556
|
return None
|
2433
2557
|
if radiusA <= 0:
|
@@ -2508,13 +2632,13 @@ class Wire(Topology):
|
|
2508
2632
|
return baseWire
|
2509
2633
|
|
2510
2634
|
@staticmethod
|
2511
|
-
def Split(wire
|
2635
|
+
def Split(wire) -> list:
|
2512
2636
|
"""
|
2513
2637
|
Splits the input wire into segments at its intersections (i.e. at any vertex where more than two edges meet).
|
2514
2638
|
|
2515
2639
|
Parameters
|
2516
2640
|
----------
|
2517
|
-
wire :
|
2641
|
+
wire : topologic_core.Wire
|
2518
2642
|
The input wire.
|
2519
2643
|
|
2520
2644
|
Returns
|
@@ -2523,6 +2647,8 @@ class Wire(Topology):
|
|
2523
2647
|
The list of split wire segments.
|
2524
2648
|
|
2525
2649
|
"""
|
2650
|
+
from topologicpy.Cluster import Cluster
|
2651
|
+
from topologicpy.Topology import Topology
|
2526
2652
|
|
2527
2653
|
def vertexDegree(v, wire):
|
2528
2654
|
edges = []
|
@@ -2532,7 +2658,7 @@ class Wire(Topology):
|
|
2532
2658
|
def vertexOtherEdge(vertex, edge, wire):
|
2533
2659
|
edges = []
|
2534
2660
|
_ = vertex.Edges(wire, edges)
|
2535
|
-
if
|
2661
|
+
if Topology.IsSame(edges[0], edge):
|
2536
2662
|
return edges[-1]
|
2537
2663
|
else:
|
2538
2664
|
return edges[0]
|
@@ -2540,14 +2666,14 @@ class Wire(Topology):
|
|
2540
2666
|
def edgeOtherVertex(edge, vertex):
|
2541
2667
|
vertices = []
|
2542
2668
|
_ = edge.Vertices(None, vertices)
|
2543
|
-
if
|
2669
|
+
if Topology.IsSame(vertex, vertices[0]):
|
2544
2670
|
return vertices[-1]
|
2545
2671
|
else:
|
2546
2672
|
return vertices[0]
|
2547
2673
|
|
2548
2674
|
def edgeInList(edge, edgeList):
|
2549
2675
|
for anEdge in edgeList:
|
2550
|
-
if
|
2676
|
+
if Topology.IsSame(anEdge, edge):
|
2551
2677
|
return True
|
2552
2678
|
return False
|
2553
2679
|
|
@@ -2577,7 +2703,7 @@ class Wire(Topology):
|
|
2577
2703
|
global_edges.append(current_edge)
|
2578
2704
|
wire_edges.append(current_edge)
|
2579
2705
|
if len(wire_edges) > 1:
|
2580
|
-
wires.append(
|
2706
|
+
wires.append(Cluster.ByTopologies(wire_edges).SelfMerge())
|
2581
2707
|
else:
|
2582
2708
|
wires.append(wire_edges[0])
|
2583
2709
|
wire_edges = []
|
@@ -2586,13 +2712,13 @@ class Wire(Topology):
|
|
2586
2712
|
return wires
|
2587
2713
|
|
2588
2714
|
@staticmethod
|
2589
|
-
def Square(origin
|
2715
|
+
def Square(origin= None, size: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
2590
2716
|
"""
|
2591
2717
|
Creates a square.
|
2592
2718
|
|
2593
2719
|
Parameters
|
2594
2720
|
----------
|
2595
|
-
origin :
|
2721
|
+
origin : topologic_core.Vertex , optional
|
2596
2722
|
The location of the origin of the square. The default is None which results in the square being placed at (0, 0, 0).
|
2597
2723
|
size : float , optional
|
2598
2724
|
The size of the square. The default is 1.0.
|
@@ -2605,20 +2731,109 @@ class Wire(Topology):
|
|
2605
2731
|
|
2606
2732
|
Returns
|
2607
2733
|
-------
|
2608
|
-
|
2734
|
+
topologic_core.Wire
|
2609
2735
|
The created square.
|
2610
2736
|
|
2611
2737
|
"""
|
2612
2738
|
return Wire.Rectangle(origin=origin, width=size, length=size, direction=direction, placement=placement, tolerance=tolerance)
|
2613
2739
|
|
2614
2740
|
@staticmethod
|
2615
|
-
def
|
2741
|
+
def Squircle(origin = None, radius: float = 0.5, sides: int = 121, a: float = 2.0, b: float = 2.0, direction: list = [0, 0, 1], placement: str = "center", angTolerance: float = 0.1, tolerance: float = 0.0001):
|
2742
|
+
"""
|
2743
|
+
Creates a Squircle which is a hybrid between a circle and a square. See https://en.wikipedia.org/wiki/Squircle
|
2744
|
+
|
2745
|
+
Parameters
|
2746
|
+
----------
|
2747
|
+
origin : topologic_core.Vertex , optional
|
2748
|
+
The location of the origin of the squircle. The default is None which results in the squircle being placed at (0, 0, 0).
|
2749
|
+
radius : float , optional
|
2750
|
+
The radius of the squircle. The default is 0.5.
|
2751
|
+
sides : int , optional
|
2752
|
+
The number of sides of the squircle. The default is 121.
|
2753
|
+
a : float , optional
|
2754
|
+
The "a" factor affects the x position of the points to interpolate between a circle and a square.
|
2755
|
+
A value of 1 will create a circle. Higher values will create a more square-like shape. The default is 2.0.
|
2756
|
+
b : float , optional
|
2757
|
+
The "b" factor affects the y position of the points to interpolate between a circle and a square.
|
2758
|
+
A value of 1 will create a circle. Higher values will create a more square-like shape. The default is 2.0.
|
2759
|
+
radius : float , optional
|
2760
|
+
The desired radius of the squircle. The default is 0.5.
|
2761
|
+
sides : int , optional
|
2762
|
+
The desired number of sides for the squircle. The default is 100.
|
2763
|
+
direction : list , optional
|
2764
|
+
The vector representing the up direction of the circle. The default is [0, 0, 1].
|
2765
|
+
placement : str , optional
|
2766
|
+
The description of the placement of the origin of the circle. This can be "center", "lowerleft", "upperleft", "lowerright", or "upperright". It is case insensitive. The default is "center".
|
2767
|
+
angTolerance : float , optional
|
2768
|
+
The desired angular tolerance. The default is 0.1.
|
2769
|
+
tolerance : float , optional
|
2770
|
+
The desired tolerance. The default is 0.0001.
|
2771
|
+
|
2772
|
+
Returns
|
2773
|
+
-------
|
2774
|
+
topologic_core.Wire
|
2775
|
+
The created squircle.
|
2776
|
+
"""
|
2777
|
+
|
2778
|
+
def get_squircle(a=1, b=1, radius=0.5, sides=100):
|
2779
|
+
import numpy as np
|
2780
|
+
t = np.linspace(0, 2*np.pi, sides)
|
2781
|
+
x = (np.abs(np.cos(t))**(1/a)) * np.sign(np.cos(t))
|
2782
|
+
y = (np.abs(np.sin(t))**(1/b)) * np.sign(np.sin(t))
|
2783
|
+
return x*radius, y*radius
|
2784
|
+
|
2785
|
+
from topologicpy.Vertex import Vertex
|
2786
|
+
from topologicpy.Wire import Wire
|
2787
|
+
from topologicpy.Topology import Topology
|
2788
|
+
|
2789
|
+
if not origin:
|
2790
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
2791
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2792
|
+
print("Wire.Squircle - Error: The input origin parameter is not a valid Vertex. Retruning None.")
|
2793
|
+
return None
|
2794
|
+
if not placement.lower() in ["center", "lowerleft", "upperleft", "lowerright", "upperright"]:
|
2795
|
+
print("Wire.Squircle - Error: The input placement parameter is not a recognised string. Retruning None.")
|
2796
|
+
return None
|
2797
|
+
radius = abs(radius)
|
2798
|
+
if radius < tolerance:
|
2799
|
+
return None
|
2800
|
+
|
2801
|
+
if a <= 0:
|
2802
|
+
print("Wire.Squircle - Error: The a input parameter must be a positive number. Returning None.")
|
2803
|
+
return None
|
2804
|
+
if b <= 0:
|
2805
|
+
print("Wire.Squircle - Error: The b input parameter must be a positive number. Returning None.")
|
2806
|
+
return None
|
2807
|
+
if a == 1 and b == 1:
|
2808
|
+
return Wire.Circle(radius=radius, sides=sides, direction=direction, placement=placement, tolerance=tolerance)
|
2809
|
+
x_list, y_list = get_squircle(a=a, b=b, radius=radius, sides=sides)
|
2810
|
+
vertices = []
|
2811
|
+
for i, x in enumerate(x_list):
|
2812
|
+
v = Vertex.ByCoordinates(x, y_list[i], 0)
|
2813
|
+
vertices.append(v)
|
2814
|
+
baseWire = Wire.ByVertices(vertices, close=True)
|
2815
|
+
baseWire = Topology.RemoveCollinearEdges(baseWire, angTolerance=angTolerance, tolerance=tolerance)
|
2816
|
+
baseWire = Wire.Simplify(baseWire, tolerance=tolerance)
|
2817
|
+
if placement.lower() == "lowerleft":
|
2818
|
+
baseWire = Topology.Translate(baseWire, radius, radius, 0)
|
2819
|
+
elif placement.lower() == "upperleft":
|
2820
|
+
baseWire = Topology.Translate(baseWire, radius, -radius, 0)
|
2821
|
+
elif placement.lower() == "lowerright":
|
2822
|
+
baseWire = Topology.Translate(baseWire, -radius, radius, 0)
|
2823
|
+
elif placement.lower() == "upperright":
|
2824
|
+
baseWire = Topology.Translate(baseWire, -radius, -radius, 0)
|
2825
|
+
if direction != [0, 0, 1]:
|
2826
|
+
baseWire = Topology.Orient(baseWire, origin=origin, dirA=[0, 0, 1], dirB=direction)
|
2827
|
+
return baseWire
|
2828
|
+
|
2829
|
+
@staticmethod
|
2830
|
+
def Star(origin= None, radiusA: float = 0.5, radiusB: float = 0.2, rays: int = 8, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
2616
2831
|
"""
|
2617
2832
|
Creates a star.
|
2618
2833
|
|
2619
2834
|
Parameters
|
2620
2835
|
----------
|
2621
|
-
origin :
|
2836
|
+
origin : topologic_core.Vertex , optional
|
2622
2837
|
The location of the origin of the star. The default is None which results in the star being placed at (0, 0, 0).
|
2623
2838
|
radiusA : float , optional
|
2624
2839
|
The outer radius of the star. The default is 1.0.
|
@@ -2635,15 +2850,16 @@ class Wire(Topology):
|
|
2635
2850
|
|
2636
2851
|
Returns
|
2637
2852
|
-------
|
2638
|
-
|
2853
|
+
topologic_core.Wire
|
2639
2854
|
The created star.
|
2640
2855
|
|
2641
2856
|
"""
|
2857
|
+
from topologicpy.Vertex import Vertex
|
2642
2858
|
from topologicpy.Topology import Topology
|
2643
2859
|
|
2644
2860
|
if not origin:
|
2645
|
-
origin =
|
2646
|
-
if not
|
2861
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
2862
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2647
2863
|
return None
|
2648
2864
|
radiusA = abs(radiusA)
|
2649
2865
|
radiusB = abs(radiusB)
|
@@ -2697,7 +2913,7 @@ class Wire(Topology):
|
|
2697
2913
|
yOffset = 0
|
2698
2914
|
tranBase = []
|
2699
2915
|
for coord in baseV:
|
2700
|
-
tranBase.append(
|
2916
|
+
tranBase.append(Vertex.ByCoordinates(coord[0]+xOffset, coord[1]+yOffset, origin.Z()))
|
2701
2917
|
|
2702
2918
|
baseWire = Wire.ByVertices(tranBase[::-1], True) #reversing the list so that the normal points up in Blender
|
2703
2919
|
if direction != [0, 0, 1]:
|
@@ -2705,7 +2921,7 @@ class Wire(Topology):
|
|
2705
2921
|
return baseWire
|
2706
2922
|
|
2707
2923
|
@staticmethod
|
2708
|
-
def StartEndVertices(wire
|
2924
|
+
def StartEndVertices(wire) -> list:
|
2709
2925
|
"""
|
2710
2926
|
Returns the start and end vertices of the input wire. The wire must be manifold and open.
|
2711
2927
|
|
@@ -2735,7 +2951,7 @@ class Wire(Topology):
|
|
2735
2951
|
return [wireStartVertex, wireEndVertex]
|
2736
2952
|
|
2737
2953
|
@staticmethod
|
2738
|
-
def StartVertex(wire
|
2954
|
+
def StartVertex(wire):
|
2739
2955
|
"""
|
2740
2956
|
Returns the start vertex of the input wire. The wire must be manifold and open.
|
2741
2957
|
|
@@ -2744,13 +2960,13 @@ class Wire(Topology):
|
|
2744
2960
|
return sv
|
2745
2961
|
|
2746
2962
|
@staticmethod
|
2747
|
-
def Trapezoid(origin
|
2963
|
+
def Trapezoid(origin= None, widthA: float = 1.0, widthB: float = 0.75, offsetA: float = 0.0, offsetB: float = 0.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
2748
2964
|
"""
|
2749
2965
|
Creates a trapezoid.
|
2750
2966
|
|
2751
2967
|
Parameters
|
2752
2968
|
----------
|
2753
|
-
origin :
|
2969
|
+
origin : topologic_core.Vertex , optional
|
2754
2970
|
The location of the origin of the trapezoid. The default is None which results in the trapezoid being placed at (0, 0, 0).
|
2755
2971
|
widthA : float , optional
|
2756
2972
|
The width of the bottom edge of the trapezoid. The default is 1.0.
|
@@ -2771,15 +2987,16 @@ class Wire(Topology):
|
|
2771
2987
|
|
2772
2988
|
Returns
|
2773
2989
|
-------
|
2774
|
-
|
2990
|
+
topologic_core.Wire
|
2775
2991
|
The created trapezoid.
|
2776
2992
|
|
2777
2993
|
"""
|
2994
|
+
from topologicpy.Vertex import Vertex
|
2778
2995
|
from topologicpy.Topology import Topology
|
2779
2996
|
|
2780
2997
|
if not origin:
|
2781
|
-
origin =
|
2782
|
-
if not
|
2998
|
+
origin = Vertex.ByCoordinates(0, 0, 0)
|
2999
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2783
3000
|
return None
|
2784
3001
|
widthA = abs(widthA)
|
2785
3002
|
widthB = abs(widthB)
|
@@ -2806,10 +3023,10 @@ class Wire(Topology):
|
|
2806
3023
|
xOffset = -(max((widthA*0.5 + offsetA), (widthB*0.5 + offsetB)))
|
2807
3024
|
yOffset = -length*0.5
|
2808
3025
|
|
2809
|
-
vb1 =
|
2810
|
-
vb2 =
|
2811
|
-
vb3 =
|
2812
|
-
vb4 =
|
3026
|
+
vb1 = Vertex.ByCoordinates(origin.X()-widthA*0.5+offsetA+xOffset,origin.Y()-length*0.5+yOffset,origin.Z())
|
3027
|
+
vb2 = Vertex.ByCoordinates(origin.X()+widthA*0.5+offsetA+xOffset,origin.Y()-length*0.5+yOffset,origin.Z())
|
3028
|
+
vb3 = Vertex.ByCoordinates(origin.X()+widthB*0.5+offsetB+xOffset,origin.Y()+length*0.5+yOffset,origin.Z())
|
3029
|
+
vb4 = Vertex.ByCoordinates(origin.X()-widthB*0.5++offsetB+xOffset,origin.Y()+length*0.5+yOffset,origin.Z())
|
2813
3030
|
|
2814
3031
|
baseWire = Wire.ByVertices([vb1, vb2, vb3, vb4], True)
|
2815
3032
|
if direction != [0, 0, 1]:
|
@@ -2817,17 +3034,17 @@ class Wire(Topology):
|
|
2817
3034
|
return baseWire
|
2818
3035
|
|
2819
3036
|
@staticmethod
|
2820
|
-
def VertexDistance(wire
|
3037
|
+
def VertexDistance(wire, vertex, origin= None, mantissa: int = 6, tolerance: float = 0.0001):
|
2821
3038
|
"""
|
2822
3039
|
Returns the distance, computed along the input wire of the input vertex from the input origin vertex.
|
2823
3040
|
|
2824
3041
|
Parameters
|
2825
3042
|
----------
|
2826
|
-
wire :
|
3043
|
+
wire : topologic_core.Wire
|
2827
3044
|
The input wire.
|
2828
|
-
vertex :
|
3045
|
+
vertex : topologic_core.Vertex
|
2829
3046
|
The input vertex
|
2830
|
-
origin :
|
3047
|
+
origin : topologic_core.Vertex , optional
|
2831
3048
|
The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input wire. The default is None.
|
2832
3049
|
mantissa : int , optional
|
2833
3050
|
The desired length of the mantissa. The default is 6.
|
@@ -2844,10 +3061,10 @@ class Wire(Topology):
|
|
2844
3061
|
from topologicpy.Edge import Edge
|
2845
3062
|
from topologicpy.Topology import Topology
|
2846
3063
|
|
2847
|
-
if not
|
3064
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2848
3065
|
print("Wire.VertexDistance - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
2849
3066
|
return None
|
2850
|
-
if not
|
3067
|
+
if not Topology.IsInstance(vertex, "Vertex"):
|
2851
3068
|
print("Wire.VertexDistance - Error: The input vertex parameter is not a valid topologic vertex. Returning None.")
|
2852
3069
|
return None
|
2853
3070
|
wire_length = Wire.Length(wire)
|
@@ -2856,7 +3073,7 @@ class Wire(Topology):
|
|
2856
3073
|
return None
|
2857
3074
|
if origin == None:
|
2858
3075
|
origin = Wire.StartVertex(wire)
|
2859
|
-
if not
|
3076
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2860
3077
|
print("Wire.VertexDistance - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
2861
3078
|
return None
|
2862
3079
|
if not Vertex.IsInternal(vertex, wire, tolerance=tolerance):
|
@@ -2888,24 +3105,24 @@ class Wire(Topology):
|
|
2888
3105
|
return round(abs(d2-d1), mantissa)
|
2889
3106
|
|
2890
3107
|
@staticmethod
|
2891
|
-
def VertexByDistance(wire
|
3108
|
+
def VertexByDistance(wire, distance: float = 0.0, origin= None, tolerance = 0.0001):
|
2892
3109
|
"""
|
2893
3110
|
Creates a vertex along the input wire offset by the input distance from the input origin.
|
2894
3111
|
|
2895
3112
|
Parameters
|
2896
3113
|
----------
|
2897
|
-
edge :
|
3114
|
+
edge : topologic_core.Edge
|
2898
3115
|
The input edge.
|
2899
3116
|
distance : float , optional
|
2900
3117
|
The offset distance. The default is 0.
|
2901
|
-
origin :
|
3118
|
+
origin : topologic_core.Vertex , optional
|
2902
3119
|
The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input edge. The default is None.
|
2903
3120
|
tolerance : float , optional
|
2904
3121
|
The desired tolerance. The default is 0.0001.
|
2905
3122
|
|
2906
3123
|
Returns
|
2907
3124
|
-------
|
2908
|
-
|
3125
|
+
topologic_core.Vertex
|
2909
3126
|
The created vertex.
|
2910
3127
|
|
2911
3128
|
"""
|
@@ -2926,7 +3143,7 @@ class Wire(Topology):
|
|
2926
3143
|
u = -(int(u) - u)
|
2927
3144
|
return round(u,dp)
|
2928
3145
|
|
2929
|
-
if not
|
3146
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2930
3147
|
print("Wire.VertexByDistance - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
2931
3148
|
return None
|
2932
3149
|
wire_length = Wire.Length(wire)
|
@@ -2942,7 +3159,7 @@ class Wire(Topology):
|
|
2942
3159
|
return None
|
2943
3160
|
if origin == None:
|
2944
3161
|
origin = Wire.StartVertex(wire)
|
2945
|
-
if not
|
3162
|
+
if not Topology.IsInstance(origin, "Vertex"):
|
2946
3163
|
print("Wire.VertexByDistance - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
2947
3164
|
return None
|
2948
3165
|
if not Vertex.IsInternal(origin, wire, tolerance=tolerance):
|
@@ -2959,26 +3176,26 @@ class Wire(Topology):
|
|
2959
3176
|
return Wire.VertexByParameter(wire, u=compute_u(u))
|
2960
3177
|
|
2961
3178
|
@staticmethod
|
2962
|
-
def VertexByParameter(wire
|
3179
|
+
def VertexByParameter(wire, u: float = 0):
|
2963
3180
|
"""
|
2964
3181
|
Creates a vertex along the input wire offset by the input *u* parameter. The wire must be manifold.
|
2965
3182
|
|
2966
3183
|
Parameters
|
2967
3184
|
----------
|
2968
|
-
wire :
|
3185
|
+
wire : topologic_core.Wire
|
2969
3186
|
The input wire.
|
2970
3187
|
u : float , optional
|
2971
3188
|
The *u* parameter along the input topologic Wire. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0.
|
2972
3189
|
|
2973
3190
|
Returns
|
2974
3191
|
-------
|
2975
|
-
|
3192
|
+
topologic_core.Vertex
|
2976
3193
|
The vertex at the input u parameter
|
2977
3194
|
|
2978
3195
|
"""
|
2979
3196
|
from topologicpy.Edge import Edge
|
2980
3197
|
|
2981
|
-
if not
|
3198
|
+
if not Topology.IsInstance(wire, "Wire"):
|
2982
3199
|
print("Wire.VertexAtParameter - Error: The input wire parameter is not a valid topologic wire. Returning None.")
|
2983
3200
|
return None
|
2984
3201
|
if u < 0 or u > 1:
|
@@ -3027,13 +3244,13 @@ class Wire(Topology):
|
|
3027
3244
|
return vertex
|
3028
3245
|
|
3029
3246
|
@staticmethod
|
3030
|
-
def Vertices(wire
|
3247
|
+
def Vertices(wire) -> list:
|
3031
3248
|
"""
|
3032
3249
|
Returns the list of vertices of the input wire.
|
3033
3250
|
|
3034
3251
|
Parameters
|
3035
3252
|
----------
|
3036
|
-
wire :
|
3253
|
+
wire : topologic_core.Wire
|
3037
3254
|
The input wire.
|
3038
3255
|
|
3039
3256
|
Returns
|
@@ -3042,7 +3259,7 @@ class Wire(Topology):
|
|
3042
3259
|
The list of vertices.
|
3043
3260
|
|
3044
3261
|
"""
|
3045
|
-
if not
|
3262
|
+
if not Topology.IsInstance(wire, "Wire"):
|
3046
3263
|
return None
|
3047
3264
|
vertices = []
|
3048
3265
|
_ = wire.Vertices(None, vertices)
|