topologicpy 0.8.93__py3-none-any.whl → 0.8.97__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 +176 -60
- topologicpy/Dictionary.py +952 -134
- topologicpy/Edge.py +84 -5
- topologicpy/Face.py +37 -1
- topologicpy/Graph.py +1559 -109
- topologicpy/Plotly.py +10 -12
- topologicpy/Topology.py +422 -8
- topologicpy/Vector.py +182 -21
- topologicpy/Vertex.py +155 -3
- topologicpy/Wire.py +29 -4
- topologicpy/version.py +1 -1
- {topologicpy-0.8.93.dist-info → topologicpy-0.8.97.dist-info}/METADATA +1 -1
- {topologicpy-0.8.93.dist-info → topologicpy-0.8.97.dist-info}/RECORD +16 -16
- {topologicpy-0.8.93.dist-info → topologicpy-0.8.97.dist-info}/WHEEL +1 -1
- {topologicpy-0.8.93.dist-info → topologicpy-0.8.97.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.93.dist-info → topologicpy-0.8.97.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
|
@@ -331,12 +331,19 @@ class Cell():
|
|
|
331
331
|
return None
|
|
332
332
|
return cell
|
|
333
333
|
|
|
334
|
+
|
|
334
335
|
@staticmethod
|
|
335
|
-
def ByThickenedFace(face, thickness: float = 1.0, bothSides: bool = True,
|
|
336
|
-
|
|
336
|
+
def ByThickenedFace(face, thickness: float = 1.0, bothSides: bool = True, wSides: int = 1,
|
|
337
|
+
reverse: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
|
337
338
|
"""
|
|
338
339
|
Creates a cell by thickening the input face.
|
|
339
340
|
|
|
341
|
+
Behaviour:
|
|
342
|
+
- Only the bottom and top faces are used as horizontal faces.
|
|
343
|
+
- wSides controls the number of vertical segments along the thickness.
|
|
344
|
+
Intermediate offset layers are used only to build side faces and are
|
|
345
|
+
not included as horizontal faces in Cell.ByFaces.
|
|
346
|
+
|
|
340
347
|
Parameters
|
|
341
348
|
----------
|
|
342
349
|
face : topologic_core.Face
|
|
@@ -344,11 +351,17 @@ class Cell():
|
|
|
344
351
|
thickness : float , optional
|
|
345
352
|
The desired thickness. Default is 1.0.
|
|
346
353
|
bothSides : bool
|
|
347
|
-
If True, the
|
|
354
|
+
If True, the thickening is symmetric about the original face
|
|
355
|
+
(i.e. from -thickness/2 to +thickness/2).
|
|
356
|
+
If False, the thickening is from 0 to +thickness along the face normal.
|
|
357
|
+
Default is True.
|
|
348
358
|
reverse : bool
|
|
349
|
-
If True, the
|
|
350
|
-
|
|
351
|
-
|
|
359
|
+
If True, the extrusion direction is flipped (normal is negated).
|
|
360
|
+
Default is False.
|
|
361
|
+
wSides: int, optional
|
|
362
|
+
The number of segments along the thickness direction.
|
|
363
|
+
This is the same definition regardless of bothSides.
|
|
364
|
+
Default is 1.
|
|
352
365
|
tolerance : float , optional
|
|
353
366
|
The desired tolerance. Default is 0.0001.
|
|
354
367
|
silent : bool , optional
|
|
@@ -357,60 +370,161 @@ class Cell():
|
|
|
357
370
|
Returns
|
|
358
371
|
-------
|
|
359
372
|
topologic_core.Cell
|
|
360
|
-
The created cell.
|
|
361
|
-
|
|
373
|
+
The created cell, or None on failure.
|
|
362
374
|
"""
|
|
375
|
+
import math
|
|
376
|
+
from topologicpy.Topology import Topology
|
|
377
|
+
from topologicpy.Face import Face
|
|
363
378
|
from topologicpy.Edge import Edge
|
|
364
379
|
from topologicpy.Wire import Wire
|
|
365
|
-
from topologicpy.
|
|
366
|
-
from topologicpy.Cluster import Cluster
|
|
367
|
-
from topologicpy.Topology import Topology
|
|
380
|
+
from topologicpy.Cell import Cell
|
|
368
381
|
|
|
382
|
+
# -----------------------------
|
|
383
|
+
# Validation
|
|
384
|
+
# -----------------------------
|
|
369
385
|
if not Topology.IsInstance(face, "Face"):
|
|
370
|
-
|
|
386
|
+
if not silent:
|
|
387
|
+
print("Cell.ByThickenedFace - Error: Input is not a valid Face. Returning None.")
|
|
371
388
|
return None
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
389
|
+
|
|
390
|
+
if thickness <= tolerance:
|
|
391
|
+
if not silent:
|
|
392
|
+
print("Cell.ByThickenedFace - Error: Thickness is less than or equal to the tolerance. Returning None.")
|
|
393
|
+
return None
|
|
394
|
+
|
|
395
|
+
if wSides < 1:
|
|
396
|
+
if not silent:
|
|
397
|
+
print("Cell.ByThickenedFace - Error: wSides is less than 1. Returning None.")
|
|
398
|
+
return None
|
|
399
|
+
|
|
400
|
+
if thickness/float(wSides) <= tolerance:
|
|
401
|
+
if not silent:
|
|
402
|
+
print("Cell.ByThickenedFace - Error: The distance between layers is less than or equal to the tolerance. Returning None.")
|
|
403
|
+
return None
|
|
404
|
+
|
|
405
|
+
# -----------------------------
|
|
406
|
+
# Face normal (normalized)
|
|
407
|
+
# -----------------------------
|
|
408
|
+
normal = Face.Normal(face)
|
|
409
|
+
if not isinstance(normal, (list, tuple)) or len(normal) != 3:
|
|
410
|
+
if not silent:
|
|
411
|
+
print("Cell.ByThickenedFace - Error: Could not compute face normal.")
|
|
412
|
+
return None
|
|
413
|
+
|
|
414
|
+
nx, ny, nz = normal
|
|
415
|
+
L = math.sqrt(nx*nx + ny*ny + nz*nz)
|
|
416
|
+
if L <= tolerance:
|
|
417
|
+
if not silent:
|
|
418
|
+
print("Cell.ByThickenedFace - Error: Degenerate face normal.")
|
|
419
|
+
return None
|
|
420
|
+
|
|
421
|
+
nx, ny, nz = nx/L, ny/L, nz/L
|
|
422
|
+
|
|
423
|
+
if reverse:
|
|
424
|
+
nx, ny, nz = -nx, -ny, -nz
|
|
425
|
+
|
|
426
|
+
# -----------------------------
|
|
427
|
+
# Build offset layers
|
|
428
|
+
# NOTE: We will only keep the min/max offset faces as bottom/top.
|
|
429
|
+
# Intermediate layers are used only for building side faces.
|
|
430
|
+
# -----------------------------
|
|
431
|
+
step = thickness / float(wSides)
|
|
432
|
+
layers = []
|
|
433
|
+
|
|
375
434
|
if bothSides:
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
topFace = Topology.Translate(face,
|
|
383
|
-
x=faceNormal[0]*0.5*thickness,
|
|
384
|
-
y=faceNormal[1]*0.5*thickness,
|
|
385
|
-
z=faceNormal[2]*0.5*thickness,
|
|
386
|
-
transferDictionaries=False,
|
|
387
|
-
silent=True)
|
|
435
|
+
# Symmetric: [-thickness/2, ..., +thickness/2]
|
|
436
|
+
start = -0.5 * thickness
|
|
437
|
+
for i in range(wSides + 1):
|
|
438
|
+
offset = start + step * i
|
|
439
|
+
f = Topology.Translate(face, nx*offset, ny*offset, nz*offset)
|
|
440
|
+
layers.append((offset, f))
|
|
388
441
|
else:
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
transferDictionaries=False,
|
|
395
|
-
silent=True)
|
|
442
|
+
# One-sided: [0, ..., thickness]
|
|
443
|
+
for i in range(wSides + 1):
|
|
444
|
+
offset = step * i
|
|
445
|
+
f = Topology.Translate(face, nx*offset, ny*offset, nz*offset)
|
|
446
|
+
layers.append((offset, f))
|
|
396
447
|
|
|
397
|
-
|
|
398
|
-
|
|
448
|
+
if len(layers) < 2:
|
|
449
|
+
if not silent:
|
|
450
|
+
print("Cell.ByThickenedFace - Error: Not enough layers to form a volume.")
|
|
451
|
+
return None
|
|
399
452
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
453
|
+
layers.sort(key=lambda x: x[0])
|
|
454
|
+
|
|
455
|
+
# Bottom and top faces only
|
|
456
|
+
bottom_face = layers[0][1]
|
|
457
|
+
top_face = layers[-1][1]
|
|
458
|
+
|
|
459
|
+
faces_all = [bottom_face, top_face]
|
|
460
|
+
|
|
461
|
+
# -----------------------------
|
|
462
|
+
# Build side faces between each consecutive pair of layers
|
|
463
|
+
# These are the vertical segmentation faces controlled by wSides.
|
|
464
|
+
# -----------------------------
|
|
465
|
+
for i in range(len(layers) - 1):
|
|
466
|
+
_, faceA = layers[i]
|
|
467
|
+
_, faceB = layers[i + 1]
|
|
468
|
+
|
|
469
|
+
edgesA = Topology.Edges(faceA)
|
|
470
|
+
edgesB = Topology.Edges(faceB)
|
|
471
|
+
|
|
472
|
+
if not edgesA or not edgesB or len(edgesA) != len(edgesB):
|
|
473
|
+
if not silent:
|
|
474
|
+
print("Cell.ByThickenedFace - Warning: Edge mismatch between layers. "
|
|
475
|
+
"Side faces may be incomplete.")
|
|
476
|
+
# We try to continue with min length
|
|
477
|
+
count = min(len(edgesA), len(edgesB))
|
|
478
|
+
|
|
479
|
+
for j in range(count):
|
|
480
|
+
eA = edgesA[j]
|
|
481
|
+
eB = edgesB[j]
|
|
482
|
+
|
|
483
|
+
vA = Topology.Vertices(eA)
|
|
484
|
+
vB = Topology.Vertices(eB)
|
|
485
|
+
|
|
486
|
+
if not vA or not vB or len(vA) != 2 or len(vB) != 2:
|
|
487
|
+
continue
|
|
488
|
+
|
|
489
|
+
vA1, vA2 = vA
|
|
490
|
+
vB1, vB2 = vB
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
e1 = Edge.ByStartVertexEndVertex(vA1, vA2)
|
|
494
|
+
e2 = Edge.ByStartVertexEndVertex(vA2, vB2)
|
|
495
|
+
e3 = Edge.ByStartVertexEndVertex(vB2, vB1)
|
|
496
|
+
e4 = Edge.ByStartVertexEndVertex(vB1, vA1)
|
|
497
|
+
|
|
498
|
+
if not (e1 and e2 and e3 and e4):
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
side_wire = Wire.ByEdges([e1, e2, e3, e4])
|
|
502
|
+
if not side_wire:
|
|
503
|
+
continue
|
|
504
|
+
|
|
505
|
+
side_face = Face.ByWire(side_wire)
|
|
506
|
+
if side_face:
|
|
507
|
+
faces_all.append(side_face)
|
|
508
|
+
except Exception:
|
|
509
|
+
# Skip problematic quads but continue
|
|
510
|
+
continue
|
|
511
|
+
|
|
512
|
+
# -----------------------------
|
|
513
|
+
# Build final cell
|
|
514
|
+
# -----------------------------
|
|
515
|
+
try:
|
|
516
|
+
cell = Cell.ByFaces(faces_all, tolerance=tolerance)
|
|
517
|
+
except Exception:
|
|
518
|
+
if not silent:
|
|
519
|
+
print("Cell.ByThickenedFace - Error: Cell.ByFaces failed.")
|
|
520
|
+
return None
|
|
521
|
+
|
|
522
|
+
if not Topology.IsInstance(cell, "Cell"):
|
|
523
|
+
if not silent:
|
|
524
|
+
print("Cell.ByThickenedFace - Error: Cell.ByFaces did not return a valid Cell.")
|
|
525
|
+
return None
|
|
526
|
+
|
|
527
|
+
return cell
|
|
414
528
|
|
|
415
529
|
@staticmethod
|
|
416
530
|
def ByThickenedShell(shell, direction: list = [0, 0, 1], thickness: float = 1.0, bothSides: bool = True, reverse: bool = False,
|
|
@@ -1158,7 +1272,7 @@ class Cell():
|
|
|
1158
1272
|
tolerance=tolerance,
|
|
1159
1273
|
silent=silent)
|
|
1160
1274
|
return_cell = Cell.ByThickenedFace(cross_shape_face, thickness=height, bothSides=True, reverse=False,
|
|
1161
|
-
|
|
1275
|
+
tolerance=tolerance, silent=silent)
|
|
1162
1276
|
xOffset = 0
|
|
1163
1277
|
yOffset = 0
|
|
1164
1278
|
zOffset = 0
|
|
@@ -1456,7 +1570,7 @@ class Cell():
|
|
|
1456
1570
|
|
|
1457
1571
|
baseWire = Wire.Circle(origin=circle_origin, radius=radius, sides=uSides, fromAngle=0, toAngle=360, close=True, direction=[0, 0, 1], placement="center", tolerance=tolerance)
|
|
1458
1572
|
baseFace = Face.ByWire(baseWire, tolerance=tolerance)
|
|
1459
|
-
cylinder = Cell.ByThickenedFace(face=baseFace, thickness=height, bothSides=False, tolerance=tolerance)
|
|
1573
|
+
cylinder = Cell.ByThickenedFace(face=baseFace, thickness=height, bothSides=False, reverse=False, tolerance=tolerance)
|
|
1460
1574
|
if vSides > 1:
|
|
1461
1575
|
cutting_planes = []
|
|
1462
1576
|
baseX = Vertex.X(origin, mantissa=mantissa) + xOffset
|
|
@@ -2972,15 +3086,16 @@ class Cell():
|
|
|
2972
3086
|
elif placement.lower() == "lowerleft":
|
|
2973
3087
|
xOffset = width*0.5
|
|
2974
3088
|
yOffset = length*0.5
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
3089
|
+
|
|
3090
|
+
vb1 = Vertex.ByCoordinates(Vertex.X(origin, mantissa=mantissa)-width*0.5+xOffset,Vertex.Y(origin, mantissa=mantissa)+length*0.5+yOffset,Vertex.Z(origin, mantissa=mantissa)+zOffset)
|
|
3091
|
+
vb2 = Vertex.ByCoordinates(Vertex.X(origin, mantissa=mantissa)+width*0.5+xOffset,Vertex.Y(origin, mantissa=mantissa)+length*0.5+yOffset,Vertex.Z(origin, mantissa=mantissa)+zOffset)
|
|
3092
|
+
vb3 = Vertex.ByCoordinates(Vertex.X(origin, mantissa=mantissa)+width*0.5+xOffset,Vertex.Y(origin, mantissa=mantissa)-length*0.5+yOffset,Vertex.Z(origin, mantissa=mantissa)+zOffset)
|
|
3093
|
+
vb4 = Vertex.ByCoordinates(Vertex.X(origin, mantissa=mantissa)-width*0.5+xOffset,Vertex.Y(origin, mantissa=mantissa)-length*0.5+yOffset,Vertex.Z(origin, mantissa=mantissa)+zOffset)
|
|
2979
3094
|
|
|
2980
3095
|
baseWire = Wire.ByVertices([vb1, vb2, vb3, vb4], close=True)
|
|
2981
3096
|
baseFace = Face.ByWire(baseWire, tolerance=tolerance)
|
|
2982
3097
|
|
|
2983
|
-
prism = Cell.ByThickenedFace(baseFace, thickness=height, bothSides = False)
|
|
3098
|
+
prism = Cell.ByThickenedFace(baseFace, thickness=height, bothSides = False, reverse=True)
|
|
2984
3099
|
|
|
2985
3100
|
if uSides > 1 or vSides > 1 or wSides > 1:
|
|
2986
3101
|
prism = sliceCell(prism, width, length, height, uSides, vSides, wSides)
|
|
@@ -3092,7 +3207,7 @@ class Cell():
|
|
|
3092
3207
|
origin = Vertex.Origin()
|
|
3093
3208
|
bottom_face = Face.RHS(origin = Vertex.Origin(), width=width, length=length, thickness=thickness, outerFillet=outerFillet, innerFillet=innerFillet, sides=sides, direction=[0,0,1], placement="center", tolerance=tolerance, silent=silent)
|
|
3094
3209
|
return_cell = Cell.ByThickenedFace(bottom_face, thickness=height, bothSides=True, reverse=False,
|
|
3095
|
-
|
|
3210
|
+
tolerance=tolerance, silent=silent)
|
|
3096
3211
|
xOffset = 0
|
|
3097
3212
|
yOffset = 0
|
|
3098
3213
|
zOffset = 0
|
|
@@ -3434,8 +3549,9 @@ class Cell():
|
|
|
3434
3549
|
sphere = Topology.Translate(sphere, 0, 0, radius)
|
|
3435
3550
|
elif placement.lower() == "lowerleft":
|
|
3436
3551
|
sphere = Topology.Translate(sphere, radius, radius, radius)
|
|
3437
|
-
|
|
3438
|
-
|
|
3552
|
+
|
|
3553
|
+
if not direction == [0,0,1]:
|
|
3554
|
+
sphere = Topology.Orient(sphere, origin=origin, dirA=[0, 0, 1], dirB=direction)
|
|
3439
3555
|
return sphere
|
|
3440
3556
|
|
|
3441
3557
|
@staticmethod
|