topologicpy 0.7.15__py3-none-any.whl → 0.7.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- topologicpy/Cell.py +16 -11
- topologicpy/CellComplex.py +2 -2
- topologicpy/DGL.py +1 -1
- topologicpy/Edge.py +46 -20
- topologicpy/Face.py +133 -25
- topologicpy/Graph.py +148 -106
- topologicpy/Neo4j.py +2 -2
- topologicpy/Shell.py +57 -11
- topologicpy/Topology.py +13 -13
- topologicpy/Vector.py +1 -3
- topologicpy/Vertex.py +2 -4
- topologicpy/Wire.py +192 -190
- topologicpy/version.py +1 -1
- {topologicpy-0.7.15.dist-info → topologicpy-0.7.17.dist-info}/METADATA +1 -1
- topologicpy-0.7.17.dist-info/RECORD +33 -0
- topologicpy-0.7.15.dist-info/RECORD +0 -33
- {topologicpy-0.7.15.dist-info → topologicpy-0.7.17.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.15.dist-info → topologicpy-0.7.17.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.15.dist-info → topologicpy-0.7.17.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
@@ -858,8 +858,7 @@ class Cell():
|
|
858
858
|
|
859
859
|
baseWire = Wire.Circle(origin=circle_origin, radius=radius, sides=uSides, fromAngle=0, toAngle=360, close=True, direction=[0, 0, 1], placement="center", tolerance=tolerance)
|
860
860
|
baseFace = Face.ByWire(baseWire, tolerance=tolerance)
|
861
|
-
cylinder = Cell.ByThickenedFace(face=baseFace, thickness=height, bothSides=False,
|
862
|
-
tolerance=tolerance)
|
861
|
+
cylinder = Cell.ByThickenedFace(face=baseFace, thickness=height, bothSides=False, tolerance=tolerance)
|
863
862
|
if vSides > 1:
|
864
863
|
cutting_planes = []
|
865
864
|
baseX = Vertex.X(origin, mantissa=mantissa) + xOffset
|
@@ -1032,14 +1031,14 @@ class Cell():
|
|
1032
1031
|
cluster = Cluster.ByTopologies(pentagons)
|
1033
1032
|
|
1034
1033
|
cluster2 = Topology.Rotate(cluster, origin=Vertex.Origin(), axis=[1, 0, 0], angle=180)
|
1035
|
-
cluster2 = Topology.Rotate(cluster2, origin=Vertex.Origin(), axis=[0, 0, 1], angle=36)
|
1036
|
-
vertices = Topology.Vertices(
|
1034
|
+
#cluster2 = Topology.Rotate(cluster2, origin=Vertex.Origin(), axis=[0, 0, 1], angle=36)
|
1035
|
+
vertices = Topology.Vertices(cluster)
|
1037
1036
|
zList = [Vertex.Z(v) for v in vertices]
|
1038
1037
|
zList = list(set(zList))
|
1039
1038
|
zList.sort()
|
1040
|
-
|
1041
|
-
|
1042
|
-
cluster2 = Topology.Translate(cluster2, 0, 0,
|
1039
|
+
zoffset = zList[1] - zList[0]
|
1040
|
+
total_height = zList[-1] - zList[0]
|
1041
|
+
cluster2 = Topology.Translate(cluster2, 0, 0, total_height+zoffset)
|
1043
1042
|
pentagons += Topology.Faces(cluster2)
|
1044
1043
|
dodecahedron = Cell.ByFaces(pentagons, tolerance=tolerance)
|
1045
1044
|
centroid = Topology.Centroid(dodecahedron)
|
@@ -1052,6 +1051,12 @@ class Cell():
|
|
1052
1051
|
elif placement == "lowerleft":
|
1053
1052
|
dodecahedron = Topology.Translate(dodecahedron, radius, radius, radius)
|
1054
1053
|
|
1054
|
+
geo = Topology.Geometry(dodecahedron)
|
1055
|
+
vertices = [Vertex.ByCoordinates(coords) for coords in geo['vertices']]
|
1056
|
+
vertices = Vertex.Fuse(vertices)
|
1057
|
+
coords = [Vertex.Coordinates(v) for v in vertices]
|
1058
|
+
dodecahedron = Topology.RemoveCoplanarFaces(Topology.SelfMerge(Topology.ByGeometry(vertices=coords, faces=geo['faces'])))
|
1059
|
+
print(dodecahedron)
|
1055
1060
|
dodecahedron = Topology.Orient(dodecahedron, origin=Vertex.Origin(), dirA=[0, 0, 1], dirB=direction, tolerance=tolerance)
|
1056
1061
|
dodecahedron = Topology.Place(dodecahedron, originA=Vertex.Origin(), originB=origin)
|
1057
1062
|
return dodecahedron
|
@@ -1393,7 +1398,7 @@ class Cell():
|
|
1393
1398
|
|
1394
1399
|
icosahedron = Cell.ByFaces([f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,
|
1395
1400
|
f11,f12,f13,f14,f15,f16,f17,f18,f19,f20], tolerance=tolerance)
|
1396
|
-
sf = 1.051*0.5 # To
|
1401
|
+
sf = 1.051*0.5 # To inscribe it in a sphere of radius 0.5
|
1397
1402
|
icosahedron = Topology.Scale(icosahedron, origin=Vertex.Origin(), x=sf, y=sf, z=sf)
|
1398
1403
|
sf = radius/0.5
|
1399
1404
|
icosahedron = Topology.Scale(icosahedron, origin=Vertex.Origin(), x=sf, y=sf, z=sf)
|
@@ -1823,7 +1828,7 @@ class Cell():
|
|
1823
1828
|
----------
|
1824
1829
|
face : topologic_core.Face
|
1825
1830
|
The input face.
|
1826
|
-
angle : float ,
|
1831
|
+
angle : float , optional
|
1827
1832
|
The desired angle in degrees of the roof. The default is 45.
|
1828
1833
|
epsilon : float , optional
|
1829
1834
|
The desired epsilon (another form of tolerance for distance from plane). The default is 0.01. (This is set to a larger number as it was found to work better)
|
@@ -1865,7 +1870,7 @@ class Cell():
|
|
1865
1870
|
Returns
|
1866
1871
|
-------
|
1867
1872
|
list
|
1868
|
-
The classified list of input cells based on their
|
1873
|
+
The classified list of input cells based on their enclosure within the input list of super cells.
|
1869
1874
|
|
1870
1875
|
"""
|
1871
1876
|
|
@@ -1972,7 +1977,7 @@ class Cell():
|
|
1972
1977
|
if not Topology.IsInstance(origin, "Vertex"):
|
1973
1978
|
print("Cell.Sphere - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
|
1974
1979
|
return None
|
1975
|
-
c = Wire.Circle(origin=Vertex.Origin(), radius=radius, sides=vSides, fromAngle
|
1980
|
+
c = Wire.Circle(origin=Vertex.Origin(), radius=radius, sides=vSides, fromAngle=0, toAngle=180, close=False, direction=[0, 0, 1], placement="center")
|
1976
1981
|
c = Topology.Rotate(c, origin=Vertex.Origin(), axis=[1, 0, 0], angle=90)
|
1977
1982
|
sphere = Topology.Spin(c, origin=Vertex.Origin(), triangulate=False, direction=[0, 0, 1], angle=360, sides=uSides, tolerance=tolerance)
|
1978
1983
|
if Topology.Type(sphere) == Topology.TypeID("CellComplex"):
|
topologicpy/CellComplex.py
CHANGED
@@ -1132,9 +1132,9 @@ class CellComplex():
|
|
1132
1132
|
vertices = Topology.Vertices(cell)
|
1133
1133
|
else:
|
1134
1134
|
vertices += Topology.Vertices(cell)
|
1135
|
-
vertices = [v for v in vertices if (Vertex.IsInternal(v, cell) or not Vertex.Index(v, Topology.Vertices(cell)) == None)]
|
1135
|
+
vertices = [v for v in vertices if (Vertex.IsInternal(v, cell) or not Vertex.Index(v, Topology.Vertices(cell), tolerance=tolerance) == None)]
|
1136
1136
|
if len(vertices) < 1:
|
1137
|
-
print("CellComplex.Voronoi - Error: The input vertices
|
1137
|
+
print("CellComplex.Voronoi - Error: The input vertices parameter does not contain any vertices that are inside the input cell parameter. Returning None.")
|
1138
1138
|
return None
|
1139
1139
|
voronoi_points = np.array([Vertex.Coordinates(v) for v in vertices])
|
1140
1140
|
cluster = fracture_with_voronoi(voronoi_points)
|
topologicpy/DGL.py
CHANGED
@@ -92,7 +92,7 @@ except:
|
|
92
92
|
from dgl import save_graphs, load_graphs
|
93
93
|
print("DGL - dgl library installed correctly.")
|
94
94
|
except:
|
95
|
-
warnings.warn("DGL - Error: Could not import dgl. The installation of the correct version of the dgl library is not trivial and is highly dependent on your
|
95
|
+
warnings.warn("DGL - Error: Could not import dgl. The installation of the correct version of the dgl library is not trivial and is highly dependent on your hardware and software configuration. Please consult the dgl installation instructions.")
|
96
96
|
|
97
97
|
try:
|
98
98
|
from tqdm.auto import tqdm
|
topologicpy/Edge.py
CHANGED
@@ -84,13 +84,39 @@ class Edge():
|
|
84
84
|
The created bisecting edge.
|
85
85
|
|
86
86
|
"""
|
87
|
-
|
88
|
-
|
87
|
+
from topologicpy.Vertex import Vertex
|
89
88
|
from topologicpy.Wire import Wire
|
90
89
|
from topologicpy.Cluster import Cluster
|
91
90
|
from topologicpy.Topology import Topology
|
92
91
|
from topologicpy.Vector import Vector
|
92
|
+
import numpy as np
|
93
93
|
|
94
|
+
|
95
|
+
def process_edges(edge1, edge2, tolerance=0.0001):
|
96
|
+
start1 = Edge.StartVertex(edge1)
|
97
|
+
end1 = Edge.EndVertex(edge1)
|
98
|
+
start2 = Edge.StartVertex(edge2)
|
99
|
+
end2 = Edge.EndVertex(edge2)
|
100
|
+
|
101
|
+
shared_vertex = None
|
102
|
+
|
103
|
+
if Vertex.Distance(start1, start2) < tolerance:
|
104
|
+
shared_vertex = start1
|
105
|
+
elif Vertex.Distance(start1, end2) < tolerance:
|
106
|
+
shared_vertex = start1
|
107
|
+
edge2 = Edge.Reverse(edge2)
|
108
|
+
elif Vertex.Distance(end1, start2) < tolerance:
|
109
|
+
shared_vertex = start2
|
110
|
+
edge1 = Edge.Reverse(edge1)
|
111
|
+
elif Vertex.Distance(end1, end2) < tolerance:
|
112
|
+
shared_vertex = end1
|
113
|
+
edge1 = Edge.Reverse(edge1)
|
114
|
+
edge2 = Edge.Reverse(edge2)
|
115
|
+
|
116
|
+
if shared_vertex is None:
|
117
|
+
return [None, None]
|
118
|
+
return edge1, edge2
|
119
|
+
|
94
120
|
if not Topology.IsInstance(edgeA, "Edge"):
|
95
121
|
print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
|
96
122
|
return None
|
@@ -104,21 +130,21 @@ class Edge():
|
|
104
130
|
print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.")
|
105
131
|
return None
|
106
132
|
|
107
|
-
|
108
|
-
|
133
|
+
|
134
|
+
edge1, edge2 = process_edges(edgeA, edgeB, tolerance=tolerance)
|
135
|
+
if edge1 == None or edge2 == None:
|
109
136
|
print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.")
|
110
137
|
return None
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
sv = Wire.Vertices(wire)[1]
|
116
|
-
|
117
|
-
dirA = Edge.Direction(edgeA)
|
118
|
-
dirB = Edge.Direction(edgeB)
|
119
|
-
bisecting_vector = Vector.Bisect(dirA, dirB)
|
138
|
+
sv = Edge.StartVertex(edge1)
|
139
|
+
dir1 = Edge.Direction(edge1)
|
140
|
+
dir2 = Edge.Direction(edge2)
|
141
|
+
bisecting_vector = Vector.Bisect(dir1, dir2)
|
120
142
|
ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length)
|
121
143
|
bisecting_edge = Edge.ByVertices([sv, ev])
|
144
|
+
if placement == 0:
|
145
|
+
bisecting_edge = Topology.TranslateByDirectionDistance(bisecting_edge, Vector.Reverse(bisecting_vector), length*0.5)
|
146
|
+
elif placement == 2:
|
147
|
+
bisecting_edge = Topology.TranslateByDirectionDistance(bisecting_edge, Vector.Reverse(bisecting_vector), length)
|
122
148
|
return bisecting_edge
|
123
149
|
|
124
150
|
@staticmethod
|
@@ -130,7 +156,7 @@ class Edge():
|
|
130
156
|
----------
|
131
157
|
face : topologic_core.Face
|
132
158
|
The input face
|
133
|
-
origin :
|
159
|
+
origin : topologic_core.Vertex , optional
|
134
160
|
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.
|
135
161
|
length : float , optional
|
136
162
|
The desired length of the edge. The default is 1.
|
@@ -178,7 +204,7 @@ class Edge():
|
|
178
204
|
The input edge.
|
179
205
|
offset : float , optional
|
180
206
|
The desired offset. The default is 1.
|
181
|
-
tolerance : float ,
|
207
|
+
tolerance : float , optional
|
182
208
|
The desired tolerance. The default is 0.0001.
|
183
209
|
|
184
210
|
Returns
|
@@ -206,7 +232,7 @@ class Edge():
|
|
206
232
|
----------
|
207
233
|
vertexA : topologic_core.Vertex
|
208
234
|
The first input vertex. This is considered the start vertex.
|
209
|
-
vertexB :
|
235
|
+
vertexB : topologic_core.Vertex
|
210
236
|
The second input vertex. This is considered the end vertex.
|
211
237
|
tolerance : float , optional
|
212
238
|
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
|
@@ -481,7 +507,7 @@ class Edge():
|
|
481
507
|
if not silent:
|
482
508
|
print("Edge.ExtendToEdge - Error: The input edges are not coplanar. Returning the original edge.")
|
483
509
|
return edgeA
|
484
|
-
if
|
510
|
+
if Edge.IsParallel(edgeA, edgeB, tolerance=tolerance):
|
485
511
|
if not silent:
|
486
512
|
print("Edge.ExtendToEdge - Error: The input edges are parallel. Returning the original edge.")
|
487
513
|
return edgeA
|
@@ -789,8 +815,8 @@ class Edge():
|
|
789
815
|
|
790
816
|
x1, y1, z1 = Vertex.Coordinates(Edge.StartVertex(edgeA), mantissa=mantissa)
|
791
817
|
x2, y2, z2 = Vertex.Coordinates(Edge.EndVertex(edgeA), mantissa=mantissa)
|
792
|
-
x3, y3, z3 = Vertex.Coordinates(Edge.StartVertex(
|
793
|
-
x4, y4, z4 = Vertex.Coordinates(Edge.EndVertex(
|
818
|
+
x3, y3, z3 = Vertex.Coordinates(Edge.StartVertex(edgeB), mantissa=mantissa)
|
819
|
+
x4, y4, z4 = Vertex.Coordinates(Edge.EndVertex(edgeB), mantissa=mantissa)
|
794
820
|
line1 = ((x1, y1, z1), (x2, y2, z2))
|
795
821
|
line2 = ((x3, y3, z3), (x4, y4, z4))
|
796
822
|
return are_lines_parallel(line1, line2, tolerance=tolerance)
|
@@ -1239,7 +1265,7 @@ class Edge():
|
|
1239
1265
|
if not silent:
|
1240
1266
|
print("Edge.TrimByEdge - Error: The input edges are not coplanar. Returning the original edge.")
|
1241
1267
|
return edgeA
|
1242
|
-
if
|
1268
|
+
if Edge.IsParallel(edgeA, edgeB, tolerance=tolerance):
|
1243
1269
|
if not silent:
|
1244
1270
|
print("Edge.TrimByEdge - Error: The input edges are parallel. Returning the original edge.")
|
1245
1271
|
return edgeA
|
topologicpy/Face.py
CHANGED
@@ -258,11 +258,9 @@ class Face():
|
|
258
258
|
return Face.ByEdges(edges, tolerance=tolerance)
|
259
259
|
|
260
260
|
@staticmethod
|
261
|
-
def ByOffset(face, offset: float = 1.0,
|
262
|
-
miterThreshold: float = None, offsetKey: str = None,
|
263
|
-
miterThresholdKey: str = None, step: bool = True, tolerance: float = 0.0001):
|
261
|
+
def ByOffset(face, offset: float = 1.0, tolerance: float = 0.0001):
|
264
262
|
"""
|
265
|
-
Creates an offset face from the input face.
|
263
|
+
Creates an offset face from the input face. A positive offset value results in a smaller face to the inside of the input face.
|
266
264
|
|
267
265
|
Parameters
|
268
266
|
----------
|
@@ -270,16 +268,6 @@ class Face():
|
|
270
268
|
The input face.
|
271
269
|
offset : float , optional
|
272
270
|
The desired offset distance. The default is 1.0.
|
273
|
-
miter : bool , optional
|
274
|
-
if set to True, the corners will be mitered. The default is False.
|
275
|
-
miterThreshold : float , optional
|
276
|
-
The distance beyond which a miter should be added. The default is None which means the miter threshold is set to the offset distance multiplied by the square root of 2.
|
277
|
-
offsetKey : str , optional
|
278
|
-
If specified, the dictionary of the edges will be queried for this key to sepcify the desired offset. The default is None.
|
279
|
-
miterThresholdKey : str , optional
|
280
|
-
If specified, the dictionary of the vertices will be queried for this key to sepcify the desired miter threshold distance. The default is None.
|
281
|
-
step : bool , optional
|
282
|
-
If set to True, The transition between collinear edges with different offsets will be a step. Otherwise, it will be a continous edge. The default is True.
|
283
271
|
tolerance : float , optional
|
284
272
|
The desired tolerance. The default is 0.0001.
|
285
273
|
|
@@ -293,18 +281,18 @@ class Face():
|
|
293
281
|
from topologicpy.Topology import Topology
|
294
282
|
|
295
283
|
if not Topology.IsInstance(face, "Face"):
|
296
|
-
print("Face.ByOffset - Warning: The input face parameter is not a valid
|
284
|
+
print("Face.ByOffset - Warning: The input face parameter is not a valid face. Returning None.")
|
297
285
|
return None
|
298
286
|
eb = Face.Wire(face)
|
299
287
|
internal_boundaries = Face.InternalBoundaries(face)
|
300
|
-
offset_external_boundary = Wire.ByOffset(wire=eb, offset=offset,
|
288
|
+
offset_external_boundary = Wire.ByOffset(wire=eb, offset=offset, bisectors=False, tolerance=tolerance)
|
301
289
|
offset_internal_boundaries = []
|
302
290
|
for internal_boundary in internal_boundaries:
|
303
|
-
offset_internal_boundaries.append(Wire.ByOffset(wire=internal_boundary, offset=offset,
|
291
|
+
offset_internal_boundaries.append(Wire.ByOffset(wire=internal_boundary, offset=offset, bisectors=False, tolerance=tolerance))
|
304
292
|
return Face.ByWires(offset_external_boundary, offset_internal_boundaries, tolerance=tolerance)
|
305
293
|
|
306
294
|
@staticmethod
|
307
|
-
def ByShell(shell, origin= None, angTolerance: float = 0.1, tolerance: float = 0.0001):
|
295
|
+
def ByShell(shell, origin= None, angTolerance: float = 0.1, tolerance: float = 0.0001, silent=False):
|
308
296
|
"""
|
309
297
|
Creates a face by merging the faces of the input shell.
|
310
298
|
|
@@ -351,13 +339,13 @@ class Face():
|
|
351
339
|
face = None
|
352
340
|
ext_boundary = Wire.RemoveCollinearEdges(Shell.ExternalBoundary(shell))
|
353
341
|
if Topology.IsInstance(ext_boundary, "Wire"):
|
354
|
-
face = Face.ByWire(ext_boundary)
|
342
|
+
face = Face.ByWire(ext_boundary, silent=silent)
|
355
343
|
elif Topology.IsInstance(ext_boundary, "Cluster"):
|
356
344
|
wires = Topology.Wires(ext_boundary)
|
357
|
-
faces = [Face.ByWire(w) for w in wires]
|
345
|
+
faces = [Face.ByWire(w, silent=silent) for w in wires]
|
358
346
|
areas = [Face.Area(f) for f in faces]
|
359
347
|
wires = Helper.Sort(wires, areas, reverseFlags=[True])
|
360
|
-
face = Face.ByWires(wires[0], wires[1:])
|
348
|
+
face = Face.ByWires(wires[0], wires[1:], silent=silent)
|
361
349
|
|
362
350
|
if Topology.IsInstance(face, "Face"):
|
363
351
|
return face
|
@@ -420,6 +408,68 @@ class Face():
|
|
420
408
|
else:
|
421
409
|
return None
|
422
410
|
|
411
|
+
@staticmethod
|
412
|
+
def ByThickenedWire(wire, offsetA: float = 1.0, offsetB: float = 0.0, tolerance: float = 0.0001):
|
413
|
+
"""
|
414
|
+
Creates a face by thickening the input wire. This method assumes the wire is manifold and planar.
|
415
|
+
|
416
|
+
Parameters
|
417
|
+
----------
|
418
|
+
wire : topologic_core.Wire
|
419
|
+
The input wire to be thickened.
|
420
|
+
offsetA : float , optional
|
421
|
+
The desired offset to the exterior of the wire. The default is 1.0.
|
422
|
+
offsetB : float , optional
|
423
|
+
The desired offset to the interior of the wire. The default is 0.0.
|
424
|
+
tolerance : float , optional
|
425
|
+
The desired tolerance. The default is 0.0001.
|
426
|
+
|
427
|
+
Returns
|
428
|
+
-------
|
429
|
+
topologic_core.Cell
|
430
|
+
The created cell.
|
431
|
+
|
432
|
+
"""
|
433
|
+
from topologicpy.Vertex import Vertex
|
434
|
+
from topologicpy.Edge import Edge
|
435
|
+
from topologicpy.Wire import Wire
|
436
|
+
from topologicpy.Vector import Vector
|
437
|
+
from topologicpy.Topology import Topology
|
438
|
+
|
439
|
+
if not Topology.IsInstance(wire, "Wire"):
|
440
|
+
print("Face.ByThickenedWire - Error: The input wire parameter is not a valid wire. Returning None.")
|
441
|
+
return None
|
442
|
+
|
443
|
+
three_vertices = Wire.Vertices(wire)[0:3]
|
444
|
+
temp_w = Wire.ByVertices(three_vertices, close=True)
|
445
|
+
flat_face = Face.ByWire(temp_w, tolerance=tolerance)
|
446
|
+
origin = Vertex.Origin()
|
447
|
+
normal = Face.Normal(flat_face)
|
448
|
+
flat_wire = Topology.Flatten(wire, origin=origin, direction=normal)
|
449
|
+
outside_wire = Wire.ByOffset(flat_wire, offset=abs(offsetA)*-1, bisectors = False, tolerance=tolerance)
|
450
|
+
inside_wire = Wire.ByOffset(flat_wire, offset=abs(offsetB), bisectors = False, tolerance=tolerance)
|
451
|
+
inside_wire = Wire.Reverse(inside_wire)
|
452
|
+
if not Wire.IsClosed(flat_wire):
|
453
|
+
sv = Topology.Vertices(flat_wire)[0]
|
454
|
+
ev = Topology.Vertices(flat_wire)[-1]
|
455
|
+
edges = Topology.Edges(flat_wire)
|
456
|
+
first_edge = Topology.SuperTopologies(sv, flat_wire, topologyType="edge")[0]
|
457
|
+
first_normal = Edge.Normal(first_edge)
|
458
|
+
last_edge = Topology.SuperTopologies(ev, flat_wire, topologyType="edge")[0]
|
459
|
+
last_normal = Edge.Normal(last_edge)
|
460
|
+
sv1 = Topology.TranslateByDirectionDistance(sv, first_normal, abs(offsetB))
|
461
|
+
sv2 = Topology.TranslateByDirectionDistance(sv, Vector.Reverse(first_normal), abs(offsetA))
|
462
|
+
ev1 = Topology.TranslateByDirectionDistance(ev, last_normal, abs(offsetB))
|
463
|
+
ev2 = Topology.TranslateByDirectionDistance(ev, Vector.Reverse(last_normal), abs(offsetA))
|
464
|
+
out_vertices = Topology.Vertices(outside_wire)[1:-1]
|
465
|
+
in_vertices = Topology.Vertices(inside_wire)[1:-1]
|
466
|
+
vertices = [sv2] + out_vertices + [ev2,ev1] + in_vertices + [sv1]
|
467
|
+
return_face = Face.ByWire(Wire.ByVertices(vertices))
|
468
|
+
else:
|
469
|
+
return_face = Face.ByWires(outside_wire, [inside_wire])
|
470
|
+
return_face = Topology.Unflatten(return_face, origin=origin, direction=normal)
|
471
|
+
return return_face
|
472
|
+
|
423
473
|
@staticmethod
|
424
474
|
def ByVertices(vertices: list, tolerance: float = 0.0001):
|
425
475
|
|
@@ -839,7 +889,7 @@ class Face():
|
|
839
889
|
def Einstein(origin= None, radius: float = 0.5, direction: list = [0, 0, 1],
|
840
890
|
placement: str = "center", tolerance: float = 0.0001):
|
841
891
|
"""
|
842
|
-
Creates an aperiodic monotile, also called an 'einstein' tile (meaning one tile in German, not the name of the famous
|
892
|
+
Creates an aperiodic monotile, also called an 'einstein' tile (meaning one tile in German, not the name of the famous physicist). See https://arxiv.org/abs/2303.10798
|
843
893
|
|
844
894
|
Parameters
|
845
895
|
----------
|
@@ -869,6 +919,64 @@ class Face():
|
|
869
919
|
return None
|
870
920
|
return Face.ByWire(wire, tolerance=tolerance)
|
871
921
|
|
922
|
+
@staticmethod
|
923
|
+
def Ellipse(origin= None, inputMode: int = 1, width: float = 2.0, length: float = 1.0, focalLength: float = 0.866025, eccentricity: float = 0.866025, majorAxisLength: float = 1.0, minorAxisLength: float = 0.5, sides: float = 32, fromAngle: float = 0.0, toAngle: float = 360.0, close: bool = True, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
|
924
|
+
"""
|
925
|
+
Creates an ellipse and returns all its geometry and parameters.
|
926
|
+
|
927
|
+
Parameters
|
928
|
+
----------
|
929
|
+
origin : topologic_core.Vertex , optional
|
930
|
+
The location of the origin of the ellipse. The default is None which results in the ellipse being placed at (0, 0, 0).
|
931
|
+
inputMode : int , optional
|
932
|
+
The method by which the ellipse is defined. The default is 1.
|
933
|
+
Based on the inputMode value, only the following inputs will be considered. The options are:
|
934
|
+
1. Width and Length (considered inputs: width, length)
|
935
|
+
2. Focal Length and Eccentricity (considered inputs: focalLength, eccentricity)
|
936
|
+
3. Focal Length and Minor Axis Length (considered inputs: focalLength, minorAxisLength)
|
937
|
+
4. Major Axis Length and Minor Axis Length (considered input: majorAxisLength, minorAxisLength)
|
938
|
+
width : float , optional
|
939
|
+
The width of the ellipse. The default is 2.0. This is considered if the inputMode is 1.
|
940
|
+
length : float , optional
|
941
|
+
The length of the ellipse. The default is 1.0. This is considered if the inputMode is 1.
|
942
|
+
focalLength : float , optional
|
943
|
+
The focal length of the ellipse. The default is 0.866025. This is considered if the inputMode is 2 or 3.
|
944
|
+
eccentricity : float , optional
|
945
|
+
The eccentricity of the ellipse. The default is 0.866025. This is considered if the inputMode is 2.
|
946
|
+
majorAxisLength : float , optional
|
947
|
+
The length of the major axis of the ellipse. The default is 1.0. This is considered if the inputMode is 4.
|
948
|
+
minorAxisLength : float , optional
|
949
|
+
The length of the minor axis of the ellipse. The default is 0.5. This is considered if the inputMode is 3 or 4.
|
950
|
+
sides : int , optional
|
951
|
+
The number of sides of the ellipse. The default is 32.
|
952
|
+
fromAngle : float , optional
|
953
|
+
The angle in degrees from which to start creating the arc of the ellipse. The default is 0.
|
954
|
+
toAngle : float , optional
|
955
|
+
The angle in degrees at which to end creating the arc of the ellipse. The default is 360.
|
956
|
+
close : bool , optional
|
957
|
+
If set to True, arcs will be closed by connecting the last vertex to the first vertex. Otherwise, they will be left open.
|
958
|
+
direction : list , optional
|
959
|
+
The vector representing the up direction of the ellipse. The default is [0, 0, 1].
|
960
|
+
placement : str , optional
|
961
|
+
The description of the placement of the origin of the ellipse. This can be "center", or "lowerleft". It is case insensitive. The default is "center".
|
962
|
+
tolerance : float , optional
|
963
|
+
The desired tolerance. The default is 0.0001.
|
964
|
+
|
965
|
+
Returns
|
966
|
+
-------
|
967
|
+
topologic_core.Face
|
968
|
+
The created ellipse
|
969
|
+
|
970
|
+
"""
|
971
|
+
from topologicpy.Wire import Wire
|
972
|
+
w = Wire.Ellipse(origin=origin, inputMode=inputMode, width=width, length=length,
|
973
|
+
focalLength=focalLength, eccentricity=eccentricity,
|
974
|
+
majorAxisLength=majorAxisLength, minorAxisLength=minorAxisLength,
|
975
|
+
sides=sides, fromAngle=fromAngle, toAngle=toAngle,
|
976
|
+
close=close, direction=direction,
|
977
|
+
placement=placement, tolerance=tolerance)
|
978
|
+
return Face.ByWire(w)
|
979
|
+
|
872
980
|
@staticmethod
|
873
981
|
def ExteriorAngles(face, includeInternalBoundaries=False, mantissa: int = 6) -> list:
|
874
982
|
"""
|
@@ -1256,10 +1364,10 @@ class Face():
|
|
1256
1364
|
return None
|
1257
1365
|
|
1258
1366
|
if not Topology.IsInstance(faceA, "Face"):
|
1259
|
-
print("Face.
|
1367
|
+
print("Face.IsInside - Error: The input faceA parameter is not a valid topologic face. Returning None.")
|
1260
1368
|
return None
|
1261
1369
|
if not Topology.IsInstance(faceB, "Face"):
|
1262
|
-
print("Face.
|
1370
|
+
print("Face.IsInside - Error: The input faceB parameter is not a valid topologic face. Returning None.")
|
1263
1371
|
return None
|
1264
1372
|
|
1265
1373
|
def normalize_plane_coefficients(plane):
|
@@ -1924,7 +2032,7 @@ class Face():
|
|
1924
2032
|
from topologicpy.Topology import Topology
|
1925
2033
|
|
1926
2034
|
if not Topology.IsInstance(face, "Face"):
|
1927
|
-
print("Face.Skeleton - Error: The input face is not a valid topologic face.
|
2035
|
+
print("Face.Skeleton - Error: The input face is not a valid topologic face. Returning None.")
|
1928
2036
|
return None
|
1929
2037
|
return Wire.Skeleton(face, tolerance=tolerance)
|
1930
2038
|
|