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.
Files changed (94) hide show
  1. topologicpy/Aperture.py +72 -72
  2. topologicpy/Cell.py +2169 -2169
  3. topologicpy/CellComplex.py +1137 -1137
  4. topologicpy/Cluster.py +1288 -1280
  5. topologicpy/Color.py +423 -393
  6. topologicpy/Context.py +79 -79
  7. topologicpy/DGL.py +3213 -3136
  8. topologicpy/Dictionary.py +698 -695
  9. topologicpy/Edge.py +1187 -1187
  10. topologicpy/EnergyModel.py +1180 -1171
  11. topologicpy/Face.py +2141 -2141
  12. topologicpy/Graph.py +7768 -7700
  13. topologicpy/Grid.py +353 -353
  14. topologicpy/Helper.py +507 -507
  15. topologicpy/Honeybee.py +461 -461
  16. topologicpy/Matrix.py +271 -271
  17. topologicpy/Neo4j.py +521 -521
  18. topologicpy/Plotly.py +2 -2
  19. topologicpy/Polyskel.py +541 -541
  20. topologicpy/Shell.py +1768 -1768
  21. topologicpy/Speckle.py +508 -508
  22. topologicpy/Topology.py +7060 -6988
  23. topologicpy/Vector.py +905 -905
  24. topologicpy/Vertex.py +1585 -1585
  25. topologicpy/Wire.py +3050 -3050
  26. topologicpy/__init__.py +22 -38
  27. topologicpy/version.py +1 -0
  28. {topologicpy-0.5.8.dist-info → topologicpy-6.0.0.dist-info}/LICENSE +661 -704
  29. topologicpy-6.0.0.dist-info/METADATA +751 -0
  30. topologicpy-6.0.0.dist-info/RECORD +32 -0
  31. topologicpy/bin/linux/topologic/__init__.py +0 -2
  32. topologicpy/bin/linux/topologic/libTKBO-6bdf205d.so.7.7.0 +0 -0
  33. topologicpy/bin/linux/topologic/libTKBRep-2960a069.so.7.7.0 +0 -0
  34. topologicpy/bin/linux/topologic/libTKBool-c44b74bd.so.7.7.0 +0 -0
  35. topologicpy/bin/linux/topologic/libTKFillet-9a670ba0.so.7.7.0 +0 -0
  36. topologicpy/bin/linux/topologic/libTKG2d-8f31849e.so.7.7.0 +0 -0
  37. topologicpy/bin/linux/topologic/libTKG3d-4c6bce57.so.7.7.0 +0 -0
  38. topologicpy/bin/linux/topologic/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
  39. topologicpy/bin/linux/topologic/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
  40. topologicpy/bin/linux/topologic/libTKMath-72572fa8.so.7.7.0 +0 -0
  41. topologicpy/bin/linux/topologic/libTKMesh-2a060427.so.7.7.0 +0 -0
  42. topologicpy/bin/linux/topologic/libTKOffset-6cab68ff.so.7.7.0 +0 -0
  43. topologicpy/bin/linux/topologic/libTKPrim-eb1262b3.so.7.7.0 +0 -0
  44. topologicpy/bin/linux/topologic/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
  45. topologicpy/bin/linux/topologic/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
  46. topologicpy/bin/linux/topologic/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
  47. topologicpy/bin/linux/topologic/libgcc_s-32c1665e.so.1 +0 -0
  48. topologicpy/bin/linux/topologic/libstdc++-672d7b41.so.6.0.30 +0 -0
  49. topologicpy/bin/linux/topologic/topologic.cpython-310-x86_64-linux-gnu.so +0 -0
  50. topologicpy/bin/linux/topologic/topologic.cpython-311-x86_64-linux-gnu.so +0 -0
  51. topologicpy/bin/linux/topologic/topologic.cpython-38-x86_64-linux-gnu.so +0 -0
  52. topologicpy/bin/linux/topologic/topologic.cpython-39-x86_64-linux-gnu.so +0 -0
  53. topologicpy/bin/linux/topologic.libs/libTKBO-6bdf205d.so.7.7.0 +0 -0
  54. topologicpy/bin/linux/topologic.libs/libTKBRep-2960a069.so.7.7.0 +0 -0
  55. topologicpy/bin/linux/topologic.libs/libTKBool-c44b74bd.so.7.7.0 +0 -0
  56. topologicpy/bin/linux/topologic.libs/libTKFillet-9a670ba0.so.7.7.0 +0 -0
  57. topologicpy/bin/linux/topologic.libs/libTKG2d-8f31849e.so.7.7.0 +0 -0
  58. topologicpy/bin/linux/topologic.libs/libTKG3d-4c6bce57.so.7.7.0 +0 -0
  59. topologicpy/bin/linux/topologic.libs/libTKGeomAlgo-26066fd9.so.7.7.0 +0 -0
  60. topologicpy/bin/linux/topologic.libs/libTKGeomBase-2116cabe.so.7.7.0 +0 -0
  61. topologicpy/bin/linux/topologic.libs/libTKMath-72572fa8.so.7.7.0 +0 -0
  62. topologicpy/bin/linux/topologic.libs/libTKMesh-2a060427.so.7.7.0 +0 -0
  63. topologicpy/bin/linux/topologic.libs/libTKOffset-6cab68ff.so.7.7.0 +0 -0
  64. topologicpy/bin/linux/topologic.libs/libTKPrim-eb1262b3.so.7.7.0 +0 -0
  65. topologicpy/bin/linux/topologic.libs/libTKShHealing-e67e5cc7.so.7.7.0 +0 -0
  66. topologicpy/bin/linux/topologic.libs/libTKTopAlgo-e4c96c33.so.7.7.0 +0 -0
  67. topologicpy/bin/linux/topologic.libs/libTKernel-fb7fe3b7.so.7.7.0 +0 -0
  68. topologicpy/bin/linux/topologic.libs/libgcc_s-32c1665e.so.1 +0 -0
  69. topologicpy/bin/linux/topologic.libs/libstdc++-672d7b41.so.6.0.30 +0 -0
  70. topologicpy/bin/macos/topologic/__init__.py +0 -2
  71. topologicpy/bin/windows/topologic/TKBO-f6b191de.dll +0 -0
  72. topologicpy/bin/windows/topologic/TKBRep-e56a600e.dll +0 -0
  73. topologicpy/bin/windows/topologic/TKBool-7b8d47ae.dll +0 -0
  74. topologicpy/bin/windows/topologic/TKFillet-0ddbf0a8.dll +0 -0
  75. topologicpy/bin/windows/topologic/TKG2d-2e2dee3d.dll +0 -0
  76. topologicpy/bin/windows/topologic/TKG3d-6674513d.dll +0 -0
  77. topologicpy/bin/windows/topologic/TKGeomAlgo-d240e370.dll +0 -0
  78. topologicpy/bin/windows/topologic/TKGeomBase-df87aba5.dll +0 -0
  79. topologicpy/bin/windows/topologic/TKMath-45bd625a.dll +0 -0
  80. topologicpy/bin/windows/topologic/TKMesh-d6e826b1.dll +0 -0
  81. topologicpy/bin/windows/topologic/TKOffset-79b9cc94.dll +0 -0
  82. topologicpy/bin/windows/topologic/TKPrim-aa430a86.dll +0 -0
  83. topologicpy/bin/windows/topologic/TKShHealing-bb48be89.dll +0 -0
  84. topologicpy/bin/windows/topologic/TKTopAlgo-7d0d1e22.dll +0 -0
  85. topologicpy/bin/windows/topologic/TKernel-08c8cfbb.dll +0 -0
  86. topologicpy/bin/windows/topologic/__init__.py +0 -2
  87. topologicpy/bin/windows/topologic/topologic.cp310-win_amd64.pyd +0 -0
  88. topologicpy/bin/windows/topologic/topologic.cp311-win_amd64.pyd +0 -0
  89. topologicpy/bin/windows/topologic/topologic.cp38-win_amd64.pyd +0 -0
  90. topologicpy/bin/windows/topologic/topologic.cp39-win_amd64.pyd +0 -0
  91. topologicpy-0.5.8.dist-info/METADATA +0 -96
  92. topologicpy-0.5.8.dist-info/RECORD +0 -91
  93. {topologicpy-0.5.8.dist-info → topologicpy-6.0.0.dist-info}/WHEEL +0 -0
  94. {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