topologicpy 0.6.3__py3-none-any.whl → 0.7.2__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/Face.py CHANGED
@@ -15,9 +15,6 @@
15
15
  # this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  import topologic_core as topologic
18
- from topologicpy.Vector import Vector
19
- from topologicpy.Wire import Wire
20
- from topologicpy.Topology import Topology
21
18
  import math
22
19
  import os
23
20
  import warnings
@@ -36,33 +33,34 @@ except:
36
33
  except:
37
34
  warnings.warn("Face - Error: Could not import numpy.")
38
35
 
39
- class Face(Topology):
36
+ class Face():
40
37
  @staticmethod
41
- def AddInternalBoundaries(face: topologic.Face, wires: list) -> topologic.Face:
38
+ def AddInternalBoundaries(face, wires: list):
42
39
  """
43
40
  Adds internal boundaries (closed wires) to the input face. Internal boundaries are considered holes in the input face.
44
41
 
45
42
  Parameters
46
43
  ----------
47
- face : topologic.Face
44
+ face : topologic_core.Face
48
45
  The input face.
49
46
  wires : list
50
47
  The input list of internal boundaries (closed wires).
51
48
 
52
49
  Returns
53
50
  -------
54
- topologic.Face
51
+ topologic_core.Face
55
52
  The created face with internal boundaries added to it.
56
53
 
57
54
  """
55
+ from topologicpy.Topology import Topology
58
56
 
59
- if not isinstance(face, topologic.Face):
57
+ if not Topology.IsInstance(face, "Face"):
60
58
  print("Face.AddInternalBoundaries - Error: The input face parameter is not a valid topologic face. Returning None.")
61
59
  return None
62
60
  if not isinstance(wires, list):
63
61
  print("Face.AddInternalBoundaries - Warning: The input wires parameter is not a valid list. Returning the input face.")
64
62
  return face
65
- wireList = [w for w in wires if isinstance(w, topologic.Wire)]
63
+ wireList = [w for w in wires if Topology.IsInstance(w, "Wire")]
66
64
  if len(wireList) < 1:
67
65
  print("Face.AddInternalBoundaries - Warning: The input wires parameter does not contain any valid wires. Returning the input face.")
68
66
  return face
@@ -71,47 +69,49 @@ class Face(Topology):
71
69
  _ = face.InternalBoundaries(faceibList)
72
70
  for wire in wires:
73
71
  faceibList.append(wire)
74
- return topologic.Face.ByExternalInternalBoundaries(faceeb, faceibList)
72
+ return Face.ByWires(faceeb, faceibList)
75
73
 
76
74
  @staticmethod
77
- def AddInternalBoundariesCluster(face: topologic.Face, cluster: topologic.Cluster) -> topologic.Face:
75
+ def AddInternalBoundariesCluster(face, cluster):
78
76
  """
79
77
  Adds the input cluster of internal boundaries (closed wires) to the input face. Internal boundaries are considered holes in the input face.
80
78
 
81
79
  Parameters
82
80
  ----------
83
- face : topologic.Face
81
+ face : topologic_core.Face
84
82
  The input face.
85
- cluster : topologic.Cluster
83
+ cluster : topologic_core.Cluster
86
84
  The input cluster of internal boundaries (topologic wires).
87
85
 
88
86
  Returns
89
87
  -------
90
- topologic.Face
88
+ topologic_core.Face
91
89
  The created face with internal boundaries added to it.
92
90
 
93
91
  """
94
- if not isinstance(face, topologic.Face):
92
+ from topologicpy.Topology import Topology
93
+
94
+ if not Topology.IsInstance(face, "Face"):
95
95
  print("Face.AddInternalBoundariesCluster - Warning: The input cluster parameter is not a valid cluster. Returning None.")
96
96
  return None
97
97
  if not cluster:
98
98
  return face
99
- if not isinstance(cluster, topologic.Cluster):
99
+ if not Topology.IsInstance(cluster, "Cluster"):
100
100
  return face
101
101
  wires = []
102
102
  _ = cluster.Wires(None, wires)
103
103
  return Face.AddInternalBoundaries(face, wires)
104
104
 
105
105
  @staticmethod
106
- def Angle(faceA: topologic.Face, faceB: topologic.Face, mantissa: int = 6) -> float:
106
+ def Angle(faceA, faceB, mantissa: int = 6) -> float:
107
107
  """
108
108
  Returns the angle in degrees between the two input faces.
109
109
 
110
110
  Parameters
111
111
  ----------
112
- faceA : topologic.Face
112
+ faceA : topologic_core.Face
113
113
  The first input face.
114
- faceB : topologic.Face
114
+ faceB : topologic_core.Face
115
115
  The second input face.
116
116
  mantissa : int , optional
117
117
  The desired length of the mantissa. The default is 6.
@@ -123,10 +123,12 @@ class Face(Topology):
123
123
 
124
124
  """
125
125
  from topologicpy.Vector import Vector
126
- if not isinstance(faceA, topologic.Face):
126
+ from topologicpy.Topology import Topology
127
+
128
+ if not Topology.IsInstance(faceA, "Face"):
127
129
  print("Face.Angle - Warning: The input faceA parameter is not a valid topologic face. Returning None.")
128
130
  return None
129
- if not isinstance(faceB, topologic.Face):
131
+ if not Topology.IsInstance(faceB, "Face"):
130
132
  print("Face.Angle - Warning: The input faceB parameter is not a valid topologic face. Returning None.")
131
133
  return None
132
134
  dirA = Face.NormalAtParameters(faceA, 0.5, 0.5, "xyz", 3)
@@ -134,13 +136,13 @@ class Face(Topology):
134
136
  return round((Vector.Angle(dirA, dirB)), mantissa)
135
137
 
136
138
  @staticmethod
137
- def Area(face: topologic.Face, mantissa: int = 6) -> float:
139
+ def Area(face, mantissa: int = 6) -> float:
138
140
  """
139
141
  Returns the area of the input face.
140
142
 
141
143
  Parameters
142
144
  ----------
143
- face : topologic.Face
145
+ face : topologic_core.Face
144
146
  The input face.
145
147
  mantissa : int , optional
146
148
  The desired length of the mantissa. The default is 6.
@@ -151,24 +153,26 @@ class Face(Topology):
151
153
  The area of the input face.
152
154
 
153
155
  """
154
- if not isinstance(face, topologic.Face):
156
+ from topologicpy.Topology import Topology
157
+
158
+ if not Topology.IsInstance(face, "Face"):
155
159
  print("Face.Area - Warning: The input face parameter is not a valid topologic face. Returning None.")
156
160
  return None
157
161
  area = None
158
162
  try:
159
- area = round(topologic.FaceUtility.Area(face), mantissa)
163
+ area = round(topologic.FaceUtility.Area(face), mantissa) # Hook to Core
160
164
  except:
161
165
  area = None
162
166
  return area
163
167
 
164
168
  @staticmethod
165
- def BoundingRectangle(topology: topologic.Topology, optimize: int = 0, tolerance: float = 0.0001) -> topologic.Face:
169
+ def BoundingRectangle(topology, optimize: int = 0, tolerance: float = 0.0001):
166
170
  """
167
171
  Returns a face representing a bounding rectangle of the input topology. The returned face contains a dictionary with key "zrot" that represents rotations around the Z axis. If applied the resulting face will become axis-aligned.
168
172
 
169
173
  Parameters
170
174
  ----------
171
- topology : topologic.Topology
175
+ topology : topologic_core.Topology
172
176
  The input topology.
173
177
  optimize : int , optional
174
178
  If set to an integer from 1 (low optimization) to 10 (high optimization), the method will attempt to optimize the bounding rectangle so that it reduces its surface area. The default is 0 which will result in an axis-aligned bounding rectangle. The default is 0.
@@ -177,93 +181,20 @@ class Face(Topology):
177
181
 
178
182
  Returns
179
183
  -------
180
- topologic.Face
184
+ topologic_core.Face
181
185
  The bounding rectangle of the input topology.
182
186
 
183
187
  """
184
188
  from topologicpy.Wire import Wire
185
- from topologicpy.Face import Face
186
- from topologicpy.Cluster import Cluster
187
189
  from topologicpy.Topology import Topology
188
- from topologicpy.Dictionary import Dictionary
189
- def bb(topology):
190
- vertices = []
191
- _ = topology.Vertices(None, vertices)
192
- x = []
193
- y = []
194
- for aVertex in vertices:
195
- x.append(aVertex.X())
196
- y.append(aVertex.Y())
197
- minX = min(x)
198
- minY = min(y)
199
- maxX = max(x)
200
- maxY = max(y)
201
- return [minX, minY, maxX, maxY]
202
-
203
- if not isinstance(topology, topologic.Topology):
204
- print("Face.BoundingRectangle - Warning: The input topology parameter is not a valid topologic topology. Returning None.")
205
- return None
206
- vertices = Topology.SubTopologies(topology, subTopologyType="vertex")
207
- topology = Cluster.ByTopologies(vertices)
208
- boundingBox = bb(topology)
209
- minX = boundingBox[0]
210
- minY = boundingBox[1]
211
- maxX = boundingBox[2]
212
- maxY = boundingBox[3]
213
- w = abs(maxX - minX)
214
- l = abs(maxY - minY)
215
- best_area = l*w
216
- orig_area = best_area
217
- best_z = 0
218
- best_bb = boundingBox
219
- origin = Topology.Centroid(topology)
220
- optimize = min(max(optimize, 0), 10)
221
- if optimize > 0:
222
- factor = (round(((11 - optimize)/30 + 0.57), 2))
223
- flag = False
224
- for n in range(10,0,-1):
225
- if flag:
226
- break
227
- za = n
228
- zb = 90+n
229
- zc = n
230
- for z in range(za,zb,zc):
231
- if flag:
232
- break
233
- t = Topology.Rotate(topology, origin=origin, axis=[0, 0, 1], angle=z)
234
- minX, minY, maxX, maxY = bb(t)
235
- w = abs(maxX - minX)
236
- l = abs(maxY - minY)
237
- area = l*w
238
- if area < orig_area*factor:
239
- best_area = area
240
- best_z = z
241
- best_bb = [minX, minY, maxX, maxY]
242
- flag = True
243
- break
244
- if area < best_area:
245
- best_area = area
246
- best_z = z
247
- best_bb = [minX, minY, maxX, maxY]
248
-
249
- else:
250
- best_bb = boundingBox
251
-
252
- minX, minY, maxX, maxY = best_bb
253
- vb1 = topologic.Vertex.ByCoordinates(minX, minY, 0)
254
- vb2 = topologic.Vertex.ByCoordinates(maxX, minY, 0)
255
- vb3 = topologic.Vertex.ByCoordinates(maxX, maxY, 0)
256
- vb4 = topologic.Vertex.ByCoordinates(minX, maxY, 0)
257
-
258
- baseWire = Wire.ByVertices([vb1, vb2, vb3, vb4], close=True)
259
- baseFace = Face.ByWire(baseWire, tolerance=tolerance)
260
- baseFace = Topology.Rotate(baseFace, origin=origin, axis=[0, 0, 1], angle=-best_z)
261
- dictionary = Dictionary.ByKeysValues(["zrot"], [best_z])
262
- baseFace = Topology.SetDictionary(baseFace, dictionary)
263
- return baseFace
190
+
191
+ br_wire = Wire.BoundingRectangle(topology=topology, optimize=optimize, tolerance=tolerance)
192
+ br_face = Face.ByWire(br_wire)
193
+ br_face = Topology.SetDictionary(br_face, Topology.Dictionary(br_wire))
194
+ return br_face
264
195
 
265
196
  @staticmethod
266
- def ByEdges(edges: list, tolerance : float = 0.0001) -> topologic.Face:
197
+ def ByEdges(edges: list, tolerance : float = 0.0001):
267
198
  """
268
199
  Creates a face from the input list of edges.
269
200
 
@@ -276,44 +207,48 @@ class Face(Topology):
276
207
 
277
208
  Returns
278
209
  -------
279
- face : topologic.Face
210
+ face : topologic_core.Face
280
211
  The created face.
281
212
 
282
213
  """
283
214
  from topologicpy.Wire import Wire
215
+ from topologicpy.Topology import Topology
216
+
284
217
  if not isinstance(edges, list):
285
218
  print("Face.ByEdges - Error: The input edges parameter is not a valid list. Returning None.")
286
219
  return None
287
- edges = [e for e in edges if isinstance(e, topologic.Edge)]
220
+ edges = [e for e in edges if Topology.IsInstance(e, "Edge")]
288
221
  if len(edges) < 1:
289
222
  print("Face.ByEdges - Error: The input edges parameter does not contain any valid edges. Returning None.")
290
223
  return None
291
224
  wire = Wire.ByEdges(edges, tolerance=tolerance)
292
- if not isinstance(wire, topologic.Wire):
225
+ if not Topology.IsInstance(wire, "Wire"):
293
226
  print("Face.ByEdges - Error: Could not create the required wire. Returning None.")
294
227
  return None
295
228
  return Face.ByWire(wire, tolerance=tolerance)
296
229
 
297
230
  @staticmethod
298
- def ByEdgesCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.Face:
231
+ def ByEdgesCluster(cluster, tolerance: float = 0.0001):
299
232
  """
300
233
  Creates a face from the input cluster of edges.
301
234
 
302
235
  Parameters
303
236
  ----------
304
- cluster : topologic.Cluster
237
+ cluster : topologic_core.Cluster
305
238
  The input cluster of edges.
306
239
  tolerance : float , optional
307
240
  The desired tolerance. The default is 0.0001.
308
241
 
309
242
  Returns
310
243
  -------
311
- face : topologic.Face
244
+ face : topologic_core.Face
312
245
  The created face.
313
246
 
314
247
  """
315
248
  from topologicpy.Cluster import Cluster
316
- if not isinstance(cluster, topologic.Cluster):
249
+ from topologicpy.Topology import Topology
250
+
251
+ if not Topology.IsInstance(cluster, "Cluster"):
317
252
  print("Face.ByEdgesCluster - Warning: The input cluster parameter is not a valid topologic cluster. Returning None.")
318
253
  return None
319
254
  edges = Cluster.Edges(cluster)
@@ -323,15 +258,15 @@ class Face(Topology):
323
258
  return Face.ByEdges(edges, tolerance=tolerance)
324
259
 
325
260
  @staticmethod
326
- def ByOffset(face: topologic.Face, offset: float = 1.0, miter: bool = False,
261
+ def ByOffset(face, offset: float = 1.0, miter: bool = False,
327
262
  miterThreshold: float = None, offsetKey: str = None,
328
- miterThresholdKey: str = None, step: bool = True, tolerance: float = 0.0001) -> topologic.Face:
263
+ miterThresholdKey: str = None, step: bool = True, tolerance: float = 0.0001):
329
264
  """
330
265
  Creates an offset face from the input face.
331
266
 
332
267
  Parameters
333
268
  ----------
334
- face : topologic.Face
269
+ face : topologic_core.Face
335
270
  The input face.
336
271
  offset : float , optional
337
272
  The desired offset distance. The default is 1.0.
@@ -350,12 +285,14 @@ class Face(Topology):
350
285
 
351
286
  Returns
352
287
  -------
353
- topologic.Face
288
+ topologic_core.Face
354
289
  The created face.
355
290
 
356
291
  """
357
292
  from topologicpy.Wire import Wire
358
- if not isinstance(face, topologic.Face):
293
+ from topologicpy.Topology import Topology
294
+
295
+ if not Topology.IsInstance(face, "Face"):
359
296
  print("Face.ByOffset - Warning: The input face parameter is not a valid toplogic face. Returning None.")
360
297
  return None
361
298
  eb = Face.Wire(face)
@@ -367,13 +304,13 @@ class Face(Topology):
367
304
  return Face.ByWires(offset_external_boundary, offset_internal_boundaries, tolerance=tolerance)
368
305
 
369
306
  @staticmethod
370
- def ByShell(shell: topologic.Shell, origin: topologic.Vertex = None, angTolerance: float = 0.1, tolerance: float = 0.0001)-> topologic.Face:
307
+ def ByShell(shell, origin= None, angTolerance: float = 0.1, tolerance: float = 0.0001):
371
308
  """
372
309
  Creates a face by merging the faces of the input shell.
373
310
 
374
311
  Parameters
375
312
  ----------
376
- shell : topologic.Shell
313
+ shell : topologic_core.Shell
377
314
  The input shell.
378
315
  angTolerance : float , optional
379
316
  The desired angular tolerance. The default is 0.1.
@@ -382,7 +319,7 @@ class Face(Topology):
382
319
 
383
320
  Returns
384
321
  -------
385
- topologic.Face
322
+ topologic_core.Face
386
323
  The created face.
387
324
 
388
325
  """
@@ -400,29 +337,29 @@ class Face(Topology):
400
337
  returnList.append(Wire.Planarize(aWire))
401
338
  return returnList
402
339
 
403
- if not isinstance(shell, topologic.Shell):
340
+ if not Topology.IsInstance(shell, "Shell"):
404
341
  print("Face.ByShell - Error: The input shell parameter is not a valid toplogic shell. Returning None.")
405
342
  return None
406
343
 
407
344
  if origin == None:
408
345
  origin = Topology.Centroid(shell)
409
- if not isinstance(origin, topologic.Vertex):
346
+ if not Topology.IsInstance(origin, "Vertex"):
410
347
  print("Face.ByShell - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
411
348
  return None
412
349
 
413
350
  # Try the simple method first
414
351
  face = None
415
352
  ext_boundary = Wire.RemoveCollinearEdges(Shell.ExternalBoundary(shell))
416
- if isinstance(ext_boundary, topologic.Wire):
353
+ if Topology.IsInstance(ext_boundary, "Wire"):
417
354
  face = Face.ByWire(ext_boundary)
418
- elif isinstance(ext_boundary, topologic.Cluster):
355
+ elif Topology.IsInstance(ext_boundary, "Cluster"):
419
356
  wires = Topology.Wires(ext_boundary)
420
357
  faces = [Face.ByWire(w) for w in wires]
421
358
  areas = [Face.Area(f) for f in faces]
422
359
  wires = Helper.Sort(wires, areas, reverseFlags=[True])
423
360
  face = Face.ByWires(wires[0], wires[1:])
424
361
 
425
- if isinstance(face, topologic.Face):
362
+ if Topology.IsInstance(face, "Face"):
426
363
  return face
427
364
  world_origin = Vertex.Origin()
428
365
  planar_shell = Shell.Planarize(shell)
@@ -437,11 +374,11 @@ class Face(Topology):
437
374
  planar_shell = Topology.SelfMerge(Topology.ReplaceVertices(planar_shell, verticesA=vertices, verticesB=new_vertices), tolerance=tolerance)
438
375
  ext_boundary = Shell.ExternalBoundary(planar_shell, tolerance=tolerance)
439
376
  ext_boundary = Topology.RemoveCollinearEdges(ext_boundary, angTolerance)
440
- if not isinstance(ext_boundary, topologic.Topology):
377
+ if not Topology.IsInstance(ext_boundary, "Topology"):
441
378
  print("Face.ByShell - Error: Could not derive the external boundary of the input shell parameter. Returning None.")
442
379
  return None
443
380
 
444
- if isinstance(ext_boundary, topologic.Wire):
381
+ if Topology.IsInstance(ext_boundary, "Wire"):
445
382
  if not Topology.IsPlanar(ext_boundary, tolerance=tolerance):
446
383
  ext_boundary = Wire.Planarize(ext_boundary, origin=origin, tolerance=tolerance)
447
384
  ext_boundary = Topology.RemoveCollinearEdges(ext_boundary, angTolerance)
@@ -452,14 +389,14 @@ class Face(Topology):
452
389
  except:
453
390
  print("Face.ByShell - Error: The operation failed. Returning None.")
454
391
  return None
455
- elif isinstance(ext_boundary, topologic.Cluster): # The shell has holes.
392
+ elif Topology.IsInstance(ext_boundary, "Cluster"): # The shell has holes.
456
393
  wires = []
457
394
  _ = ext_boundary.Wires(None, wires)
458
395
  faces = []
459
396
  areas = []
460
397
  for wire in wires:
461
398
  aFace = Face.ByWire(wire, tolerance=tolerance)
462
- if not isinstance(aFace, topologic.Face):
399
+ if not Topology.IsInstance(aFace, "Face"):
463
400
  print("Face.ByShell - Error: The operation failed. Returning None.")
464
401
  return None
465
402
  anArea = abs(Face.Area(aFace))
@@ -484,7 +421,7 @@ class Face(Topology):
484
421
  return None
485
422
 
486
423
  @staticmethod
487
- def ByVertices(vertices: list, tolerance: float = 0.0001) -> topologic.Face:
424
+ def ByVertices(vertices: list, tolerance: float = 0.0001):
488
425
 
489
426
  """
490
427
  Creates a face from the input list of vertices.
@@ -498,7 +435,7 @@ class Face(Topology):
498
435
 
499
436
  Returns
500
437
  -------
501
- topologic.Face
438
+ topologic_core.Face
502
439
  The created face.
503
440
 
504
441
  """
@@ -507,7 +444,7 @@ class Face(Topology):
507
444
 
508
445
  if not isinstance(vertices, list):
509
446
  return None
510
- vertexList = [x for x in vertices if isinstance(x, topologic.Vertex)]
447
+ vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")]
511
448
  if len(vertexList) < 3:
512
449
  return None
513
450
 
@@ -516,37 +453,39 @@ class Face(Topology):
516
453
  return f
517
454
 
518
455
  @staticmethod
519
- def ByVerticesCluster(cluster: topologic.Cluster, tolerance: float = 0.0001) -> topologic.Face:
456
+ def ByVerticesCluster(cluster, tolerance: float = 0.0001):
520
457
  """
521
458
  Creates a face from the input cluster of vertices.
522
459
 
523
460
  Parameters
524
461
  ----------
525
- cluster : topologic.Cluster
462
+ cluster : topologic_core.Cluster
526
463
  The input cluster of vertices.
527
464
  tolerance : float , optional
528
465
  The desired tolerance. The default is 0.0001.
529
466
 
530
467
  Returns
531
468
  -------
532
- topologic.Face
533
- The crearted face.
469
+ topologic_core.Face
470
+ The created face.
534
471
 
535
472
  """
536
473
  from topologicpy.Cluster import Cluster
537
- if not isinstance(cluster, topologic.Cluster):
474
+ from topologicpy.Topology import Topology
475
+
476
+ if not Topology.IsInstance(cluster, "Cluster"):
538
477
  return None
539
478
  vertices = Cluster.Vertices(cluster)
540
479
  return Face.ByVertices(vertices, tolerance=tolerance)
541
480
 
542
481
  @staticmethod
543
- def ByWire(wire: topologic.Wire, tolerance: float = 0.0001, silent=False) -> topologic.Face:
482
+ def ByWire(wire, tolerance: float = 0.0001, silent=False):
544
483
  """
545
484
  Creates a face from the input closed wire.
546
485
 
547
486
  Parameters
548
487
  ----------
549
- wire : topologic.Wire
488
+ wire : topologic_core.Wire
550
489
  The input wire.
551
490
  tolerance : float , optional
552
491
  The desired tolerance. The default is 0.0001.
@@ -555,7 +494,7 @@ class Face(Topology):
555
494
 
556
495
  Returns
557
496
  -------
558
- topologic.Face or list
497
+ topologic_core.Face or list
559
498
  The created face. If the wire is non-planar, the method will attempt to triangulate the wire and return a list of faces.
560
499
 
561
500
  """
@@ -571,11 +510,11 @@ class Face(Topology):
571
510
  wire = Topology.RemoveCollinearEdges(wire)
572
511
  vertices = Topology.Vertices(wire)
573
512
  shell = Shell.Delaunay(vertices)
574
- if isinstance(shell, topologic.Topology):
513
+ if Topology.IsInstance(shell, "Topology"):
575
514
  return Topology.Faces(shell)
576
515
  else:
577
516
  return []
578
- if not isinstance(wire, topologic.Wire):
517
+ if not Topology.IsInstance(wire, "Wire"):
579
518
  if not silent:
580
519
  print("Face.ByWire - Error: The input wire parameter is not a valid topologic wire. Returning None.")
581
520
  return None
@@ -588,9 +527,9 @@ class Face(Topology):
588
527
  wire = Topology.SelfMerge(Cluster.ByTopologies(edges), tolerance=tolerance)
589
528
  vertices = Topology.Vertices(wire)
590
529
  fList = []
591
- if isinstance(wire, topologic.Wire):
530
+ if Topology.IsInstance(wire, "Wire"):
592
531
  try:
593
- fList = topologic.Face.ByExternalBoundary(wire)
532
+ fList = topologic.Face.ByExternalBoundary(wire) # Hook to Core
594
533
  except:
595
534
  if not silent:
596
535
  print("Face.ByWire - Warning: Could not create face by external boundary. Trying other methods.")
@@ -608,7 +547,7 @@ class Face(Topology):
608
547
  wire = Face.ExternalBoundary(f)
609
548
  wire = Wire.Invert(wire)
610
549
  try:
611
- f = topologic.Face.ByExternalBoundary(wire)
550
+ f = topologic.Face.ByExternalBoundary(wire) # Hook to Core
612
551
  returnList.append(f)
613
552
  except:
614
553
  pass
@@ -626,13 +565,13 @@ class Face(Topology):
626
565
  return returnList
627
566
 
628
567
  @staticmethod
629
- def ByWires(externalBoundary: topologic.Wire, internalBoundaries: list = [], tolerance: float = 0.0001, silent: bool = False) -> topologic.Face:
568
+ def ByWires(externalBoundary, internalBoundaries: list = [], tolerance: float = 0.0001, silent: bool = False):
630
569
  """
631
570
  Creates a face from the input external boundary (closed wire) and the input list of internal boundaries (closed wires).
632
571
 
633
572
  Parameters
634
573
  ----------
635
- externalBoundary : topologic.Wire
574
+ externalBoundary : topologic_core.Wire
636
575
  The input external boundary.
637
576
  internalBoundaries : list , optional
638
577
  The input list of internal boundaries (closed wires). The default is an empty list.
@@ -643,11 +582,14 @@ class Face(Topology):
643
582
 
644
583
  Returns
645
584
  -------
646
- topologic.Face
585
+ topologic_core.Face
647
586
  The created face.
648
587
 
649
588
  """
650
- if not isinstance(externalBoundary, topologic.Wire):
589
+ from topologicpy.Wire import Wire
590
+ from topologicpy.Topology import Topology
591
+
592
+ if not Topology.IsInstance(externalBoundary, "Wire"):
651
593
  if not silent:
652
594
  print("Face.ByWires - Error: The input externalBoundary parameter is not a valid topologic wire. Returning None.")
653
595
  return None
@@ -655,10 +597,10 @@ class Face(Topology):
655
597
  if not silent:
656
598
  print("Face.ByWires - Error: The input externalBoundary parameter is not a closed topologic wire. Returning None.")
657
599
  return None
658
- ibList = [x for x in internalBoundaries if isinstance(x, topologic.Wire) and Wire.IsClosed(x)]
600
+ ibList = [x for x in internalBoundaries if Topology.IsInstance(x, "Wire") and Wire.IsClosed(x)]
659
601
  face = None
660
602
  try:
661
- face = topologic.Face.ByExternalInternalBoundaries(externalBoundary, ibList, tolerance)
603
+ face = topologic.Face.ByExternalInternalBoundaries(externalBoundary, ibList, tolerance) # Hook to Core
662
604
  except:
663
605
  if not silent:
664
606
  print("Face.ByWires - Error: The operation failed. Returning None.")
@@ -667,15 +609,15 @@ class Face(Topology):
667
609
 
668
610
 
669
611
  @staticmethod
670
- def ByWiresCluster(externalBoundary: topologic.Wire, internalBoundariesCluster: topologic.Cluster = None, tolerance: float = 0.0001, silent: bool = False) -> topologic.Face:
612
+ def ByWiresCluster(externalBoundary, internalBoundariesCluster = None, tolerance: float = 0.0001, silent: bool = False):
671
613
  """
672
614
  Creates a face from the input external boundary (closed wire) and the input cluster of internal boundaries (closed wires).
673
615
 
674
616
  Parameters
675
617
  ----------
676
- externalBoundary : topologic.Wire
618
+ externalBoundary topologic_core.Wire
677
619
  The input external boundary (closed wire).
678
- internalBoundariesCluster : topologic.Cluster
620
+ internalBoundariesCluster : topologic_core.Cluster
679
621
  The input cluster of internal boundaries (closed wires). The default is None.
680
622
  tolerance : float , optional
681
623
  The desired tolerance. The default is 0.0001.
@@ -684,13 +626,15 @@ class Face(Topology):
684
626
 
685
627
  Returns
686
628
  -------
687
- topologic.Face
629
+ topologic_core.Face
688
630
  The created face.
689
631
 
690
632
  """
691
633
  from topologicpy.Wire import Wire
692
634
  from topologicpy.Cluster import Cluster
693
- if not isinstance(externalBoundary, topologic.Wire):
635
+ from topologicpy.Topology import Topology
636
+
637
+ if not Topology.IsInstance(externalBoundary, "Wire"):
694
638
  if not silent:
695
639
  print("Face.ByWiresCluster - Error: The input externalBoundary parameter is not a valid topologic wire. Returning None.")
696
640
  return None
@@ -700,7 +644,7 @@ class Face(Topology):
700
644
  return None
701
645
  if not internalBoundariesCluster:
702
646
  internalBoundaries = []
703
- elif not isinstance(internalBoundariesCluster, topologic.Cluster):
647
+ elif not Topology.IsInstance(internalBoundariesCluster, "Cluster"):
704
648
  if not silent:
705
649
  print("Face.ByWiresCluster - Error: The input internalBoundariesCluster parameter is not a valid topologic cluster. Returning None.")
706
650
  return None
@@ -709,14 +653,14 @@ class Face(Topology):
709
653
  return Face.ByWires(externalBoundary, internalBoundaries, tolerance=tolerance, silent=silent)
710
654
 
711
655
  @staticmethod
712
- def NorthArrow(origin: topologic.Vertex = None, radius: float = 0.5, sides: int = 16, direction: list = [0, 0, 1], northAngle: float = 0.0,
713
- placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
656
+ def NorthArrow(origin= None, radius: float = 0.5, sides: int = 16, direction: list = [0, 0, 1], northAngle: float = 0.0,
657
+ placement: str = "center", tolerance: float = 0.0001):
714
658
  """
715
659
  Creates a north arrow.
716
660
 
717
661
  Parameters
718
662
  ----------
719
- origin : topologic.Vertex, optional
663
+ origin : topologic_core.Vertex, optional
720
664
  The location of the origin of the circle. The default is None which results in the circle being placed at (0, 0, 0).
721
665
  radius : float , optional
722
666
  The radius of the circle. The default is 1.
@@ -733,7 +677,7 @@ class Face(Topology):
733
677
 
734
678
  Returns
735
679
  -------
736
- topologic.Face
680
+ topologic_core.Face
737
681
  The created circle.
738
682
 
739
683
  """
@@ -760,14 +704,14 @@ class Face(Topology):
760
704
  return arrow
761
705
 
762
706
  @staticmethod
763
- def Circle(origin: topologic.Vertex = None, radius: float = 0.5, sides: int = 16, fromAngle: float = 0.0, toAngle: float = 360.0, direction: list = [0, 0, 1],
764
- placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
707
+ def Circle(origin= None, radius: float = 0.5, sides: int = 16, fromAngle: float = 0.0, toAngle: float = 360.0, direction: list = [0, 0, 1],
708
+ placement: str = "center", tolerance: float = 0.0001):
765
709
  """
766
710
  Creates a circle.
767
711
 
768
712
  Parameters
769
713
  ----------
770
- origin : topologic.Vertex, optional
714
+ origin : topologic_core.Vertex, optional
771
715
  The location of the origin of the circle. The default is None which results in the circle being placed at (0, 0, 0).
772
716
  radius : float , optional
773
717
  The radius of the circle. The default is 1.
@@ -786,24 +730,26 @@ class Face(Topology):
786
730
 
787
731
  Returns
788
732
  -------
789
- topologic.Face
733
+ topologic_core.Face
790
734
  The created circle.
791
735
 
792
736
  """
793
737
  from topologicpy.Wire import Wire
738
+ from topologicpy.Topology import Topology
739
+
794
740
  wire = Wire.Circle(origin=origin, radius=radius, sides=sides, fromAngle=fromAngle, toAngle=toAngle, close=True, direction=direction, placement=placement, tolerance=tolerance)
795
- if not isinstance(wire, topologic.Wire):
741
+ if not Topology.IsInstance(wire, "Wire"):
796
742
  return None
797
743
  return Face.ByWire(wire, tolerance=tolerance)
798
744
 
799
745
  @staticmethod
800
- def Compactness(face: topologic.Face, mantissa: int = 6) -> float:
746
+ def Compactness(face, mantissa: int = 6) -> float:
801
747
  """
802
748
  Returns the compactness measure of the input face. See https://en.wikipedia.org/wiki/Compactness_measure_of_a_shape
803
749
 
804
750
  Parameters
805
751
  ----------
806
- face : topologic.Face
752
+ face : topologic_core.Face
807
753
  The input face.
808
754
  mantissa : int , optional
809
755
  The desired length of the mantissa. The default is 6.
@@ -814,12 +760,14 @@ class Face(Topology):
814
760
  The compactness measure of the input face.
815
761
 
816
762
  """
763
+ from topologicpy.Edge import Edge
764
+
817
765
  exb = face.ExternalBoundary()
818
766
  edges = []
819
767
  _ = exb.Edges(None, edges)
820
768
  perimeter = 0.0
821
769
  for anEdge in edges:
822
- perimeter = perimeter + abs(topologic.EdgeUtility.Length(anEdge))
770
+ perimeter = perimeter + abs(Edge.Length(anEdge))
823
771
  area = abs(Face.Area(face))
824
772
  compactness = 0
825
773
  #From https://en.wikipedia.org/wiki/Compactness_measure_of_a_shape
@@ -832,13 +780,13 @@ class Face(Topology):
832
780
  return round(compactness, mantissa)
833
781
 
834
782
  @staticmethod
835
- def CompassAngle(face: topologic.Face, north: list = None, mantissa: int = 6) -> float:
783
+ def CompassAngle(face, north: list = None, mantissa: int = 6) -> float:
836
784
  """
837
785
  Returns the horizontal compass angle in degrees between the normal vector of the input face and the input vector. The angle is measured in counter-clockwise fashion. Only the first two elements of the vectors are considered.
838
786
 
839
787
  Parameters
840
788
  ----------
841
- face : topologic.Face
789
+ face : topologic_core.Face
842
790
  The input face.
843
791
  north : list , optional
844
792
  The second vector representing the north direction. The default is the positive YAxis ([0,1,0]).
@@ -854,7 +802,9 @@ class Face(Topology):
854
802
 
855
803
  """
856
804
  from topologicpy.Vector import Vector
857
- if not isinstance(face, topologic.Face):
805
+ from topologicpy.Topology import Topology
806
+
807
+ if not Topology.IsInstance(face, "Face"):
858
808
  return None
859
809
  if not north:
860
810
  north = Vector.North()
@@ -862,13 +812,13 @@ class Face(Topology):
862
812
  return Vector.CompassAngle(vectorA=dirA, vectorB=north, mantissa=mantissa)
863
813
 
864
814
  @staticmethod
865
- def Edges(face: topologic.Face) -> list:
815
+ def Edges(face) -> list:
866
816
  """
867
817
  Returns the edges of the input face.
868
818
 
869
819
  Parameters
870
820
  ----------
871
- face : topologic.Face
821
+ face : topologic_core.Face
872
822
  The input face.
873
823
 
874
824
  Returns
@@ -877,21 +827,23 @@ class Face(Topology):
877
827
  The list of edges.
878
828
 
879
829
  """
880
- if not isinstance(face, topologic.Face):
830
+ from topologicpy.Topology import Topology
831
+
832
+ if not Topology.IsInstance(face, "Face"):
881
833
  return None
882
834
  edges = []
883
835
  _ = face.Edges(None, edges)
884
836
  return edges
885
837
 
886
838
  @staticmethod
887
- def Einstein(origin: topologic.Vertex = None, radius: float = 0.5, direction: list = [0, 0, 1],
888
- placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
839
+ def Einstein(origin= None, radius: float = 0.5, direction: list = [0, 0, 1],
840
+ placement: str = "center", tolerance: float = 0.0001):
889
841
  """
890
842
  Creates an aperiodic monotile, also called an 'einstein' tile (meaning one tile in German, not the name of the famous physist). See https://arxiv.org/abs/2303.10798
891
843
 
892
844
  Parameters
893
845
  ----------
894
- origin : topologic.Vertex , optional
846
+ origin : topologic_core.Vertex , optional
895
847
  The location of the origin of the tile. The default is None which results in the tiles first vertex being placed at (0, 0, 0).
896
848
  radius : float , optional
897
849
  The radius of the hexagon determining the size of the tile. The default is 0.5.
@@ -904,26 +856,27 @@ class Face(Topology):
904
856
 
905
857
  Returns
906
858
  --------
907
- topologic.Face
859
+ topologic_core.Face
908
860
  The created Einstein tile.
909
861
 
910
862
  """
911
863
  from topologicpy.Wire import Wire
864
+ from topologicpy.Topology import Topology
912
865
 
913
866
  wire = Wire.Einstein(origin=origin, radius=radius, direction=direction, placement=placement)
914
- if not isinstance(wire, topologic.Wire):
867
+ if not Topology.IsInstance(wire, "Wire"):
915
868
  print("Face.Einstein - Error: Could not create base wire for the Einstein tile. Returning None.")
916
869
  return None
917
870
  return Face.ByWire(wire, tolerance=tolerance)
918
871
 
919
872
  @staticmethod
920
- def ExteriorAngles(face: topologic.Face, includeInternalBoundaries=False, mantissa: int = 6) -> list:
873
+ def ExteriorAngles(face, includeInternalBoundaries=False, mantissa: int = 6) -> list:
921
874
  """
922
875
  Returns the exterior angles of the input face in degrees. The face must be planar.
923
876
 
924
877
  Parameters
925
878
  ----------
926
- face : topologic.Face
879
+ face : topologic_core.Face
927
880
  The input face.
928
881
  includeInternalBoundaries : bool , optional
929
882
  If set to True and if the face has internal boundaries (holes), the returned list will be a nested list where the first list is the list
@@ -940,8 +893,9 @@ class Face(Topology):
940
893
  """
941
894
 
942
895
  from topologicpy.Wire import Wire
896
+ from topologicpy.Topology import Topology
943
897
 
944
- if not isinstance(face, topologic.Face):
898
+ if not Topology.IsInstance(face, "Face"):
945
899
  print("Face.ExteriorAngles - Error: The input face parameter is not a valid face. Returning None.")
946
900
  return None
947
901
  eb = Face.ExternalBoundary(face)
@@ -958,31 +912,43 @@ class Face(Topology):
958
912
  return return_list
959
913
 
960
914
  @staticmethod
961
- def ExternalBoundary(face: topologic.Face) -> topologic.Wire:
915
+ def ExternalBoundary(face):
962
916
  """
963
917
  Returns the external boundary (closed wire) of the input face.
964
918
 
965
919
  Parameters
966
920
  ----------
967
- face : topologic.Face
921
+ face : topologic_core.Face
968
922
  The input face.
969
923
 
970
924
  Returns
971
925
  -------
972
- topologic.Wire
926
+ topologic_core.Wire
973
927
  The external boundary of the input face.
974
928
 
975
929
  """
976
- return face.ExternalBoundary()
930
+ from topologicpy.Vector import Vector
931
+ from topologicpy.Wire import Wire
932
+ from topologicpy.Topology import Topology
933
+
934
+ eb = face.ExternalBoundary()
935
+ f_dir = Face.Normal(face)
936
+ faceVertices = Topology.Vertices(eb)
937
+ temp_face = Face.ByWire(eb)
938
+ temp_dir = Face.Normal(temp_face)
939
+ if Vector.IsAntiParallel(f_dir, temp_dir):
940
+ faceVertices.reverse()
941
+ eb = Wire.ByVertices(faceVertices)
942
+ return eb
977
943
 
978
944
  @staticmethod
979
- def FacingToward(face: topologic.Face, direction: list = [0,0,-1], asVertex: bool = False, tolerance: float = 0.0001) -> bool:
945
+ def FacingToward(face, direction: list = [0,0,-1], asVertex: bool = False, tolerance: float = 0.0001) -> bool:
980
946
  """
981
947
  Returns True if the input face is facing toward the input direction.
982
948
 
983
949
  Parameters
984
950
  ----------
985
- face : topologic.Face
951
+ face : topologic_core.Face
986
952
  The input face.
987
953
  direction : list , optional
988
954
  The input direction. The default is [0,0,-1].
@@ -997,8 +963,10 @@ class Face(Topology):
997
963
  True if the face is facing toward the direction. False otherwise.
998
964
 
999
965
  """
1000
- faceNormal = topologic.FaceUtility.NormalAtParameters(face,0.5, 0.5)
1001
- faceCenter = topologic.FaceUtility.VertexAtParameters(face,0.5,0.5)
966
+ from topologicpy.Vector import Vector
967
+
968
+ faceNormal = Face.Normal(face)
969
+ faceCenter = Face.VertexByParameters(face,0.5,0.5)
1002
970
  cList = [faceCenter.X(), faceCenter.Y(), faceCenter.Z()]
1003
971
  try:
1004
972
  vList = [direction.X(), direction.Y(), direction.Z()]
@@ -1017,21 +985,80 @@ class Face(Topology):
1017
985
  return False
1018
986
  return True
1019
987
 
988
+
1020
989
  @staticmethod
1021
- def Harmonize(face: topologic.Face, tolerance: float = 0.0001) -> topologic.Face:
990
+ def Fillet(face, radius: float = 0, radiusKey: str = None, tolerance: float = 0.0001, silent: bool = False):
991
+ """
992
+ Fillets (rounds) the interior and exterior corners of the input face given the input radius. See https://en.wikipedia.org/wiki/Fillet_(mechanics)
993
+
994
+ Parameters
995
+ ----------
996
+ face : topologic_core.Face
997
+ The input face.
998
+ radius : float
999
+ The desired radius of the fillet.
1000
+ radiusKey : str , optional
1001
+ If specified, the dictionary of the vertices will be queried for this key to specify the desired fillet radius. The default is None.
1002
+ tolerance : float , optional
1003
+ The desired tolerance. The default is 0.0001.
1004
+ silent : bool , optional
1005
+ If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
1006
+
1007
+ Returns
1008
+ -------
1009
+ topologic_core.Face
1010
+ The filleted face.
1011
+
1012
+ """
1013
+ from topologicpy.Wire import Wire
1014
+ from topologicpy.Topology import Topology
1015
+
1016
+ if not Topology.IsInstance(face, "Face"):
1017
+ if not silent:
1018
+ print("Face.Fillet - Error: The input face parameter is not a valid face. Returning None.")
1019
+ return None
1020
+
1021
+ eb = Topology.Copy(Face.ExternalBoundary(face))
1022
+ ib_list = Face.InternalBoundaries(face)
1023
+ ib_list = [Topology.Copy(ib) for ib in ib_list]
1024
+ f_vertices = Face.Vertices(face)
1025
+ if isinstance(radiusKey, str):
1026
+ eb = Topology.TransferDictionariesBySelectors(eb, selectors=f_vertices, tranVertices=True)
1027
+ eb = Wire.Fillet(eb, radius=radius, radiusKey=radiusKey, tolerance=tolerance)
1028
+ if not Topology.IsInstance(eb, "Wire"):
1029
+ if not silent:
1030
+ print("Face.Fillet - Error: The operation failed. Returning None.")
1031
+ return None
1032
+ ib_wires = []
1033
+ for ib in ib_list:
1034
+ ib = Wire.ByVertices(Topology.Vertices(ib))
1035
+ ib = Wire.Reverse(ib)
1036
+ if isinstance(radiusKey, str):
1037
+ ib = Topology.TransferDictionariesBySelectors(ib, selectors=f_vertices, tranVertices=True)
1038
+
1039
+ ib_wire = Wire.Fillet(ib, radius=radius, radiusKey=radiusKey, tolerance=tolerance, silent=silent)
1040
+ if Topology.IsInstance(ib, "Wire"):
1041
+ ib_wires.append(ib_wire)
1042
+ else:
1043
+ if not silent:
1044
+ print("Face.Fillet - Error: The operation for one of the interior boundaries failed. Skipping.")
1045
+ return Face.ByWires(eb, ib_wires)
1046
+
1047
+ @staticmethod
1048
+ def Harmonize(face, tolerance: float = 0.0001):
1022
1049
  """
1023
1050
  Returns a harmonized version of the input face such that the *u* and *v* origins are always in the upperleft corner.
1024
1051
 
1025
1052
  Parameters
1026
1053
  ----------
1027
- face : topologic.Face
1054
+ face : topologic_core.Face
1028
1055
  The input face.
1029
1056
  tolerance : float , optional
1030
1057
  The desired tolerance. The default is 0.0001.
1031
1058
 
1032
1059
  Returns
1033
1060
  -------
1034
- topologic.Face
1061
+ topologic_core.Face
1035
1062
  The harmonized face.
1036
1063
 
1037
1064
  """
@@ -1040,7 +1067,7 @@ class Face(Topology):
1040
1067
  from topologicpy.Topology import Topology
1041
1068
  from topologicpy.Dictionary import Dictionary
1042
1069
 
1043
- if not isinstance(face, topologic.Face):
1070
+ if not Topology.IsInstance(face, "Face"):
1044
1071
  print("Face.Harmonize - Error: The input face parameter is not a valid face. Returning None.")
1045
1072
  return None
1046
1073
  normal = Face.Normal(face)
@@ -1059,13 +1086,13 @@ class Face(Topology):
1059
1086
  return harmonizedFace
1060
1087
 
1061
1088
  @staticmethod
1062
- def InteriorAngles(face: topologic.Face, includeInternalBoundaries: bool = False, mantissa: int = 6) -> list:
1089
+ def InteriorAngles(face, includeInternalBoundaries: bool = False, mantissa: int = 6) -> list:
1063
1090
  """
1064
1091
  Returns the interior angles of the input face in degrees. The face must be planar.
1065
1092
 
1066
1093
  Parameters
1067
1094
  ----------
1068
- face : topologic.Face
1095
+ face : topologic_core.Face
1069
1096
  The input face.
1070
1097
  includeInternalBoundaries : bool , optional
1071
1098
  If set to True and if the face has internal boundaries (holes), the returned list will be a nested list where the first list is the list
@@ -1080,10 +1107,10 @@ class Face(Topology):
1080
1107
  list
1081
1108
  The list of interior angles.
1082
1109
  """
1083
-
1084
1110
  from topologicpy.Wire import Wire
1111
+ from topologicpy.Topology import Topology
1085
1112
 
1086
- if not isinstance(face, topologic.Face):
1113
+ if not Topology.IsInstance(face, "Face"):
1087
1114
  print("Face.InteriorAngles - Error: The input face parameter is not a valid face. Returning None.")
1088
1115
  return None
1089
1116
  eb = Face.ExternalBoundary(face)
@@ -1100,13 +1127,13 @@ class Face(Topology):
1100
1127
  return return_list
1101
1128
 
1102
1129
  @staticmethod
1103
- def InternalBoundaries(face: topologic.Face) -> list:
1130
+ def InternalBoundaries(face) -> list:
1104
1131
  """
1105
1132
  Returns the internal boundaries (closed wires) of the input face.
1106
1133
 
1107
1134
  Parameters
1108
1135
  ----------
1109
- face : topologic.Face
1136
+ face : topologic_core.Face
1110
1137
  The input face.
1111
1138
 
1112
1139
  Returns
@@ -1115,33 +1142,36 @@ class Face(Topology):
1115
1142
  The list of internal boundaries (closed wires).
1116
1143
 
1117
1144
  """
1118
- if not isinstance(face, topologic.Face):
1145
+ from topologicpy.Topology import Topology
1146
+
1147
+ if not Topology.IsInstance(face, "Face"):
1119
1148
  return None
1120
1149
  wires = []
1121
1150
  _ = face.InternalBoundaries(wires)
1122
1151
  return list(wires)
1123
1152
 
1124
1153
  @staticmethod
1125
- def InternalVertex(face: topologic.Face, tolerance: float = 0.0001) -> topologic.Vertex:
1154
+ def InternalVertex(face, tolerance: float = 0.0001):
1126
1155
  """
1127
1156
  Creates a vertex guaranteed to be inside the input face.
1128
1157
 
1129
1158
  Parameters
1130
1159
  ----------
1131
- face : topologic.Face
1160
+ face : topologic_core.Face
1132
1161
  The input face.
1133
1162
  tolerance : float , optional
1134
1163
  The desired tolerance. The default is 0.0001.
1135
1164
 
1136
1165
  Returns
1137
1166
  -------
1138
- topologic.Vertex
1167
+ topologic_core.Vertex
1139
1168
  The created vertex.
1140
1169
 
1141
1170
  """
1142
1171
  from topologicpy.Vertex import Vertex
1143
1172
  from topologicpy.Topology import Topology
1144
- if not isinstance(face, topologic.Face):
1173
+
1174
+ if not Topology.IsInstance(face, "Face"):
1145
1175
  return None
1146
1176
  v = Topology.Centroid(face)
1147
1177
  if Vertex.IsInternal(v, face, tolerance=tolerance):
@@ -1152,30 +1182,31 @@ class Face(Topology):
1152
1182
  v = Face.VertexByParameters(face, u, v)
1153
1183
  if Vertex.IsInternal(v, face, tolerance=tolerance):
1154
1184
  return v
1155
- v = topologic.FaceUtility.InternalVertex(face, tolerance)
1185
+ v = topologic.FaceUtility.InternalVertex(face, tolerance) # Hook to Core
1156
1186
  return v
1157
1187
 
1158
1188
  @staticmethod
1159
- def Invert(face: topologic.Face, tolerance: float = 0.0001) -> topologic.Face:
1189
+ def Invert(face, tolerance: float = 0.0001):
1160
1190
  """
1161
1191
  Creates a face that is an inverse (mirror) of the input face.
1162
1192
 
1163
1193
  Parameters
1164
1194
  ----------
1165
- face : topologic.Face
1195
+ face : topologic_core.Face
1166
1196
  The input face.
1167
1197
  tolerance : float , optional
1168
1198
  The desired tolerance. The default is 0.0001.
1169
1199
 
1170
1200
  Returns
1171
1201
  -------
1172
- topologic.Face
1202
+ topologic_core.Face
1173
1203
  The inverted face.
1174
1204
 
1175
1205
  """
1176
1206
  from topologicpy.Wire import Wire
1207
+ from topologicpy.Topology import Topology
1177
1208
 
1178
- if not isinstance(face, topologic.Face):
1209
+ if not Topology.IsInstance(face, "Face"):
1179
1210
  return None
1180
1211
  eb = Face.ExternalBoundary(face)
1181
1212
  vertices = Wire.Vertices(eb)
@@ -1189,15 +1220,15 @@ class Face(Topology):
1189
1220
  return inverted_face
1190
1221
 
1191
1222
  @staticmethod
1192
- def IsCoplanar(faceA: topologic.Face, faceB: topologic.Face, tolerance: float = 0.0001) -> bool:
1223
+ def IsCoplanar(faceA, faceB, tolerance: float = 0.0001) -> bool:
1193
1224
  """
1194
1225
  Returns True if the two input faces are coplanar. Returns False otherwise.
1195
1226
 
1196
1227
  Parameters
1197
1228
  ----------
1198
- faceA : topologic.Face
1229
+ faceA : topologic_core.Face
1199
1230
  The first input face.
1200
- faceB : topologic.Face
1231
+ faceB : topologic_core.Face
1201
1232
  The second input face
1202
1233
  tolerance : float , optional
1203
1234
  The desired tolerance. The deafault is 0.0001.
@@ -1213,24 +1244,112 @@ class Face(Topology):
1213
1244
  True if the two input faces are coplanar. False otherwise.
1214
1245
 
1215
1246
  """
1216
- if not isinstance(faceA, topologic.Face):
1247
+ from topologicpy.Vector import Vector
1248
+ from topologicpy.Topology import Topology
1249
+
1250
+ if not Topology.IsInstance(faceA, "Face"):
1217
1251
  print("Face.IsInide - Error: The input faceA parameter is not a valid topologic face. Returning None.")
1218
1252
  return None
1219
- if not isinstance(faceB, topologic.Face):
1253
+ if not Topology.IsInstance(faceB, "Face"):
1220
1254
  print("Face.IsInide - Error: The input faceB parameter is not a valid topologic face. Returning None.")
1221
1255
  return None
1222
1256
  dirA = Face.NormalAtParameters(faceA, 0.5, 0.5, "xyz", 3)
1223
1257
  dirB = Face.NormalAtParameters(faceB, 0.5, 0.5, "xyz", 3)
1224
1258
  return Vector.IsCollinear(dirA, dirB)
1225
-
1259
+
1260
+ @staticmethod
1261
+ def Isovist(face, vertex, obstacles = None, fromAngle=0, toAngle=360, tolerance: float = 0.0001):
1262
+ """
1263
+ Returns the face representing the isovist projection from the input viewpoint.
1264
+ This method assumes all input is in 2D. Z coordinates are ignored.
1265
+
1266
+ Parameters
1267
+ ----------
1268
+ face : topologic_core.Face
1269
+ The face representing the boundary of the isovist.
1270
+ vertex : topologic_core.Vertex
1271
+ The vertex representing the location of the viewpoint of the isovist.
1272
+ obstacles : list , optional
1273
+ A list of wires representing the obstacles within the face. All obstacles are assumed to be within the
1274
+ boundary of the face.
1275
+ fromAngle : float , optional
1276
+ The angle in degrees from which to start creating the arc of the circle. The default is 0.
1277
+ 0 is considered to be in the positive X-axis direction. 90 is considered to be in the
1278
+ positive Y-axis direction.
1279
+ toAngle : float , optional
1280
+ The angle in degrees at which to end creating the arc of the circle. The default is 360.
1281
+ Angles are measured in an anti-clockwise fashion.
1282
+ tolerance : float , optional:
1283
+ The desired tolerance. The default is 0.0001.
1284
+
1285
+ Returns
1286
+ -------
1287
+ topologic_core.Face
1288
+ The face representing the isovist projection from the input viewpoint.
1289
+
1290
+ """
1291
+ from topologicpy.Vertex import Vertex
1292
+ from topologicpy.Edge import Edge
1293
+ from topologicpy.Wire import Wire
1294
+ from topologicpy.Face import Face
1295
+ from topologicpy.Shell import Shell
1296
+ from topologicpy.Cluster import Cluster
1297
+ from topologicpy.Topology import Topology
1298
+
1299
+ def vertexPartofFace(vertex, face, tolerance):
1300
+ vertices = []
1301
+ _ = face.Vertices(None, vertices)
1302
+ for v in vertices:
1303
+ if Vertex.Distance(vertex, v) < tolerance:
1304
+ return True
1305
+ return False
1306
+
1307
+ if not Topology.IsInstance(face, "Face"):
1308
+ print("Face.Isovist - Error: The input boundary parameter is not a valid Face. Returning None")
1309
+ return None
1310
+ if not Topology.IsInstance(vertex, "Vertex"):
1311
+ print("Face.Isovist - Error: The input viewPoint parameter is not a valid Vertex. Returning None")
1312
+ return None
1313
+ if isinstance(obstacles, list):
1314
+ obstacles = [obs for obs in obstacles if Topology.IsInstance(obs, "Wire")]
1315
+ for obs in obstacles:
1316
+ face = Topology.Difference(face, Face.ByWire(obs))
1317
+ targets = Topology.Vertices(face)
1318
+ distances = []
1319
+ for target in targets:
1320
+ distances.append(Vertex.Distance(vertex, target))
1321
+ distances.sort()
1322
+ max_d = distances[-1]*1.05
1323
+ edges = []
1324
+ for target in targets:
1325
+ e = Edge.ByVertices(vertex, target)
1326
+ e = Edge.SetLength(e, length=max_d, bothSides=False)
1327
+ edges.append(e)
1328
+ shell = Topology.Slice(face, Cluster.ByTopologies(edges))
1329
+ faces = Topology.Faces(shell)
1330
+ final_faces = []
1331
+ for face in faces:
1332
+ if vertexPartofFace(vertex, face, tolerance=0.001):
1333
+ final_faces.append(face)
1334
+ shell = Shell.ByFaces(final_faces)
1335
+ return_face = Topology.RemoveCoplanarFaces(shell)
1336
+ if abs(360 - toAngle - fromAngle) > tolerance:
1337
+ c = Wire.Circle(origin= vertex, radius=max_d, sides=180, fromAngle=fromAngle, toAngle=toAngle, close = False)
1338
+ e1 = Edge.ByVertices(Wire.StartVertex(c), vertex)
1339
+ e2 = Edge.ByVertices(Wire.EndVertex(c), vertex)
1340
+ edges = Topology.Edges(c) + [e1,e2]
1341
+ pie = Face.ByWire(Topology.SelfMerge(Cluster.ByTopologies(edges)))
1342
+ return_face = Topology.Intersect(pie, return_face)
1343
+ return return_face
1344
+
1226
1345
  @staticmethod
1227
- def MedialAxis(face: topologic.Face, resolution: int = 0, externalVertices: bool = False, internalVertices: bool = False, toLeavesOnly: bool = False, angTolerance: float = 0.1, tolerance: float = 0.0001) -> topologic.Wire:
1346
+ def MedialAxis(face, resolution: int = 0, externalVertices: bool = False, internalVertices: bool = False, toLeavesOnly: bool = False, angTolerance: float = 0.1, tolerance: float = 0.0001):
1228
1347
  """
1229
1348
  Returns a wire representing an approximation of the medial axis of the input topology. See https://en.wikipedia.org/wiki/Medial_axis.
1230
1349
 
1231
1350
  Parameters
1232
1351
  ----------
1233
- face : topologic.Face
1352
+ face : topologic_core.Face
1234
1353
  The input face.
1235
1354
  resolution : int , optional
1236
1355
  The desired resolution of the solution (range is 0: standard resolution to 10: high resolution). This determines the density of the sampling along each edge. The default is 0.
@@ -1247,7 +1366,7 @@ class Face(Topology):
1247
1366
 
1248
1367
  Returns
1249
1368
  -------
1250
- topologic.Wire
1369
+ topologic_core.Wire
1251
1370
  The medial axis of the input face.
1252
1371
 
1253
1372
  """
@@ -1260,7 +1379,7 @@ class Face(Topology):
1260
1379
  from topologicpy.Dictionary import Dictionary
1261
1380
 
1262
1381
  def touchesEdge(vertex,edges, tolerance=0.0001):
1263
- if not isinstance(vertex, topologic.Vertex):
1382
+ if not Topology.IsInstance(vertex, "Vertex"):
1264
1383
  return False
1265
1384
  for edge in edges:
1266
1385
  u = Edge.ParameterAtVertex(edge, vertex, mantissa=6)
@@ -1313,13 +1432,13 @@ class Face(Topology):
1313
1432
  theVertices = theVertices+extVertices
1314
1433
 
1315
1434
  tempWire = Topology.SelfMerge(Cluster.ByTopologies(medialAxisEdges), tolerance=tolerance)
1316
- if isinstance(tempWire, topologic.Wire) and angTolerance > 0:
1435
+ if Topology.IsInstance(tempWire, "Wire") and angTolerance > 0:
1317
1436
  tempWire = Wire.RemoveCollinearEdges(tempWire, angTolerance=angTolerance)
1318
1437
  medialAxisEdges = Wire.Edges(tempWire)
1319
1438
  for v in theVertices:
1320
1439
  nv = Vertex.NearestVertex(v, tempWire, useKDTree=False)
1321
1440
 
1322
- if isinstance(nv, topologic.Vertex):
1441
+ if Topology.IsInstance(nv, "Vertex"):
1323
1442
  if toLeavesOnly:
1324
1443
  adjVertices = Topology.AdjacentTopologies(nv, tempWire)
1325
1444
  if len(adjVertices) < 2:
@@ -1327,19 +1446,19 @@ class Face(Topology):
1327
1446
  else:
1328
1447
  medialAxisEdges.append(Edge.ByVertices([nv, v], tolerance=tolerance))
1329
1448
  medialAxis = Topology.SelfMerge(Cluster.ByTopologies(medialAxisEdges), tolerance=tolerance)
1330
- if isinstance(medialAxis, topologic.Wire) and angTolerance > 0:
1449
+ if Topology.IsInstance(medialAxis, "Wire") and angTolerance > 0:
1331
1450
  medialAxis = Topology.RemoveCollinearEdges(medialAxis, angTolerance=angTolerance)
1332
1451
  medialAxis = Topology.Unflatten(medialAxis, origin=origin,direction=normal)
1333
1452
  return medialAxis
1334
1453
 
1335
1454
  @staticmethod
1336
- def Normal(face: topologic.Face, outputType: str = "xyz", mantissa: int = 6) -> list:
1455
+ def Normal(face, outputType: str = "xyz", mantissa: int = 6) -> list:
1337
1456
  """
1338
1457
  Returns the normal vector to the input face. A normal vector of a face is a vector perpendicular to it.
1339
1458
 
1340
1459
  Parameters
1341
1460
  ----------
1342
- face : topologic.Face
1461
+ face : topologic_core.Face
1343
1462
  The input face.
1344
1463
  outputType : string , optional
1345
1464
  The string defining the desired output. This can be any subset or permutation of "xyz". It is case insensitive. The default is "xyz".
@@ -1355,13 +1474,13 @@ class Face(Topology):
1355
1474
  return Face.NormalAtParameters(face, u=0.5, v=0.5, outputType=outputType, mantissa=mantissa)
1356
1475
 
1357
1476
  @staticmethod
1358
- def NormalAtParameters(face: topologic.Face, u: float = 0.5, v: float = 0.5, outputType: str = "xyz", mantissa: int = 6) -> list:
1477
+ def NormalAtParameters(face, u: float = 0.5, v: float = 0.5, outputType: str = "xyz", mantissa: int = 6) -> list:
1359
1478
  """
1360
1479
  Returns the normal vector to the input face. A normal vector of a face is a vector perpendicular to it.
1361
1480
 
1362
1481
  Parameters
1363
1482
  ----------
1364
- face : topologic.Face
1483
+ face : topologic_core.Face
1365
1484
  The input face.
1366
1485
  u : float , optional
1367
1486
  The *u* parameter at which to compute the normal to the input face. The default is 0.5.
@@ -1380,7 +1499,7 @@ class Face(Topology):
1380
1499
  """
1381
1500
  returnResult = []
1382
1501
  try:
1383
- coords = topologic.FaceUtility.NormalAtParameters(face, u, v)
1502
+ coords = topologic.FaceUtility.NormalAtParameters(face, u, v) # Hook to Core
1384
1503
  x = round(coords[0], mantissa)
1385
1504
  y = round(coords[1], mantissa)
1386
1505
  z = round(coords[2], mantissa)
@@ -1397,13 +1516,13 @@ class Face(Topology):
1397
1516
  return returnResult
1398
1517
 
1399
1518
  @staticmethod
1400
- def NormalEdge(face: topologic.Face, length: float = 1.0, tolerance: float = 0.0001, silent: bool = False) -> topologic.Edge:
1519
+ def NormalEdge(face, length: float = 1.0, tolerance: float = 0.0001, silent: bool = False):
1401
1520
  """
1402
1521
  Returns the normal vector to the input face as an edge with the desired input length. A normal vector of a face is a vector perpendicular to it.
1403
1522
 
1404
1523
  Parameters
1405
1524
  ----------
1406
- face : topologic.Face
1525
+ face : topologic_core.Face
1407
1526
  The input face.
1408
1527
  length : float , optional
1409
1528
  The desired length of the normal edge. The default is 1.
@@ -1412,13 +1531,14 @@ class Face(Topology):
1412
1531
 
1413
1532
  Returns
1414
1533
  -------
1415
- topologic.Edge
1534
+ topologic_core.Edge
1416
1535
  The created normal edge to the input face. This is computed at the approximate center of the face.
1417
1536
 
1418
1537
  """
1419
1538
  from topologicpy.Edge import Edge
1539
+ from topologicpy.Topology import Topology
1420
1540
 
1421
- if not isinstance(face, topologic.Face):
1541
+ if not Topology.IsInstance(face, "Face"):
1422
1542
  if not silent:
1423
1543
  print("Face.NormalEdge - Error: The input face parameter is not a valid face. Retuning None.")
1424
1544
  return None
@@ -1433,13 +1553,13 @@ class Face(Topology):
1433
1553
  return Edge.ByVertices([iv, ev], tolerance=tolerance, silent=silent)
1434
1554
 
1435
1555
  @staticmethod
1436
- def NormalEdgeAtParameters(face: topologic.Face, u: float = 0.5, v: float = 0.5, length: float = 1.0, tolerance: float = 0.0001) -> topologic.Edge:
1556
+ def NormalEdgeAtParameters(face, u: float = 0.5, v: float = 0.5, length: float = 1.0, tolerance: float = 0.0001):
1437
1557
  """
1438
1558
  Returns the normal vector to the input face as an edge with the desired input length. A normal vector of a face is a vector perpendicular to it.
1439
1559
 
1440
1560
  Parameters
1441
1561
  ----------
1442
- face : topologic.Face
1562
+ face : topologic_core.Face
1443
1563
  The input face.
1444
1564
  u : float , optional
1445
1565
  The *u* parameter at which to compute the normal to the input face. The default is 0.5.
@@ -1452,13 +1572,13 @@ class Face(Topology):
1452
1572
 
1453
1573
  Returns
1454
1574
  -------
1455
- topologic.Edge
1575
+ topologic_core.Edge
1456
1576
  The created normal edge to the input face. This is computed at the approximate center of the face.
1457
1577
 
1458
1578
  """
1459
1579
  from topologicpy.Edge import Edge
1460
1580
  from topologicpy.Topology import Topology
1461
- if not isinstance(face, topologic.Face):
1581
+ if not Topology.IsInstance(face, "Face"):
1462
1582
  return None
1463
1583
  sv = Face.VertexByParameters(face=face, u=u, v=v)
1464
1584
  vec = Face.NormalAtParameters(face, u=u, v=v)
@@ -1466,13 +1586,13 @@ class Face(Topology):
1466
1586
  return Edge.ByVertices([sv, ev], tolerance=tolerance, silent=True)
1467
1587
 
1468
1588
  @staticmethod
1469
- def PlaneEquation(face: topologic.Face, mantissa: int = 6) -> dict:
1589
+ def PlaneEquation(face, mantissa: int = 6) -> dict:
1470
1590
  """
1471
1591
  Returns the a, b, c, d coefficients of the plane equation of the input face. The input face is assumed to be planar.
1472
1592
 
1473
1593
  Parameters
1474
1594
  ----------
1475
- face : topologic.Face
1595
+ face : topologic_core.Face
1476
1596
  The input face.
1477
1597
 
1478
1598
  Returns
@@ -1486,7 +1606,7 @@ class Face(Topology):
1486
1606
  import random
1487
1607
  import time
1488
1608
 
1489
- if not isinstance(face, topologic.Face):
1609
+ if not Topology.IsInstance(face, "Face"):
1490
1610
  print("Face.PlaneEquation - Error: The input face is not a valid topologic face. Returning None.")
1491
1611
  return None
1492
1612
  vertices = Topology.Vertices(face)
@@ -1496,23 +1616,23 @@ class Face(Topology):
1496
1616
  return Vertex.PlaneEquation(vertices, mantissa=mantissa)
1497
1617
 
1498
1618
  @staticmethod
1499
- def Planarize(face: topologic.Face, origin: topologic.Vertex = None,
1500
- tolerance: float = 0.0001) -> topologic.Face:
1619
+ def Planarize(face, origin= None,
1620
+ tolerance: float = 0.0001):
1501
1621
  """
1502
1622
  Planarizes the input face such that its center of mass is located at the input origin and its normal is pointed in the input direction.
1503
1623
 
1504
1624
  Parameters
1505
1625
  ----------
1506
- face : topologic.Face
1626
+ face : topologic_core.Face
1507
1627
  The input face.
1508
- origin : topologic.Vertex , optional
1628
+ origin : topologic_core.Vertex , optional
1509
1629
  The desired vertex to use as the origin of the plane to project the face unto. If set to None, the centroidof the input face is used. The default is None.
1510
1630
  tolerance : float , optional
1511
1631
  The desired tolerance. The default is 0.0001.
1512
1632
 
1513
1633
  Returns
1514
1634
  -------
1515
- topologic.Face
1635
+ topologic_core.Face
1516
1636
  The planarized face.
1517
1637
 
1518
1638
  """
@@ -1520,9 +1640,9 @@ class Face(Topology):
1520
1640
  from topologicpy.Wire import Wire
1521
1641
  from topologicpy.Topology import Topology
1522
1642
 
1523
- if not isinstance(face, topologic.Face):
1643
+ if not Topology.IsInstance(face, "Face"):
1524
1644
  return None
1525
- if not isinstance(origin, topologic.Vertex):
1645
+ if not Topology.IsInstance(origin, "Vertex"):
1526
1646
  origin = Topology.Centroid(face)
1527
1647
  eb = Face.ExternalBoundary(face)
1528
1648
  plan_eb = Wire.Planarize(eb, origin=origin)
@@ -1534,16 +1654,16 @@ class Face(Topology):
1534
1654
  return plan_face
1535
1655
 
1536
1656
  @staticmethod
1537
- def Project(faceA: topologic.Face, faceB: topologic.Face, direction : list = None,
1538
- mantissa: int = 6, tolerance: float = 0.0001) -> topologic.Face:
1657
+ def Project(faceA, faceB, direction : list = None,
1658
+ mantissa: int = 6, tolerance: float = 0.0001):
1539
1659
  """
1540
1660
  Creates a projection of the first input face unto the second input face.
1541
1661
 
1542
1662
  Parameters
1543
1663
  ----------
1544
- faceA : topologic.Face
1664
+ faceA : topologic_core.Face
1545
1665
  The face to be projected.
1546
- faceB : topologic.Face
1666
+ faceB : topologic_core.Face
1547
1667
  The face unto which the first input face will be projected.
1548
1668
  direction : list, optional
1549
1669
  The vector direction of the projection. If None, the reverse vector of the receiving face normal will be used. The default is None.
@@ -1554,20 +1674,20 @@ class Face(Topology):
1554
1674
 
1555
1675
  Returns
1556
1676
  -------
1557
- topologic.Face
1677
+ topologic_core.Face
1558
1678
  The projected Face.
1559
1679
 
1560
1680
  """
1561
-
1562
1681
  from topologicpy.Wire import Wire
1682
+ from topologicpy.Topology import Topology
1563
1683
 
1564
1684
  if not faceA:
1565
1685
  return None
1566
- if not isinstance(faceA, topologic.Face):
1686
+ if not Topology.IsInstance(faceA, "Face"):
1567
1687
  return None
1568
1688
  if not faceB:
1569
1689
  return None
1570
- if not isinstance(faceB, topologic.Face):
1690
+ if not Topology.IsInstance(faceB, "Face"):
1571
1691
  return None
1572
1692
 
1573
1693
  eb = faceA.ExternalBoundary()
@@ -1582,7 +1702,7 @@ class Face(Topology):
1582
1702
  return Face.ByWires(p_eb, p_ib_list, tolerance=tolerance)
1583
1703
 
1584
1704
  @staticmethod
1585
- def RectangleByPlaneEquation(origin: topologic.Vertex = None, width: float = 1.0, length: float = 1.0, placement: str = "center", equation: dict = None, tolerance: float = 0.0001) -> topologic.Face:
1705
+ def RectangleByPlaneEquation(origin= None, width: float = 1.0, length: float = 1.0, placement: str = "center", equation: dict = None, tolerance: float = 0.0001):
1586
1706
  from topologicpy.Vertex import Vertex
1587
1707
  # Extract coefficients of the plane equation
1588
1708
  a = equation['a']
@@ -1598,13 +1718,13 @@ class Face(Topology):
1598
1718
  return Face.Rectangle(origin=origin, width=width, length=length, direction = direction, placement=placement, tolerance=tolerance)
1599
1719
 
1600
1720
  @staticmethod
1601
- def Rectangle(origin: topologic.Vertex = None, width: float = 1.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
1721
+ def Rectangle(origin= None, width: float = 1.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
1602
1722
  """
1603
1723
  Creates a rectangle.
1604
1724
 
1605
1725
  Parameters
1606
1726
  ----------
1607
- origin : topologic.Vertex, optional
1727
+ origin : topologic_core.Vertex, optional
1608
1728
  The location of the origin of the rectangle. The default is None which results in the rectangle being placed at (0, 0, 0).
1609
1729
  width : float , optional
1610
1730
  The width of the rectangle. The default is 1.0.
@@ -1619,26 +1739,27 @@ class Face(Topology):
1619
1739
 
1620
1740
  Returns
1621
1741
  -------
1622
- topologic.Face
1742
+ topologic_core.Face
1623
1743
  The created face.
1624
1744
 
1625
1745
  """
1626
1746
  from topologicpy.Wire import Wire
1747
+ from topologicpy.Topology import Topology
1627
1748
 
1628
1749
  wire = Wire.Rectangle(origin=origin, width=width, length=length, direction=direction, placement=placement, tolerance=tolerance)
1629
- if not isinstance(wire, topologic.Wire):
1750
+ if not Topology.IsInstance(wire, "Wire"):
1630
1751
  print("Face.Rectangle - Error: Could not create the base wire for the rectangle. Returning None.")
1631
1752
  return None
1632
1753
  return Face.ByWire(wire, tolerance=tolerance)
1633
1754
 
1634
1755
  @staticmethod
1635
- def RemoveCollinearEdges(face: topologic.Face, angTolerance: float = 0.1, tolerance: float = 0.0001) -> topologic.Wire:
1756
+ def RemoveCollinearEdges(face, angTolerance: float = 0.1, tolerance: float = 0.0001):
1636
1757
  """
1637
1758
  Removes any collinear edges in the input face.
1638
1759
 
1639
1760
  Parameters
1640
1761
  ----------
1641
- face : topologic.Face
1762
+ face : topologic_core.Face
1642
1763
  The input face.
1643
1764
  angTolerance : float , optional
1644
1765
  The desired angular tolerance. The default is 0.1.
@@ -1647,19 +1768,51 @@ class Face(Topology):
1647
1768
 
1648
1769
  Returns
1649
1770
  -------
1650
- topologic.Face
1771
+ topologic_core.Face
1651
1772
  The created face without any collinear edges.
1652
1773
 
1653
1774
  """
1654
1775
  from topologicpy.Wire import Wire
1776
+ from topologicpy.Topology import Topology
1655
1777
 
1656
- if not isinstance(face, topologic.Face):
1778
+ if not Topology.IsInstance(face, "Face"):
1657
1779
  print("Face.RemoveCollinearEdges - Error: The input face parameter is not a valid face. Returning None.")
1658
1780
  return None
1659
1781
  eb = Wire.RemoveCollinearEdges(Face.Wire(face), angTolerance=angTolerance, tolerance=tolerance)
1660
1782
  ib = [Wire.RemoveCollinearEdges(w, angTolerance=angTolerance, tolerance=tolerance) for w in Face.InternalBoundaries(face)]
1661
1783
  return Face.ByWires(eb, ib)
1662
1784
 
1785
+ @staticmethod
1786
+ def Simplify(face, tolerance=0.0001):
1787
+ """
1788
+ Simplifies the input face edges based on the Douglas Peucker algorthim. See https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
1789
+ Part of this code was contributed by gaoxipeng. See https://github.com/wassimj/topologicpy/issues/35
1790
+
1791
+ Parameters
1792
+ ----------
1793
+ face : topologic_core.Face
1794
+ The input face.
1795
+ tolerance : float , optional
1796
+ The desired tolerance. The default is 0.0001. Edges shorter than this length will be removed.
1797
+
1798
+ Returns
1799
+ -------
1800
+ topologic_core.Face
1801
+ The simplified face.
1802
+ """
1803
+ from topologicpy.Wire import Wire
1804
+ from topologicpy.Topology import Topology
1805
+
1806
+ if not Topology.IsInstance(face, "Face"):
1807
+ print("Face.Simplify - Error: The input face parameter is not a valid face. Returning None.")
1808
+ return None
1809
+
1810
+ eb = Face.ExternalBoundary(face)
1811
+ eb = Wire.Simplify(eb, tolerance=tolerance)
1812
+ ibList = Face.InternalBoundaries(face)
1813
+ ibList = [Wire.Simplify(ib) for ib in ibList]
1814
+ return Face.ByWires(eb, ibList)
1815
+
1663
1816
  @staticmethod
1664
1817
  def Skeleton(face, tolerance=0.001):
1665
1818
  """
@@ -1668,31 +1821,33 @@ class Face(Topology):
1668
1821
 
1669
1822
  Parameters
1670
1823
  ----------
1671
- face : topologic.Face
1824
+ face : topologic_core.Face
1672
1825
  The input face.
1673
1826
  tolerance : float , optional
1674
1827
  The desired tolerance. The default is 0.001. (This is set to a larger number than the usual 0.0001 as it was found to work better)
1675
1828
 
1676
1829
  Returns
1677
1830
  -------
1678
- topologic.Wire
1831
+ topologic_core.Wire
1679
1832
  The created straight skeleton.
1680
1833
 
1681
1834
  """
1682
1835
  from topologicpy.Wire import Wire
1683
- if not isinstance(face, topologic.Face):
1836
+ from topologicpy.Topology import Topology
1837
+
1838
+ if not Topology.IsInstance(face, "Face"):
1684
1839
  print("Face.Skeleton - Error: The input face is not a valid topologic face. Retruning None.")
1685
1840
  return None
1686
1841
  return Wire.Skeleton(face, tolerance=tolerance)
1687
1842
 
1688
1843
  @staticmethod
1689
- def Square(origin: topologic.Vertex = None, size: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
1844
+ def Square(origin= None, size: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
1690
1845
  """
1691
1846
  Creates a square.
1692
1847
 
1693
1848
  Parameters
1694
1849
  ----------
1695
- origin : topologic.Vertex , optional
1850
+ origin : topologic_core.Vertex , optional
1696
1851
  The location of the origin of the square. The default is None which results in the square being placed at (0, 0, 0).
1697
1852
  size : float , optional
1698
1853
  The size of the square. The default is 1.0.
@@ -1705,20 +1860,62 @@ class Face(Topology):
1705
1860
 
1706
1861
  Returns
1707
1862
  -------
1708
- topologic.Face
1863
+ topologic_core.Face
1709
1864
  The created square.
1710
1865
 
1711
1866
  """
1712
1867
  return Face.Rectangle(origin=origin, width=size, length=size, direction=direction, placement=placement, tolerance=tolerance)
1713
1868
 
1869
+
1870
+ @staticmethod
1871
+ def Squircle(origin = None, radius: float = 0.5, sides: int = 121, a: float = 2.0, b: float = 2.0, direction: list = [0, 0, 1], placement: str = "center", angTolerance: float = 0.1, tolerance: float = 0.0001):
1872
+ """
1873
+ Creates a Squircle which is a hybrid between a circle and a square. See https://en.wikipedia.org/wiki/Squircle
1874
+
1875
+ Parameters
1876
+ ----------
1877
+ origin : topologic_core.Vertex , optional
1878
+ The location of the origin of the squircle. The default is None which results in the squircle being placed at (0, 0, 0).
1879
+ radius : float , optional
1880
+ The radius of the squircle. The default is 0.5.
1881
+ sides : int , optional
1882
+ The number of sides of the squircle. The default is 121.
1883
+ a : float , optional
1884
+ The "a" factor affects the x position of the points to interpolate between a circle and a square.
1885
+ A value of 1 will create a circle. Higher values will create a more square-like shape. The default is 2.0.
1886
+ b : float , optional
1887
+ The "b" factor affects the y position of the points to interpolate between a circle and a square.
1888
+ A value of 1 will create a circle. Higher values will create a more square-like shape. The default is 2.0.
1889
+ radius : float , optional
1890
+ The desired radius of the squircle. The default is 0.5.
1891
+ sides : int , optional
1892
+ The desired number of sides for the squircle. The default is 100.
1893
+ direction : list , optional
1894
+ The vector representing the up direction of the circle. The default is [0, 0, 1].
1895
+ placement : str , optional
1896
+ The description of the placement of the origin of the circle. This can be "center", "lowerleft", "upperleft", "lowerright", or "upperright". It is case insensitive. The default is "center".
1897
+ angTolerance : float , optional
1898
+ The desired angular tolerance. The default is 0.1.
1899
+ tolerance : float , optional
1900
+ The desired tolerance. The default is 0.0001.
1901
+
1902
+ Returns
1903
+ -------
1904
+ topologic_core.Face
1905
+ The created squircle.
1906
+ """
1907
+ from topologicpy.Wire import Wire
1908
+ wire = Wire.Squircle(origin = origin, radius= radius, sides = sides, a = a, b = b, direction = direction, placement = placement, angTolerance = angTolerance, tolerance = tolerance)
1909
+ return Face.ByWire(wire)
1910
+
1714
1911
  @staticmethod
1715
- def Star(origin: topologic.Vertex = None, radiusA: float = 1.0, radiusB: float = 0.4, rays: int = 5, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
1912
+ def Star(origin= None, radiusA: float = 1.0, radiusB: float = 0.4, rays: int = 5, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
1716
1913
  """
1717
1914
  Creates a star.
1718
1915
 
1719
1916
  Parameters
1720
1917
  ----------
1721
- origin : topologic.Vertex, optional
1918
+ origin : topologic_core.Vertex, optional
1722
1919
  The location of the origin of the star. The default is None which results in the star being placed at (0, 0, 0).
1723
1920
  radiusA : float , optional
1724
1921
  The outer radius of the star. The default is 1.0.
@@ -1735,25 +1932,27 @@ class Face(Topology):
1735
1932
 
1736
1933
  Returns
1737
1934
  -------
1738
- topologic.Face
1935
+ topologic_core.Face
1739
1936
  The created face.
1740
1937
 
1741
1938
  """
1742
1939
  from topologicpy.Wire import Wire
1940
+ from topologicpy.Topology import Topology
1941
+
1743
1942
  wire = Wire.Star(origin=origin, radiusA=radiusA, radiusB=radiusB, rays=rays, direction=direction, placement=placement, tolerance=tolerance)
1744
- if not isinstance(wire, topologic.Wire):
1943
+ if not Topology.IsInstance(wire, "Wire"):
1745
1944
  print("Face.Rectangle - Error: Could not create the base wire for the star. Returning None.")
1746
1945
  return None
1747
1946
  return Face.ByWire(wire, tolerance=tolerance)
1748
1947
 
1749
1948
  @staticmethod
1750
- def Trapezoid(origin: topologic.Vertex = None, widthA: float = 1.0, widthB: float = 0.75, offsetA: float = 0.0, offsetB: float = 0.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001) -> topologic.Face:
1949
+ def Trapezoid(origin= None, widthA: float = 1.0, widthB: float = 0.75, offsetA: float = 0.0, offsetB: float = 0.0, length: float = 1.0, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
1751
1950
  """
1752
1951
  Creates a trapezoid.
1753
1952
 
1754
1953
  Parameters
1755
1954
  ----------
1756
- origin : topologic.Vertex, optional
1955
+ origin : topologic_core.Vertex, optional
1757
1956
  The location of the origin of the trapezoid. The default is None which results in the trapezoid being placed at (0, 0, 0).
1758
1957
  widthA : float , optional
1759
1958
  The width of the bottom edge of the trapezoid. The default is 1.0.
@@ -1774,25 +1973,27 @@ class Face(Topology):
1774
1973
 
1775
1974
  Returns
1776
1975
  -------
1777
- topologic.Face
1976
+ topologic_core.Face
1778
1977
  The created trapezoid.
1779
1978
 
1780
1979
  """
1781
1980
  from topologicpy.Wire import Wire
1981
+ from topologicpy.Topology import Topology
1982
+
1782
1983
  wire = Wire.Trapezoid(origin=origin, widthA=widthA, widthB=widthB, offsetA=offsetA, offsetB=offsetB, length=length, direction=direction, placement=placement, tolerance=tolerance)
1783
- if not isinstance(wire, topologic.Wire):
1984
+ if not Topology.IsInstance(wire, "Wire"):
1784
1985
  print("Face.Rectangle - Error: Could not create the base wire for the trapezoid. Returning None.")
1785
1986
  return None
1786
1987
  return Face.ByWire(wire, tolerance=tolerance)
1787
1988
 
1788
1989
  @staticmethod
1789
- def Triangulate(face:topologic.Face, mode: int = 0, meshSize: float = None, tolerance: float = 0.0001) -> list:
1990
+ def Triangulate(face, mode: int = 0, meshSize: float = None, tolerance: float = 0.0001) -> list:
1790
1991
  """
1791
1992
  Triangulates the input face and returns a list of faces.
1792
1993
 
1793
1994
  Parameters
1794
1995
  ----------
1795
- face : topologic.Face
1996
+ face : topologic_core.Face
1796
1997
  The input face.
1797
1998
  tolerance : float , optional
1798
1999
  The desired tolerance. The default is 0.0001.
@@ -1828,7 +2029,7 @@ class Face(Topology):
1828
2029
 
1829
2030
  Parameters
1830
2031
  ----------
1831
- face : topologic.Face
2032
+ face : topologic_core.Face
1832
2033
  The input face.
1833
2034
  meshSize : float , optional
1834
2035
  The desired mesh size.
@@ -1837,7 +2038,7 @@ class Face(Topology):
1837
2038
 
1838
2039
  Returns
1839
2040
  ----------
1840
- topologic.Shell
2041
+ topologic_core.Shell
1841
2042
  The shell of triangular meshes.
1842
2043
 
1843
2044
  """
@@ -1877,7 +2078,7 @@ class Face(Topology):
1877
2078
  from topologicpy.Wire import Wire
1878
2079
  from topologicpy.Face import Face
1879
2080
 
1880
- if not isinstance(face, topologic.Face):
2081
+ if not Topology.IsInstance(face, "Face"):
1881
2082
  print("Shell.ByMeshFace - Error: The input face parameter is not a valid face. Returning None.")
1882
2083
  return None
1883
2084
  if not meshSize:
@@ -1952,7 +2153,7 @@ class Face(Topology):
1952
2153
  faces.append(Face.ByVertices(face_vertices))
1953
2154
  return faces
1954
2155
 
1955
- if not isinstance(face, topologic.Face):
2156
+ if not Topology.IsInstance(face, "Face"):
1956
2157
  print("Face.Triangulate - Error: The input face parameter is not a valid face. Returning None.")
1957
2158
  return None
1958
2159
  vertices = Topology.Vertices(face)
@@ -1966,7 +2167,7 @@ class Face(Topology):
1966
2167
  shell_faces = []
1967
2168
  for i in range(0,5,1):
1968
2169
  try:
1969
- _ = topologic.FaceUtility.Triangulate(flatFace, float(i)*0.1, shell_faces)
2170
+ _ = topologic.FaceUtility.Triangulate(flatFace, float(i)*0.1, shell_faces) # Hook to Core
1970
2171
  break
1971
2172
  except:
1972
2173
  continue
@@ -1981,49 +2182,51 @@ class Face(Topology):
1981
2182
  if Face.Angle(face, f) > 90:
1982
2183
  wire = Face.ExternalBoundary(f)
1983
2184
  wire = Wire.Invert(wire)
1984
- f = topologic.Face.ByExternalBoundary(wire)
2185
+ f = Face.ByWire(wire)
1985
2186
  finalFaces.append(f)
1986
2187
  else:
1987
2188
  finalFaces.append(f)
1988
2189
  return finalFaces
1989
2190
 
1990
2191
  @staticmethod
1991
- def TrimByWire(face: topologic.Face, wire: topologic.Wire, reverse: bool = False) -> topologic.Face:
2192
+ def TrimByWire(face, wire, reverse: bool = False):
1992
2193
  """
1993
2194
  Trims the input face by the input wire.
1994
2195
 
1995
2196
  Parameters
1996
2197
  ----------
1997
- face : topologic.Face
2198
+ face : topologic_core.Face
1998
2199
  The input face.
1999
- wire : topologic.Wire
2200
+ wire : topologic_core.Wire
2000
2201
  The input wire.
2001
2202
  reverse : bool , optional
2002
2203
  If set to True, the effect of the trim will be reversed. The default is False.
2003
2204
 
2004
2205
  Returns
2005
2206
  -------
2006
- topologic.Face
2207
+ topologic_core.Face
2007
2208
  The resulting trimmed face.
2008
2209
 
2009
2210
  """
2010
- if not isinstance(face, topologic.Face):
2211
+ from topologicpy.Topology import Topology
2212
+
2213
+ if not Topology.IsInstance(face, "Face"):
2011
2214
  return None
2012
- if not isinstance(wire, topologic.Wire):
2215
+ if not Topology.IsInstance(wire, "Wire"):
2013
2216
  return face
2014
- trimmed_face = topologic.FaceUtility.TrimByWire(face, wire, False)
2217
+ trimmed_face = topologic.FaceUtility.TrimByWire(face, wire, False) # Hook to Core
2015
2218
  if reverse:
2016
2219
  trimmed_face = face.Difference(trimmed_face)
2017
2220
  return trimmed_face
2018
2221
 
2019
2222
  @staticmethod
2020
- def VertexByParameters(face: topologic.Face, u: float = 0.5, v: float = 0.5) -> topologic.Vertex:
2223
+ def VertexByParameters(face, u: float = 0.5, v: float = 0.5):
2021
2224
  """
2022
2225
  Creates a vertex at the *u* and *v* parameters of the input face.
2023
2226
 
2024
2227
  Parameters
2025
2228
  ----------
2026
- face : topologic.Face
2229
+ face : topologic_core.Face
2027
2230
  The input face.
2028
2231
  u : float , optional
2029
2232
  The *u* parameter of the input face. The default is 0.5.
@@ -2036,20 +2239,22 @@ class Face(Topology):
2036
2239
  The created vertex.
2037
2240
 
2038
2241
  """
2039
- if not isinstance(face, topologic.Face):
2242
+ from topologicpy.Topology import Topology
2243
+
2244
+ if not Topology.IsInstance(face, "Face"):
2040
2245
  return None
2041
- return topologic.FaceUtility.VertexAtParameters(face, u, v)
2246
+ return topologic.FaceUtility.VertexAtParameters(face, u, v) # Hook to Core
2042
2247
 
2043
2248
  @staticmethod
2044
- def VertexParameters(face: topologic.Face, vertex: topologic.Vertex, outputType: str = "uv", mantissa: int = 6) -> list:
2249
+ def VertexParameters(face, vertex, outputType: str = "uv", mantissa: int = 6) -> list:
2045
2250
  """
2046
2251
  Returns the *u* and *v* parameters of the input face at the location of the input vertex.
2047
2252
 
2048
2253
  Parameters
2049
2254
  ----------
2050
- face : topologic.Face
2255
+ face : topologic_core.Face
2051
2256
  The input face.
2052
- vertex : topologic.Vertex
2257
+ vertex : topologic_core.Vertex
2053
2258
  The input vertex.
2054
2259
  outputType : string , optional
2055
2260
  The string defining the desired output. This can be any subset or permutation of "uv". It is case insensitive. The default is "uv".
@@ -2062,11 +2267,13 @@ class Face(Topology):
2062
2267
  The list of *u* and/or *v* as specified by the outputType input.
2063
2268
 
2064
2269
  """
2065
- if not isinstance(face, topologic.Face):
2270
+ from topologicpy.Topology import Topology
2271
+
2272
+ if not Topology.IsInstance(face, "Face"):
2066
2273
  return None
2067
- if not isinstance(vertex, topologic.Vertex):
2274
+ if not Topology.IsInstance(vertex, "Vertex"):
2068
2275
  return None
2069
- params = topologic.FaceUtility.ParametersAtVertex(face, vertex)
2276
+ params = topologic.FaceUtility.ParametersAtVertex(face, vertex) # Hook to Core
2070
2277
  u = round(params[0], mantissa)
2071
2278
  v = round(params[1], mantissa)
2072
2279
  outputType = list(outputType.lower())
@@ -2079,13 +2286,13 @@ class Face(Topology):
2079
2286
  return returnResult
2080
2287
 
2081
2288
  @staticmethod
2082
- def Vertices(face: topologic.Face) -> list:
2289
+ def Vertices(face) -> list:
2083
2290
  """
2084
2291
  Returns the vertices of the input face.
2085
2292
 
2086
2293
  Parameters
2087
2294
  ----------
2088
- face : topologic.Face
2295
+ face : topologic_core.Face
2089
2296
  The input face.
2090
2297
 
2091
2298
  Returns
@@ -2094,38 +2301,40 @@ class Face(Topology):
2094
2301
  The list of vertices.
2095
2302
 
2096
2303
  """
2097
- if not isinstance(face, topologic.Face):
2304
+ from topologicpy.Topology import Topology
2305
+
2306
+ if not Topology.IsInstance(face, "Face"):
2098
2307
  return None
2099
2308
  vertices = []
2100
2309
  _ = face.Vertices(None, vertices)
2101
2310
  return vertices
2102
2311
 
2103
2312
  @staticmethod
2104
- def Wire(face: topologic.Face) -> topologic.Wire:
2313
+ def Wire(face):
2105
2314
  """
2106
2315
  Returns the external boundary (closed wire) of the input face.
2107
2316
 
2108
2317
  Parameters
2109
2318
  ----------
2110
- face : topologic.Face
2319
+ face : topologic_core.Face
2111
2320
  The input face.
2112
2321
 
2113
2322
  Returns
2114
2323
  -------
2115
- topologic.Wire
2324
+ topologic_core.Wire
2116
2325
  The external boundary of the input face.
2117
2326
 
2118
2327
  """
2119
- return face.ExternalBoundary()
2328
+ return Face.ExternalBoundary(face)
2120
2329
 
2121
2330
  @staticmethod
2122
- def Wires(face: topologic.Face) -> list:
2331
+ def Wires(face) -> list:
2123
2332
  """
2124
2333
  Returns the wires of the input face.
2125
2334
 
2126
2335
  Parameters
2127
2336
  ----------
2128
- face : topologic.Face
2337
+ face : topologic_core.Face
2129
2338
  The input face.
2130
2339
 
2131
2340
  Returns
@@ -2134,7 +2343,9 @@ class Face(Topology):
2134
2343
  The list of wires.
2135
2344
 
2136
2345
  """
2137
- if not isinstance(face, topologic.Face):
2346
+ from topologicpy.Topology import Topology
2347
+
2348
+ if not Topology.IsInstance(face, "Face"):
2138
2349
  return None
2139
2350
  wires = []
2140
2351
  _ = face.Wires(None, wires)