topologicpy 0.5.8__py3-none-any.whl → 6.0.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 +72 -72
- topologicpy/Cell.py +2169 -2169
- topologicpy/CellComplex.py +1137 -1137
- topologicpy/Cluster.py +1288 -1280
- topologicpy/Color.py +423 -393
- topologicpy/Context.py +79 -79
- topologicpy/DGL.py +3213 -3136
- topologicpy/Dictionary.py +698 -695
- topologicpy/Edge.py +1187 -1187
- topologicpy/EnergyModel.py +1180 -1171
- topologicpy/Face.py +2141 -2141
- topologicpy/Graph.py +7768 -7700
- topologicpy/Grid.py +353 -353
- topologicpy/Helper.py +507 -507
- topologicpy/Honeybee.py +461 -461
- topologicpy/Matrix.py +271 -271
- topologicpy/Neo4j.py +521 -521
- topologicpy/Plotly.py +2 -2
- topologicpy/Polyskel.py +541 -541
- topologicpy/Shell.py +1768 -1768
- topologicpy/Speckle.py +508 -508
- topologicpy/Topology.py +7060 -6988
- topologicpy/Vector.py +905 -905
- topologicpy/Vertex.py +1585 -1585
- topologicpy/Wire.py +3050 -3050
- topologicpy/__init__.py +22 -38
- topologicpy/version.py +1 -0
- {topologicpy-0.5.8.dist-info → topologicpy-6.0.0.dist-info}/LICENSE +661 -704
- topologicpy-6.0.0.dist-info/METADATA +751 -0
- topologicpy-6.0.0.dist-info/RECORD +32 -0
- topologicpy/bin/linux/topologic/__init__.py +0 -2
- topologicpy/bin/linux/topologic/libTKBO-6bdf205d.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKBRep-2960a069.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKBool-c44b74bd.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKFillet-9a670ba0.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKG2d-8f31849e.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKG3d-4c6bce57.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKMath-72572fa8.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKMesh-2a060427.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKOffset-6cab68ff.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKPrim-eb1262b3.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic/libgcc_s-32c1665e.so.1 +0 -0
- topologicpy/bin/linux/topologic/libstdc++-672d7b41.so.6.0.30 +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-310-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-311-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-38-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic/topologic.cpython-39-x86_64-linux-gnu.so +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBO-6bdf205d.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBRep-2960a069.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKBool-c44b74bd.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKFillet-9a670ba0.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG2d-8f31849e.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKG3d-4c6bce57.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMath-72572fa8.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKMesh-2a060427.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKOffset-6cab68ff.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKPrim-eb1262b3.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
- topologicpy/bin/linux/topologic.libs/libgcc_s-32c1665e.so.1 +0 -0
- topologicpy/bin/linux/topologic.libs/libstdc++-672d7b41.so.6.0.30 +0 -0
- topologicpy/bin/macos/topologic/__init__.py +0 -2
- topologicpy/bin/windows/topologic/TKBO-f6b191de.dll +0 -0
- topologicpy/bin/windows/topologic/TKBRep-e56a600e.dll +0 -0
- topologicpy/bin/windows/topologic/TKBool-7b8d47ae.dll +0 -0
- topologicpy/bin/windows/topologic/TKFillet-0ddbf0a8.dll +0 -0
- topologicpy/bin/windows/topologic/TKG2d-2e2dee3d.dll +0 -0
- topologicpy/bin/windows/topologic/TKG3d-6674513d.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomAlgo-d240e370.dll +0 -0
- topologicpy/bin/windows/topologic/TKGeomBase-df87aba5.dll +0 -0
- topologicpy/bin/windows/topologic/TKMath-45bd625a.dll +0 -0
- topologicpy/bin/windows/topologic/TKMesh-d6e826b1.dll +0 -0
- topologicpy/bin/windows/topologic/TKOffset-79b9cc94.dll +0 -0
- topologicpy/bin/windows/topologic/TKPrim-aa430a86.dll +0 -0
- topologicpy/bin/windows/topologic/TKShHealing-bb48be89.dll +0 -0
- topologicpy/bin/windows/topologic/TKTopAlgo-7d0d1e22.dll +0 -0
- topologicpy/bin/windows/topologic/TKernel-08c8cfbb.dll +0 -0
- topologicpy/bin/windows/topologic/__init__.py +0 -2
- topologicpy/bin/windows/topologic/topologic.cp310-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp311-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp38-win_amd64.pyd +0 -0
- topologicpy/bin/windows/topologic/topologic.cp39-win_amd64.pyd +0 -0
- topologicpy-0.5.8.dist-info/METADATA +0 -96
- topologicpy-0.5.8.dist-info/RECORD +0 -91
- {topologicpy-0.5.8.dist-info → topologicpy-6.0.0.dist-info}/WHEEL +0 -0
- {topologicpy-0.5.8.dist-info → topologicpy-6.0.0.dist-info}/top_level.txt +0 -0
topologicpy/Edge.py
CHANGED
@@ -1,1188 +1,1188 @@
|
|
1
|
-
# Copyright (C) 2024
|
2
|
-
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
|
-
#
|
4
|
-
# This program is free software: you can redistribute it and/or modify it under
|
5
|
-
# the terms of the GNU Affero General Public License as published by the Free Software
|
6
|
-
# Foundation, either version 3 of the License, or (at your option) any later
|
7
|
-
# version.
|
8
|
-
#
|
9
|
-
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
-
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
-
# details.
|
13
|
-
#
|
14
|
-
# You should have received a copy of the GNU Affero General Public License along with
|
15
|
-
# this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
-
|
17
|
-
import topologic
|
18
|
-
from topologicpy.Vertex import Vertex
|
19
|
-
from topologicpy.Vector import Vector
|
20
|
-
from topologicpy.Topology import Topology
|
21
|
-
|
22
|
-
class Edge(Topology):
|
23
|
-
@staticmethod
|
24
|
-
def Angle(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, bracket: bool = False) -> float:
|
25
|
-
"""
|
26
|
-
Returns the angle in degrees between the two input edges.
|
27
|
-
|
28
|
-
Parameters
|
29
|
-
----------
|
30
|
-
edgeA : topologic.Edge
|
31
|
-
The first input edge.
|
32
|
-
edgeB : topologic Edge
|
33
|
-
The second input edge.
|
34
|
-
mantissa : int , optional
|
35
|
-
The desired length of the mantissa. The default is 6.
|
36
|
-
bracket : bool
|
37
|
-
If set to True, the returned angle is bracketed between 0 and 180. The default is False.
|
38
|
-
|
39
|
-
Returns
|
40
|
-
-------
|
41
|
-
float
|
42
|
-
The angle in degrees between the two input edges.
|
43
|
-
|
44
|
-
"""
|
45
|
-
|
46
|
-
if not isinstance(edgeA, topologic.Edge):
|
47
|
-
print("Edge.Angle - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
48
|
-
return None
|
49
|
-
if not isinstance(edgeB, topologic.Edge):
|
50
|
-
print("Edge.Angle - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
51
|
-
return None
|
52
|
-
dirA = Edge.Direction(edgeA, mantissa)
|
53
|
-
dirB = Edge.Direction(edgeB, mantissa)
|
54
|
-
ang = Vector.Angle(dirA, dirB)
|
55
|
-
if bracket:
|
56
|
-
if ang > 90:
|
57
|
-
ang = 180 - ang
|
58
|
-
return round(ang, mantissa)
|
59
|
-
|
60
|
-
@staticmethod
|
61
|
-
def Bisect(edgeA: topologic.Edge, edgeB: topologic.Edge, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001) -> topologic.Edge:
|
62
|
-
"""
|
63
|
-
Creates a bisecting edge between edgeA and edgeB.
|
64
|
-
|
65
|
-
Parameters
|
66
|
-
----------
|
67
|
-
edgeA : topologic.Edge
|
68
|
-
The first topologic Edge.
|
69
|
-
edgeB : topologic Edge
|
70
|
-
The second topologic Edge.
|
71
|
-
length : float , optional
|
72
|
-
The desired length of the bisecting edge. The default is 1.0.
|
73
|
-
placement : int , optional
|
74
|
-
The desired placement of the bisecting edge.
|
75
|
-
If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge.
|
76
|
-
If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge.
|
77
|
-
If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge.
|
78
|
-
If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0.
|
79
|
-
tolerance : float , optional
|
80
|
-
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
|
81
|
-
|
82
|
-
Returns
|
83
|
-
-------
|
84
|
-
topologic.Edge
|
85
|
-
The created bisecting edge.
|
86
|
-
|
87
|
-
"""
|
88
|
-
import numpy as np
|
89
|
-
|
90
|
-
from topologicpy.Wire import Wire
|
91
|
-
from topologicpy.Cluster import Cluster
|
92
|
-
from topologicpy.Topology import Topology
|
93
|
-
from topologicpy.Vector import Vector
|
94
|
-
|
95
|
-
if not isinstance(edgeA, topologic.Edge):
|
96
|
-
print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
97
|
-
return None
|
98
|
-
if not isinstance(edgeB, topologic.Edge):
|
99
|
-
print("Edge.Bisect - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
100
|
-
return None
|
101
|
-
if Edge.Length(edgeA) < tolerance:
|
102
|
-
print("Edge.Bisect - Error: The input edgeA parameter is shorter than the input tolerance parameter. Returning None.")
|
103
|
-
return None
|
104
|
-
if Edge.Length(edgeB) < tolerance:
|
105
|
-
print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.")
|
106
|
-
return None
|
107
|
-
|
108
|
-
wire = Topology.SelfMerge(Cluster.ByTopologies([edgeA, edgeB]), tolerance=tolerance)
|
109
|
-
if not isinstance(wire, topologic.Wire):
|
110
|
-
print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.")
|
111
|
-
return None
|
112
|
-
edges = Topology.Edges(wire)
|
113
|
-
edgeA = edges[0]
|
114
|
-
edgeB = edges[1]
|
115
|
-
|
116
|
-
sv = Wire.Vertices(wire)[1]
|
117
|
-
|
118
|
-
dirA = Edge.Direction(edgeA)
|
119
|
-
dirB = Edge.Direction(edgeB)
|
120
|
-
bisecting_vector = Vector.Bisect(dirA, dirB)
|
121
|
-
ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length)
|
122
|
-
bisecting_edge = Edge.ByVertices([sv, ev])
|
123
|
-
return bisecting_edge
|
124
|
-
|
125
|
-
@staticmethod
|
126
|
-
def ByFaceNormal(face: topologic.Face, origin: topologic.Vertex = None, length: float = 1.0, tolerance: float = 0.0001) -> topologic.Edge:
|
127
|
-
"""
|
128
|
-
Creates a straight edge representing the normal to the input face.
|
129
|
-
|
130
|
-
Parameters
|
131
|
-
----------
|
132
|
-
face : topologic.Face
|
133
|
-
The input face
|
134
|
-
origin : toopologic.Vertex , optional
|
135
|
-
The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None.
|
136
|
-
length : float , optional
|
137
|
-
The desired length of the edge. The default is 1.
|
138
|
-
tolerance : float , optional
|
139
|
-
The desired tolerance. The default is 0.0001.
|
140
|
-
|
141
|
-
Returns
|
142
|
-
-------
|
143
|
-
edge : topologic.Edge
|
144
|
-
The created edge.
|
145
|
-
|
146
|
-
"""
|
147
|
-
from topologicpy.Vertex import Vertex
|
148
|
-
from topologicpy.Face import Face
|
149
|
-
from topologicpy.Topology import Topology
|
150
|
-
edge = None
|
151
|
-
if not isinstance(face, topologic.Face):
|
152
|
-
print("Edge.ByFaceNormal - Error: The input face parameter is not a valid topologic face. Returning None.")
|
153
|
-
return None
|
154
|
-
if not isinstance(origin, topologic.Vertex):
|
155
|
-
origin = Topology.Centroid(face)
|
156
|
-
if not isinstance(origin, topologic.Vertex):
|
157
|
-
print("Edge.ByFaceNormal - Error: The input origin parameter is not a valid topologic origin. Returning None.")
|
158
|
-
return None
|
159
|
-
n = Face.Normal(face)
|
160
|
-
v2 = Topology.Translate(origin, n[0], n[1], n[2])
|
161
|
-
edge = Edge.ByStartVertexEndVertex(origin, v2, tolerance=tolerance, silent=True)
|
162
|
-
if not isinstance(edge, topologic.Edge):
|
163
|
-
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
|
164
|
-
return None
|
165
|
-
edge = Edge.SetLength(edge, length, bothSides=False)
|
166
|
-
if not isinstance(edge, topologic.Edge):
|
167
|
-
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
|
168
|
-
return None
|
169
|
-
return edge
|
170
|
-
|
171
|
-
@staticmethod
|
172
|
-
def ByOffset2D(edge: topologic.Edge, offset: float = 1.0, tolerance: float = 0.0001) -> topologic.Edge:
|
173
|
-
"""
|
174
|
-
Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane.
|
175
|
-
|
176
|
-
Parameters
|
177
|
-
----------
|
178
|
-
edge : topologic.Edge
|
179
|
-
The input edge.
|
180
|
-
offset : float , optional
|
181
|
-
The desired offset. The default is 1.
|
182
|
-
tolerance : float , optiona
|
183
|
-
The desired tolerance. The default is 0.0001.
|
184
|
-
|
185
|
-
Returns
|
186
|
-
-------
|
187
|
-
topologic.Edge
|
188
|
-
An edge offset from the input edge.
|
189
|
-
|
190
|
-
"""
|
191
|
-
from topologicpy.Topology import Topology
|
192
|
-
n = Edge.Normal(edge)
|
193
|
-
n = Vector.Normalize(n)
|
194
|
-
n = Vector.Multiply(n, offset, tolerance)
|
195
|
-
edge = Topology.Translate(edge, n[0], n[1], n[2])
|
196
|
-
return edge
|
197
|
-
|
198
|
-
|
199
|
-
@staticmethod
|
200
|
-
def ByStartVertexEndVertex(vertexA: topologic.Vertex, vertexB: topologic.Vertex, tolerance: float = 0.0001, silent=False) -> topologic.Edge:
|
201
|
-
"""
|
202
|
-
Creates a straight edge that connects the input vertices.
|
203
|
-
|
204
|
-
Parameters
|
205
|
-
----------
|
206
|
-
vertexA : topologic.Vertex
|
207
|
-
The first input vertex. This is considered the start vertex.
|
208
|
-
vertexB : toopologic.Vertex
|
209
|
-
The second input vertex. This is considered the end vertex.
|
210
|
-
tolerance : float , optional
|
211
|
-
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
|
212
|
-
silent : bool , optional
|
213
|
-
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
214
|
-
|
215
|
-
Returns
|
216
|
-
-------
|
217
|
-
edge : topologic.Edge
|
218
|
-
The created edge.
|
219
|
-
|
220
|
-
"""
|
221
|
-
from topologicpy.Vertex import Vertex
|
222
|
-
edge = None
|
223
|
-
if not isinstance(vertexA, topologic.Vertex):
|
224
|
-
if not silent:
|
225
|
-
print("Edge.ByStartVertexEndVertex - Error: The input vertexA parameter is not a valid topologic vertex. Returning None.")
|
226
|
-
return None
|
227
|
-
if not isinstance(vertexB, topologic.Vertex):
|
228
|
-
if not silent:
|
229
|
-
print("Edge.ByStartVertexEndVertex - Error: The input vertexB parameter is not a valid topologic vertex. Returning None.")
|
230
|
-
return None
|
231
|
-
if topologic.Topology.IsSame(vertexA, vertexB):
|
232
|
-
if not silent:
|
233
|
-
print("Edge.ByStartVertexEndVertex - Error: The input vertexA and vertexB parameters are the same vertex. Returning None.")
|
234
|
-
return None
|
235
|
-
if Vertex.Distance(vertexA, vertexB) < tolerance:
|
236
|
-
if not silent:
|
237
|
-
print("Edge.ByStartVertexEndVertex - Error: The distance between the input vertexA and vertexB parameters is less than the input tolerance. Returning None.")
|
238
|
-
return None
|
239
|
-
try:
|
240
|
-
edge = topologic.Edge.ByStartVertexEndVertex(vertexA, vertexB)
|
241
|
-
except:
|
242
|
-
if not silent:
|
243
|
-
print("Edge.ByStartVertexEndVertex - Error: Could not create an edge. Returning None.")
|
244
|
-
edge = None
|
245
|
-
return edge
|
246
|
-
|
247
|
-
@staticmethod
|
248
|
-
def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False) -> topologic.Edge:
|
249
|
-
"""
|
250
|
-
Creates a straight edge that connects the input list of vertices.
|
251
|
-
|
252
|
-
Parameters
|
253
|
-
----------
|
254
|
-
vertices : list
|
255
|
-
The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
|
256
|
-
tolerance : float , optional
|
257
|
-
The desired tolerance to decide if an edge can be created. The default is 0.0001.
|
258
|
-
silent : bool , optional
|
259
|
-
If set to True, error and warning messages are printed. Otherwise, they are not. The default is True.
|
260
|
-
|
261
|
-
Returns
|
262
|
-
-------
|
263
|
-
topologic.Edge
|
264
|
-
The created edge.
|
265
|
-
|
266
|
-
"""
|
267
|
-
|
268
|
-
from topologicpy.Helper import Helper
|
269
|
-
|
270
|
-
if len(args) == 0:
|
271
|
-
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
|
272
|
-
return None
|
273
|
-
if len(args) == 1:
|
274
|
-
vertices = args[0]
|
275
|
-
if isinstance(vertices, list):
|
276
|
-
if len(vertices) == 0:
|
277
|
-
if not silent:
|
278
|
-
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
|
279
|
-
return None
|
280
|
-
else:
|
281
|
-
vertexList = [x for x in vertices if isinstance(x, topologic.Vertex)]
|
282
|
-
if len(vertexList) == 0:
|
283
|
-
if not silent:
|
284
|
-
print("Edge.ByVertices - Error: The input vertices parameter does not contain any valid vertices. Returning None.")
|
285
|
-
return None
|
286
|
-
else:
|
287
|
-
if not silent:
|
288
|
-
print("Edge.ByVertices - Warning: The input vertices parameter contains only one vertex. Returning None.")
|
289
|
-
return None
|
290
|
-
else:
|
291
|
-
vertexList = Helper.Flatten(list(args))
|
292
|
-
vertexList = [x for x in vertexList if isinstance(x, topologic.Vertex)]
|
293
|
-
if len(vertexList) < 2:
|
294
|
-
if not silent:
|
295
|
-
print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.")
|
296
|
-
return None
|
297
|
-
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent)
|
298
|
-
|
299
|
-
@staticmethod
|
300
|
-
def ByVerticesCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.Edge:
|
301
|
-
"""
|
302
|
-
Creates a straight edge that connects the input cluster of vertices.
|
303
|
-
|
304
|
-
Parameters
|
305
|
-
----------
|
306
|
-
cluster : topologic.Cluster
|
307
|
-
The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
|
308
|
-
tolerance : float , optional
|
309
|
-
The desired tolerance to decide if an edge can be created. The default is 0.0001.
|
310
|
-
|
311
|
-
Returns
|
312
|
-
-------
|
313
|
-
topologic.Edge
|
314
|
-
The created edge.
|
315
|
-
|
316
|
-
"""
|
317
|
-
from topologicpy.Cluster import Cluster
|
318
|
-
if not isinstance(cluster, topologic.Cluster):
|
319
|
-
print("Edge.ByVerticesCluster - Error: The input cluster parameter is not a valid topologic cluster. Returning None.")
|
320
|
-
return None
|
321
|
-
vertices = Cluster.Vertices(cluster)
|
322
|
-
vertexList = [x for x in vertices if isinstance(x, topologic.Vertex)]
|
323
|
-
if len(vertexList) < 2:
|
324
|
-
print("Edge.ByVerticesCluster - Error: The input cluster parameter contains less than two vertices. Returning None.")
|
325
|
-
return None
|
326
|
-
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance)
|
327
|
-
|
328
|
-
@staticmethod
|
329
|
-
def Direction(edge: topologic.Edge, mantissa: int = 6) -> list:
|
330
|
-
"""
|
331
|
-
Returns the direction of the input edge expressed as a list of three numbers.
|
332
|
-
|
333
|
-
Parameters
|
334
|
-
----------
|
335
|
-
edge : topologic.Edge
|
336
|
-
The input edge.
|
337
|
-
mantissa : int , optional
|
338
|
-
The desired length of the mantissa. The default is 6.
|
339
|
-
|
340
|
-
Returns
|
341
|
-
-------
|
342
|
-
list
|
343
|
-
The direction of the input edge.
|
344
|
-
|
345
|
-
"""
|
346
|
-
|
347
|
-
from topologicpy.Vector import Vector
|
348
|
-
|
349
|
-
if not isinstance(edge, topologic.Edge):
|
350
|
-
print("Edge.Direction - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
351
|
-
return None
|
352
|
-
ev = edge.EndVertex()
|
353
|
-
sv = edge.StartVertex()
|
354
|
-
x = ev.X() - sv.X()
|
355
|
-
y = ev.Y() - sv.Y()
|
356
|
-
z = ev.Z() - sv.Z()
|
357
|
-
uvec = Vector.Normalize([x,y,z])
|
358
|
-
x = round(uvec[0], mantissa)
|
359
|
-
y = round(uvec[1], mantissa)
|
360
|
-
z = round(uvec[2], mantissa)
|
361
|
-
return [x, y, z]
|
362
|
-
|
363
|
-
@staticmethod
|
364
|
-
def EndVertex(edge: topologic.Edge) -> topologic.Vertex:
|
365
|
-
"""
|
366
|
-
Returns the end vertex of the input edge.
|
367
|
-
|
368
|
-
Parameters
|
369
|
-
----------
|
370
|
-
edge : topologic.Edge
|
371
|
-
The input edge.
|
372
|
-
|
373
|
-
Returns
|
374
|
-
-------
|
375
|
-
topologic.Vertex
|
376
|
-
The end vertex of the input edge.
|
377
|
-
|
378
|
-
"""
|
379
|
-
if not isinstance(edge, topologic.Edge):
|
380
|
-
print("Edge.EndVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
381
|
-
return None
|
382
|
-
vert = None
|
383
|
-
try:
|
384
|
-
vert = edge.EndVertex()
|
385
|
-
except:
|
386
|
-
vert = None
|
387
|
-
return vert
|
388
|
-
|
389
|
-
@staticmethod
|
390
|
-
def Extend(edge: topologic.Edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
391
|
-
"""
|
392
|
-
Extends the input edge by the input distance.
|
393
|
-
|
394
|
-
Parameters
|
395
|
-
----------
|
396
|
-
edge : topologic.Edge
|
397
|
-
The input edge.
|
398
|
-
distance : float , optional
|
399
|
-
The offset distance. The default is 1.
|
400
|
-
bothSides : bool , optional
|
401
|
-
If set to True, the edge will be extended by half the distance at each end. The default is False.
|
402
|
-
reverse : bool , optional
|
403
|
-
If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False.
|
404
|
-
tolerance : float , optional
|
405
|
-
The desired tolerance. The default is 0.0001.
|
406
|
-
|
407
|
-
Returns
|
408
|
-
-------
|
409
|
-
topologic.Edge
|
410
|
-
The extended edge.
|
411
|
-
|
412
|
-
"""
|
413
|
-
if not isinstance(edge, topologic.Edge):
|
414
|
-
print("Edge.Extend - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
415
|
-
return None
|
416
|
-
distance = abs(distance)
|
417
|
-
if distance < tolerance:
|
418
|
-
return edge
|
419
|
-
sv = Edge.StartVertex(edge)
|
420
|
-
ev = Edge.EndVertex(edge)
|
421
|
-
if bothSides:
|
422
|
-
sve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=sv, tolerance=tolerance)
|
423
|
-
eve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=ev, tolerance=tolerance)
|
424
|
-
elif reverse:
|
425
|
-
sve = Edge.VertexByDistance(edge, distance=-distance, origin=sv, tolerance=tolerance)
|
426
|
-
eve = Edge.EndVertex(edge)
|
427
|
-
else:
|
428
|
-
sve = Edge.StartVertex(edge)
|
429
|
-
eve = Edge.VertexByDistance(edge, distance=distance, origin=ev, tolerance=tolerance)
|
430
|
-
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
431
|
-
|
432
|
-
@staticmethod
|
433
|
-
def ExtendToEdge2D(edgeA: topologic.Edge, edgeB: topologic.Edge, tolerance: float = 0.0001) -> topologic.Edge:
|
434
|
-
"""
|
435
|
-
Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored.
|
436
|
-
|
437
|
-
Parameters
|
438
|
-
----------
|
439
|
-
edgeA : topologic.Edge
|
440
|
-
The first input edge.
|
441
|
-
edgeB : topologic.Edge
|
442
|
-
The second input edge.
|
443
|
-
tolerance : float , optional
|
444
|
-
The desired tolerance. The default is 0.0001.
|
445
|
-
|
446
|
-
Returns
|
447
|
-
-------
|
448
|
-
topologic.Edge
|
449
|
-
The extended edge.
|
450
|
-
|
451
|
-
"""
|
452
|
-
|
453
|
-
from topologicpy.Vertex import Vertex
|
454
|
-
from topologicpy.Topology import Topology
|
455
|
-
|
456
|
-
if not isinstance(edgeA, topologic.Edge):
|
457
|
-
print("Edge.ExtendToEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
458
|
-
return None
|
459
|
-
if not isinstance(edgeB, topologic.Edge):
|
460
|
-
print("Edge.ExtendToEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
461
|
-
return None
|
462
|
-
sva = Edge.StartVertex(edgeA)
|
463
|
-
eva = Edge.EndVertex(edgeA)
|
464
|
-
intVertex = Edge.Intersect2D(edgeA, edgeB)
|
465
|
-
if intVertex and not (Vertex.IsInternal(intVertex, edgeA)):
|
466
|
-
e1 = Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
|
467
|
-
e2 = Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
468
|
-
l1 = Edge.Length(e1)
|
469
|
-
l2 = Edge.Length(e2)
|
470
|
-
if l1 > l2:
|
471
|
-
return e1
|
472
|
-
else:
|
473
|
-
return e2
|
474
|
-
print("Edge.ExtendToEdge2D - Error: The operation failed. Returning None.")
|
475
|
-
return None
|
476
|
-
|
477
|
-
@staticmethod
|
478
|
-
def Index(edge: topologic.Edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int:
|
479
|
-
"""
|
480
|
-
Returns index of the input edge in the input list of edges
|
481
|
-
|
482
|
-
Parameters
|
483
|
-
----------
|
484
|
-
edge : topologic.Edge
|
485
|
-
The input edge.
|
486
|
-
edges : list
|
487
|
-
The input list of edges.
|
488
|
-
strict : bool , optional
|
489
|
-
If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False.
|
490
|
-
tolerance : float , optional
|
491
|
-
The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001.
|
492
|
-
|
493
|
-
Returns
|
494
|
-
-------
|
495
|
-
int
|
496
|
-
The index of the input edge in the input list of edges.
|
497
|
-
|
498
|
-
"""
|
499
|
-
from topologicpy.Topology import Topology
|
500
|
-
if not isinstance(edge, topologic.Edge):
|
501
|
-
print("Edge.Index - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
502
|
-
return None
|
503
|
-
if not isinstance(edges, list):
|
504
|
-
print("Edge.Index - Error: The input edges parameter is not a valid list. Returning None.")
|
505
|
-
return None
|
506
|
-
edges = [e for e in edges if isinstance(e, topologic.Edge)]
|
507
|
-
if len(edges) < 1:
|
508
|
-
print("Edge.Index - Error: The input edges parameter contains no valid edges. Returning None.")
|
509
|
-
return None
|
510
|
-
sva = Edge.StartVertex(edge)
|
511
|
-
eva = Edge.EndVertex(edge)
|
512
|
-
for i in range(len(edges)):
|
513
|
-
if strict:
|
514
|
-
if Topology.IsSame(edge, edges[i]):
|
515
|
-
return i
|
516
|
-
else:
|
517
|
-
svb = Edge.StartVertex(edges[i])
|
518
|
-
evb = Edge.EndVertex(edges[i])
|
519
|
-
dsvsv = Vertex.Distance(sva, svb)
|
520
|
-
devev = Vertex.Distance(eva, evb)
|
521
|
-
if dsvsv < tolerance and devev < tolerance:
|
522
|
-
return i
|
523
|
-
dsvev = Vertex.Distance(sva, evb)
|
524
|
-
devsv = Vertex.Distance(eva, svb)
|
525
|
-
if dsvev < tolerance and devsv < tolerance:
|
526
|
-
return i
|
527
|
-
return None
|
528
|
-
|
529
|
-
@staticmethod
|
530
|
-
def Intersect2D(edgeA: topologic.Edge, edgeB: topologic.Edge, silent: bool = False) -> topologic.Vertex:
|
531
|
-
"""
|
532
|
-
Returns the intersection of the two input edges as a topologic.Vertex. This works only in the XY plane. Z coordinates are ignored.
|
533
|
-
|
534
|
-
Parameters
|
535
|
-
----------
|
536
|
-
edgeA : topologic.Edge
|
537
|
-
The first input edge.
|
538
|
-
edgeB : topologic.Edge
|
539
|
-
The second input edge.
|
540
|
-
silent : bool , optional
|
541
|
-
If set to False, error and warning messages are displayed. Otherwise they are not. The default is False.
|
542
|
-
|
543
|
-
Returns
|
544
|
-
-------
|
545
|
-
topologic.Vertex
|
546
|
-
The intersection of the two input edges.
|
547
|
-
|
548
|
-
"""
|
549
|
-
if not isinstance(edgeA, topologic.Edge):
|
550
|
-
if not silent:
|
551
|
-
print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
552
|
-
return None
|
553
|
-
if not isinstance(edgeB, topologic.Edge):
|
554
|
-
if not silent:
|
555
|
-
print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
556
|
-
return None
|
557
|
-
sva = Edge.StartVertex(edgeA)
|
558
|
-
eva = Edge.EndVertex(edgeA)
|
559
|
-
svb = Edge.StartVertex(edgeB)
|
560
|
-
evb = Edge.EndVertex(edgeB)
|
561
|
-
# Line AB represented as a1x + b1y = c1
|
562
|
-
a1 = Vertex.Y(eva) - Vertex.Y(sva)
|
563
|
-
b1 = Vertex.X(sva) - Vertex.X(eva)
|
564
|
-
c1 = a1*(Vertex.X(sva)) + b1*(Vertex.Y(sva))
|
565
|
-
|
566
|
-
# Line CD represented as a2x + b2y = c2
|
567
|
-
a2 = Vertex.Y(evb) - Vertex.Y(svb)
|
568
|
-
b2 = Vertex.X(svb) - Vertex.X(evb)
|
569
|
-
c2 = a2*(Vertex.X(svb)) + b2*(Vertex.Y(svb))
|
570
|
-
|
571
|
-
determinant = a1*b2 - a2*b1
|
572
|
-
|
573
|
-
if (determinant == 0):
|
574
|
-
# The lines are parallel. This is simplified
|
575
|
-
# by returning a pair of FLT_MAX
|
576
|
-
if not silent:
|
577
|
-
print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.")
|
578
|
-
return None
|
579
|
-
else:
|
580
|
-
x = (b2*c1 - b1*c2)/determinant
|
581
|
-
y = (a1*c2 - a2*c1)/determinant
|
582
|
-
return Vertex.ByCoordinates(x,y,0)
|
583
|
-
|
584
|
-
|
585
|
-
@staticmethod
|
586
|
-
def IsCollinear(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, angTolerance: float = 0.1, tolerance: float = 0.0001) -> bool:
|
587
|
-
"""
|
588
|
-
Return True if the two input edges are collinear. Returns False otherwise.
|
589
|
-
|
590
|
-
Parameters
|
591
|
-
----------
|
592
|
-
edgeA : topologic.Edge
|
593
|
-
The first input edge.
|
594
|
-
edgeB : topologic.Edge
|
595
|
-
The second input edge.
|
596
|
-
mantissa : int , optional
|
597
|
-
The desired length of the mantissa. The default is 6.
|
598
|
-
angTolerance : float , optional
|
599
|
-
The angular tolerance used for the test. The default is 0.1.
|
600
|
-
tolerance : float , optional
|
601
|
-
The desired tolerance. The default is 0.0001.
|
602
|
-
|
603
|
-
Returns
|
604
|
-
-------
|
605
|
-
bool
|
606
|
-
True if the two edges are collinear. False otherwise.
|
607
|
-
|
608
|
-
"""
|
609
|
-
if not isinstance(edgeA, topologic.Edge):
|
610
|
-
print("Edge.IsCollinear - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
611
|
-
return None
|
612
|
-
if not isinstance(edgeB, topologic.Edge):
|
613
|
-
print("Edge.IsCollinear - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
614
|
-
return None
|
615
|
-
ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
|
616
|
-
svA = Edge.StartVertex(edgeA)
|
617
|
-
evA = Edge.EndVertex(edgeA)
|
618
|
-
svB = Edge.StartVertex(edgeB)
|
619
|
-
evB = Edge.EndVertex(edgeB)
|
620
|
-
d1 = Vertex.Distance(svA, svB)
|
621
|
-
d2 = Vertex.Distance(svA, evB)
|
622
|
-
d3 = Vertex.Distance(evA, svB)
|
623
|
-
d4 = Vertex.Distance(evA, evB)
|
624
|
-
if (d1 < tolerance or d2 < tolerance or d3 < tolerance or d4 < tolerance) and (abs(ang) < angTolerance or (abs(180 - ang) < angTolerance)):
|
625
|
-
return True
|
626
|
-
return False
|
627
|
-
|
628
|
-
@staticmethod
|
629
|
-
def IsParallel(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, angTolerance: float = 0.1) -> bool:
|
630
|
-
"""
|
631
|
-
Return True if the two input edges are parallel. Returns False otherwise.
|
632
|
-
|
633
|
-
Parameters
|
634
|
-
----------
|
635
|
-
edgeA : topologic.Edge
|
636
|
-
The first input edge.
|
637
|
-
edgeB : topologic.Edge
|
638
|
-
The second input edge.
|
639
|
-
mantissa : int , optional
|
640
|
-
The desired length of the mantissa. The default is 6.
|
641
|
-
angTolerance : float , optional
|
642
|
-
The angular tolerance used for the test. The default is 0.1.
|
643
|
-
|
644
|
-
Returns
|
645
|
-
-------
|
646
|
-
bool
|
647
|
-
True if the two edges are collinear. False otherwise.
|
648
|
-
|
649
|
-
"""
|
650
|
-
if not isinstance(edgeA, topologic.Edge):
|
651
|
-
print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
652
|
-
return None
|
653
|
-
if not isinstance(edgeB, topologic.Edge):
|
654
|
-
print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
655
|
-
return None
|
656
|
-
ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
|
657
|
-
if abs(ang) < angTolerance or abs(180 - ang) < angTolerance:
|
658
|
-
return True
|
659
|
-
return False
|
660
|
-
|
661
|
-
@staticmethod
|
662
|
-
def Length(edge: topologic.Edge, mantissa: int = 6) -> float:
|
663
|
-
"""
|
664
|
-
Returns the length of the input edge.
|
665
|
-
|
666
|
-
Parameters
|
667
|
-
----------
|
668
|
-
edge : topologic.Edge
|
669
|
-
The input edge.
|
670
|
-
mantissa : int , optional
|
671
|
-
The desired length of the mantissa. The default is 6.
|
672
|
-
|
673
|
-
Returns
|
674
|
-
-------
|
675
|
-
float
|
676
|
-
The length of the input edge.
|
677
|
-
|
678
|
-
"""
|
679
|
-
if not isinstance(edge, topologic.Edge):
|
680
|
-
print("Edge.Length - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
681
|
-
return None
|
682
|
-
length = None
|
683
|
-
try:
|
684
|
-
length = round(topologic.EdgeUtility.Length(edge), mantissa)
|
685
|
-
except:
|
686
|
-
length = None
|
687
|
-
if length == None:
|
688
|
-
print("Edge.Length - Error: Could not compute the length of the input edge parameter. Returning None.")
|
689
|
-
return length
|
690
|
-
|
691
|
-
@staticmethod
|
692
|
-
def Line(origin: topologic.Vertex = None, length: float = 1, direction: list = [1,0,0], placement: str ="center", tolerance: float = 0.0001) -> topologic.Edge:
|
693
|
-
"""
|
694
|
-
Creates a straight edge (line) using the input parameters.
|
695
|
-
|
696
|
-
Parameters
|
697
|
-
----------
|
698
|
-
origin : topologic.Vertex , optional
|
699
|
-
The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0).
|
700
|
-
length : float , optional
|
701
|
-
The desired length of the edge. The default is 1.0.
|
702
|
-
direction : list , optional
|
703
|
-
The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis).
|
704
|
-
placement : str , optional
|
705
|
-
The desired placement of the edge. The options are:
|
706
|
-
1. "center" which places the center of the edge at the origin.
|
707
|
-
2. "start" which places the start of the edge at the origin.
|
708
|
-
3. "end" which places the end of the edge at the origin.
|
709
|
-
The default is "center".
|
710
|
-
tolerance : float , optional
|
711
|
-
The desired tolerance. The default is 0.0001.
|
712
|
-
Returns
|
713
|
-
-------
|
714
|
-
topology.Edge
|
715
|
-
The created edge
|
716
|
-
"""
|
717
|
-
|
718
|
-
from topologicpy.Vertex import Vertex
|
719
|
-
from topologicpy.Vector import Vector
|
720
|
-
from topologicpy.Topology import Topology
|
721
|
-
|
722
|
-
if origin == None:
|
723
|
-
origin = Vertex.Origin()
|
724
|
-
if not isinstance(origin, topologic.Vertex):
|
725
|
-
print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
726
|
-
return None
|
727
|
-
if length <= 0:
|
728
|
-
print("Edge.Line - Error: The input length is less than or equal to zero. Returning None.")
|
729
|
-
return None
|
730
|
-
if not isinstance(direction, list):
|
731
|
-
print("Edge.Line - Error: The input direction parameter is not a valid list. Returning None.")
|
732
|
-
return None
|
733
|
-
if not len(direction) == 3:
|
734
|
-
print("Edge.Line - Error: The length of the input direction parameter is not equal to three. Returning None.")
|
735
|
-
return None
|
736
|
-
direction = Vector.Normalize(direction)
|
737
|
-
if "center" in placement.lower():
|
738
|
-
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length*0.5)
|
739
|
-
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
740
|
-
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
741
|
-
if "start" in placement.lower():
|
742
|
-
sv = origin
|
743
|
-
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
744
|
-
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
745
|
-
if "end" in placement.lower():
|
746
|
-
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length)
|
747
|
-
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
748
|
-
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
749
|
-
else:
|
750
|
-
print("Edge.Line - Error: The input placement string is not one of center, start, or end. Returning None.")
|
751
|
-
return None
|
752
|
-
|
753
|
-
@staticmethod
|
754
|
-
def Normal(edge: topologic.Edge, angle: float = 0.0):
|
755
|
-
"""
|
756
|
-
Returns the normal (perpendicular) vector to the input edge.
|
757
|
-
|
758
|
-
Parameters
|
759
|
-
----------
|
760
|
-
edge : topologic.Edge
|
761
|
-
The input edge.
|
762
|
-
angle : float , optional
|
763
|
-
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
|
764
|
-
by the angle value around the axis defined by the input edge. The default is 0.0.
|
765
|
-
|
766
|
-
Returns
|
767
|
-
-------
|
768
|
-
list
|
769
|
-
The normal (perpendicular ) vector to the input edge.
|
770
|
-
|
771
|
-
"""
|
772
|
-
if not isinstance(edge, topologic.Edge):
|
773
|
-
print("Edge.Normal - Error: The input edge parameter is not a valid edge. Returning None.")
|
774
|
-
return None
|
775
|
-
normal_edge = Edge.NormalAsEdge(edge, length=1.0, u=0.5, angle=angle)
|
776
|
-
return Edge.Direction(normal_edge)
|
777
|
-
|
778
|
-
@staticmethod
|
779
|
-
def NormalAsEdge(edge: topologic.Edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0):
|
780
|
-
"""
|
781
|
-
Returns the normal (perpendicular) vector to the input edge as an edge.
|
782
|
-
|
783
|
-
Parameters
|
784
|
-
----------
|
785
|
-
edge : topologic.Edge
|
786
|
-
The input edge.
|
787
|
-
length : float , optional
|
788
|
-
The desired length of the normal edge. The default is 1.0.
|
789
|
-
u : float , optional
|
790
|
-
The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge
|
791
|
-
at the start vertex of the input edge, a value of 0.5 places the normal edge
|
792
|
-
at the midpoint of the input edge, and a value of 1.0 places the normal edge
|
793
|
-
at the end vertex of the input edge. The default is 0.5
|
794
|
-
angle : float , optional
|
795
|
-
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
|
796
|
-
by the angle value around the axis defined by the input edge. The default is 0.0.
|
797
|
-
|
798
|
-
Returns
|
799
|
-
-------
|
800
|
-
topologic.Edge
|
801
|
-
The normal (perpendicular) vector to the input edge as an edge.
|
802
|
-
|
803
|
-
"""
|
804
|
-
import numpy as np
|
805
|
-
from numpy.linalg import norm
|
806
|
-
import topologic
|
807
|
-
from topologicpy.Vertex import Vertex
|
808
|
-
from topologicpy.Topology import Topology
|
809
|
-
|
810
|
-
def calculate_normal(start_vertex, end_vertex):
|
811
|
-
start_vertex = [float(x) for x in start_vertex]
|
812
|
-
end_vertex = [float(x) for x in end_vertex]
|
813
|
-
# Calculate the direction vector of the line segment
|
814
|
-
direction_vector = np.array(end_vertex) - np.array(start_vertex)
|
815
|
-
|
816
|
-
# Calculate the normal vector by swapping components and negating one of them
|
817
|
-
normal_vector = np.array([-direction_vector[1], direction_vector[0], 0])
|
818
|
-
|
819
|
-
# Normalize the normal vector
|
820
|
-
normal_vector /= norm(normal_vector)
|
821
|
-
|
822
|
-
return normal_vector
|
823
|
-
|
824
|
-
|
825
|
-
def calculate_normal_line(start_vertex, end_vertex):
|
826
|
-
# Calculate the normal vector of the line
|
827
|
-
normal_vector = calculate_normal(start_vertex, end_vertex)
|
828
|
-
|
829
|
-
# Calculate the new end vertex for the normal line to have a length of 1
|
830
|
-
normal_end_vertex = np.array(start_vertex) + normal_vector
|
831
|
-
|
832
|
-
# Return the start and end vertices of the normal line
|
833
|
-
return start_vertex, list(normal_end_vertex)
|
834
|
-
|
835
|
-
if not isinstance(edge, topologic.Edge):
|
836
|
-
print("Edge.NormalAsEdge - Error: The input edge parameter is not a valid edge. Returning None.")
|
837
|
-
return None
|
838
|
-
if length <= 0.0:
|
839
|
-
print("Edge.NormalAsEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.")
|
840
|
-
return None
|
841
|
-
edge_direction = Edge.Direction(edge)
|
842
|
-
x, y, z = edge_direction
|
843
|
-
start_vertex = Vertex.Coordinates(Edge.StartVertex(edge))
|
844
|
-
end_vertex = Vertex.Coordinates(Edge.EndVertex(edge))
|
845
|
-
normal_line_start, normal_line_end = calculate_normal_line(start_vertex, end_vertex)
|
846
|
-
sv = Vertex.ByCoordinates(normal_line_start)
|
847
|
-
ev = Vertex.ByCoordinates(list(normal_line_end))
|
848
|
-
normal_edge = Edge.ByVertices([sv, ev])
|
849
|
-
normal_edge = Edge.SetLength(normal_edge, length, bothSides=False)
|
850
|
-
normal_edge = Topology.Rotate(normal_edge, origin=Edge.StartVertex(normal_edge), axis=[x,y,z], angle=angle)
|
851
|
-
dist = Edge.Length(edge)*u
|
852
|
-
normal_edge = Topology.TranslateByDirectionDistance(normal_edge, edge_direction, dist)
|
853
|
-
return normal_edge
|
854
|
-
|
855
|
-
@staticmethod
|
856
|
-
def Normalize(edge: topologic.Edge, useEndVertex: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
857
|
-
"""
|
858
|
-
Creates a normalized edge that has the same direction as the input edge, but a length of 1.
|
859
|
-
|
860
|
-
Parameters
|
861
|
-
----------
|
862
|
-
edge : topologic.Edge
|
863
|
-
The input edge.
|
864
|
-
useEndVertex : bool , optional
|
865
|
-
If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False.
|
866
|
-
tolerance : float , optional
|
867
|
-
The desired tolerance. The default is 0.0001.
|
868
|
-
|
869
|
-
Returns
|
870
|
-
-------
|
871
|
-
topologic.Edge
|
872
|
-
The normalized edge.
|
873
|
-
|
874
|
-
"""
|
875
|
-
if not isinstance(edge, topologic.Edge):
|
876
|
-
print("Edge.Normalize - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
877
|
-
return None
|
878
|
-
if not useEndVertex:
|
879
|
-
sv = edge.StartVertex()
|
880
|
-
ev = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
|
881
|
-
else:
|
882
|
-
sv = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
|
883
|
-
ev = edge.EndVertex()
|
884
|
-
return Edge.ByVertices([sv, ev], tolerance=tolerance)
|
885
|
-
|
886
|
-
@staticmethod
|
887
|
-
def ParameterAtVertex(edge: topologic.Edge, vertex: topologic.Vertex, mantissa: int = 6, silent: bool = False) -> float:
|
888
|
-
"""
|
889
|
-
Returns the *u* parameter along the input edge based on the location of the input vertex.
|
890
|
-
|
891
|
-
Parameters
|
892
|
-
----------
|
893
|
-
edge : topologic.Edge
|
894
|
-
The input edge.
|
895
|
-
vertex : topologic.Vertex
|
896
|
-
The input vertex.
|
897
|
-
mantissa : int , optional
|
898
|
-
The desired length of the mantissa. The default is 6.
|
899
|
-
silent : bool , optional
|
900
|
-
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
901
|
-
|
902
|
-
Returns
|
903
|
-
-------
|
904
|
-
float
|
905
|
-
The *u* parameter along the input edge based on the location of the input vertex.
|
906
|
-
|
907
|
-
"""
|
908
|
-
if not isinstance(edge, topologic.Edge):
|
909
|
-
if not silent:
|
910
|
-
print("Edge.ParameterAtVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
911
|
-
return None
|
912
|
-
if not isinstance(vertex, topologic.Vertex):
|
913
|
-
if not silent:
|
914
|
-
print("Edge.ParameterAtVertex - Error: The input vertex parameter is not a valid topologic vertex. Returning None.")
|
915
|
-
return None
|
916
|
-
parameter = None
|
917
|
-
try:
|
918
|
-
parameter = topologic.EdgeUtility.ParameterAtPoint(edge, vertex)
|
919
|
-
except:
|
920
|
-
return None #Return silently because topologic C++ returns a runtime error if point is not on curve.
|
921
|
-
return round(parameter, mantissa)
|
922
|
-
|
923
|
-
@staticmethod
|
924
|
-
def Reverse(edge: topologic.Edge, tolerance: float = 0.0001) -> topologic.Edge:
|
925
|
-
"""
|
926
|
-
Creates an edge that has the reverse direction of the input edge.
|
927
|
-
|
928
|
-
Parameters
|
929
|
-
----------
|
930
|
-
edge : topologic.Edge
|
931
|
-
The input edge.
|
932
|
-
tolerance : float , optional
|
933
|
-
The desired tolerance. The default is 0.0001.
|
934
|
-
|
935
|
-
Returns
|
936
|
-
-------
|
937
|
-
topologic.Edge
|
938
|
-
The reversed edge.
|
939
|
-
|
940
|
-
"""
|
941
|
-
if not isinstance(edge, topologic.Edge):
|
942
|
-
print("Edge.Reverse - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
943
|
-
return None
|
944
|
-
return Edge.ByVertices([edge.EndVertex(), edge.StartVertex()], tolerance=tolerance)
|
945
|
-
|
946
|
-
@staticmethod
|
947
|
-
def SetLength(edge: topologic.Edge , length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
948
|
-
"""
|
949
|
-
Returns an edge with the new length in the same direction as the input edge.
|
950
|
-
|
951
|
-
Parameters
|
952
|
-
----------
|
953
|
-
edge : topologic.Edge
|
954
|
-
The input edge.
|
955
|
-
length : float , optional
|
956
|
-
The desired length of the edge. The default is 1.
|
957
|
-
bothSides : bool , optional
|
958
|
-
If set to True, the edge will be offset symmetrically from each end. The default is True.
|
959
|
-
reverse : bool , optional
|
960
|
-
If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False.
|
961
|
-
tolerance : float , optional
|
962
|
-
The desired tolerance. The default is 0.0001.
|
963
|
-
|
964
|
-
Returns
|
965
|
-
-------
|
966
|
-
topologic.Edge
|
967
|
-
The extended edge.
|
968
|
-
|
969
|
-
"""
|
970
|
-
if not isinstance(edge, topologic.Edge):
|
971
|
-
print("Edge.SetLength - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
972
|
-
return None
|
973
|
-
distance = (length - Edge.Length(edge))
|
974
|
-
if distance > 0:
|
975
|
-
return Edge.Extend(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
|
976
|
-
return Edge.Trim(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
|
977
|
-
|
978
|
-
@staticmethod
|
979
|
-
def StartVertex(edge: topologic.Edge) -> topologic.Vertex:
|
980
|
-
"""
|
981
|
-
Returns the start vertex of the input edge.
|
982
|
-
|
983
|
-
Parameters
|
984
|
-
----------
|
985
|
-
edge : topologic.Edge
|
986
|
-
The input edge.
|
987
|
-
|
988
|
-
Returns
|
989
|
-
-------
|
990
|
-
topologic.Vertex
|
991
|
-
The start vertex of the input edge.
|
992
|
-
|
993
|
-
"""
|
994
|
-
if not isinstance(edge, topologic.Edge):
|
995
|
-
print("Edge.StartVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
996
|
-
return None
|
997
|
-
vert = None
|
998
|
-
try:
|
999
|
-
vert = edge.StartVertex()
|
1000
|
-
except:
|
1001
|
-
vert = None
|
1002
|
-
return vert
|
1003
|
-
|
1004
|
-
@staticmethod
|
1005
|
-
def Trim(edge: topologic.Edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
1006
|
-
"""
|
1007
|
-
Trims the input edge by the input distance.
|
1008
|
-
|
1009
|
-
Parameters
|
1010
|
-
----------
|
1011
|
-
edge : topologic.Edge
|
1012
|
-
The input edge.
|
1013
|
-
distance : float , optional
|
1014
|
-
The offset distance. The default is 0.
|
1015
|
-
bothSides : bool , optional
|
1016
|
-
If set to True, the edge will be trimmed by half the distance at each end. The default is False.
|
1017
|
-
reverse : bool , optional
|
1018
|
-
If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False.
|
1019
|
-
tolerance : float , optional
|
1020
|
-
The desired tolerance. The default is 0.0001.
|
1021
|
-
|
1022
|
-
Returns
|
1023
|
-
-------
|
1024
|
-
topologic.Edge
|
1025
|
-
The trimmed edge.
|
1026
|
-
|
1027
|
-
"""
|
1028
|
-
if not isinstance(edge, topologic.Edge):
|
1029
|
-
print("Edge.Trim - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1030
|
-
return None
|
1031
|
-
distance = abs(distance)
|
1032
|
-
if distance == 0:
|
1033
|
-
return edge
|
1034
|
-
if distance < tolerance:
|
1035
|
-
print("Edge.Trim - Warning: The input distance parameter is less than the input tolerance parameter. Returning the input edge.")
|
1036
|
-
return edge
|
1037
|
-
sv = Edge.StartVertex(edge)
|
1038
|
-
ev = Edge.EndVertex(edge)
|
1039
|
-
if bothSides:
|
1040
|
-
sve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=sv, tolerance=tolerance)
|
1041
|
-
eve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=ev, tolerance=tolerance)
|
1042
|
-
elif reverse:
|
1043
|
-
sve = Edge.VertexByDistance(edge, distance=distance, origin=sv, tolerance=tolerance)
|
1044
|
-
eve = Edge.EndVertex(edge)
|
1045
|
-
else:
|
1046
|
-
sve = Edge.StartVertex(edge)
|
1047
|
-
eve = Edge.VertexByDistance(edge, distance=-distance, origin=ev, tolerance=tolerance)
|
1048
|
-
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
1049
|
-
|
1050
|
-
@staticmethod
|
1051
|
-
def TrimByEdge2D(edgeA: topologic.Edge, edgeB: topologic.Edge, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
1052
|
-
"""
|
1053
|
-
Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored.
|
1054
|
-
|
1055
|
-
Parameters
|
1056
|
-
----------
|
1057
|
-
edgeA : topologic.Edge
|
1058
|
-
The first input edge.
|
1059
|
-
edgeB : topologic.Edge
|
1060
|
-
The second input edge.
|
1061
|
-
tolerance : float , optional
|
1062
|
-
The desired tolerance. The default is 0.0001.
|
1063
|
-
|
1064
|
-
Returns
|
1065
|
-
-------
|
1066
|
-
topologic.Edge
|
1067
|
-
The trimmed edge.
|
1068
|
-
|
1069
|
-
"""
|
1070
|
-
from topologicpy.Topology import Topology
|
1071
|
-
if not isinstance(edgeA, topologic.Edge):
|
1072
|
-
print("Edge.TrimByEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
1073
|
-
return None
|
1074
|
-
if not isinstance(edgeB, topologic.Edge):
|
1075
|
-
print("Edge.TrimByEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
1076
|
-
return None
|
1077
|
-
sva = Edge.StartVertex(edgeA)
|
1078
|
-
eva = Edge.EndVertex(edgeA)
|
1079
|
-
intVertex = Edge.Intersect2D(edgeA, edgeB)
|
1080
|
-
if intVertex and (Vertex.IsInternal(intVertex, edgeA)):
|
1081
|
-
if reverse:
|
1082
|
-
return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
1083
|
-
else:
|
1084
|
-
return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
|
1085
|
-
return edgeA
|
1086
|
-
|
1087
|
-
@staticmethod
|
1088
|
-
def VertexByDistance(edge: topologic.Edge, distance: float = 0.0, origin: topologic.Vertex = None, tolerance: float = 0.0001) -> topologic.Vertex:
|
1089
|
-
"""
|
1090
|
-
Creates a vertex along the input edge offset by the input distance from the input origin.
|
1091
|
-
|
1092
|
-
Parameters
|
1093
|
-
----------
|
1094
|
-
edge : topologic.Edge
|
1095
|
-
The input edge.
|
1096
|
-
distance : float , optional
|
1097
|
-
The offset distance. The default is 0.
|
1098
|
-
origin : topologic.Vertex , optional
|
1099
|
-
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.
|
1100
|
-
tolerance : float , optional
|
1101
|
-
The desired tolerance. The default is 0.0001.
|
1102
|
-
|
1103
|
-
Returns
|
1104
|
-
-------
|
1105
|
-
topologic.Vertex
|
1106
|
-
The created vertex.
|
1107
|
-
|
1108
|
-
"""
|
1109
|
-
|
1110
|
-
if not isinstance(edge, topologic.Edge):
|
1111
|
-
print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1112
|
-
return None
|
1113
|
-
if not origin:
|
1114
|
-
origin = edge.StartVertex()
|
1115
|
-
if not isinstance(origin, topologic.Vertex):
|
1116
|
-
print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
1117
|
-
return None
|
1118
|
-
sv = edge.StartVertex()
|
1119
|
-
ev = edge.EndVertex()
|
1120
|
-
vx = ev.X() - sv.X()
|
1121
|
-
vy = ev.Y() - sv.Y()
|
1122
|
-
vz = ev.Z() - sv.Z()
|
1123
|
-
vector = Vector.Normalize([vx, vy, vz])
|
1124
|
-
vector = Vector.Multiply(vector, distance, tolerance)
|
1125
|
-
return topologic.Vertex.ByCoordinates(origin.X()+vector[0], origin.Y()+vector[1], origin.Z()+vector[2])
|
1126
|
-
|
1127
|
-
@staticmethod
|
1128
|
-
def VertexByParameter(edge: topologic.Edge, u: float = 0.0) -> topologic.Vertex:
|
1129
|
-
"""
|
1130
|
-
Creates a vertex along the input edge offset by the input *u* parameter.
|
1131
|
-
|
1132
|
-
Parameters
|
1133
|
-
----------
|
1134
|
-
edge : topologic.Edge
|
1135
|
-
The input edge.
|
1136
|
-
u : float , optional
|
1137
|
-
The *u* parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0.
|
1138
|
-
|
1139
|
-
Returns
|
1140
|
-
-------
|
1141
|
-
topologic.Vertex
|
1142
|
-
The created vertex.
|
1143
|
-
|
1144
|
-
"""
|
1145
|
-
from topologicpy.Topology import Topology
|
1146
|
-
|
1147
|
-
if not isinstance(edge, topologic.Edge):
|
1148
|
-
print("Edge.VertexByParameter - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1149
|
-
return None
|
1150
|
-
vertex = None
|
1151
|
-
if u == 0:
|
1152
|
-
vertex = edge.StartVertex()
|
1153
|
-
elif u == 1:
|
1154
|
-
vertex = edge.EndVertex()
|
1155
|
-
else:
|
1156
|
-
dir = Edge.Direction(edge)
|
1157
|
-
edge_length = Edge.Length(edge)
|
1158
|
-
dist = edge_length*u
|
1159
|
-
vertex = Topology.TranslateByDirectionDistance(Edge.StartVertex(edge), direction=dir, distance=dist)
|
1160
|
-
#try:
|
1161
|
-
#vertex = topologic.EdgeUtility.PointAtParameter(edge, u)
|
1162
|
-
#except:
|
1163
|
-
#print("Edge.VertexByParameter - Error: Could not create a vertex at the input parameter. Returning None.")
|
1164
|
-
#vertex = None
|
1165
|
-
return vertex
|
1166
|
-
|
1167
|
-
@staticmethod
|
1168
|
-
def Vertices(edge: topologic.Edge) -> list:
|
1169
|
-
"""
|
1170
|
-
Returns the list of vertices of the input edge.
|
1171
|
-
|
1172
|
-
Parameters
|
1173
|
-
----------
|
1174
|
-
edge : topologic.Edge
|
1175
|
-
The input edge.
|
1176
|
-
|
1177
|
-
Returns
|
1178
|
-
-------
|
1179
|
-
list
|
1180
|
-
The list of vertices.
|
1181
|
-
|
1182
|
-
"""
|
1183
|
-
if not isinstance(edge, topologic.Edge):
|
1184
|
-
print("Edge.Vertices - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1185
|
-
return None
|
1186
|
-
vertices = []
|
1187
|
-
_ = edge.Vertices(None, vertices)
|
1
|
+
# Copyright (C) 2024
|
2
|
+
# Wassim Jabi <wassim.jabi@gmail.com>
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free Software
|
6
|
+
# Foundation, either version 3 of the License, or (at your option) any later
|
7
|
+
# version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License along with
|
15
|
+
# this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
import topologic_core as topologic
|
18
|
+
from topologicpy.Vertex import Vertex
|
19
|
+
from topologicpy.Vector import Vector
|
20
|
+
from topologicpy.Topology import Topology
|
21
|
+
|
22
|
+
class Edge(Topology):
|
23
|
+
@staticmethod
|
24
|
+
def Angle(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, bracket: bool = False) -> float:
|
25
|
+
"""
|
26
|
+
Returns the angle in degrees between the two input edges.
|
27
|
+
|
28
|
+
Parameters
|
29
|
+
----------
|
30
|
+
edgeA : topologic.Edge
|
31
|
+
The first input edge.
|
32
|
+
edgeB : topologic Edge
|
33
|
+
The second input edge.
|
34
|
+
mantissa : int , optional
|
35
|
+
The desired length of the mantissa. The default is 6.
|
36
|
+
bracket : bool
|
37
|
+
If set to True, the returned angle is bracketed between 0 and 180. The default is False.
|
38
|
+
|
39
|
+
Returns
|
40
|
+
-------
|
41
|
+
float
|
42
|
+
The angle in degrees between the two input edges.
|
43
|
+
|
44
|
+
"""
|
45
|
+
|
46
|
+
if not isinstance(edgeA, topologic.Edge):
|
47
|
+
print("Edge.Angle - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
48
|
+
return None
|
49
|
+
if not isinstance(edgeB, topologic.Edge):
|
50
|
+
print("Edge.Angle - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
51
|
+
return None
|
52
|
+
dirA = Edge.Direction(edgeA, mantissa)
|
53
|
+
dirB = Edge.Direction(edgeB, mantissa)
|
54
|
+
ang = Vector.Angle(dirA, dirB)
|
55
|
+
if bracket:
|
56
|
+
if ang > 90:
|
57
|
+
ang = 180 - ang
|
58
|
+
return round(ang, mantissa)
|
59
|
+
|
60
|
+
@staticmethod
|
61
|
+
def Bisect(edgeA: topologic.Edge, edgeB: topologic.Edge, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001) -> topologic.Edge:
|
62
|
+
"""
|
63
|
+
Creates a bisecting edge between edgeA and edgeB.
|
64
|
+
|
65
|
+
Parameters
|
66
|
+
----------
|
67
|
+
edgeA : topologic.Edge
|
68
|
+
The first topologic Edge.
|
69
|
+
edgeB : topologic Edge
|
70
|
+
The second topologic Edge.
|
71
|
+
length : float , optional
|
72
|
+
The desired length of the bisecting edge. The default is 1.0.
|
73
|
+
placement : int , optional
|
74
|
+
The desired placement of the bisecting edge.
|
75
|
+
If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge.
|
76
|
+
If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge.
|
77
|
+
If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge.
|
78
|
+
If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0.
|
79
|
+
tolerance : float , optional
|
80
|
+
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
-------
|
84
|
+
topologic.Edge
|
85
|
+
The created bisecting edge.
|
86
|
+
|
87
|
+
"""
|
88
|
+
import numpy as np
|
89
|
+
|
90
|
+
from topologicpy.Wire import Wire
|
91
|
+
from topologicpy.Cluster import Cluster
|
92
|
+
from topologicpy.Topology import Topology
|
93
|
+
from topologicpy.Vector import Vector
|
94
|
+
|
95
|
+
if not isinstance(edgeA, topologic.Edge):
|
96
|
+
print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
97
|
+
return None
|
98
|
+
if not isinstance(edgeB, topologic.Edge):
|
99
|
+
print("Edge.Bisect - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
100
|
+
return None
|
101
|
+
if Edge.Length(edgeA) < tolerance:
|
102
|
+
print("Edge.Bisect - Error: The input edgeA parameter is shorter than the input tolerance parameter. Returning None.")
|
103
|
+
return None
|
104
|
+
if Edge.Length(edgeB) < tolerance:
|
105
|
+
print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.")
|
106
|
+
return None
|
107
|
+
|
108
|
+
wire = Topology.SelfMerge(Cluster.ByTopologies([edgeA, edgeB]), tolerance=tolerance)
|
109
|
+
if not isinstance(wire, topologic.Wire):
|
110
|
+
print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.")
|
111
|
+
return None
|
112
|
+
edges = Topology.Edges(wire)
|
113
|
+
edgeA = edges[0]
|
114
|
+
edgeB = edges[1]
|
115
|
+
|
116
|
+
sv = Wire.Vertices(wire)[1]
|
117
|
+
|
118
|
+
dirA = Edge.Direction(edgeA)
|
119
|
+
dirB = Edge.Direction(edgeB)
|
120
|
+
bisecting_vector = Vector.Bisect(dirA, dirB)
|
121
|
+
ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length)
|
122
|
+
bisecting_edge = Edge.ByVertices([sv, ev])
|
123
|
+
return bisecting_edge
|
124
|
+
|
125
|
+
@staticmethod
|
126
|
+
def ByFaceNormal(face: topologic.Face, origin: topologic.Vertex = None, length: float = 1.0, tolerance: float = 0.0001) -> topologic.Edge:
|
127
|
+
"""
|
128
|
+
Creates a straight edge representing the normal to the input face.
|
129
|
+
|
130
|
+
Parameters
|
131
|
+
----------
|
132
|
+
face : topologic.Face
|
133
|
+
The input face
|
134
|
+
origin : toopologic.Vertex , optional
|
135
|
+
The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None.
|
136
|
+
length : float , optional
|
137
|
+
The desired length of the edge. The default is 1.
|
138
|
+
tolerance : float , optional
|
139
|
+
The desired tolerance. The default is 0.0001.
|
140
|
+
|
141
|
+
Returns
|
142
|
+
-------
|
143
|
+
edge : topologic.Edge
|
144
|
+
The created edge.
|
145
|
+
|
146
|
+
"""
|
147
|
+
from topologicpy.Vertex import Vertex
|
148
|
+
from topologicpy.Face import Face
|
149
|
+
from topologicpy.Topology import Topology
|
150
|
+
edge = None
|
151
|
+
if not isinstance(face, topologic.Face):
|
152
|
+
print("Edge.ByFaceNormal - Error: The input face parameter is not a valid topologic face. Returning None.")
|
153
|
+
return None
|
154
|
+
if not isinstance(origin, topologic.Vertex):
|
155
|
+
origin = Topology.Centroid(face)
|
156
|
+
if not isinstance(origin, topologic.Vertex):
|
157
|
+
print("Edge.ByFaceNormal - Error: The input origin parameter is not a valid topologic origin. Returning None.")
|
158
|
+
return None
|
159
|
+
n = Face.Normal(face)
|
160
|
+
v2 = Topology.Translate(origin, n[0], n[1], n[2])
|
161
|
+
edge = Edge.ByStartVertexEndVertex(origin, v2, tolerance=tolerance, silent=True)
|
162
|
+
if not isinstance(edge, topologic.Edge):
|
163
|
+
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
|
164
|
+
return None
|
165
|
+
edge = Edge.SetLength(edge, length, bothSides=False)
|
166
|
+
if not isinstance(edge, topologic.Edge):
|
167
|
+
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
|
168
|
+
return None
|
169
|
+
return edge
|
170
|
+
|
171
|
+
@staticmethod
|
172
|
+
def ByOffset2D(edge: topologic.Edge, offset: float = 1.0, tolerance: float = 0.0001) -> topologic.Edge:
|
173
|
+
"""
|
174
|
+
Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane.
|
175
|
+
|
176
|
+
Parameters
|
177
|
+
----------
|
178
|
+
edge : topologic.Edge
|
179
|
+
The input edge.
|
180
|
+
offset : float , optional
|
181
|
+
The desired offset. The default is 1.
|
182
|
+
tolerance : float , optiona
|
183
|
+
The desired tolerance. The default is 0.0001.
|
184
|
+
|
185
|
+
Returns
|
186
|
+
-------
|
187
|
+
topologic.Edge
|
188
|
+
An edge offset from the input edge.
|
189
|
+
|
190
|
+
"""
|
191
|
+
from topologicpy.Topology import Topology
|
192
|
+
n = Edge.Normal(edge)
|
193
|
+
n = Vector.Normalize(n)
|
194
|
+
n = Vector.Multiply(n, offset, tolerance)
|
195
|
+
edge = Topology.Translate(edge, n[0], n[1], n[2])
|
196
|
+
return edge
|
197
|
+
|
198
|
+
|
199
|
+
@staticmethod
|
200
|
+
def ByStartVertexEndVertex(vertexA: topologic.Vertex, vertexB: topologic.Vertex, tolerance: float = 0.0001, silent=False) -> topologic.Edge:
|
201
|
+
"""
|
202
|
+
Creates a straight edge that connects the input vertices.
|
203
|
+
|
204
|
+
Parameters
|
205
|
+
----------
|
206
|
+
vertexA : topologic.Vertex
|
207
|
+
The first input vertex. This is considered the start vertex.
|
208
|
+
vertexB : toopologic.Vertex
|
209
|
+
The second input vertex. This is considered the end vertex.
|
210
|
+
tolerance : float , optional
|
211
|
+
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
|
212
|
+
silent : bool , optional
|
213
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
214
|
+
|
215
|
+
Returns
|
216
|
+
-------
|
217
|
+
edge : topologic.Edge
|
218
|
+
The created edge.
|
219
|
+
|
220
|
+
"""
|
221
|
+
from topologicpy.Vertex import Vertex
|
222
|
+
edge = None
|
223
|
+
if not isinstance(vertexA, topologic.Vertex):
|
224
|
+
if not silent:
|
225
|
+
print("Edge.ByStartVertexEndVertex - Error: The input vertexA parameter is not a valid topologic vertex. Returning None.")
|
226
|
+
return None
|
227
|
+
if not isinstance(vertexB, topologic.Vertex):
|
228
|
+
if not silent:
|
229
|
+
print("Edge.ByStartVertexEndVertex - Error: The input vertexB parameter is not a valid topologic vertex. Returning None.")
|
230
|
+
return None
|
231
|
+
if topologic.Topology.IsSame(vertexA, vertexB):
|
232
|
+
if not silent:
|
233
|
+
print("Edge.ByStartVertexEndVertex - Error: The input vertexA and vertexB parameters are the same vertex. Returning None.")
|
234
|
+
return None
|
235
|
+
if Vertex.Distance(vertexA, vertexB) < tolerance:
|
236
|
+
if not silent:
|
237
|
+
print("Edge.ByStartVertexEndVertex - Error: The distance between the input vertexA and vertexB parameters is less than the input tolerance. Returning None.")
|
238
|
+
return None
|
239
|
+
try:
|
240
|
+
edge = topologic.Edge.ByStartVertexEndVertex(vertexA, vertexB)
|
241
|
+
except:
|
242
|
+
if not silent:
|
243
|
+
print("Edge.ByStartVertexEndVertex - Error: Could not create an edge. Returning None.")
|
244
|
+
edge = None
|
245
|
+
return edge
|
246
|
+
|
247
|
+
@staticmethod
|
248
|
+
def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False) -> topologic.Edge:
|
249
|
+
"""
|
250
|
+
Creates a straight edge that connects the input list of vertices.
|
251
|
+
|
252
|
+
Parameters
|
253
|
+
----------
|
254
|
+
vertices : list
|
255
|
+
The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
|
256
|
+
tolerance : float , optional
|
257
|
+
The desired tolerance to decide if an edge can be created. The default is 0.0001.
|
258
|
+
silent : bool , optional
|
259
|
+
If set to True, error and warning messages are printed. Otherwise, they are not. The default is True.
|
260
|
+
|
261
|
+
Returns
|
262
|
+
-------
|
263
|
+
topologic.Edge
|
264
|
+
The created edge.
|
265
|
+
|
266
|
+
"""
|
267
|
+
|
268
|
+
from topologicpy.Helper import Helper
|
269
|
+
|
270
|
+
if len(args) == 0:
|
271
|
+
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
|
272
|
+
return None
|
273
|
+
if len(args) == 1:
|
274
|
+
vertices = args[0]
|
275
|
+
if isinstance(vertices, list):
|
276
|
+
if len(vertices) == 0:
|
277
|
+
if not silent:
|
278
|
+
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
|
279
|
+
return None
|
280
|
+
else:
|
281
|
+
vertexList = [x for x in vertices if isinstance(x, topologic.Vertex)]
|
282
|
+
if len(vertexList) == 0:
|
283
|
+
if not silent:
|
284
|
+
print("Edge.ByVertices - Error: The input vertices parameter does not contain any valid vertices. Returning None.")
|
285
|
+
return None
|
286
|
+
else:
|
287
|
+
if not silent:
|
288
|
+
print("Edge.ByVertices - Warning: The input vertices parameter contains only one vertex. Returning None.")
|
289
|
+
return None
|
290
|
+
else:
|
291
|
+
vertexList = Helper.Flatten(list(args))
|
292
|
+
vertexList = [x for x in vertexList if isinstance(x, topologic.Vertex)]
|
293
|
+
if len(vertexList) < 2:
|
294
|
+
if not silent:
|
295
|
+
print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.")
|
296
|
+
return None
|
297
|
+
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent)
|
298
|
+
|
299
|
+
@staticmethod
|
300
|
+
def ByVerticesCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.Edge:
|
301
|
+
"""
|
302
|
+
Creates a straight edge that connects the input cluster of vertices.
|
303
|
+
|
304
|
+
Parameters
|
305
|
+
----------
|
306
|
+
cluster : topologic.Cluster
|
307
|
+
The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
|
308
|
+
tolerance : float , optional
|
309
|
+
The desired tolerance to decide if an edge can be created. The default is 0.0001.
|
310
|
+
|
311
|
+
Returns
|
312
|
+
-------
|
313
|
+
topologic.Edge
|
314
|
+
The created edge.
|
315
|
+
|
316
|
+
"""
|
317
|
+
from topologicpy.Cluster import Cluster
|
318
|
+
if not isinstance(cluster, topologic.Cluster):
|
319
|
+
print("Edge.ByVerticesCluster - Error: The input cluster parameter is not a valid topologic cluster. Returning None.")
|
320
|
+
return None
|
321
|
+
vertices = Cluster.Vertices(cluster)
|
322
|
+
vertexList = [x for x in vertices if isinstance(x, topologic.Vertex)]
|
323
|
+
if len(vertexList) < 2:
|
324
|
+
print("Edge.ByVerticesCluster - Error: The input cluster parameter contains less than two vertices. Returning None.")
|
325
|
+
return None
|
326
|
+
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance)
|
327
|
+
|
328
|
+
@staticmethod
|
329
|
+
def Direction(edge: topologic.Edge, mantissa: int = 6) -> list:
|
330
|
+
"""
|
331
|
+
Returns the direction of the input edge expressed as a list of three numbers.
|
332
|
+
|
333
|
+
Parameters
|
334
|
+
----------
|
335
|
+
edge : topologic.Edge
|
336
|
+
The input edge.
|
337
|
+
mantissa : int , optional
|
338
|
+
The desired length of the mantissa. The default is 6.
|
339
|
+
|
340
|
+
Returns
|
341
|
+
-------
|
342
|
+
list
|
343
|
+
The direction of the input edge.
|
344
|
+
|
345
|
+
"""
|
346
|
+
|
347
|
+
from topologicpy.Vector import Vector
|
348
|
+
|
349
|
+
if not isinstance(edge, topologic.Edge):
|
350
|
+
print("Edge.Direction - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
351
|
+
return None
|
352
|
+
ev = edge.EndVertex()
|
353
|
+
sv = edge.StartVertex()
|
354
|
+
x = ev.X() - sv.X()
|
355
|
+
y = ev.Y() - sv.Y()
|
356
|
+
z = ev.Z() - sv.Z()
|
357
|
+
uvec = Vector.Normalize([x,y,z])
|
358
|
+
x = round(uvec[0], mantissa)
|
359
|
+
y = round(uvec[1], mantissa)
|
360
|
+
z = round(uvec[2], mantissa)
|
361
|
+
return [x, y, z]
|
362
|
+
|
363
|
+
@staticmethod
|
364
|
+
def EndVertex(edge: topologic.Edge) -> topologic.Vertex:
|
365
|
+
"""
|
366
|
+
Returns the end vertex of the input edge.
|
367
|
+
|
368
|
+
Parameters
|
369
|
+
----------
|
370
|
+
edge : topologic.Edge
|
371
|
+
The input edge.
|
372
|
+
|
373
|
+
Returns
|
374
|
+
-------
|
375
|
+
topologic.Vertex
|
376
|
+
The end vertex of the input edge.
|
377
|
+
|
378
|
+
"""
|
379
|
+
if not isinstance(edge, topologic.Edge):
|
380
|
+
print("Edge.EndVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
381
|
+
return None
|
382
|
+
vert = None
|
383
|
+
try:
|
384
|
+
vert = edge.EndVertex()
|
385
|
+
except:
|
386
|
+
vert = None
|
387
|
+
return vert
|
388
|
+
|
389
|
+
@staticmethod
|
390
|
+
def Extend(edge: topologic.Edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
391
|
+
"""
|
392
|
+
Extends the input edge by the input distance.
|
393
|
+
|
394
|
+
Parameters
|
395
|
+
----------
|
396
|
+
edge : topologic.Edge
|
397
|
+
The input edge.
|
398
|
+
distance : float , optional
|
399
|
+
The offset distance. The default is 1.
|
400
|
+
bothSides : bool , optional
|
401
|
+
If set to True, the edge will be extended by half the distance at each end. The default is False.
|
402
|
+
reverse : bool , optional
|
403
|
+
If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False.
|
404
|
+
tolerance : float , optional
|
405
|
+
The desired tolerance. The default is 0.0001.
|
406
|
+
|
407
|
+
Returns
|
408
|
+
-------
|
409
|
+
topologic.Edge
|
410
|
+
The extended edge.
|
411
|
+
|
412
|
+
"""
|
413
|
+
if not isinstance(edge, topologic.Edge):
|
414
|
+
print("Edge.Extend - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
415
|
+
return None
|
416
|
+
distance = abs(distance)
|
417
|
+
if distance < tolerance:
|
418
|
+
return edge
|
419
|
+
sv = Edge.StartVertex(edge)
|
420
|
+
ev = Edge.EndVertex(edge)
|
421
|
+
if bothSides:
|
422
|
+
sve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=sv, tolerance=tolerance)
|
423
|
+
eve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=ev, tolerance=tolerance)
|
424
|
+
elif reverse:
|
425
|
+
sve = Edge.VertexByDistance(edge, distance=-distance, origin=sv, tolerance=tolerance)
|
426
|
+
eve = Edge.EndVertex(edge)
|
427
|
+
else:
|
428
|
+
sve = Edge.StartVertex(edge)
|
429
|
+
eve = Edge.VertexByDistance(edge, distance=distance, origin=ev, tolerance=tolerance)
|
430
|
+
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
431
|
+
|
432
|
+
@staticmethod
|
433
|
+
def ExtendToEdge2D(edgeA: topologic.Edge, edgeB: topologic.Edge, tolerance: float = 0.0001) -> topologic.Edge:
|
434
|
+
"""
|
435
|
+
Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored.
|
436
|
+
|
437
|
+
Parameters
|
438
|
+
----------
|
439
|
+
edgeA : topologic.Edge
|
440
|
+
The first input edge.
|
441
|
+
edgeB : topologic.Edge
|
442
|
+
The second input edge.
|
443
|
+
tolerance : float , optional
|
444
|
+
The desired tolerance. The default is 0.0001.
|
445
|
+
|
446
|
+
Returns
|
447
|
+
-------
|
448
|
+
topologic.Edge
|
449
|
+
The extended edge.
|
450
|
+
|
451
|
+
"""
|
452
|
+
|
453
|
+
from topologicpy.Vertex import Vertex
|
454
|
+
from topologicpy.Topology import Topology
|
455
|
+
|
456
|
+
if not isinstance(edgeA, topologic.Edge):
|
457
|
+
print("Edge.ExtendToEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
458
|
+
return None
|
459
|
+
if not isinstance(edgeB, topologic.Edge):
|
460
|
+
print("Edge.ExtendToEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
461
|
+
return None
|
462
|
+
sva = Edge.StartVertex(edgeA)
|
463
|
+
eva = Edge.EndVertex(edgeA)
|
464
|
+
intVertex = Edge.Intersect2D(edgeA, edgeB)
|
465
|
+
if intVertex and not (Vertex.IsInternal(intVertex, edgeA)):
|
466
|
+
e1 = Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
|
467
|
+
e2 = Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
468
|
+
l1 = Edge.Length(e1)
|
469
|
+
l2 = Edge.Length(e2)
|
470
|
+
if l1 > l2:
|
471
|
+
return e1
|
472
|
+
else:
|
473
|
+
return e2
|
474
|
+
print("Edge.ExtendToEdge2D - Error: The operation failed. Returning None.")
|
475
|
+
return None
|
476
|
+
|
477
|
+
@staticmethod
|
478
|
+
def Index(edge: topologic.Edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int:
|
479
|
+
"""
|
480
|
+
Returns index of the input edge in the input list of edges
|
481
|
+
|
482
|
+
Parameters
|
483
|
+
----------
|
484
|
+
edge : topologic.Edge
|
485
|
+
The input edge.
|
486
|
+
edges : list
|
487
|
+
The input list of edges.
|
488
|
+
strict : bool , optional
|
489
|
+
If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False.
|
490
|
+
tolerance : float , optional
|
491
|
+
The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001.
|
492
|
+
|
493
|
+
Returns
|
494
|
+
-------
|
495
|
+
int
|
496
|
+
The index of the input edge in the input list of edges.
|
497
|
+
|
498
|
+
"""
|
499
|
+
from topologicpy.Topology import Topology
|
500
|
+
if not isinstance(edge, topologic.Edge):
|
501
|
+
print("Edge.Index - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
502
|
+
return None
|
503
|
+
if not isinstance(edges, list):
|
504
|
+
print("Edge.Index - Error: The input edges parameter is not a valid list. Returning None.")
|
505
|
+
return None
|
506
|
+
edges = [e for e in edges if isinstance(e, topologic.Edge)]
|
507
|
+
if len(edges) < 1:
|
508
|
+
print("Edge.Index - Error: The input edges parameter contains no valid edges. Returning None.")
|
509
|
+
return None
|
510
|
+
sva = Edge.StartVertex(edge)
|
511
|
+
eva = Edge.EndVertex(edge)
|
512
|
+
for i in range(len(edges)):
|
513
|
+
if strict:
|
514
|
+
if Topology.IsSame(edge, edges[i]):
|
515
|
+
return i
|
516
|
+
else:
|
517
|
+
svb = Edge.StartVertex(edges[i])
|
518
|
+
evb = Edge.EndVertex(edges[i])
|
519
|
+
dsvsv = Vertex.Distance(sva, svb)
|
520
|
+
devev = Vertex.Distance(eva, evb)
|
521
|
+
if dsvsv < tolerance and devev < tolerance:
|
522
|
+
return i
|
523
|
+
dsvev = Vertex.Distance(sva, evb)
|
524
|
+
devsv = Vertex.Distance(eva, svb)
|
525
|
+
if dsvev < tolerance and devsv < tolerance:
|
526
|
+
return i
|
527
|
+
return None
|
528
|
+
|
529
|
+
@staticmethod
|
530
|
+
def Intersect2D(edgeA: topologic.Edge, edgeB: topologic.Edge, silent: bool = False) -> topologic.Vertex:
|
531
|
+
"""
|
532
|
+
Returns the intersection of the two input edges as a topologic.Vertex. This works only in the XY plane. Z coordinates are ignored.
|
533
|
+
|
534
|
+
Parameters
|
535
|
+
----------
|
536
|
+
edgeA : topologic.Edge
|
537
|
+
The first input edge.
|
538
|
+
edgeB : topologic.Edge
|
539
|
+
The second input edge.
|
540
|
+
silent : bool , optional
|
541
|
+
If set to False, error and warning messages are displayed. Otherwise they are not. The default is False.
|
542
|
+
|
543
|
+
Returns
|
544
|
+
-------
|
545
|
+
topologic.Vertex
|
546
|
+
The intersection of the two input edges.
|
547
|
+
|
548
|
+
"""
|
549
|
+
if not isinstance(edgeA, topologic.Edge):
|
550
|
+
if not silent:
|
551
|
+
print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
552
|
+
return None
|
553
|
+
if not isinstance(edgeB, topologic.Edge):
|
554
|
+
if not silent:
|
555
|
+
print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
556
|
+
return None
|
557
|
+
sva = Edge.StartVertex(edgeA)
|
558
|
+
eva = Edge.EndVertex(edgeA)
|
559
|
+
svb = Edge.StartVertex(edgeB)
|
560
|
+
evb = Edge.EndVertex(edgeB)
|
561
|
+
# Line AB represented as a1x + b1y = c1
|
562
|
+
a1 = Vertex.Y(eva) - Vertex.Y(sva)
|
563
|
+
b1 = Vertex.X(sva) - Vertex.X(eva)
|
564
|
+
c1 = a1*(Vertex.X(sva)) + b1*(Vertex.Y(sva))
|
565
|
+
|
566
|
+
# Line CD represented as a2x + b2y = c2
|
567
|
+
a2 = Vertex.Y(evb) - Vertex.Y(svb)
|
568
|
+
b2 = Vertex.X(svb) - Vertex.X(evb)
|
569
|
+
c2 = a2*(Vertex.X(svb)) + b2*(Vertex.Y(svb))
|
570
|
+
|
571
|
+
determinant = a1*b2 - a2*b1
|
572
|
+
|
573
|
+
if (determinant == 0):
|
574
|
+
# The lines are parallel. This is simplified
|
575
|
+
# by returning a pair of FLT_MAX
|
576
|
+
if not silent:
|
577
|
+
print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.")
|
578
|
+
return None
|
579
|
+
else:
|
580
|
+
x = (b2*c1 - b1*c2)/determinant
|
581
|
+
y = (a1*c2 - a2*c1)/determinant
|
582
|
+
return Vertex.ByCoordinates(x,y,0)
|
583
|
+
|
584
|
+
|
585
|
+
@staticmethod
|
586
|
+
def IsCollinear(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, angTolerance: float = 0.1, tolerance: float = 0.0001) -> bool:
|
587
|
+
"""
|
588
|
+
Return True if the two input edges are collinear. Returns False otherwise.
|
589
|
+
|
590
|
+
Parameters
|
591
|
+
----------
|
592
|
+
edgeA : topologic.Edge
|
593
|
+
The first input edge.
|
594
|
+
edgeB : topologic.Edge
|
595
|
+
The second input edge.
|
596
|
+
mantissa : int , optional
|
597
|
+
The desired length of the mantissa. The default is 6.
|
598
|
+
angTolerance : float , optional
|
599
|
+
The angular tolerance used for the test. The default is 0.1.
|
600
|
+
tolerance : float , optional
|
601
|
+
The desired tolerance. The default is 0.0001.
|
602
|
+
|
603
|
+
Returns
|
604
|
+
-------
|
605
|
+
bool
|
606
|
+
True if the two edges are collinear. False otherwise.
|
607
|
+
|
608
|
+
"""
|
609
|
+
if not isinstance(edgeA, topologic.Edge):
|
610
|
+
print("Edge.IsCollinear - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
611
|
+
return None
|
612
|
+
if not isinstance(edgeB, topologic.Edge):
|
613
|
+
print("Edge.IsCollinear - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
614
|
+
return None
|
615
|
+
ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
|
616
|
+
svA = Edge.StartVertex(edgeA)
|
617
|
+
evA = Edge.EndVertex(edgeA)
|
618
|
+
svB = Edge.StartVertex(edgeB)
|
619
|
+
evB = Edge.EndVertex(edgeB)
|
620
|
+
d1 = Vertex.Distance(svA, svB)
|
621
|
+
d2 = Vertex.Distance(svA, evB)
|
622
|
+
d3 = Vertex.Distance(evA, svB)
|
623
|
+
d4 = Vertex.Distance(evA, evB)
|
624
|
+
if (d1 < tolerance or d2 < tolerance or d3 < tolerance or d4 < tolerance) and (abs(ang) < angTolerance or (abs(180 - ang) < angTolerance)):
|
625
|
+
return True
|
626
|
+
return False
|
627
|
+
|
628
|
+
@staticmethod
|
629
|
+
def IsParallel(edgeA: topologic.Edge, edgeB: topologic.Edge, mantissa: int = 6, angTolerance: float = 0.1) -> bool:
|
630
|
+
"""
|
631
|
+
Return True if the two input edges are parallel. Returns False otherwise.
|
632
|
+
|
633
|
+
Parameters
|
634
|
+
----------
|
635
|
+
edgeA : topologic.Edge
|
636
|
+
The first input edge.
|
637
|
+
edgeB : topologic.Edge
|
638
|
+
The second input edge.
|
639
|
+
mantissa : int , optional
|
640
|
+
The desired length of the mantissa. The default is 6.
|
641
|
+
angTolerance : float , optional
|
642
|
+
The angular tolerance used for the test. The default is 0.1.
|
643
|
+
|
644
|
+
Returns
|
645
|
+
-------
|
646
|
+
bool
|
647
|
+
True if the two edges are collinear. False otherwise.
|
648
|
+
|
649
|
+
"""
|
650
|
+
if not isinstance(edgeA, topologic.Edge):
|
651
|
+
print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
652
|
+
return None
|
653
|
+
if not isinstance(edgeB, topologic.Edge):
|
654
|
+
print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
655
|
+
return None
|
656
|
+
ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
|
657
|
+
if abs(ang) < angTolerance or abs(180 - ang) < angTolerance:
|
658
|
+
return True
|
659
|
+
return False
|
660
|
+
|
661
|
+
@staticmethod
|
662
|
+
def Length(edge: topologic.Edge, mantissa: int = 6) -> float:
|
663
|
+
"""
|
664
|
+
Returns the length of the input edge.
|
665
|
+
|
666
|
+
Parameters
|
667
|
+
----------
|
668
|
+
edge : topologic.Edge
|
669
|
+
The input edge.
|
670
|
+
mantissa : int , optional
|
671
|
+
The desired length of the mantissa. The default is 6.
|
672
|
+
|
673
|
+
Returns
|
674
|
+
-------
|
675
|
+
float
|
676
|
+
The length of the input edge.
|
677
|
+
|
678
|
+
"""
|
679
|
+
if not isinstance(edge, topologic.Edge):
|
680
|
+
print("Edge.Length - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
681
|
+
return None
|
682
|
+
length = None
|
683
|
+
try:
|
684
|
+
length = round(topologic.EdgeUtility.Length(edge), mantissa)
|
685
|
+
except:
|
686
|
+
length = None
|
687
|
+
if length == None:
|
688
|
+
print("Edge.Length - Error: Could not compute the length of the input edge parameter. Returning None.")
|
689
|
+
return length
|
690
|
+
|
691
|
+
@staticmethod
|
692
|
+
def Line(origin: topologic.Vertex = None, length: float = 1, direction: list = [1,0,0], placement: str ="center", tolerance: float = 0.0001) -> topologic.Edge:
|
693
|
+
"""
|
694
|
+
Creates a straight edge (line) using the input parameters.
|
695
|
+
|
696
|
+
Parameters
|
697
|
+
----------
|
698
|
+
origin : topologic.Vertex , optional
|
699
|
+
The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0).
|
700
|
+
length : float , optional
|
701
|
+
The desired length of the edge. The default is 1.0.
|
702
|
+
direction : list , optional
|
703
|
+
The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis).
|
704
|
+
placement : str , optional
|
705
|
+
The desired placement of the edge. The options are:
|
706
|
+
1. "center" which places the center of the edge at the origin.
|
707
|
+
2. "start" which places the start of the edge at the origin.
|
708
|
+
3. "end" which places the end of the edge at the origin.
|
709
|
+
The default is "center".
|
710
|
+
tolerance : float , optional
|
711
|
+
The desired tolerance. The default is 0.0001.
|
712
|
+
Returns
|
713
|
+
-------
|
714
|
+
topology.Edge
|
715
|
+
The created edge
|
716
|
+
"""
|
717
|
+
|
718
|
+
from topologicpy.Vertex import Vertex
|
719
|
+
from topologicpy.Vector import Vector
|
720
|
+
from topologicpy.Topology import Topology
|
721
|
+
|
722
|
+
if origin == None:
|
723
|
+
origin = Vertex.Origin()
|
724
|
+
if not isinstance(origin, topologic.Vertex):
|
725
|
+
print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
726
|
+
return None
|
727
|
+
if length <= 0:
|
728
|
+
print("Edge.Line - Error: The input length is less than or equal to zero. Returning None.")
|
729
|
+
return None
|
730
|
+
if not isinstance(direction, list):
|
731
|
+
print("Edge.Line - Error: The input direction parameter is not a valid list. Returning None.")
|
732
|
+
return None
|
733
|
+
if not len(direction) == 3:
|
734
|
+
print("Edge.Line - Error: The length of the input direction parameter is not equal to three. Returning None.")
|
735
|
+
return None
|
736
|
+
direction = Vector.Normalize(direction)
|
737
|
+
if "center" in placement.lower():
|
738
|
+
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length*0.5)
|
739
|
+
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
740
|
+
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
741
|
+
if "start" in placement.lower():
|
742
|
+
sv = origin
|
743
|
+
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
744
|
+
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
745
|
+
if "end" in placement.lower():
|
746
|
+
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length)
|
747
|
+
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
|
748
|
+
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
|
749
|
+
else:
|
750
|
+
print("Edge.Line - Error: The input placement string is not one of center, start, or end. Returning None.")
|
751
|
+
return None
|
752
|
+
|
753
|
+
@staticmethod
|
754
|
+
def Normal(edge: topologic.Edge, angle: float = 0.0):
|
755
|
+
"""
|
756
|
+
Returns the normal (perpendicular) vector to the input edge.
|
757
|
+
|
758
|
+
Parameters
|
759
|
+
----------
|
760
|
+
edge : topologic.Edge
|
761
|
+
The input edge.
|
762
|
+
angle : float , optional
|
763
|
+
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
|
764
|
+
by the angle value around the axis defined by the input edge. The default is 0.0.
|
765
|
+
|
766
|
+
Returns
|
767
|
+
-------
|
768
|
+
list
|
769
|
+
The normal (perpendicular ) vector to the input edge.
|
770
|
+
|
771
|
+
"""
|
772
|
+
if not isinstance(edge, topologic.Edge):
|
773
|
+
print("Edge.Normal - Error: The input edge parameter is not a valid edge. Returning None.")
|
774
|
+
return None
|
775
|
+
normal_edge = Edge.NormalAsEdge(edge, length=1.0, u=0.5, angle=angle)
|
776
|
+
return Edge.Direction(normal_edge)
|
777
|
+
|
778
|
+
@staticmethod
|
779
|
+
def NormalAsEdge(edge: topologic.Edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0):
|
780
|
+
"""
|
781
|
+
Returns the normal (perpendicular) vector to the input edge as an edge.
|
782
|
+
|
783
|
+
Parameters
|
784
|
+
----------
|
785
|
+
edge : topologic.Edge
|
786
|
+
The input edge.
|
787
|
+
length : float , optional
|
788
|
+
The desired length of the normal edge. The default is 1.0.
|
789
|
+
u : float , optional
|
790
|
+
The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge
|
791
|
+
at the start vertex of the input edge, a value of 0.5 places the normal edge
|
792
|
+
at the midpoint of the input edge, and a value of 1.0 places the normal edge
|
793
|
+
at the end vertex of the input edge. The default is 0.5
|
794
|
+
angle : float , optional
|
795
|
+
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
|
796
|
+
by the angle value around the axis defined by the input edge. The default is 0.0.
|
797
|
+
|
798
|
+
Returns
|
799
|
+
-------
|
800
|
+
topologic.Edge
|
801
|
+
The normal (perpendicular) vector to the input edge as an edge.
|
802
|
+
|
803
|
+
"""
|
804
|
+
import numpy as np
|
805
|
+
from numpy.linalg import norm
|
806
|
+
import topologic_core as topologic
|
807
|
+
from topologicpy.Vertex import Vertex
|
808
|
+
from topologicpy.Topology import Topology
|
809
|
+
|
810
|
+
def calculate_normal(start_vertex, end_vertex):
|
811
|
+
start_vertex = [float(x) for x in start_vertex]
|
812
|
+
end_vertex = [float(x) for x in end_vertex]
|
813
|
+
# Calculate the direction vector of the line segment
|
814
|
+
direction_vector = np.array(end_vertex) - np.array(start_vertex)
|
815
|
+
|
816
|
+
# Calculate the normal vector by swapping components and negating one of them
|
817
|
+
normal_vector = np.array([-direction_vector[1], direction_vector[0], 0])
|
818
|
+
|
819
|
+
# Normalize the normal vector
|
820
|
+
normal_vector /= norm(normal_vector)
|
821
|
+
|
822
|
+
return normal_vector
|
823
|
+
|
824
|
+
|
825
|
+
def calculate_normal_line(start_vertex, end_vertex):
|
826
|
+
# Calculate the normal vector of the line
|
827
|
+
normal_vector = calculate_normal(start_vertex, end_vertex)
|
828
|
+
|
829
|
+
# Calculate the new end vertex for the normal line to have a length of 1
|
830
|
+
normal_end_vertex = np.array(start_vertex) + normal_vector
|
831
|
+
|
832
|
+
# Return the start and end vertices of the normal line
|
833
|
+
return start_vertex, list(normal_end_vertex)
|
834
|
+
|
835
|
+
if not isinstance(edge, topologic.Edge):
|
836
|
+
print("Edge.NormalAsEdge - Error: The input edge parameter is not a valid edge. Returning None.")
|
837
|
+
return None
|
838
|
+
if length <= 0.0:
|
839
|
+
print("Edge.NormalAsEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.")
|
840
|
+
return None
|
841
|
+
edge_direction = Edge.Direction(edge)
|
842
|
+
x, y, z = edge_direction
|
843
|
+
start_vertex = Vertex.Coordinates(Edge.StartVertex(edge))
|
844
|
+
end_vertex = Vertex.Coordinates(Edge.EndVertex(edge))
|
845
|
+
normal_line_start, normal_line_end = calculate_normal_line(start_vertex, end_vertex)
|
846
|
+
sv = Vertex.ByCoordinates(normal_line_start)
|
847
|
+
ev = Vertex.ByCoordinates(list(normal_line_end))
|
848
|
+
normal_edge = Edge.ByVertices([sv, ev])
|
849
|
+
normal_edge = Edge.SetLength(normal_edge, length, bothSides=False)
|
850
|
+
normal_edge = Topology.Rotate(normal_edge, origin=Edge.StartVertex(normal_edge), axis=[x,y,z], angle=angle)
|
851
|
+
dist = Edge.Length(edge)*u
|
852
|
+
normal_edge = Topology.TranslateByDirectionDistance(normal_edge, edge_direction, dist)
|
853
|
+
return normal_edge
|
854
|
+
|
855
|
+
@staticmethod
|
856
|
+
def Normalize(edge: topologic.Edge, useEndVertex: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
857
|
+
"""
|
858
|
+
Creates a normalized edge that has the same direction as the input edge, but a length of 1.
|
859
|
+
|
860
|
+
Parameters
|
861
|
+
----------
|
862
|
+
edge : topologic.Edge
|
863
|
+
The input edge.
|
864
|
+
useEndVertex : bool , optional
|
865
|
+
If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False.
|
866
|
+
tolerance : float , optional
|
867
|
+
The desired tolerance. The default is 0.0001.
|
868
|
+
|
869
|
+
Returns
|
870
|
+
-------
|
871
|
+
topologic.Edge
|
872
|
+
The normalized edge.
|
873
|
+
|
874
|
+
"""
|
875
|
+
if not isinstance(edge, topologic.Edge):
|
876
|
+
print("Edge.Normalize - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
877
|
+
return None
|
878
|
+
if not useEndVertex:
|
879
|
+
sv = edge.StartVertex()
|
880
|
+
ev = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
|
881
|
+
else:
|
882
|
+
sv = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
|
883
|
+
ev = edge.EndVertex()
|
884
|
+
return Edge.ByVertices([sv, ev], tolerance=tolerance)
|
885
|
+
|
886
|
+
@staticmethod
|
887
|
+
def ParameterAtVertex(edge: topologic.Edge, vertex: topologic.Vertex, mantissa: int = 6, silent: bool = False) -> float:
|
888
|
+
"""
|
889
|
+
Returns the *u* parameter along the input edge based on the location of the input vertex.
|
890
|
+
|
891
|
+
Parameters
|
892
|
+
----------
|
893
|
+
edge : topologic.Edge
|
894
|
+
The input edge.
|
895
|
+
vertex : topologic.Vertex
|
896
|
+
The input vertex.
|
897
|
+
mantissa : int , optional
|
898
|
+
The desired length of the mantissa. The default is 6.
|
899
|
+
silent : bool , optional
|
900
|
+
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
|
901
|
+
|
902
|
+
Returns
|
903
|
+
-------
|
904
|
+
float
|
905
|
+
The *u* parameter along the input edge based on the location of the input vertex.
|
906
|
+
|
907
|
+
"""
|
908
|
+
if not isinstance(edge, topologic.Edge):
|
909
|
+
if not silent:
|
910
|
+
print("Edge.ParameterAtVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
911
|
+
return None
|
912
|
+
if not isinstance(vertex, topologic.Vertex):
|
913
|
+
if not silent:
|
914
|
+
print("Edge.ParameterAtVertex - Error: The input vertex parameter is not a valid topologic vertex. Returning None.")
|
915
|
+
return None
|
916
|
+
parameter = None
|
917
|
+
try:
|
918
|
+
parameter = topologic.EdgeUtility.ParameterAtPoint(edge, vertex)
|
919
|
+
except:
|
920
|
+
return None #Return silently because topologic C++ returns a runtime error if point is not on curve.
|
921
|
+
return round(parameter, mantissa)
|
922
|
+
|
923
|
+
@staticmethod
|
924
|
+
def Reverse(edge: topologic.Edge, tolerance: float = 0.0001) -> topologic.Edge:
|
925
|
+
"""
|
926
|
+
Creates an edge that has the reverse direction of the input edge.
|
927
|
+
|
928
|
+
Parameters
|
929
|
+
----------
|
930
|
+
edge : topologic.Edge
|
931
|
+
The input edge.
|
932
|
+
tolerance : float , optional
|
933
|
+
The desired tolerance. The default is 0.0001.
|
934
|
+
|
935
|
+
Returns
|
936
|
+
-------
|
937
|
+
topologic.Edge
|
938
|
+
The reversed edge.
|
939
|
+
|
940
|
+
"""
|
941
|
+
if not isinstance(edge, topologic.Edge):
|
942
|
+
print("Edge.Reverse - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
943
|
+
return None
|
944
|
+
return Edge.ByVertices([edge.EndVertex(), edge.StartVertex()], tolerance=tolerance)
|
945
|
+
|
946
|
+
@staticmethod
|
947
|
+
def SetLength(edge: topologic.Edge , length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
948
|
+
"""
|
949
|
+
Returns an edge with the new length in the same direction as the input edge.
|
950
|
+
|
951
|
+
Parameters
|
952
|
+
----------
|
953
|
+
edge : topologic.Edge
|
954
|
+
The input edge.
|
955
|
+
length : float , optional
|
956
|
+
The desired length of the edge. The default is 1.
|
957
|
+
bothSides : bool , optional
|
958
|
+
If set to True, the edge will be offset symmetrically from each end. The default is True.
|
959
|
+
reverse : bool , optional
|
960
|
+
If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False.
|
961
|
+
tolerance : float , optional
|
962
|
+
The desired tolerance. The default is 0.0001.
|
963
|
+
|
964
|
+
Returns
|
965
|
+
-------
|
966
|
+
topologic.Edge
|
967
|
+
The extended edge.
|
968
|
+
|
969
|
+
"""
|
970
|
+
if not isinstance(edge, topologic.Edge):
|
971
|
+
print("Edge.SetLength - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
972
|
+
return None
|
973
|
+
distance = (length - Edge.Length(edge))
|
974
|
+
if distance > 0:
|
975
|
+
return Edge.Extend(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
|
976
|
+
return Edge.Trim(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
|
977
|
+
|
978
|
+
@staticmethod
|
979
|
+
def StartVertex(edge: topologic.Edge) -> topologic.Vertex:
|
980
|
+
"""
|
981
|
+
Returns the start vertex of the input edge.
|
982
|
+
|
983
|
+
Parameters
|
984
|
+
----------
|
985
|
+
edge : topologic.Edge
|
986
|
+
The input edge.
|
987
|
+
|
988
|
+
Returns
|
989
|
+
-------
|
990
|
+
topologic.Vertex
|
991
|
+
The start vertex of the input edge.
|
992
|
+
|
993
|
+
"""
|
994
|
+
if not isinstance(edge, topologic.Edge):
|
995
|
+
print("Edge.StartVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
996
|
+
return None
|
997
|
+
vert = None
|
998
|
+
try:
|
999
|
+
vert = edge.StartVertex()
|
1000
|
+
except:
|
1001
|
+
vert = None
|
1002
|
+
return vert
|
1003
|
+
|
1004
|
+
@staticmethod
|
1005
|
+
def Trim(edge: topologic.Edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
1006
|
+
"""
|
1007
|
+
Trims the input edge by the input distance.
|
1008
|
+
|
1009
|
+
Parameters
|
1010
|
+
----------
|
1011
|
+
edge : topologic.Edge
|
1012
|
+
The input edge.
|
1013
|
+
distance : float , optional
|
1014
|
+
The offset distance. The default is 0.
|
1015
|
+
bothSides : bool , optional
|
1016
|
+
If set to True, the edge will be trimmed by half the distance at each end. The default is False.
|
1017
|
+
reverse : bool , optional
|
1018
|
+
If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False.
|
1019
|
+
tolerance : float , optional
|
1020
|
+
The desired tolerance. The default is 0.0001.
|
1021
|
+
|
1022
|
+
Returns
|
1023
|
+
-------
|
1024
|
+
topologic.Edge
|
1025
|
+
The trimmed edge.
|
1026
|
+
|
1027
|
+
"""
|
1028
|
+
if not isinstance(edge, topologic.Edge):
|
1029
|
+
print("Edge.Trim - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1030
|
+
return None
|
1031
|
+
distance = abs(distance)
|
1032
|
+
if distance == 0:
|
1033
|
+
return edge
|
1034
|
+
if distance < tolerance:
|
1035
|
+
print("Edge.Trim - Warning: The input distance parameter is less than the input tolerance parameter. Returning the input edge.")
|
1036
|
+
return edge
|
1037
|
+
sv = Edge.StartVertex(edge)
|
1038
|
+
ev = Edge.EndVertex(edge)
|
1039
|
+
if bothSides:
|
1040
|
+
sve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=sv, tolerance=tolerance)
|
1041
|
+
eve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=ev, tolerance=tolerance)
|
1042
|
+
elif reverse:
|
1043
|
+
sve = Edge.VertexByDistance(edge, distance=distance, origin=sv, tolerance=tolerance)
|
1044
|
+
eve = Edge.EndVertex(edge)
|
1045
|
+
else:
|
1046
|
+
sve = Edge.StartVertex(edge)
|
1047
|
+
eve = Edge.VertexByDistance(edge, distance=-distance, origin=ev, tolerance=tolerance)
|
1048
|
+
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
|
1049
|
+
|
1050
|
+
@staticmethod
|
1051
|
+
def TrimByEdge2D(edgeA: topologic.Edge, edgeB: topologic.Edge, reverse: bool = False, tolerance: float = 0.0001) -> topologic.Edge:
|
1052
|
+
"""
|
1053
|
+
Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored.
|
1054
|
+
|
1055
|
+
Parameters
|
1056
|
+
----------
|
1057
|
+
edgeA : topologic.Edge
|
1058
|
+
The first input edge.
|
1059
|
+
edgeB : topologic.Edge
|
1060
|
+
The second input edge.
|
1061
|
+
tolerance : float , optional
|
1062
|
+
The desired tolerance. The default is 0.0001.
|
1063
|
+
|
1064
|
+
Returns
|
1065
|
+
-------
|
1066
|
+
topologic.Edge
|
1067
|
+
The trimmed edge.
|
1068
|
+
|
1069
|
+
"""
|
1070
|
+
from topologicpy.Topology import Topology
|
1071
|
+
if not isinstance(edgeA, topologic.Edge):
|
1072
|
+
print("Edge.TrimByEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
1073
|
+
return None
|
1074
|
+
if not isinstance(edgeB, topologic.Edge):
|
1075
|
+
print("Edge.TrimByEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
|
1076
|
+
return None
|
1077
|
+
sva = Edge.StartVertex(edgeA)
|
1078
|
+
eva = Edge.EndVertex(edgeA)
|
1079
|
+
intVertex = Edge.Intersect2D(edgeA, edgeB)
|
1080
|
+
if intVertex and (Vertex.IsInternal(intVertex, edgeA)):
|
1081
|
+
if reverse:
|
1082
|
+
return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
|
1083
|
+
else:
|
1084
|
+
return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
|
1085
|
+
return edgeA
|
1086
|
+
|
1087
|
+
@staticmethod
|
1088
|
+
def VertexByDistance(edge: topologic.Edge, distance: float = 0.0, origin: topologic.Vertex = None, tolerance: float = 0.0001) -> topologic.Vertex:
|
1089
|
+
"""
|
1090
|
+
Creates a vertex along the input edge offset by the input distance from the input origin.
|
1091
|
+
|
1092
|
+
Parameters
|
1093
|
+
----------
|
1094
|
+
edge : topologic.Edge
|
1095
|
+
The input edge.
|
1096
|
+
distance : float , optional
|
1097
|
+
The offset distance. The default is 0.
|
1098
|
+
origin : topologic.Vertex , optional
|
1099
|
+
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.
|
1100
|
+
tolerance : float , optional
|
1101
|
+
The desired tolerance. The default is 0.0001.
|
1102
|
+
|
1103
|
+
Returns
|
1104
|
+
-------
|
1105
|
+
topologic.Vertex
|
1106
|
+
The created vertex.
|
1107
|
+
|
1108
|
+
"""
|
1109
|
+
|
1110
|
+
if not isinstance(edge, topologic.Edge):
|
1111
|
+
print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1112
|
+
return None
|
1113
|
+
if not origin:
|
1114
|
+
origin = edge.StartVertex()
|
1115
|
+
if not isinstance(origin, topologic.Vertex):
|
1116
|
+
print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
1117
|
+
return None
|
1118
|
+
sv = edge.StartVertex()
|
1119
|
+
ev = edge.EndVertex()
|
1120
|
+
vx = ev.X() - sv.X()
|
1121
|
+
vy = ev.Y() - sv.Y()
|
1122
|
+
vz = ev.Z() - sv.Z()
|
1123
|
+
vector = Vector.Normalize([vx, vy, vz])
|
1124
|
+
vector = Vector.Multiply(vector, distance, tolerance)
|
1125
|
+
return topologic.Vertex.ByCoordinates(origin.X()+vector[0], origin.Y()+vector[1], origin.Z()+vector[2])
|
1126
|
+
|
1127
|
+
@staticmethod
|
1128
|
+
def VertexByParameter(edge: topologic.Edge, u: float = 0.0) -> topologic.Vertex:
|
1129
|
+
"""
|
1130
|
+
Creates a vertex along the input edge offset by the input *u* parameter.
|
1131
|
+
|
1132
|
+
Parameters
|
1133
|
+
----------
|
1134
|
+
edge : topologic.Edge
|
1135
|
+
The input edge.
|
1136
|
+
u : float , optional
|
1137
|
+
The *u* parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0.
|
1138
|
+
|
1139
|
+
Returns
|
1140
|
+
-------
|
1141
|
+
topologic.Vertex
|
1142
|
+
The created vertex.
|
1143
|
+
|
1144
|
+
"""
|
1145
|
+
from topologicpy.Topology import Topology
|
1146
|
+
|
1147
|
+
if not isinstance(edge, topologic.Edge):
|
1148
|
+
print("Edge.VertexByParameter - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1149
|
+
return None
|
1150
|
+
vertex = None
|
1151
|
+
if u == 0:
|
1152
|
+
vertex = edge.StartVertex()
|
1153
|
+
elif u == 1:
|
1154
|
+
vertex = edge.EndVertex()
|
1155
|
+
else:
|
1156
|
+
dir = Edge.Direction(edge)
|
1157
|
+
edge_length = Edge.Length(edge)
|
1158
|
+
dist = edge_length*u
|
1159
|
+
vertex = Topology.TranslateByDirectionDistance(Edge.StartVertex(edge), direction=dir, distance=dist)
|
1160
|
+
#try:
|
1161
|
+
#vertex = topologic.EdgeUtility.PointAtParameter(edge, u)
|
1162
|
+
#except:
|
1163
|
+
#print("Edge.VertexByParameter - Error: Could not create a vertex at the input parameter. Returning None.")
|
1164
|
+
#vertex = None
|
1165
|
+
return vertex
|
1166
|
+
|
1167
|
+
@staticmethod
|
1168
|
+
def Vertices(edge: topologic.Edge) -> list:
|
1169
|
+
"""
|
1170
|
+
Returns the list of vertices of the input edge.
|
1171
|
+
|
1172
|
+
Parameters
|
1173
|
+
----------
|
1174
|
+
edge : topologic.Edge
|
1175
|
+
The input edge.
|
1176
|
+
|
1177
|
+
Returns
|
1178
|
+
-------
|
1179
|
+
list
|
1180
|
+
The list of vertices.
|
1181
|
+
|
1182
|
+
"""
|
1183
|
+
if not isinstance(edge, topologic.Edge):
|
1184
|
+
print("Edge.Vertices - Error: The input edge parameter is not a valid topologic edge. Returning None.")
|
1185
|
+
return None
|
1186
|
+
vertices = []
|
1187
|
+
_ = edge.Vertices(None, vertices)
|
1188
1188
|
return vertices
|