7
class TopoShapeAssertions:
9
def assertAttrEqual(self, toposhape, attr_value_list, msg=None):
10
for attr, value in attr_value_list:
11
result = toposhape.__getattribute__(
14
if result.__str__() != value.__str__():
16
msg = f"TopoShape {attr} is incorrect: {result} should be {value}",
17
raise AssertionError(msg)
19
def assertAttrAlmostEqual(self, toposhape, attr_value_list, places=5, msg=None):
20
range = 1 / 10 ** places
21
for attr, value in attr_value_list:
22
result = toposhape.__getattribute__(
25
if abs(result - value) > range:
27
msg = f"TopoShape {attr} is incorrect: {result} should be {value}"
28
raise AssertionError(msg)
30
def assertAttrCount(self, toposhape, attr_value_list, msg=None):
31
for attr, value in attr_value_list:
32
result = toposhape.__getattribute__(
35
if len(result) != value:
37
msg = f"TopoShape {attr} is incorrect: {result} should have {value} elements"
38
raise AssertionError(msg)
40
def assertKeysInMap(self, map, keys, msg=None):
44
msg = f"Key {key} not found in map: {map}"
45
raise AssertionError(msg)
47
def assertBounds(self, shape, bounds, msg=None, precision=App.Base.Precision.confusion() * 100):
48
shape_bounds = shape.BoundBox
49
shape_bounds_max = App.BoundBox(shape_bounds)
50
shape_bounds_max.enlarge(precision)
51
bounds_max = App.BoundBox(bounds)
52
bounds_max.enlarge(precision)
53
if not (shape_bounds_max.isInside(bounds) and bounds_max.isInside(shape_bounds)):
55
msg = f"Bounds {shape_bounds} doesn't match {bounds}"
56
raise AssertionError(msg)
59
class TopoShapeTest(unittest.TestCase, TopoShapeAssertions):
61
"""Create a document and some TopoShapes of various types"""
62
self.doc = App.newDocument("TopoShape")
68
self.doc.addObject("Part::Box", "Box1")
69
self.doc.Box1.Length = 1
70
self.doc.Box1.Width = 2
71
self.doc.Box1.Height = 2
72
self.doc.addObject("Part::Box", "Box2")
73
self.doc.Box2.Length = 2
74
self.doc.Box2.Width = 1
75
self.doc.Box2.Height = 2
77
self.box = self.doc.Box1.Shape
78
self.box2 = self.doc.Box2.Shape
81
App.closeDocument("TopoShape")
83
def testTopoShapeBox(self):
85
box2_toposhape = self.doc.Box2.Shape
88
["BoundBox", App.BoundBox(0, 0, 0, 2, 1, 2)],
89
["CenterOfGravity", App.Vector(1, 0.5, 1)],
90
["CenterOfMass", App.Vector(1, 0.5, 1)],
93
["Content", "<ElementMap/>\n"],
95
["ElementReverseMap", {}],
100
1.66667, 0, 0, 0, 0, 2.66667, 0, 0, 0, 0, 1.66667, 0, 0, 0, 0, 1
104
["Orientation", "Forward"],
106
["Placement", App.Placement()],
108
"PrincipalProperties",
110
"SymmetryAxis": True,
111
"SymmetryPoint": False,
117
"FirstAxisOfInertia": App.Vector(0.0, 1.0, 0.0),
118
"SecondAxisOfInertia": App.Vector(0.0, 0.0, 1.0),
119
"ThirdAxisOfInertia": App.Vector(1.0, 0.0, 0.0),
120
"RadiusOfGyration": (
127
["ShapeType", "Solid"],
130
(3.999999999999999, 1.9999999999999996, 3.999999999999999),
133
["TypeId", "Part::TopoShape"],
136
self.assertAttrEqual(box2_toposhape, attr_value_list)
141
["ElementMapSize", 0],
149
self.assertAttrAlmostEqual(box2_toposhape, attr_value_list, 5)
162
self.assertAttrCount(box2_toposhape, attr_value_list)
164
def testTopoShapeElementMap(self):
165
"""Tests TopoShape elementMap"""
168
compound1 = Part.Compound(
169
[self.doc.Objects[-1].Shape, self.doc.Objects[-2].Shape]
171
self.doc.addObject("Part::Compound", "Compound")
172
self.doc.Compound.Links = [
173
App.activeDocument().Box1,
174
App.activeDocument().Box2,
177
compound2 = self.doc.Compound.Shape
180
if compound1.ElementMapVersion != "":
187
compound2.ElementMapSize,
189
"ElementMap is Incorrect: {0}".format(compound2.ElementMap),
192
self.assertBounds(compound2, App.BoundBox(0, 0, 0, 2, 2, 2))
194
def testPartCommon(self):
196
self.doc.addObject("Part::MultiCommon", "Common")
197
self.doc.Common.Shapes = [self.doc.Box1, self.doc.Box2]
200
common1 = self.doc.Common.Shape
202
if common1.ElementMapVersion != "":
203
self.assertKeysInMap(common1.ElementReverseMap,
234
self.assertBounds(common1, App.BoundBox(0, 0, 0, 1, 1, 2))
236
def testPartCut(self):
238
self.doc.addObject("Part::Cut", "Cut")
239
self.doc.Cut.Base = self.doc.Box1
240
self.doc.Cut.Tool = self.doc.Box2
243
cut1 = self.doc.Cut.Shape
245
if cut1.ElementMapVersion != "":
246
self.assertKeysInMap(cut1.ElementReverseMap,
277
self.assertBounds(cut1, App.BoundBox(0, 1, 0, 1, 2, 2))
279
def testPartFuse(self):
281
self.doc.addObject("Part::Fuse", "Fuse")
282
self.doc.Fuse.Refine = False
283
self.doc.Fuse.Base = self.doc.Box1
284
self.doc.Fuse.Tool = self.doc.Box2
287
fuse1 = self.doc.Fuse.Shape
289
if fuse1.ElementMapVersion != "":
290
self.assertEqual(fuse1.ElementMapSize, 58)
291
self.doc.Fuse.Refine = True
293
self.assertEqual(fuse1.ElementMapSize, 58)
296
self.assertBounds(fuse1, App.BoundBox(0, 0, 0, 2, 2, 2))
298
def testAppPartMakeCompound(self):
302
compound1 = Part.makeCompound([self.doc.Box1.Shape, self.doc.Box2.Shape])
304
if compound1.ElementMapVersion != "":
305
self.assertEqual(compound1.ElementMapSize, 52)
307
self.assertBounds(compound1, App.BoundBox(0, 0, 0, 2, 2, 2))
309
def testAppPartMakeShell(self):
311
shell1 = Part.makeShell(self.doc.Box1.Shape.Faces)
313
if shell1.ElementMapVersion != "":
314
self.assertEqual(shell1.ElementMapSize, 26)
316
self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2))
318
def testAppPartMakeFace(self):
320
face1 = Part.makeFace(self.doc.Box1.Shape.Faces[0], "Part::FaceMakerCheese")
322
if face1.ElementMapVersion != "":
323
self.assertEqual(face1.ElementMapSize, 10)
325
self.assertBounds(face1, App.BoundBox(0, 0, 0, 0, 2, 2))
327
def testAppPartmakeFilledFace(self):
328
face1 = Part.makeFilledFace(self.doc.Box1.Shape.Faces[3].Edges)
330
if face1.ElementMapVersion != "":
331
self.assertEqual(face1.ElementMapSize, 9)
333
self.assertBounds(face1, App.BoundBox(-0.05, 2, -0.1, 1.05, 2, 2.1))
335
def testAppPartMakeSolid(self):
337
solid1 = Part.makeSolid(self.doc.Box1.Shape.Shells[0])
339
if solid1.ElementMapVersion != "":
340
self.assertEqual(solid1.ElementMapSize, 26)
342
self.assertBounds(solid1, App.BoundBox(0, 0, 0, 1, 2, 2))
344
def testAppPartMakeRuled(self):
346
surface1 = Part.makeRuledSurface(*self.doc.Box1.Shape.Edges[3:5])
348
if surface1.ElementMapVersion != "":
349
self.assertEqual(surface1.ElementMapSize, 9)
351
self.assertBounds(surface1, App.BoundBox(0, 0, 0, 1, 2, 2))
353
def testAppPartMakeShellFromWires(self):
355
wire1 = self.doc.Box1.Shape.Wires[0]
356
wire2 = self.doc.Box1.Shape.Wires[1]
358
shell1 = Part.makeShellFromWires([wire1, wire2])
360
if shell1.ElementMapVersion != "":
361
self.assertEqual(shell1.ElementMapSize, 24)
363
self.assertBounds(shell1, App.BoundBox(0, 0, 0, 1, 2, 2))
365
def testAppPartMakeSweepSurface(self):
367
circle = Part.makeCircle(5, App.Vector(0, 0, 0))
368
path = Part.makeLine(App.Vector(), App.Vector(0, 0, 10))
369
Part.show(circle, "Circle")
370
Part.show(path, "Path")
373
surface1 = Part.makeSweepSurface(self.doc.Path.Shape, self.doc.Circle.Shape, 0.001, 0)
374
Part.show(surface1, "Sweep")
377
if surface1.ElementMapVersion != "":
378
self.assertEqual(surface1.ElementMapSize, 6)
379
self.assertBounds(surface1, App.BoundBox(-5, -5, 0, 5, 5, 10), precision=2)
391
self.assertBounds(surface1, App.BoundBox(-5, -2.72011, 0, 5, 5, 6.28319), precision=2)
394
def testAppPartMakeLoft(self):
396
solid1 = Part.makeLoft(self.doc.Box1.Shape.Wires[0:2])
398
if solid1.ElementMapVersion != "":
399
self.assertEqual(solid1.ElementMapSize, 24)
401
self.assertBounds(solid1, App.BoundBox(0, 0, 0, 1, 2, 2))
403
def testAppPartMakeSplitShape(self):
406
edge1 = self.doc.Box1.Shape.Faces[0].Edges[0].translated(App.Vector(0, 0.5, 0))
407
face1 = self.doc.Box1.Shape.Faces[0]
409
solids1 = Part.makeSplitShape(face1, [(edge1, face1)])
411
self.assertEqual(len(solids1), 2)
412
self.assertEqual(len(solids1[0]), 1)
413
if solids1[0][0].ElementMapVersion != "":
414
self.assertEqual(solids1[0][0].ElementMapSize, 9)
415
self.assertEqual(solids1[1][0].ElementMapSize, 9)
417
self.assertBounds(solids1[0][0], App.BoundBox(0, 0.5, 0, 0, 2, 2))
418
self.assertBounds(solids1[1][0], App.BoundBox(0, 0.5, 0, 0, 2, 2))
420
def testTopoShapePyInit(self):
422
self.doc.addObject("Part::Compound", "Compound")
423
self.doc.Compound.Links = [
424
App.activeDocument().Box1,
425
App.activeDocument().Box2,
428
compound = self.doc.Compound.Shape
430
new_toposhape = Part.Shape(compound)
431
new_empty_toposhape = Part.Shape()
433
if compound.ElementMapVersion != "":
434
self.assertEqual(compound.ElementMapSize, 52)
435
self.assertEqual(new_toposhape.ElementMapSize, 52)
437
def testTopoShapeCopy(self):
439
self.doc.addObject("Part::Compound", "Compound")
440
self.doc.Compound.Links = [
441
App.activeDocument().Box1,
442
App.activeDocument().Box2,
445
compound = self.doc.Compound.Shape
447
compound_copy = compound.copy()
449
if compound.ElementMapVersion != "":
450
self.assertEqual(compound.ElementMapSize, 52)
451
self.assertEqual(compound_copy.ElementMapSize, 52)
453
def testTopoShapeCleaned(self):
455
self.doc.addObject("Part::Compound", "Compound")
456
self.doc.Compound.Links = [
457
App.activeDocument().Box1,
458
App.activeDocument().Box2,
461
compound = self.doc.Compound.Shape
463
compound_cleaned = compound.cleaned()
465
if compound.ElementMapVersion != "":
466
self.assertEqual(compound.ElementMapSize, 52)
467
self.assertEqual(compound_cleaned.ElementMapSize, 52)
469
def testTopoShapeReplaceShape(self):
471
self.doc.addObject("Part::Compound", "Compound")
472
self.doc.Compound.Links = [
473
App.activeDocument().Box1,
474
App.activeDocument().Box2,
477
compound = self.doc.Compound.Shape
479
compound_replaced = compound.replaceShape([(App.activeDocument().Box2.Shape,
480
App.activeDocument().Box1.Shape)])
482
if compound.ElementMapVersion != "":
483
self.assertEqual(compound.ElementMapSize, 52)
484
self.assertEqual(compound_replaced.ElementMapSize, 52)
486
def testTopoShapeRemoveShape(self):
488
self.doc.addObject("Part::Compound", "Compound")
489
self.doc.Compound.Links = [
490
App.activeDocument().Box1,
491
App.activeDocument().Box2,
494
compound = self.doc.Compound.Shape
496
compound_removed = compound.removeShape([App.ActiveDocument.Box2.Shape])
498
if compound.ElementMapVersion != "":
499
self.assertEqual(compound.ElementMapSize, 52)
500
self.assertEqual(compound_removed.ElementMapSize, 52)
502
def testTopoShapeExtrude(self):
504
face = self.doc.Box1.Shape.Faces[0]
506
extrude = face.extrude(App.Vector(2, 0, 0))
509
if extrude.ElementMapVersion != "":
510
self.assertEqual(extrude.ElementMapSize, 26)
512
def testTopoShapeRevolve(self):
514
face = self.doc.Box1.Shape.Faces[0]
516
face.revolve(App.Vector(), App.Vector(1, 0, 0), 45)
519
if face.ElementMapVersion != "":
520
self.assertEqual(face.ElementMapSize, 9)
522
def testTopoShapeFuse(self):
524
fused = self.doc.Box1.Shape.fuse(self.doc.Box2.Shape)
527
if fused.ElementMapVersion != "":
528
self.assertEqual(fused.ElementMapSize, 58)
530
def testTopoShapeMultiFuse(self):
532
fused = self.doc.Box1.Shape.multiFuse([self.doc.Box2.Shape])
535
if fused.ElementMapVersion != "":
536
self.assertEqual(fused.ElementMapSize, 58)
538
def testTopoShapeCommon(self):
540
common = self.doc.Box1.Shape.common(self.doc.Box2.Shape)
543
if common.ElementMapVersion != "":
544
self.assertEqual(common.ElementMapSize, 26)
546
def testTopoShapeSection(self):
548
section = self.doc.Box1.Shape.Faces[0].section(self.doc.Box2.Shape.Faces[3])
551
if section.ElementMapVersion != "":
552
self.assertEqual(section.ElementMapSize, 3)
554
def testTopoShapeSlice(self):
556
slice = self.doc.Box1.Shape.slice(App.Vector(10, 10, 0), 1)
559
self.assertEqual(len(slice), 1)
560
if slice[0].ElementMapVersion != "":
561
self.assertEqual(slice[0].ElementMapSize, 8)
563
def testTopoShapeSlices(self):
565
slices = self.doc.Box1.Shape.Faces[0].slices(App.Vector(10, 10, 0), [1, 2])
568
if slices.ElementMapVersion != "":
569
self.assertEqual(slices.ElementMapSize, 6)
571
def testTopoShapeCut(self):
573
cut = self.doc.Box1.Shape.cut(self.doc.Box2.Shape)
576
if cut.ElementMapVersion != "":
577
self.assertEqual(cut.ElementMapSize, 26)
579
def testTopoShapeGeneralFuse(self):
581
fuse = self.doc.Box1.Shape.generalFuse([self.doc.Box2.Shape])
584
self.assertEqual(len(fuse), 2)
585
if fuse[0].ElementMapVersion != "":
586
self.assertEqual(fuse[0].ElementMapSize, 60)
588
def testTopoShapeChildShapes(self):
590
childShapes = self.doc.Box1.Shape.childShapes()
593
self.assertEqual(len(childShapes), 1)
594
if childShapes[0].ElementMapVersion != "":
595
self.assertEqual(childShapes[0].ElementMapSize, 26)
597
def testTopoShapeMirror(self):
599
mirror = self.doc.Box1.Shape.mirror(App.Vector(), App.Vector(1, 0, 0))
602
if mirror.ElementMapVersion != "":
603
self.assertEqual(mirror.ElementMapSize, 26)
605
def testTopoShapeScale(self):
607
scale = self.doc.Box1.Shape.scaled(2)
610
if scale.ElementMapVersion != "":
611
self.assertEqual(scale.ElementMapSize, 26)
613
def testTopoShapeMakeFillet(self):
615
fillet = self.doc.Box1.Shape.makeFillet(0.1, self.doc.Box1.Shape.Faces[0].Edges)
618
if fillet.ElementMapVersion != "":
619
self.assertEqual(fillet.ElementMapSize, 42)
621
def testTopoShapeMakeChamfer(self):
623
chamfer = self.doc.Box1.Shape.makeChamfer(0.1, self.doc.Box1.Shape.Faces[0].Edges)
626
if chamfer.ElementMapVersion != "":
627
self.assertEqual(chamfer.ElementMapSize, 42)
629
def testTopoShapeMakeThickness(self):
631
thickness = self.doc.Box1.Shape.makeThickness(self.doc.Box1.Shape.Faces[0:2], 0.1, 0.0001)
634
if thickness.ElementMapVersion != "":
635
self.assertEqual(thickness.ElementMapSize, 74)
637
def testTopoShapeMakeOffsetShape(self):
639
offset = self.doc.Box1.Shape.Faces[0].makeOffset(1)
642
if offset.ElementMapVersion != "":
643
self.assertEqual(offset.ElementMapSize, 17)
645
def testTopoShapeOffset2D(self):
647
offset = self.doc.Box1.Shape.Faces[0].makeOffset2D(1)
650
if offset.ElementMapVersion != "":
651
self.assertEqual(offset.ElementMapSize, 17)
653
def testTopoShapeRemoveSplitter(self):
655
fused = self.doc.Box1.Shape.fuse(self.doc.Box2.Shape)
656
removed = fused.removeSplitter()
659
if removed.ElementMapVersion != "":
660
self.assertEqual(removed.ElementMapSize, 38)
662
def testTopoShapeCompSolid(self):
664
compSolid = Part.CompSolid([self.doc.Box1.Shape, self.doc.Box2.Shape])
665
box1ts = self.doc.Box1.Shape
666
compSolid.add(box1ts.Solids[0])
668
if compSolid.ElementMapVersion != "":
669
self.assertEqual(compSolid.ElementMapSize, 78)
671
def testTopoShapeFaceOffset(self):
673
box_toposhape = self.doc.Box1.Shape
675
offset = box_toposhape.Faces[0].makeOffset(2.0)
677
if box_toposhape.Faces[0].ElementMapVersion != "":
678
self.assertEqual(box_toposhape.Faces[0].ElementMapSize, 9)
679
self.assertEqual(offset.ElementMapSize, 17)
692
def testTopoShapePart(self):
694
box1ts = self.doc.Box1.Shape
695
face1 = box1ts.Faces[0]
696
box1ts2 = box1ts.copy()
698
face2 = box1ts.getElement("Face2")
699
indexed_name = box1ts.findSubShape(face1)
700
faces1 = box1ts.findSubShapesWithSharedVertex(face2)
701
subshapes1 = box1ts.getChildShapes("Solid1")
704
self.assertTrue(face2.isSame(box1ts.Faces[1]))
705
self.assertEqual(indexed_name[0], "Face")
706
self.assertEqual(indexed_name[1], 1)
707
self.assertEqual(len(faces1), 1)
708
self.assertTrue(faces1[0].isSame(box1ts.Faces[1]))
709
self.assertEqual(len(subshapes1), 1)
710
self.assertTrue(subshapes1[0].isSame(box1ts.Solids[0]))
712
def testTopoShapeMapSubElement(self):
714
box = Part.makeBox(1,2,3)
717
self.assertEqual(box.ElementMapSize,0)
718
self.assertEqual(box.Faces[0].ElementMapSize,0)
720
box.mapSubElement(box.Faces[0])
722
if box.ElementMapVersion != "":
723
self.assertEqual(box.ElementMapSize,9)
724
self.assertEqual(box.Faces[0].ElementMapSize,9)
726
def testTopoShapeGetElementHistory(self):
727
self.doc.addObject("Part::Fuse", "Fuse")
728
self.doc.Fuse.Base = self.doc.Box1
729
self.doc.Fuse.Tool = self.doc.Box2
732
fuse1 = self.doc.Fuse.Shape
733
if fuse1.ElementMapVersion != "":
734
history1 = fuse1.getElementHistory(fuse1.ElementReverseMap["Vertex1"])
736
self.assertEqual(len(history1),3)