# SPDX-License-Identifier: LGPL-2.1-or-later # *************************************************************************** # * * # * Copyright (c) 2024 bgbsww@gmail.com * # * * # * This file is part of FreeCAD. * # * * # * FreeCAD is free software: you can redistribute it and/or modify it * # * under the terms of the GNU Lesser General Public License as * # * published by the Free Software Foundation, either version 2.1 of the * # * License, or (at your option) any later version. * # * * # * FreeCAD is distributed in the hope that it will be useful, but * # * WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * # * Lesser General Public License for more details. * # * * # * You should have received a copy of the GNU Lesser General Public * # * License along with FreeCAD. If not, see * # * . * # * * # *************************************************************************** """ Tests related to the Topological Naming Problem """ import math import unittest import FreeCAD as App import Part import Sketcher import TestSketcherApp class TestTopologicalNamingProblem(unittest.TestCase): """Tests related to the Topological Naming Problem""" # pylint: disable=attribute-defined-outside-init def setUp(self): """Create a document for each test in the test suite""" self.Doc = App.newDocument("PartDesignTestTNP." + self._testMethodName) def countFacesEdgesVertexes(self, map): """Helper to return a tuple of the counts of Faces, Edges, and Vertexes in a map for easier test writing""" faces = [name for name in map.keys() if name.startswith("Face")] edges = [name for name in map.keys() if name.startswith("Edge")] vertexes = [name for name in map.keys() if name.startswith("Vertex")] return (len(faces), len(edges), len(vertexes)) def testPadsOnBaseObject(self): """Simple TNP test case By creating three Pads dependent on each other in succession, and then moving the middle one we can determine if the last one breaks because of a broken reference to the middle one. This is the essence of a TNP. Pretty much a duplicate of the steps at https://wiki.freecad.org/Topological_naming_problem""" # Arrange self.Body = self.Doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad self.PadSketch = self.Doc.addObject("Sketcher::SketchObject", "SketchPad") self.Body.addObject(self.PadSketch) TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (1, 1)) self.Doc.recompute() self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad") self.Body.addObject(self.Pad) self.Pad.Profile = self.PadSketch self.Pad.Length = 1 self.Doc.recompute() # Attach a second pad to the top of the first. self.PadSketch1 = self.Doc.addObject("Sketcher::SketchObject", "SketchPad1") self.Body.addObject(self.PadSketch1) self.PadSketch1.MapMode = "FlatFace" self.PadSketch1.AttachmentSupport = [(self.Doc.getObject("Pad"), "Face6")] TestSketcherApp.CreateRectangleSketch(self.PadSketch1, (0, 0), (1, 1)) self.Doc.recompute() self.Pad1 = self.Doc.addObject("PartDesign::Pad", "Pad1") self.Body.addObject(self.Pad1) self.Pad1.Profile = self.PadSketch1 self.Pad1.Length = 1 self.Doc.recompute() # Attach a third pad to the top of the second. self.PadSketch2 = self.Doc.addObject("Sketcher::SketchObject", "SketchPad2") self.Body.addObject(self.PadSketch2) self.PadSketch2.MapMode = "FlatFace" self.PadSketch2.AttachmentSupport = [(self.Doc.getObject("Pad1"), "Face6")] TestSketcherApp.CreateRectangleSketch(self.PadSketch2, (0, 0), (1, 1)) self.Doc.recompute() self.Pad2 = self.Doc.addObject("PartDesign::Pad", "Pad2") self.Body.addObject(self.Pad2) self.Pad2.Profile = self.PadSketch2 self.Pad2.Length = 1 self.Doc.recompute() # Assert everything is valid self.assertTrue(self.Pad.isValid()) self.assertTrue(self.Pad1.isValid()) self.assertTrue(self.Pad2.isValid()) # Act # Move the second pad ( the sketch attachment point ) self.PadSketch1.AttachmentOffset = App.Placement( App.Vector(0.5000000000, 0.0000000000, 0.0000000000), App.Rotation(0.0000000000, 0.0000000000, 0.0000000000), ) self.Doc.recompute() # Assert everything is still valid. self.assertTrue(self.Pad.isValid()) self.assertTrue(self.Pad1.isValid()) if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. self.assertFalse( self.Pad2.isValid() ) # TNP problem is present without ElementMaps else: self.assertTrue( self.Pad2.isValid() ) # TNP problem is not present with ElementMaps def testPartDesignElementMapSketch(self): """Test that creating a sketch results in a correct element map.""" # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "SketchPad") body.addObject(sketch) TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) # Act self.Doc.recompute() if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return reverseMap = sketch.Shape.ElementReverseMap reverseFaces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] # Assert self.assertEqual(sketch.Shape.ElementMapSize, 12) self.assertEqual(len(reverseMap), 8) self.assertEqual(len(reverseFaces), 0) self.assertEqual(len(edges), 4) self.assertEqual(len(vertexes), 4) def testPartDesignBasicFusion(self): """Test that a basic fusion creates an element map, and refine retains it""" # Arrange doc = self.Doc box1 = doc.addObject("Part::Box", "Box") if App.GuiUp: mat = App.Material() mat.AmbientColor = (128, 0, 0) box1.ViewObject.ShapeAppearance = ( mat # Change color ( material ) for at least one ) box2 = doc.addObject("Part::Box", "Box001") box3 = doc.addObject("Part::Box", "Box002") cyl1 = doc.addObject("Part::Cylinder", "Cylinder") fuse1 = doc.addObject("Part::MultiFuse", "Fusion") doc.Fusion.Shapes = [box1, box2] fuse2 = doc.addObject("Part::MultiFuse", "Fusion001") doc.Fusion001.Shapes = [box3, cyl1] doc.recompute() # Assert self.assertEqual(fuse1.Shape.ElementMapSize, 26) self.assertEqual(fuse2.Shape.ElementMapSize, 44) # Act doc.Fusion.Refine = True # activate refinement doc.Fusion001.Refine = True # activate refinement doc.recompute() self.assertEqual(fuse1.Shape.ElementMapSize, 26) self.assertEqual(fuse2.Shape.ElementMapSize, 44) def testPartDesignElementMapPad(self): """Test that padding a sketch results in a correct element map. Note that comprehensive testing of the geometric functionality of the Pad is in TestPad.py""" # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") padSketch = self.Doc.addObject("Sketcher::SketchObject", "SketchPad") pad = self.Doc.addObject("PartDesign::Pad", "Pad") body.addObject(padSketch) body.addObject(pad) TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (1, 1)) pad.Profile = padSketch pad.Length = 1 # Act self.Doc.recompute() if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return reverseMap = pad.Shape.ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] # Assert self.assertEqual(pad.Shape.ElementMapSize, 30) # 4 duplicated Vertexes in here self.assertEqual(len(reverseMap), 26) self.assertEqual(len(faces), 6) self.assertEqual(len(edges), 12) self.assertEqual(len(vertexes), 8) def testPartDesignElementMapBox(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(box.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(box.Shape.childShapes()), 1) self.assertEqual(box.Shape.childShapes()[0].ElementMapSize, 26) body.addObject(box) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 26) def testPartDesignElementMapCylinder(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") cylinder = self.Doc.addObject("PartDesign::AdditiveCylinder", "Cylinder") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(cylinder.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(cylinder.Shape.childShapes()), 1) self.assertEqual(cylinder.Shape.childShapes()[0].ElementMapSize, 8) body.addObject(cylinder) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 8) self.assertEqual(len(reverseMap), 8) self.assertEqual(len(faces), 3) self.assertEqual(len(edges), 3) self.assertEqual(len(vertexes), 2) def testPartDesignElementMapSphere(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sphere = self.Doc.addObject("PartDesign::AdditiveSphere", "Sphere") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(sphere.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(sphere.Shape.childShapes()), 1) self.assertEqual(sphere.Shape.childShapes()[0].ElementMapSize, 6) body.addObject(sphere) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 6) self.assertEqual(len(reverseMap), 6) self.assertEqual(len(faces), 1) self.assertEqual(len(edges), 3) self.assertEqual(len(vertexes), 2) def testPartDesignElementMapCone(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") cone = self.Doc.addObject("PartDesign::AdditiveCone", "Cone") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(cone.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(cone.Shape.childShapes()), 1) self.assertEqual(cone.Shape.childShapes()[0].ElementMapSize, 8) body.addObject(cone) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 8) self.assertEqual(len(reverseMap), 8) self.assertEqual(len(faces), 3) self.assertEqual(len(edges), 3) self.assertEqual(len(vertexes), 2) def testPartDesignElementMapEllipsoid(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") ellipsoid = self.Doc.addObject("PartDesign::AdditiveEllipsoid", "Ellipsoid") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(ellipsoid.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(ellipsoid.Shape.childShapes()), 1) self.assertEqual(ellipsoid.Shape.childShapes()[0].ElementMapSize, 6) body.addObject(ellipsoid) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 6) self.assertEqual(len(reverseMap), 6) self.assertEqual(len(faces), 1) self.assertEqual(len(edges), 3) self.assertEqual(len(vertexes), 2) def testPartDesignElementMapTorus(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") torus = self.Doc.addObject("PartDesign::AdditiveTorus", "Torus") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(torus.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(torus.Shape.childShapes()), 1) self.assertEqual(torus.Shape.childShapes()[0].ElementMapSize, 4) body.addObject(torus) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 4) self.assertEqual(len(reverseMap), 4) self.assertEqual(len(faces), 1) self.assertEqual(len(edges), 2) self.assertEqual(len(vertexes), 1) def testPartDesignElementMapPrism(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") prism = self.Doc.addObject("PartDesign::AdditivePrism", "Prism") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(prism.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(prism.Shape.childShapes()), 1) self.assertEqual(prism.Shape.childShapes()[0].ElementMapSize, 38) body.addObject(prism) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 38) self.assertEqual(len(reverseMap), 38) self.assertEqual(len(faces), 8) self.assertEqual(len(edges), 18) self.assertEqual(len(vertexes), 12) def testPartDesignElementMapWedge(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") wedge = self.Doc.addObject("PartDesign::AdditiveWedge", "Wedge") if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act / Assert self.assertEqual(len(wedge.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(wedge.Shape.childShapes()), 1) self.assertEqual(wedge.Shape.childShapes()[0].ElementMapSize, 26) body.addObject(wedge) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 26) self.assertEqual(len(reverseMap), 26) self.assertEqual(len(faces), 6) self.assertEqual(len(edges), 12) self.assertEqual(len(vertexes), 8) # body.BaseFeature = box def testPartDesignElementMapSubBox(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subbox = self.Doc.addObject("PartDesign::SubtractiveBox", "Box") subbox.BaseFeature = box body.addObject(subbox) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 44) def testPartDesignElementMapSubCylinder(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subcylinder = self.Doc.addObject("PartDesign::SubtractiveCylinder", "Cylinder") subcylinder.BaseFeature = box body.addObject(subcylinder) # Assert self.Doc.recompute() self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 38) def testPartDesignElementMapSubSphere(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subsphere = self.Doc.addObject("PartDesign::SubtractiveSphere", "Sphere") subsphere.BaseFeature = box body.addObject(subsphere) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 33) def testPartDesignElementMapSubCone(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subcone = self.Doc.addObject("PartDesign::SubtractiveCone", "Cone") subcone.BaseFeature = box body.addObject(subcone) # Assert self.Doc.recompute() self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 38) def testPartDesignElementMapSubEllipsoid(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subellipsoid = self.Doc.addObject( "PartDesign::SubtractiveEllipsoid", "Ellipsoid" ) subellipsoid.BaseFeature = box body.addObject(subellipsoid) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 33) def testPartDesignElementMapSubTorus(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subtorus = self.Doc.addObject("PartDesign::SubtractiveTorus", "Torus") subtorus.BaseFeature = box body.addObject(subtorus) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 38) def testPartDesignElementMapSubPrism(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subprism = self.Doc.addObject("PartDesign::SubtractivePrism", "Prism") subprism.BaseFeature = box body.addObject(subprism) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 44) def testPartDesignElementMapSubWedge(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") box.Length = 20 box.Width = 20 box.Height = 20 body.addObject(box) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act subwedge = self.Doc.addObject("PartDesign::SubtractiveWedge", "Wedge") subwedge.BaseFeature = box body.addObject(subwedge) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 50) def testPartDesignElementPadSketch(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act pad = self.Doc.addObject("PartDesign::Pad", "Pad") pad.Profile = sketch body.addObject(sketch) body.addObject(pad) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 30) # The pad self.assertEqual(body.Shape.ElementMapSize, 26) self.assertEqual(sketch.Shape.ElementMapSize, 12) self.assertEqual( pad.Shape.ElementMapSize, 30 ) # pad has the 26 plus the 4 original self.assertNotEqual( pad.Shape.ElementReverseMap["Vertex1"], "Vertex1" ) # NewName, not OldName self.assertEqual( self.countFacesEdgesVertexes(pad.Shape.ElementReverseMap), (6, 12, 8) ) # Todo: Offer a way to turn on hashing and check that with a # starting # Pad -> Extrusion -> makes compounds and does booleans, thus the resulting newName element maps # See if we can turn those off, or try them on the other types? def testPartDesignElementMapRevolution(self): # App.KeepTestDoc = True # Uncomment this if you want to keep the test document to examine self.Doc.UseHasher = False # Arrange body = self.Doc.addObject('PartDesign::Body', 'Body') sketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch') TestSketcherApp.CreateRectangleSketch(sketch, (0, 1), (3, 2)) # (pt), (w,l) body.addObject(sketch) self.Doc.recompute() pad = self.Doc.addObject('PartDesign::Pad', 'Pad') pad.Profile = sketch pad.Length = 3 body.addObject(pad) self.Doc.recompute() sketch2 = self.Doc.addObject('Sketcher::SketchObject', 'Sketch001') TestSketcherApp.CreateRectangleSketch(sketch2, (2, -3), (1, 2)) # (pt), (w,l) sketch2.AttachmentSupport = (pad, ["Face5"]) sketch2.MapMode = 'FlatFace' body.addObject(sketch2) self.Doc.recompute() revolution = self.Doc.addObject('PartDesign::Revolution', 'Revolution') revolution.ReferenceAxis = (sketch2, ['V_Axis']) revolution.Reversed = 1 revolution.Profile = sketch2 revolution.Angle=180 revolution.Refine = True body.addObject(revolution) volume = (math.pi * 3 * 3 - math.pi * 2 * 2) * 2 / 2 padVolume = 3 * 3 * 2 # 50.26548245743668 # Act self.Doc.recompute() # Assert the Shape is correct self.assertEqual(len(body.Shape.childShapes()), 1) self.assertAlmostEqual(pad.Shape.Volume, padVolume) self.assertAlmostEqual(revolution.Shape.Volume, volume + padVolume) # Assert the element map is correct self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 46) self.assertEqual(revolution.Shape.ElementMapSize, 46) self.assertEqual(self.countFacesEdgesVertexes(revolution.Shape.ElementReverseMap), (9, 21, 14)) self.assertEqual( revolution.Shape.ElementReverseMap["Vertex9"][1].count(";"), 3) self.assertEqual( revolution.Shape.ElementReverseMap["Face9"].count(";"), 16) # Arrange for an UpToFace mode test revolution.Type = 3 revolution.UpToFace = (pad, ("Face4")) revolution.Reversed = 1 revolution.Midplane = 0 volume = (math.pi * 3 * 3 - math.pi * 2 * 2) * 2 / 4 * 3 # Act self.Doc.recompute() # Assert UpToFace shape is correct self.assertAlmostEqual(revolution.Shape.Volume, volume + padVolume) # Assert UpToFace element map is correct self.assertEqual(self.countFacesEdgesVertexes(revolution.Shape.ElementReverseMap), (8, 18, 12)) # Assertions modified/added while reviewing PR#17119 by CalligaroV # Previously the condition counted the number of ";" (element map operations prefix) # If the number of operations changes then the number of ";" will change accordingly # # However, it is more useful to count the number of times an elemement name is # present in the MappedName of an element (a MappedName is definined also using the # element names - "Vertex*", "Edge*", "Face*" - used by an OCCT operation to generate # output elements) self.assertEqual( revolution.Shape.ElementReverseMap["Face8"].count("Face8"), 3) self.assertEqual( revolution.Shape.ElementReverseMap["Face8"].count("Face10"), 3) def testPartDesignBinderRevolution(self): doc = self.Doc body = doc.addObject('PartDesign::Body', 'Body') sketch = body.newObject('Sketcher::SketchObject', 'Sketch') sketch.AttachmentSupport = (doc.getObject('XY_Plane'), ['']) sketch.MapMode = 'FlatFace' doc.recompute() geoList = [] geoList.append(Part.LineSegment(App.Vector(-44.107212, 34.404858, 0.000000), App.Vector(-44.107212, 9.881049, 0.000000))) geoList.append(Part.LineSegment(App.Vector(-44.107212, 9.881049, 0.0000000), App.Vector(-10.297691, 9.881049, 0.000000))) geoList.append(Part.LineSegment(App.Vector(-10.297691, 9.881049, 0.0000000), App.Vector(-10.297691, 34.404858, 0.00000))) geoList.append(Part.LineSegment(App.Vector(-10.297691, 34.404858, 0.000000), App.Vector(-44.107212, 34.404858, 0.00000))) sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint('Coincident', 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint('Coincident', 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint('Coincident', 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint('Coincident', 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint('Vertical', 0)) constraintList.append(Sketcher.Constraint('Vertical', 2)) constraintList.append(Sketcher.Constraint('Horizontal', 1)) constraintList.append(Sketcher.Constraint('Horizontal', 3)) sketch.addConstraint(constraintList) del constraintList doc.recompute() binder = body.newObject('PartDesign::ShapeBinder','ShapeBinder') binder.Support = [sketch, (''),] binder.Visibility = False doc.recompute() revolve = body.newObject('PartDesign::Revolution','Revolution') revolve.Profile = (doc.getObject('ShapeBinder'), ['',]) revolve.ReferenceAxis = (doc.getObject('Y_Axis'), ['']) revolve.Angle = 360.0 doc.recompute() self.assertTrue(revolve.isValid()) def testPartDesignElementMapLoft(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) sketch2 = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch2, (0, 0), (2, 2)) sketch2.Placement.move(App.Vector(0, 0, 3)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act loft = self.Doc.addObject("PartDesign::AdditiveLoft", "Loft") loft.Profile = sketch loft.Sections = [sketch2] body.addObject(sketch) body.addObject(sketch2) body.addObject(loft) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) # 6 face 12 edge 8 vertexes = 26 # 4 edges are duplicated (the originals from the sketch loft profile, and then those in the loft) # 4 vertexes are quad dups for 12 more. 26 + 4 + 12 = 42 # self.assertEqual(body.Shape.ElementMapSize, 42) revMap = body.Shape.ElementReverseMap self.assertNotEqual(loft.Shape.ElementReverseMap["Vertex1"], "Vertex1") self.assertNotEqual(revMap["Vertex1"], "Vertex1") self.assertEqual( self.countFacesEdgesVertexes(loft.Shape.ElementReverseMap), (6, 12, 8) ) volume = 7.0 self.assertAlmostEqual(loft.Shape.Volume, volume) def testPartDesignElementMapPipe(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) sketch2 = self.Doc.addObject("Sketcher::SketchObject", "Sketch001") sketch2.AttachmentSupport = (self.Doc.getObject("XZ_Plane"), [""]) sketch2.addGeometry(Part.LineSegment(App.Vector(0, 0, 0), App.Vector(0, 1, 0))) sketch2.Placement = App.Placement( App.Vector(0, 0, 0), App.Rotation(App.Vector(1.00, 0.00, 0.00), 90.00) ) # Need to set sketch2 placement? if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act pipe = self.Doc.addObject("PartDesign::AdditivePipe", "Pipe") pipe.Profile = sketch pipe.Spine = sketch2 body.addObject(sketch) body.addObject(sketch2) body.addObject(pipe) self.Doc.recompute() # Assert self.assertAlmostEqual(body.Shape.Volume, 1) self.assertAlmostEqual(body.Shape.BoundBox.XMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.YMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.ZMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.XMax, 1) self.assertAlmostEqual(body.Shape.BoundBox.YMax, 1) self.assertAlmostEqual(body.Shape.BoundBox.ZMax, 1) self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 26) revMap = body.Shape.childShapes()[0].ElementReverseMap # revMap = pipe.Shape.ElementReverseMap # TODO: This is a child of the body and not the actual Pipe. # 1: is that okay and normal, or should the pipe have an element map self.assertEqual(self.countFacesEdgesVertexes(revMap), (6, 12, 8)) def testPartDesignElementMapHelix(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act helix = self.Doc.addObject("PartDesign::AdditiveHelix", "Helix") helix.Profile = sketch helix.ReferenceAxis = (self.Doc.getObject("Sketch"), ["N_Axis"]) # helix.Mode = 0 body.addObject(sketch) body.addObject(helix) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertGreaterEqual(body.Shape.childShapes()[0].ElementMapSize, 26) revMap = body.Shape.childShapes()[0].ElementReverseMap self.assertEqual(self.countFacesEdgesVertexes(revMap), (14, 28, 16)) Radius = 0 # Rectangle is on the axis, but wouldn't matter regardless here Area = Part.Face(sketch.Shape).Area # General helix formula; not actually used here since devolves to just the # height in this orientation. helixLength = ( helix.Height.Value / helix.Pitch.Value * math.sqrt((math.pi * Radius) ** 2 + helix.Pitch.Value**2) ) Volume = Area * helixLength self.assertAlmostEqual(Area, 1) self.assertAlmostEqual(helixLength, helix.Height.Value) self.assertAlmostEqual(helix.Shape.Volume, Volume, 2) self.assertEqual(body.Shape.ElementMapSize, 58) def testPartDesignElementMapPocket(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") sketch.AttachmentSupport = (box, "Face6") sketch.MapMode = "FlatFace" TestSketcherApp.CreateRectangleSketch(sketch, (1, 1), (1, 1)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act pocket = self.Doc.addObject("PartDesign::Pocket", "Pocket") pocket.Profile = sketch pocket.Length = 5 pocket.Direction = (0, 0, -1) pocket.ReferenceAxis = (sketch, ["N_Axis"]) pocket.Refine = True body.addObject(sketch) body.addObject(pocket) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 51) self.assertEqual(body.Shape.ElementMapSize, 51) self.assertEqual(sketch.Shape.ElementMapSize, 12) self.assertEqual(pocket.Shape.ElementMapSize, 51) self.assertNotEqual( pocket.Shape.ElementReverseMap["Vertex1"], "Vertex1" ) # NewName, not OldName self.assertEqual( self.countFacesEdgesVertexes(pocket.Shape.ElementReverseMap), (11, 24, 16) ) volume = 1000 - 5 * 1 * 1 self.assertAlmostEqual(pocket.Shape.Volume, volume) def testPartDesignElementMapHole(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") sketch.AttachmentSupport = (box, "Face6") sketch.MapMode = "FlatFace" TestSketcherApp.CreateCircleSketch(sketch, (5, 5), 1) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act hole = self.Doc.addObject("PartDesign::Hole", "Hole") hole.Profile = sketch body.addObject(sketch) body.addObject(hole) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 32) self.assertEqual(body.Shape.ElementMapSize, 32) self.assertEqual(sketch.Shape.ElementMapSize, 2) self.assertEqual(hole.Shape.ElementMapSize, 32) # self.assertNotEqual(hole.Shape.ElementReverseMap['Vertex1'],"Vertex1") # NewName, not OldName self.assertEqual( self.countFacesEdgesVertexes(hole.Shape.ElementReverseMap), (7, 15, 10) ) volume = 1000 - 10 * math.pi * 3 * 3 self.assertAlmostEqual(hole.Shape.Volume, volume) def testPartDesignElementMapGroove(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) groove = self.Doc.addObject("PartDesign::Groove", "Groove") body.addObject(groove) groove.ReferenceAxis = (self.Doc.getObject("Y_Axis"), [""]) groove.Angle = 360.0 groove.Profile = (box, ["Face6"]) groove.ReferenceAxis = (box, ["Edge9"]) groove.Midplane = 0 groove.Reversed = 0 groove.Base = App.Vector(0, 0, 0) self.Doc.recompute() if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Assert revMap = ( groove.Shape.ElementReverseMap ) # body.Shape.childShapes()[0].ElementReverseMap self.assertEqual(self.countFacesEdgesVertexes(revMap), (5, 9, 6)) volume = 785.3981633974482 # TODO: math formula to calc this. Maybe make a sketch as the Profile. self.assertAlmostEqual(groove.Shape.Volume, volume) def testPartDesignElementMapSubLoft(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (1, 1), (1, 1)) sketch2 = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch2, (1, 1), (2, 2)) sketch2.Placement.move(App.Vector(0, 0, 3)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act loft = self.Doc.addObject("PartDesign::SubtractiveLoft", "SubLoft") loft.Profile = sketch loft.Sections = [sketch2] body.addObject(loft) self.Doc.recompute() if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Assert revMap = ( loft.Shape.ElementReverseMap ) # body.Shape.childShapes()[0].ElementReverseMap self.assertEqual(self.countFacesEdgesVertexes(revMap), (11, 24, 16)) volume = 993 # TODO: math formula to calc this. self.assertAlmostEqual(loft.Shape.Volume, volume) def testPartDesignElementMapSubPipe(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) sketch2 = self.Doc.addObject("Sketcher::SketchObject", "Sketch001") sketch2.AttachmentSupport = (self.Doc.getObject("XZ_Plane"), [""]) sketch2.addGeometry(Part.LineSegment(App.Vector(0, 0, 0), App.Vector(0, 1, 0))) sketch2.Placement = App.Placement( App.Vector(0, 0, 0), App.Rotation(App.Vector(1.00, 0.00, 0.00), 90.00) ) # Need to set sketch2 placement? if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act pipe = self.Doc.addObject("PartDesign::SubtractivePipe", "SubPipe") pipe.Profile = sketch pipe.Spine = sketch2 body.addObject(sketch) body.addObject(sketch2) body.addObject(pipe) self.Doc.recompute() # Assert self.assertAlmostEqual(body.Shape.Volume, 999) self.assertAlmostEqual(body.Shape.BoundBox.XMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.YMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.ZMin, 0) self.assertAlmostEqual(body.Shape.BoundBox.XMax, 10) self.assertAlmostEqual(body.Shape.BoundBox.YMax, 10) self.assertAlmostEqual(body.Shape.BoundBox.ZMax, 10) self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 44) revMap = body.Shape.ElementReverseMap # self.assertEqual(self.countFacesEdgesVertexes(revMap), (9, 21, 14)) def testPartDesignElementMapSubHelix(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (5, 5), (1, 1)) if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Act helix = self.Doc.addObject("PartDesign::SubtractiveHelix", "SubHelix") helix.Profile = sketch helix.ReferenceAxis = (self.Doc.getObject("Sketch"), ["V_Axis"]) helix.Reversed = True body.addObject(sketch) body.addObject(helix) self.Doc.recompute() # Assert self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 50) revMap = body.Shape.childShapes()[0].ElementReverseMap self.assertEqual(self.countFacesEdgesVertexes(revMap), (10, 24, 16)) volume = 991.3606 # TODO: math formula to calc this. self.assertAlmostEqual(helix.Shape.Volume, volume, 4) def testPartDesignElementMapChamfer(self): """Test Chamfer ( and FeatureDressup )""" # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") if body.Shape.ElementMapVersion == "": # Skip without element maps. return chamfer = self.Doc.addObject("PartDesign::Chamfer", "Chamfer") chamfer.Base = ( box, [ "Edge1", "Edge2", "Edge3", "Edge4", "Edge5", "Edge6", "Edge7", "Edge8", "Edge9", "Edge10", "Edge11", "Edge12", ], ) chamfer.Size = 1 chamfer.UseAllEdges = True # Act / Assert body.addObject(box) body.addObject(chamfer) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 98) self.assertEqual(len(reverseMap), 98) self.assertEqual(len(faces), 26) # 6 Faces become 26 ( +8 + 2*6 ) self.assertEqual(len(edges), 48) # 12 Edges become 48 self.assertEqual(len(vertexes), 24) # 8 Vertices become 24 def testPartDesignElementMapFillet(self): """Test Fillet ( and FeatureDressup )""" # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") if body.Shape.ElementMapVersion == "": # Skip without element maps. return fillet = self.Doc.addObject("PartDesign::Fillet", "Fillet") fillet.Base = ( box, [ "Edge1", "Edge2", "Edge3", "Edge4", "Edge5", "Edge6", "Edge7", "Edge8", "Edge9", "Edge10", "Edge11", "Edge12", ], ) # Act / Assert body.addObject(box) body.addObject(fillet) self.Doc.recompute() reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 106) self.assertEqual(len(reverseMap), 106) self.assertEqual(len(faces), 26) # 6 Faces become 26 ( +8 + 2*6 ) self.assertEqual(len(edges), 56) # 12 Edges become 56 Why? self.assertEqual(len(vertexes), 24) # 8 Vertices become 24 def testPartDesignElementMapTransform(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") if body.Shape.ElementMapVersion == "": # Skip without element maps. return multitransform = self.Doc.addObject( "PartDesign::MultiTransform", "MultiTransform" ) scaled = self.Doc.addObject("PartDesign::Scaled", "Scaled") scaled.Factor = 2 scaled.Occurrences = 2 multitransform.Transformations = scaled multitransform.Shape = box.Shape # Act / Assert self.Doc.recompute() body.addObject(box) body.addObject(multitransform) self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 26) def testPartDesignElementMapShapeBinder(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") shapebinder = self.Doc.addObject("PartDesign::ShapeBinder", "ShapeBinder") if body.Shape.ElementMapVersion == "": # Skip without element maps. return # Act / Assert body.addObject(box) body.addObject(shapebinder) shapebinder.Support = [box] self.Doc.recompute() self.assertEqual(len(shapebinder.Shape.childShapes()), 1) self.assertEqual(shapebinder.Shape.childShapes()[0].ElementMapSize, 26) def testPartDesignElementMapSubShapeBinder(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") subshapebinder = self.Doc.addObject( "PartDesign::SubShapeBinder", "SubShapeBinder" ) if body.Shape.ElementMapVersion == "": # Skip without element maps. return # Act / Assert body.addObject(box) body.addObject(subshapebinder) subshapebinder.Support = [(box, ["Face1"])] self.assertEqual(len(body.Shape.childShapes()), 0) self.Doc.recompute() self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(subshapebinder.Shape.childShapes()[0].ElementMapSize, 9) def testSketchElementMap(self): body = self.Doc.addObject("PartDesign::Body", "Body") sketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1)) body.addObject(sketch) self.Doc.recompute() self.assertEqual(sketch.Shape.ElementMapSize, 12) pad = self.Doc.addObject("PartDesign::Pad", "Pad") pad.Profile = sketch body.addObject(pad) self.Doc.recompute() if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Assert self.assertEqual(sketch.Shape.ElementMapSize, 12) self.assertEqual( pad.Shape.ElementMapSize, 30 ) # The sketch plus the pad in the map # TODO: differing results between main and LS3 on these values. Does it matter? # self.assertEqual(body.Shape.ElementMapSize,0) # 8? # self.assertEqual(body.Shape.ElementMapSize,30) # 26 def testPlaneElementMap(self): plane = self.Doc.addObject("Part::Plane", "Plane") plane.Length = 10 plane.Width = 10 self.Doc.recompute() self.assertEqual(plane.Shape.ElementMapSize, 0) pad = self.Doc.addObject("PartDesign::Pad", "Pad") pad.Profile = plane self.Doc.recompute() if pad.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return # Assert self.assertEqual(plane.Shape.ElementMapSize, 0) self.assertEqual(pad.Shape.ElementMapSize, 26) def testChangeSketch(self): # Arrange doc = self.Doc body = doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad padSketch = doc.addObject("Sketcher::SketchObject", "Sketch") body.addObject(padSketch) TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (31.37, 25.2)) doc.recompute() pad = doc.addObject("PartDesign::Pad", "Pad") body.addObject(pad) pad.Profile = padSketch pad.Length = 10 doc.recompute() sketch001 = body.newObject("Sketcher::SketchObject", "Sketch001") sketch001 = doc.Sketch001 sketch001.AttachmentSupport = ( doc.getObject("Pad"), [ "Face6", ], ) sketch001.MapMode = "FlatFace" App.ActiveDocument.recompute() geoList = [] geoList.append( Part.Circle( App.Vector(15.093666, 13.036922, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 5.000000, ) ) sketch001.addGeometry(geoList, False) del geoList sketch001.addConstraint(Sketcher.Constraint("Radius", 0, 5.000000)) doc.recompute() pad001 = body.newObject("PartDesign::Pad", "Pad001") pad001.Profile = doc.getObject("Sketch001") pad001.Length = 10 App.ActiveDocument.recompute() pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) sketch001.Visibility = False App.ActiveDocument.recompute() pad001.Length = 10.000000 pad001.TaperAngle = 0.000000 pad001.UseCustomVector = 0 pad001.Direction = (0, 0, 1) pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) pad001.AlongSketchNormal = 1 pad001.Type = 0 pad001.UpToFace = None pad001.Reversed = 0 pad001.Midplane = 0 pad001.Offset = 0 doc.recompute() doc.getObject("Pad").Visibility = False doc.getObject("Sketch001").Visibility = False # Modify the original sketch to generate TNP issue geoList = [] geoList.append( Part.LineSegment( App.Vector(2.510468, 22.837425, 0.000000), App.Vector(2.510468, 19.933617, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(2.510468, 19.933617, 0.000000), App.Vector(4.869811, 19.933617, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(4.869811, 19.933617, 0.000000), App.Vector(4.869811, 22.837425, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(4.869811, 22.837425, 0.000000), App.Vector(2.510468, 22.837425, 0.000000), ) ) padSketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 4, 2, 5, 1)) constraintList.append(Sketcher.Constraint("Coincident", 5, 2, 6, 1)) constraintList.append(Sketcher.Constraint("Coincident", 6, 2, 7, 1)) constraintList.append(Sketcher.Constraint("Coincident", 7, 2, 4, 1)) constraintList.append(Sketcher.Constraint("Vertical", 4)) constraintList.append(Sketcher.Constraint("Vertical", 6)) constraintList.append(Sketcher.Constraint("Horizontal", 5)) constraintList.append(Sketcher.Constraint("Horizontal", 7)) padSketch.addConstraint(constraintList) del constraintList doc.recompute() # Assert if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return self.assertEqual(body.Shape.BoundBox.XMin, 0) self.assertEqual(body.Shape.BoundBox.YMin, 0) self.assertEqual(body.Shape.BoundBox.ZMin, 0) self.assertEqual(body.Shape.BoundBox.XMax, 31.37) self.assertEqual(body.Shape.BoundBox.YMax, 25.2) self.assertEqual(body.Shape.BoundBox.ZMax, 20) def testApplyFillet(self): # Arrange doc = self.Doc body = doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad padSketch = doc.addObject("Sketcher::SketchObject", "Sketch") body.addObject(padSketch) TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (31.37, 25.2)) doc.recompute() pad = doc.addObject("PartDesign::Pad", "Pad") body.addObject(pad) pad.Profile = padSketch pad.Length = 10 doc.recompute() sketch001 = body.newObject("Sketcher::SketchObject", "Sketch001") sketch001.AttachmentSupport = ( doc.getObject("Pad"), [ "Face6", ], ) sketch001.MapMode = "FlatFace" geoList = [] geoList.append( Part.Circle( App.Vector(15.093666, 13.036922, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 5.000000, ) ) sketch001.addGeometry(geoList, False) del geoList sketch001.addConstraint(Sketcher.Constraint("Radius", 0, 5.000000)) doc.recompute() pad001 = body.newObject("PartDesign::Pad", "Pad001") pad001.Profile = doc.getObject("Sketch001") pad001.Length = 10 App.ActiveDocument.recompute() pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) sketch001.Visibility = False App.ActiveDocument.recompute() pad001.Length = 10.000000 pad001.TaperAngle = 0.000000 pad001.UseCustomVector = 0 pad001.Direction = (0, 0, 1) pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) pad001.AlongSketchNormal = 1 pad001.Type = 0 pad001.UpToFace = None pad001.Reversed = 0 pad001.Midplane = 0 pad001.Offset = 0 doc.recompute() doc.getObject("Pad").Visibility = False doc.getObject("Sketch001").Visibility = False area1 = pad.Shape.Area # Act doc.getObject("Sketch").fillet( 2, 3, App.Vector(6.673934, 25.000000, 0), App.Vector(0.000000, 21.980343, 0), 4.740471, True, True, False, ) doc.recompute() area2 = pad.Shape.Area # Assert if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return self.assertEqual(body.Shape.BoundBox.XMin, 0) self.assertEqual(body.Shape.BoundBox.YMin, 0) self.assertEqual(body.Shape.BoundBox.ZMin, 0) self.assertEqual(body.Shape.BoundBox.XMax, 31.37) self.assertAlmostEqual(body.Shape.BoundBox.YMax, 25.2) self.assertEqual(body.Shape.BoundBox.ZMax, 20) self.assertNotEqual(area1, area2) def testShapeBinder(self): doc = self.Doc self.Body = doc.addObject("PartDesign::Body", "TNP_Test_Body_SubShape") doc.getObject("TNP_Test_Body_SubShape").Label = "TNP_Test_Body_SubShape" doc.recompute() doc.getObject("TNP_Test_Body_SubShape").newObject( "Sketcher::SketchObject", "Sketch" ) doc.Sketch.AttachmentSupport = (doc.getObject("XY_Plane"), [""]) doc.Sketch.MapMode = "FlatFace" doc.recompute() geoList = [] geoList.append( Part.LineSegment( App.Vector(0.000000, 0.000000, 0.000000), App.Vector(35.000000, 0.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(35.000000, 0.000000, 0.000000), App.Vector(35.000000, 25.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(35.000000, 25.000000, 0.000000), App.Vector(0.000000, 25.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(0.000000, 25.000000, 0.000000), App.Vector(0.000000, 0.000000, 0.000000), ) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Horizontal", 0)) constraintList.append(Sketcher.Constraint("Horizontal", 2)) constraintList.append(Sketcher.Constraint("Vertical", 1)) constraintList.append(Sketcher.Constraint("Vertical", 3)) doc.Sketch.addConstraint(constraintList) del constraintList doc.Sketch.addConstraint(Sketcher.Constraint("Distance", 1, 1, 3, 2, 35.000000)) doc.Sketch.addConstraint(Sketcher.Constraint("Distance", 0, 1, 2, 2, 25.000000)) doc.Sketch.addConstraint(Sketcher.Constraint("Coincident", 0, 1, -1, 1)) doc.recompute() doc.getObject("TNP_Test_Body_SubShape").newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = doc.Sketch doc.Pad.Length = 10 doc.recompute() doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.recompute() doc.Pad.Length = 10.000000 doc.Pad.TaperAngle = 0.000000 doc.Pad.UseCustomVector = 0 doc.Pad.Direction = (0, 0, 1) doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Pad.AlongSketchNormal = 1 doc.Pad.Type = 0 doc.Pad.UpToFace = None doc.Pad.Reversed = 0 doc.Pad.Midplane = 0 doc.Pad.Offset = 0 doc.recompute() doc.Sketch.Visibility = False doc.addObject("PartDesign::Body", "TNP_Test_Body_Second") doc.getObject("TNP_Test_Body_Second").Label = "TNP_Test_Body_Second" doc.recompute() obj = doc.getObject("TNP_Test_Body_Second").newObject( "PartDesign::ShapeBinder", "ShapeBinder" ) obj.Support = (doc.getObject("TNP_Test_Body_SubShape"), ["Face6"]) doc.recompute() doc.getObject("TNP_Test_Body_Second").newObject( "Sketcher::SketchObject", "Sketch001" ) doc.getObject("Sketch001").AttachmentSupport = ( doc.getObject("ShapeBinder"), [""], ) doc.getObject("Sketch001").MapMode = "FlatFace" doc.recompute() geoList = [] geoList.append( Part.Circle( App.Vector(14.725412, 16.666899, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 2.162720, ) ) doc.getObject("Sketch001").addGeometry(geoList, False) del geoList doc.recompute() doc.getObject("TNP_Test_Body_Second").newObject("PartDesign::Pad", "Pad001") doc.getObject("Pad001").Profile = doc.getObject("Sketch001") doc.getObject("Pad001").Length = 10 doc.recompute() doc.getObject("Pad001").ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) doc.getObject("Sketch001").Visibility = False doc.recompute() doc.getObject("Pad001").Length = 10.000000 doc.getObject("Pad001").TaperAngle = 0.000000 doc.getObject("Pad001").UseCustomVector = 0 doc.getObject("Pad001").Direction = (0, 0, 1) doc.getObject("Pad001").ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) doc.getObject("Pad001").AlongSketchNormal = 1 doc.getObject("Pad001").Type = 0 doc.getObject("Pad001").UpToFace = None doc.getObject("Pad001").Reversed = 0 doc.getObject("Pad001").Midplane = 0 doc.getObject("Pad001").Offset = 0 doc.recompute() doc.getObject("ShapeBinder").Visibility = False doc.getObject("Sketch001").Visibility = False geoList = [] geoList.append( Part.LineSegment( App.Vector(28.380075, 21.486303, 0.000000), App.Vector(28.380075, 15.462212, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(28.380075, 15.462212, 0.000000), App.Vector(32.797741, 15.462212, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(32.797741, 15.462212, 0.000000), App.Vector(32.797741, 21.486303, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(32.797741, 21.486303, 0.000000), App.Vector(28.380075, 21.486303, 0.000000), ) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 4, 2, 5, 1)) constraintList.append(Sketcher.Constraint("Coincident", 5, 2, 6, 1)) constraintList.append(Sketcher.Constraint("Coincident", 6, 2, 7, 1)) constraintList.append(Sketcher.Constraint("Coincident", 7, 2, 4, 1)) constraintList.append(Sketcher.Constraint("Vertical", 4)) constraintList.append(Sketcher.Constraint("Vertical", 6)) constraintList.append(Sketcher.Constraint("Horizontal", 5)) constraintList.append(Sketcher.Constraint("Horizontal", 7)) doc.Sketch.addConstraint(constraintList) del constraintList doc.recompute() # Assert if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return self.assertEqual(self.Body.Shape.BoundBox.XMin, 0) self.assertEqual(self.Body.Shape.BoundBox.YMin, 0) self.assertEqual(self.Body.Shape.BoundBox.ZMin, 0) self.assertEqual(self.Body.Shape.BoundBox.XMax, 35) self.assertEqual(self.Body.Shape.BoundBox.YMax, 25) self.assertEqual(self.Body.Shape.BoundBox.ZMax, 10) def testSubShapeBinder(self): doc = self.Doc self.Body = doc.addObject("PartDesign::Body", "Body") doc.Body.Label = "Body" doc.recompute() doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (doc.getObject("XY_Plane"), [""]) doc.Sketch.MapMode = "FlatFace" doc.recompute() geoList = [] geoList.append( Part.LineSegment( App.Vector(0.000000, 0.000000, 0.000000), App.Vector(35.000000, 0.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(35.000000, 0.000000, 0.000000), App.Vector(35.000000, 25.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(35.000000, 25.000000, 0.000000), App.Vector(0.000000, 25.000000, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(0.000000, 25.000000, 0.000000), App.Vector(0.000000, 0.000000, 0.000000), ) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Horizontal", 0)) constraintList.append(Sketcher.Constraint("Horizontal", 2)) constraintList.append(Sketcher.Constraint("Vertical", 1)) constraintList.append(Sketcher.Constraint("Vertical", 3)) doc.Sketch.addConstraint(constraintList) del constraintList doc.Sketch.addConstraint(Sketcher.Constraint("Distance", 1, 1, 3, 2, 35.000000)) doc.Sketch.addConstraint(Sketcher.Constraint("Distance", 0, 1, 2, 2, 25.000000)) doc.Sketch.addConstraint(Sketcher.Constraint("Coincident", 0, 1, -1, 1)) doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = doc.Sketch doc.Pad.Length = 10 doc.recompute() doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.Pad.Length = 10.000000 doc.Pad.TaperAngle = 0.000000 doc.Pad.UseCustomVector = 0 doc.Pad.Direction = (0, 0, 1) doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Pad.AlongSketchNormal = 1 doc.Pad.Type = 0 doc.Pad.UpToFace = None doc.Pad.Reversed = 0 doc.Pad.Midplane = 0 doc.Pad.Offset = 0 doc.recompute() doc.Sketch.Visibility = False doc.addObject("PartDesign::Body", "Body001") doc.getObject("Body001").Label = "Body" doc.recompute() binder = doc.getObject("Body001").newObject( "PartDesign::SubShapeBinder", "Binder" ) binder.Support = self.Body doc.getObject("Body001").newObject("Sketcher::SketchObject", "Sketch001") doc.getObject("Sketch001").AttachmentSupport = ( doc.getObject("Binder"), [ "Face6", ], ) doc.getObject("Sketch001").MapMode = "FlatFace" doc.recompute() geoList = [] geoList.append( Part.Circle( App.Vector(16.566162, 13.537925, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 2.197371, ) ) doc.getObject("Sketch001").addGeometry(geoList, False) del geoList doc.recompute() ### Begin command PartDesign_Pad doc.getObject("Body001").newObject("PartDesign::Pad", "Pad001") doc.Pad001.Profile = doc.getObject("Sketch001") doc.Pad001.Length = 10 doc.recompute() doc.Pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) doc.getObject("Sketch001").Visibility = False doc.recompute() doc.Pad001.Length = 10.000000 doc.Pad001.TaperAngle = 0.000000 doc.Pad001.UseCustomVector = 0 doc.Pad001.Direction = (0, 0, 1) doc.Pad001.ReferenceAxis = (doc.getObject("Sketch001"), ["N_Axis"]) doc.Pad001.AlongSketchNormal = 1 doc.Pad001.Type = 0 doc.Pad001.UpToFace = None doc.Pad001.Reversed = 0 doc.Pad001.Midplane = 0 doc.Pad001.Offset = 0 doc.recompute() doc.getObject("Binder").Visibility = False doc.getObject("Sketch001").Visibility = False geoList = [] geoList.append( Part.LineSegment( App.Vector(30.009926, 21.026653, 0.000000), App.Vector(30.009926, 16.425089, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(30.009926, 16.425089, 0.000000), App.Vector(31.994911, 16.425089, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(31.994911, 16.425089, 0.000000), App.Vector(31.994911, 21.026653, 0.000000), ) ) geoList.append( Part.LineSegment( App.Vector(31.994911, 21.026653, 0.000000), App.Vector(30.009926, 21.026653, 0.000000), ) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 4, 2, 5, 1)) constraintList.append(Sketcher.Constraint("Coincident", 5, 2, 6, 1)) constraintList.append(Sketcher.Constraint("Coincident", 6, 2, 7, 1)) constraintList.append(Sketcher.Constraint("Coincident", 7, 2, 4, 1)) constraintList.append(Sketcher.Constraint("Vertical", 4)) constraintList.append(Sketcher.Constraint("Vertical", 6)) constraintList.append(Sketcher.Constraint("Horizontal", 5)) constraintList.append(Sketcher.Constraint("Horizontal", 7)) doc.Sketch.addConstraint(constraintList) del constraintList doc.recompute() # Assert if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return self.assertEqual(self.Body.Shape.BoundBox.XMin, 0) self.assertEqual(self.Body.Shape.BoundBox.YMin, 0) self.assertEqual(self.Body.Shape.BoundBox.ZMin, 0) self.assertEqual(self.Body.Shape.BoundBox.XMax, 35) self.assertEqual(self.Body.Shape.BoundBox.YMax, 25) self.assertEqual(self.Body.Shape.BoundBox.ZMax, 10) def testPartDesignTNPChamfer(self): """Test Chamfer""" # Arrange doc = self.Doc body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) self.Doc.recompute() volume1 = body.Shape.Volume chamfer = self.Doc.addObject("PartDesign::Chamfer", "Chamfer") chamfer.Base = ( box, [ "Edge1", "Edge5", "Edge7", ], ) chamfer.Size = 1 body.addObject(chamfer) self.Doc.recompute() volume2 = body.Shape.Volume doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (chamfer, "Face8") doc.Sketch.MapMode = "FlatFace" doc.recompute() x1, x2, y1, y2 = ( 10 / math.sqrt(2) - math.sqrt(2), 10 / math.sqrt(2) + math.sqrt(2), 6, 11, ) geoList = [] geoList.append( Part.LineSegment(App.Vector(x1, y1, 0.0), App.Vector(x1, y2, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x1, y2, 0.0), App.Vector(x2, y2, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x2, y2, 0.0), App.Vector(x2, y1, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x2, y1, 0.0), App.Vector(x1, y1, 0.0)) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Horizontal", 0)) constraintList.append(Sketcher.Constraint("Horizontal", 2)) constraintList.append(Sketcher.Constraint("Vertical", 1)) constraintList.append(Sketcher.Constraint("Vertical", 3)) doc.Sketch.addConstraint(constraintList) del constraintList body.addObject(doc.Sketch) pocket = self.Doc.addObject("PartDesign::Pocket", "Pocket") pocket.Type = "Length" pocket.Length = 3 pocket.Direction = App.Vector(-0.710000000, 0.7100000000, 0.0000000000) pocket.Profile = doc.Sketch body.addObject(pocket) self.Doc.recompute() volume3 = body.Shape.Volume # Change the chamfered edges, potentially triggering TNP chamfer.Base = ( box, [ "Edge5", "Edge7", ], ) self.Doc.recompute() volume4 = body.Shape.Volume # Assert if body.Shape.ElementMapVersion == "": # Skip without element maps. return reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 62) self.assertEqual(len(reverseMap), 62) self.assertEqual(len(faces), 12) self.assertEqual(len(edges), 30) self.assertEqual(len(vertexes), 20) boxVolume = 10 * 10 * 10 chamferVolume = 1 * 1 * 0.5 * 10 # cut area is rectangle with sqrt(2) as one side minus 2 isosceles right triangles cutArea = (2 * math.sqrt(2)) * 3 - ( (math.sqrt(2) / 2 * math.sqrt(2) / 2) / 2 ) * 2 cutVolume = cutArea * 4 # height is 4 ( 11-6 with a limit of 10 from the box ) self.assertAlmostEqual(volume1, boxVolume) self.assertAlmostEqual(volume2, boxVolume - 3 * chamferVolume) self.assertAlmostEqual(volume3, boxVolume - 3 * chamferVolume - cutVolume, 4) self.assertAlmostEqual(volume4, boxVolume - 2 * chamferVolume - cutVolume, 4) def testPartDesignTNPFillet(self): """Test Fillet""" # Arrange doc = self.Doc body = self.Doc.addObject("PartDesign::Body", "Body") box = self.Doc.addObject("PartDesign::AdditiveBox", "Box") body.addObject(box) self.Doc.recompute() volume1 = body.Shape.Volume fillet = self.Doc.addObject("PartDesign::Fillet", "Fillet") fillet.Refine = True fillet.Base = ( box, [ "Edge1", "Edge5", "Edge7", ], ) # fillet.Size = 1 body.addObject(fillet) self.Doc.recompute() volume2 = body.Shape.Volume doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (fillet, "Face2") doc.Sketch.MapMode = "FlatFace" doc.recompute() x1, x2, y1, y2 = 4, 6, 6, 11 geoList = [] geoList.append( Part.LineSegment(App.Vector(x1, y1, 0.0), App.Vector(x1, y2, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x1, y2, 0.0), App.Vector(x2, y2, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x2, y2, 0.0), App.Vector(x2, y1, 0.0)) ) geoList.append( Part.LineSegment(App.Vector(x2, y1, 0.0), App.Vector(x1, y1, 0.0)) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Horizontal", 0)) constraintList.append(Sketcher.Constraint("Horizontal", 2)) constraintList.append(Sketcher.Constraint("Vertical", 1)) constraintList.append(Sketcher.Constraint("Vertical", 3)) doc.Sketch.addConstraint(constraintList) del constraintList body.addObject(doc.Sketch) pocket = self.Doc.addObject("PartDesign::Pocket", "Pocket") pocket.Refine = True pocket.Type = "Length" pocket.Length = 3 pocket.Direction = App.Vector(-0.710000000, 0.7100000000, 0.0000000000) pocket.Profile = doc.Sketch # pocket.Reversed = False body.addObject(pocket) self.Doc.recompute() volume3 = body.Shape.Volume # Change the filleted edges, potentially triggering TNP fillet.Base = ( box, [ "Edge5", "Edge7", ], ) self.Doc.recompute() volume4 = body.Shape.Volume # Assert if body.Shape.ElementMapVersion == "": # Skip without element maps. return reverseMap = body.Shape.childShapes()[0].ElementReverseMap faces = [name for name in reverseMap.keys() if name.startswith("Face")] edges = [name for name in reverseMap.keys() if name.startswith("Edge")] vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")] self.assertEqual(len(body.Shape.childShapes()), 1) self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 62) self.assertEqual(len(reverseMap), 62) self.assertEqual(len(faces), 12) self.assertEqual(len(edges), 30) self.assertEqual(len(vertexes), 20) boxVolume = 10 * 10 * 10 # Full prism minus the rounded triangle prism. filletVolume = 1 * 1 * 10 - 1 * 1 * math.pi / 4 * 10 # 0.5 * 10 cutVolume = 24 self.assertAlmostEqual(volume1, boxVolume) self.assertAlmostEqual(volume2, boxVolume - 3 * filletVolume) self.assertAlmostEqual(volume3, boxVolume - 3 * filletVolume - cutVolume, 4) self.assertAlmostEqual(volume4, boxVolume - 2 * filletVolume - cutVolume, 4) # TODO: ENABLE THIS TEST WHEN MULTISOLIDS AND TNP PLAY NICELY # def testPD_TNPSketchPadMultipleSolids(self): # """ Prove that a sketch with multiple wires works correctly""" # doc = App.ActiveDocument # App.activeDocument().addObject('PartDesign::Body','Body') # doc.Body.newObject('Sketcher::SketchObject','Sketch') # doc.Sketch.AttachmentSupport = (doc.XY_Plane,['']) # doc.Sketch.MapMode = 'FlatFace' # radius = 15 # geoList = [] # geoList.append(Part.Circle(App.Vector(-20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(20, -20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(-20,-20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # del geoList # doc.recompute() # doc.Body.newObject('PartDesign::Pad','Pad') # doc.Pad.Profile = (doc.Sketch, ['',]) # doc.Pad.Length = 10 # doc.Pad.ReferenceAxis = (doc.Sketch,['N_Axis']) # doc.Sketch.Visibility = False # doc.recompute() # expected_volume = math.pi * radius * radius * 10 * 4 # Volume of 4 padded circles # self.assertAlmostEqual(doc.Body.Shape.Volume, expected_volume ) # # Add additional code to attach another sketch, then change the original sketch and check TNP def testPD_TNPSketchPadTouching(self): """Prove that a sketch with touching wires works correctly""" doc = App.ActiveDocument App.activeDocument().addObject("PartDesign::Body", "Body") doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (doc.XY_Plane, [""]) doc.Sketch.MapMode = "FlatFace" radius = 20 geoList = [] geoList.append( Part.Circle( App.Vector(-20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius, ) ) doc.Sketch.addGeometry(geoList, False) geoList = [] geoList.append( Part.Circle( App.Vector(20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius, ) ) doc.Sketch.addGeometry(geoList, False) geoList = [] geoList.append( Part.Circle( App.Vector(20, -20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius, ) ) doc.Sketch.addGeometry(geoList, False) geoList = [] geoList.append( Part.Circle( App.Vector(-20, -20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius, ) ) doc.Sketch.addGeometry(geoList, False) del geoList doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = ( doc.Sketch, [ "", ], ) doc.Pad.Length = 10 doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.recompute() expected_volume = ( math.pi * radius * radius * 10 * 4 ) # Volume of 4 padded circles # self.assertAlmostEqual(doc.Body.Shape.Volume, expected_volume ) # TODO ENABLE THIS ASSERTION WHEN IT PASSES # # Add additional code to attach another sketch, then change the original sketch and check TNP # TODO ENABLE THIS TEST IF CODE IS WRITTEN TO SUPPORT SKETCHES WITH OVERLAPS. # def testPD_TNPSketchPadOverlapping(self): # """ Prove that a sketch with overlapping wires works correctly""" # doc = App.ActiveDocument # App.activeDocument().addObject('PartDesign::Body','Body') # doc.Body.newObject('Sketcher::SketchObject','Sketch') # doc.Sketch.AttachmentSupport = (doc.XY_Plane,['']) # doc.Sketch.MapMode = 'FlatFace' # radius = 25 # geoList = [] # geoList.append(Part.Circle(App.Vector(-20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(20, 20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(20, -20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # geoList = [] # geoList.append(Part.Circle(App.Vector(-20,-20, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), radius)) # doc.Sketch.addGeometry(geoList,False) # del geoList # doc.recompute() # doc.Body.newObject('PartDesign::Pad','Pad') # doc.Pad.Profile = (doc.Sketch, ['',]) # doc.Pad.Length = 10 # doc.Pad.ReferenceAxis = (doc.Sketch,['N_Axis']) # doc.Sketch.Visibility = False # doc.recompute() # expected_volume = math.pi * radius * radius * 10 * 4 # Volume of 4 padded circles # length = 12 # FIXME arbitrary guess, figure out the right value for either this or the angle. # angle = 2 * math.asin(length/2*radius) # expected_volume = expected_volume - 1/2 * radius * radius * (angle-math.sin(angle)) # Volume of the overlap areas # self.assertAlmostEqual(doc.Body.Shape.Volume, expected_volume ) # # Add additional code to attach another sketch, then change the original sketch and check TNP def testPD_TNPSketchPadSketchMove(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has geometry move""" doc = App.ActiveDocument App.activeDocument().addObject("PartDesign::Body", "Body") doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (doc.XY_Plane, [""]) doc.Sketch.MapMode = "FlatFace" geoList = [] geoList.append(Part.LineSegment(App.Vector(0, 0, 0), App.Vector(40, 0, 0))) geoList.append(Part.LineSegment(App.Vector(40, 0, 0), App.Vector(40, 20, 0))) geoList.append(Part.LineSegment(App.Vector(40, 20, 0), App.Vector(0, 20, 0))) geoList.append(Part.LineSegment(App.Vector(0, 20, 0), App.Vector(0, 0, 0))) doc.Sketch.addGeometry(geoList, False) constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Horizontal", 0)) constraintList.append(Sketcher.Constraint("Horizontal", 2)) constraintList.append(Sketcher.Constraint("Vertical", 1)) constraintList.append(Sketcher.Constraint("Vertical", 3)) doc.Sketch.addConstraint(constraintList) doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = ( doc.Sketch, [ "", ], ) doc.Pad.Length = 10 doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.Pad.Length = 10.000000 doc.Pad.TaperAngle = 0.000000 doc.Pad.UseCustomVector = 0 doc.Pad.Direction = (0, 0, 1) doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Pad.AlongSketchNormal = 1 doc.Pad.Type = 0 doc.Pad.UpToFace = None doc.Pad.Reversed = 0 doc.Pad.Midplane = 0 doc.Pad.Offset = 0 doc.recompute() doc.Sketch.Visibility = False doc.Body.newObject("Sketcher::SketchObject", "Sketch001") doc.Sketch001.AttachmentSupport = ( doc.Pad, [ "Face6", ], ) doc.Sketch001.MapMode = "FlatFace" geoList = [] geoList.append(Part.LineSegment(App.Vector(5, 5, 0), App.Vector(5, 10, 0))) geoList.append(Part.LineSegment(App.Vector(5, 10, 0), App.Vector(25, 10, 0))) geoList.append(Part.LineSegment(App.Vector(25, 10, 0), App.Vector(25, 5, 0))) geoList.append(Part.LineSegment(App.Vector(25, 5, 0), App.Vector(5, 5, 0))) doc.Sketch001.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Vertical", 0)) constraintList.append(Sketcher.Constraint("Vertical", 2)) constraintList.append(Sketcher.Constraint("Horizontal", 1)) constraintList.append(Sketcher.Constraint("Horizontal", 3)) doc.Sketch001.addConstraint(constraintList) doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad001") doc.Pad001.Profile = ( doc.Sketch001, [ "", ], ) doc.Pad001.Length = 10 doc.Pad001.ReferenceAxis = (doc.Sketch001, ["N_Axis"]) doc.Sketch001.Visibility = False doc.Pad001.Length = 10.000000 doc.Pad001.TaperAngle = 0.000000 doc.Pad001.UseCustomVector = 0 doc.Pad001.Direction = (0, 0, 1) doc.Pad001.ReferenceAxis = (doc.Sketch001, ["N_Axis"]) doc.Pad001.AlongSketchNormal = 1 doc.Pad001.Type = 0 doc.Pad001.UpToFace = None doc.Pad001.Reversed = 0 doc.Pad001.Midplane = 0 doc.Pad001.Offset = 0 doc.recompute() doc.Pad.Visibility = False doc.Sketch001.Visibility = False doc.Sketch.movePoint(3, 0, App.Vector(-5, 0, 0), 1) doc.Sketch.movePoint(0, 0, App.Vector(0.000000, -5, 0), 1) doc.Sketch.movePoint(1, 0, App.Vector(-5, 0.000000, 0), 1) doc.Sketch.movePoint(2, 0, App.Vector(-0, -5, 0), 1) doc.recompute() # If Sketch001 is still at the right start point, we are good. self.assertTrue(doc.Sketch001.AttachmentOffset.Matrix == App.Matrix()) matrix1 = App.Matrix() matrix1.A34 = 10 # Z offset by 10. self.assertTrue(doc.Sketch001.Placement.Matrix == matrix1) def testPD_TNPSketchPadSketchDelete(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has geometry deleted""" doc = App.ActiveDocument App.activeDocument().addObject("PartDesign::Body", "Body") doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (doc.XY_Plane, [""]) doc.Sketch.MapMode = "FlatFace" import ProfileLib.RegularPolygon ProfileLib.RegularPolygon.makeRegularPolygon( doc.Sketch, 6, App.Vector(0.000000, 0.000000, 0), App.Vector(24, 12, 0), False, ) doc.Sketch.addConstraint(Sketcher.Constraint("Coincident", 6, 3, -1, 1)) doc.Sketch.addConstraint(Sketcher.Constraint("PointOnObject", 0, 2, -2)) doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = ( doc.Sketch, [ "", ], ) doc.Pad.Length = 10 doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.Pad.Length = 10.000000 doc.Pad.TaperAngle = 0.000000 doc.Pad.UseCustomVector = 0 doc.Pad.Direction = (0, 0, 1) doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Pad.AlongSketchNormal = 1 doc.Pad.Type = 0 doc.Pad.UpToFace = None doc.Pad.Reversed = 0 doc.Pad.Midplane = 0 doc.Pad.Offset = 0 doc.recompute() doc.Sketch.Visibility = False doc.Body.newObject("Sketcher::SketchObject", "Sketch001") doc.Sketch001.AttachmentSupport = ( doc.Pad, [ "Face8", ], ) doc.Sketch001.MapMode = "FlatFace" geoList = [] geoList.append( Part.LineSegment(App.Vector(-5, 5, 0.000000), App.Vector(-5, -5, 0.000000)) ) geoList.append( Part.LineSegment(App.Vector(-5, -5, 0.000000), App.Vector(5, -5, 0.000000)) ) geoList.append( Part.LineSegment(App.Vector(5, -5, 0.000000), App.Vector(5, 5, 0.000000)) ) geoList.append( Part.LineSegment(App.Vector(5, 5, 0.000000), App.Vector(-5, 5, 0.000000)) ) doc.Sketch001.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Vertical", 0)) constraintList.append(Sketcher.Constraint("Vertical", 2)) constraintList.append(Sketcher.Constraint("Horizontal", 1)) constraintList.append(Sketcher.Constraint("Horizontal", 3)) doc.Sketch001.addConstraint(constraintList) constraintList = [] doc.recompute() doc.Body.newObject("PartDesign::Pad", "Pad001") doc.Pad001.Profile = ( doc.Sketch001, [ "", ], ) doc.Pad001.Length = 10 doc.Pad001.ReferenceAxis = (doc.Sketch001, ["N_Axis"]) doc.Sketch001.Visibility = False doc.Pad001.Length = 10.000000 doc.Pad001.TaperAngle = 0.000000 doc.Pad001.UseCustomVector = 0 doc.Pad001.Direction = (0, 0, 1) doc.Pad001.ReferenceAxis = (doc.Sketch001, ["N_Axis"]) doc.Pad001.AlongSketchNormal = 1 doc.Pad001.Type = 0 doc.Pad001.UpToFace = None doc.Pad001.Reversed = 0 doc.Pad001.Midplane = 0 doc.Pad001.Offset = 0 doc.recompute() doc.Pad.Visibility = False doc.Sketch001.Visibility = False doc.Sketch.delGeometries([4]) doc.Sketch.addConstraint(Sketcher.Constraint("Coincident", 3, 2, 4, 1)) doc.Sketch.delConstraint(12) doc.recompute() # If Sketch001 is still at the right start point, we are good. self.assertTrue(doc.Sketch001.AttachmentOffset.Matrix == App.Matrix()) matrix1 = App.Matrix() matrix1.A34 = 10 # Z offset by 10 self.assertTrue(doc.Sketch001.Placement.Matrix == matrix1) def testPD_TNPSketchPadSketchConstructionChange(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has geometry changed from Construction""" pass # TODO def testPD_TNPSketchPadSketchTrim(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has geometry trimmed""" pass # TODO def testPD_TNPSketchPadSketchExternal(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has external geometry changed""" pass # TODO def testPD_TNPSketchPadSketchTransform(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has a transformation applied""" pass # TODO def testPD_TNPSketchPadSketchSymmetry(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has Symmetry applied""" pass # TODO def testPD_TNPSketchPadSketchBSpline(self): """Prove that a sketch attached to a padded sketch shape does not have a problem when the initial sketch has BSpline changed""" pass # TODO def testPD_TNPSketchRotSketchMove(self): """Prove that a sketch attached to a rotated sketch shape does not have a problem when the initial sketch has geometry moved""" pass # TODO def testPD_TNPSketchPocketSketchMove(self): """Prove that a sketch attached to a pocketed sketch shape does not have a problem when the initial sketch has geometry moved""" pass # TODO def testPD_TNPSketchLoftSketchMove(self): """Prove that a sketch attached to a lofted sketch shape does not have a problem when the initial sketch has geometry moved""" pass # TODO def testPD_TNPSketchPipeSketchMove(self): """Prove that a sketch attached to a piped sketch shape does not have a problem when the initial sketch has geometry moved""" pass # TODO def testSubelementNames(self): # Arrange doc = App.ActiveDocument plane = doc.addObject("Part::Plane", "Plane") plane.Length = 10 plane.Width = 10 extrude = doc.addObject("Part::Extrusion", "Extrude") extrude.Base = plane extrude.LengthFwd = 10 doc.recompute() if not App.GuiUp: return # Act App.Gui.Selection.addSelection("", extrude.Name, "Face2") # Assert self.assertEqual( len(App.Gui.Selection.getSelectionEx("", 0)[0].SubElementNames), 1 ) if extrude.ElementMapVersion == "": # Should be '4' as of Mar 2023. self.assertEqual( App.Gui.Selection.getSelectionEx("", 0)[0].SubElementNames[0], "Face2" ) else: self.assertEqual( App.Gui.Selection.getSelectionEx("", 0)[0].SubElementNames[0][-8:], ",F.Face2", ) def testGetElementFunctionality(self): # Arrange body = self.Doc.addObject("PartDesign::Body", "Body") padSketch = self.Doc.addObject("Sketcher::SketchObject", "SketchPad") pad = self.Doc.addObject("PartDesign::Pad", "Pad") body.addObject(padSketch) body.addObject(pad) TestSketcherApp.CreateRectangleSketch(padSketch, (0, 0), (1, 1)) pad.Profile = padSketch pad.Length = 1 # Act self.Doc.recompute() if pad.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023. return map = pad.Shape.ElementMap # Assert self.assertGreater(pad.Shape.ElementMapSize, 0) for tnpName in map.keys(): element1 = pad.Shape.getElement(tnpName) element2 = pad.Shape.getElement(map[tnpName]) self.assertTrue(element1.isSame(element2)) def testFileSaveRestore(self): # Arrange self.Body = self.Doc.addObject("PartDesign::Body", "Body") self.create_t_sketch() self.assertEqual(self.Doc.Sketch.Shape.ElementMapSize, 18) filename = self.Doc.Name # Act self.Doc.saveAs(filename) App.closeDocument(filename) self.Doc = App.openDocument(filename + ".FCStd") self.Doc.recompute() # Assert self.assertEqual(self.Doc.Sketch.Shape.ElementMapSize, 18) def testBodySubShapeBinderElementMap(self): # Arrange doc = App.ActiveDocument doc.addObject("Part::Box", "Box") doc.ActiveObject.Label = "Cube" doc.addObject("Part::Box", "Box") doc.ActiveObject.Label = "Cube" doc.addObject("Part::MultiFuse", "Fusion") doc.Fusion.Refine = False doc.Fusion.Shapes = [ doc.Box, doc.Box001, ] doc.recompute() self.assertEqual(doc.Fusion.Shape.ElementMapSize, 26) doc.addObject("PartDesign::Body", "Body") doc.Body.Label = "Body" doc.addObject("PartDesign::Body", "Body001") doc.Body001.Label = "Body001" # act # Set up the subshapebinder version binder = doc.Body.newObject("PartDesign::SubShapeBinder", "Binder") binder.Support = [(doc.Fusion, (""))] doc.recompute() # Set up the base feature version doc.Body001.BaseFeature = App.activeDocument().Fusion doc.recompute() # assert self.assertEqual( doc.Body.OutList[1].Shape.ElementMapSize, 26 ) # subobjects ( subshapebinder here ) should have elementmap self.assertEqual( doc.Body.Shape.ElementMapSize, 0 ) # TODO: This is Sus, although LS3 passes. Might be because # SubShapeBinder is different in LS3. self.assertEqual( doc.Body001.BaseFeature.Shape.ElementMapSize, 26 ) # base feature lookup should have element map self.assertEqual( doc.Body001.Shape.ElementMapSize, 26 ) # Body Shape should have element map def testBaseFeatureAttachmentSupport(self): # Arrange doc = App.ActiveDocument doc.addObject("Part::Box", "Box") doc.ActiveObject.Label = "Cube" doc.recompute() doc.addObject("Part::Box", "Box") doc.ActiveObject.Label = "Cube" doc.Box001.Placement = App.Placement( App.Vector(5.00, 5.00, 5.00), App.Rotation(App.Vector(0.00, 0.00, 1.00), 0.00), ) doc.recompute() doc.addObject("Part::MultiFuse", "Fusion") doc.Fusion.Refine = False doc.Fusion.Shapes = [ doc.Box, doc.Box001, ] doc.recompute() # doc.Box.Visibility = False # doc.Box001.Visibility = False # doc.recompute() doc.addObject("PartDesign::Body", "Body") doc.Body.Label = "Body" doc.Body.BaseFeature = App.activeDocument().Fusion doc.recompute() doc.Body.newObject("Sketcher::SketchObject", "Sketch") doc.Sketch.AttachmentSupport = (doc.getObject("BaseFeature"), ("Face8")) doc.Sketch.MapMode = "FlatFace" doc.recompute() geoList = [] geoList.append( Part.LineSegment( App.Vector(12.0, 13.0, 0.000000), App.Vector(12.0, 11.0, 0.000000) ) ) geoList.append( Part.LineSegment( App.Vector(12.0, 11, 0.000000), App.Vector(14.0, 11.0, 0.000000) ) ) geoList.append( Part.LineSegment( App.Vector(14.0, 11, 0.000000), App.Vector(14.0, 13.0, 0.000000) ) ) geoList.append( Part.LineSegment( App.Vector(14.0, 13.0, 0.000000), App.Vector(12, 13.0, 0.000000) ) ) doc.Sketch.addGeometry(geoList, False) del geoList constraintList = [] constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) constraintList.append(Sketcher.Constraint("Vertical", 0)) constraintList.append(Sketcher.Constraint("Vertical", 2)) constraintList.append(Sketcher.Constraint("Horizontal", 1)) constraintList.append(Sketcher.Constraint("Horizontal", 3)) doc.Sketch.addConstraint(constraintList) del constraintList constraintList = [] doc.recompute() # Assert that we have a sketch element map before proceeding self.assertEqual(doc.Sketch.Shape.ElementMapSize, 12) # Arrange doc.Body.newObject("PartDesign::Pad", "Pad") doc.Pad.Profile = ( doc.Sketch, [ "", ], ) doc.Pad.Length = 10 doc.recompute() doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Sketch.Visibility = False doc.Pad.Length = 10.000000 doc.Pad.TaperAngle = 0.000000 doc.Pad.UseCustomVector = 0 doc.Pad.Direction = (0, -1, 0) doc.Pad.ReferenceAxis = (doc.Sketch, ["N_Axis"]) doc.Pad.AlongSketchNormal = 1 doc.Pad.Type = 0 doc.Pad.UpToFace = None doc.Pad.Reversed = 0 doc.Pad.Midplane = 0 doc.Pad.Offset = 0 doc.BaseFeature.Visibility = False doc.Sketch.Visibility = False doc.recompute() # Act doc.Box001.Width = "3.00 mm" doc.Box001.Placement = App.Placement( App.Vector(5.00, 5.00, 5.00), App.Rotation(App.Vector(0.00, 0.00, 1.00), 0.00), ) doc.recompute() # Assert self.assertEqual( len(doc.Body.Shape.Faces), 17 ) # Check that the object seems right. self.assertEqual(len(doc.Body.Shape.Edges), 42) self.assertEqual(len(doc.Body.Shape.Vertexes), 28) self.assertEqual(len(doc.Body.Shape.Shells), 1) self.assertEqual(len(doc.Body.Shape.Solids), 1) self.assertEqual( doc.Sketch.AttachmentSupport[0][1][0], "Face9" ) # Attachment autochanged from Face8. # potentially check the .BoundBox ( calc seems off on this, Not applying sketch position to Pad object ) def create_t_sketch(self): self.Doc.getObject("Body").newObject("Sketcher::SketchObject", "Sketch") geo_list = [ Part.LineSegment(App.Vector(0, 0, 0), App.Vector(20, 0, 0)), Part.LineSegment(App.Vector(20, 0, 0), App.Vector(20, 10, 0)), Part.LineSegment(App.Vector(20, 10, 0), App.Vector(10, 10, 0)), Part.LineSegment(App.Vector(10, 10, 0), App.Vector(10, 20, 0)), Part.LineSegment(App.Vector(10, 20, 0), App.Vector(0, 20, 0)), Part.LineSegment(App.Vector(0, 20, 0), App.Vector(0, 0, 0)), ] self.Doc.getObject("Sketch").addGeometry(geo_list, False) con_list = [ Sketcher.Constraint("Coincident", 0, 2, 1, 1), Sketcher.Constraint("Coincident", 1, 2, 2, 1), Sketcher.Constraint("Coincident", 2, 2, 3, 1), Sketcher.Constraint("Coincident", 3, 2, 4, 1), Sketcher.Constraint("Coincident", 4, 2, 5, 1), Sketcher.Constraint("Coincident", 5, 2, 0, 1), Sketcher.Constraint("Horizontal", 0), Sketcher.Constraint("Horizontal", 2), Sketcher.Constraint("Horizontal", 4), Sketcher.Constraint("Vertical", 1), Sketcher.Constraint("Vertical", 3), Sketcher.Constraint("Vertical", 5), ] self.Doc.getObject("Sketch").addConstraint(con_list) del geo_list, con_list self.Doc.recompute() def testRectanglewithArcChangeinGlobalCenter(self): # Arrange self.Body = self.Doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad self.PadSketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") self.Body.addObject(self.PadSketch) TestSketcherApp.CreateRectangleSketch(self.PadSketch, (-50, -25), (100, 50)) self.Doc.recompute() self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad") self.Body.addObject(self.Pad) self.Pad.Profile = self.PadSketch self.Pad.Length = 10 self.Doc.recompute() self.Sketch001 = self.Body.newObject("Sketcher::SketchObject", "Sketch001") self.Sketch001.AttachmentSupport = ( self.Doc.getObject("Pad"), [ "Face6", ], ) self.Sketch001.MapMode = "FlatFace" TestSketcherApp.CreateRectangleSketch(self.Sketch001, (-40, -20), (80, 40)) self.Doc.recompute() self.Pad1 = self.Doc.addObject("PartDesign::Pad", "Pad1") self.Body.addObject(self.Pad1) self.Pad1.Profile = self.Sketch001 self.Pad1.Length = 10 self.Doc.recompute() self.geoList = [] self.geoList.append( Part.ArcOfCircle( Part.Circle( App.Vector(0.000000, -109.419670, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 88.713871, ), 1.258384, 1.886112, ) ) self.PadSketch.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("PointOnObject", 4, 3, -2)) self.constraintList.append(Sketcher.Constraint("PointOnObject", 4, 1, 2)) self.constraintList.append(Sketcher.Constraint("PointOnObject", 4, 2, 2)) self.PadSketch.addConstraint(self.constraintList) del self.constraintList self.PadSketch.trim(2, App.Vector(7.337847, -25.000000, 0)) self.PadSketch.addConstraint(Sketcher.Constraint("Equal", 3, 1)) self.PadSketch.addConstraint(Sketcher.Constraint("Horizontal", 5)) self.PadSketch.addConstraint(Sketcher.Constraint("Radius", 4, 73.031111)) self.PadSketch.setDatum(18, App.Units.Quantity("70.000000 mm")) self.PadSketch.addConstraint( Sketcher.Constraint("DistanceY", 4, 3, -1, 1, 88.867210) ) self.PadSketch.setDatum(19, App.Units.Quantity("80.000000 mm")) self.Doc.recompute() self.assertTrue(self.Sketch001.isValid()) def testRectanglewithArcChangeinGlobalUpperRight(self): # Arrange self.Body = self.Doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad self.PadSketch = self.Body.newObject("Sketcher::SketchObject", "Sketch") self.PadSketch.AttachmentSupport = (self.Doc.getObject("XY_Plane"), [""]) self.PadSketch.MapMode = "FlatFace" self.Doc.recompute() lastGeoId = len(self.PadSketch.Geometry) self.geoList = [] self.geoList.append( Part.LineSegment( App.Vector(6.565019, 5.821458, 0.000000), App.Vector(131.750198, 5.821458, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(131.750198, 5.821458, 0.000000), App.Vector(131.750198, 75.265900, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(131.750198, 75.265900, 0.000000), App.Vector(6.565019, 75.265900, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(6.565019, 75.265900, 0.000000), App.Vector(6.565019, 5.821458, 0.000000), ) ) self.PadSketch.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) self.constraintList.append(Sketcher.Constraint("Horizontal", 0)) self.constraintList.append(Sketcher.Constraint("Horizontal", 2)) self.constraintList.append(Sketcher.Constraint("Vertical", 1)) self.constraintList.append(Sketcher.Constraint("Vertical", 3)) self.PadSketch.addConstraint(self.constraintList) del self.constraintList self.Doc.recompute() self.Pad = self.Body.newObject("PartDesign::Pad", "Pad") self.Pad.Profile = ( self.Doc.getObject("Sketch"), [ "", ], ) self.Pad.Length = 10 self.Doc.recompute() self.Pad.ReferenceAxis = (self.Doc.getObject("Sketch"), ["N_Axis"]) self.Doc.recompute() self.Pad.Length = 10.000000 self.Pad.TaperAngle = 0.000000 self.Pad.UseCustomVector = 0 self.Pad.Direction = (0, 0, 1) self.Pad.ReferenceAxis = (self.Doc.getObject("Sketch"), ["N_Axis"]) self.Pad.AlongSketchNormal = 1 self.Pad.Type = 0 self.Pad.UpToFace = None self.Pad.Reversed = 0 self.Pad.Midplane = 0 self.Pad.Offset = 0 self.Doc.recompute() self.Sketch001 = self.Body.newObject("Sketcher::SketchObject", "Sketch001") self.Sketch001.AttachmentSupport = ( self.Doc.getObject("Pad"), [ "Face6", ], ) self.Sketch001.MapMode = "FlatFace" self.Doc.recompute() lastGeoId = len(self.Sketch001.Geometry) self.geoList = [] self.geoList.append( Part.LineSegment( App.Vector(33.048996, 24.872660, 0.000000), App.Vector(125.086029, 24.872660, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(125.086029, 24.872660, 0.000000), App.Vector(125.086029, 72.835625, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(125.086029, 72.835625, 0.000000), App.Vector(33.048996, 72.835625, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(33.048996, 72.835625, 0.000000), App.Vector(33.048996, 24.872660, 0.000000), ) ) self.Sketch001.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) self.constraintList.append(Sketcher.Constraint("Horizontal", 0)) self.constraintList.append(Sketcher.Constraint("Horizontal", 2)) self.constraintList.append(Sketcher.Constraint("Vertical", 1)) self.constraintList.append(Sketcher.Constraint("Vertical", 3)) self.Sketch001.addConstraint(self.constraintList) del self.constraintList self.Doc.recompute() self.Pad1 = self.Body.newObject("PartDesign::Pad", "Pad001") self.Pad1.Profile = ( self.Doc.getObject("Sketch001"), [ "", ], ) self.Pad1.Length = 10 self.Doc.recompute() self.Pad1.ReferenceAxis = (self.Doc.getObject("Sketch001"), ["N_Axis"]) self.Doc.recompute() self.Pad1.Length = 10.000000 self.Pad1.TaperAngle = 0.000000 self.Pad1.UseCustomVector = 0 self.Pad1.Direction = (0, 0, 1) self.Pad1.ReferenceAxis = (self.Doc.getObject("Sketch001"), ["N_Axis"]) self.Pad1.AlongSketchNormal = 1 self.Pad1.Type = 0 self.Pad1.UpToFace = None self.Pad1.Reversed = 0 self.Pad1.Midplane = 0 self.Pad1.Offset = 0 self.Doc.recompute() lastGeoId = len(self.Sketch001.Geometry) self.geoList = [] self.geoList.append( Part.ArcOfCircle( Part.Circle( App.Vector(73.611900, -60.502949, 0.000000), App.Vector(0.000000, 0.000000, 1.000000), 80.806032, ), 0.997061, 2.178808, ) ) self.PadSketch.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("PointOnObject", 4, 2, 0)) self.constraintList.append(Sketcher.Constraint("PointOnObject", 4, 1, 0)) self.PadSketch.addConstraint(self.constraintList) del self.constraintList self.Doc.recompute() self.PadSketch.trim(0, App.Vector(69.157609, 5.865876, 0)) self.Doc.recompute() self.assertTrue(self.Sketch001.isValid()) def testPadChange_UpToFirst_to_Dimension(self): # Arrange self.Body = self.Doc.addObject("PartDesign::Body", "Body") # Make first offset cube Pad self.PadSketch = self.Doc.addObject("Sketcher::SketchObject", "Sketch") self.Body.addObject(self.PadSketch) TestSketcherApp.CreateRectangleSketch(self.PadSketch, (-42.5, -42.5), (85, 85)) self.Doc.recompute() TestSketcherApp.CreateRectangleSketch(self.PadSketch, (-37.5, -37.5), (75, 75)) self.Doc.recompute() self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad") self.Body.addObject(self.Pad) self.Pad.Profile = self.PadSketch self.Pad.Length = 10 self.Doc.recompute() self.Sketch001 = self.Body.newObject("Sketcher::SketchObject", "Sketch001") self.Sketch001.AttachmentSupport = ( self.Doc.getObject("Pad"), [ "Face5", ], ) self.Sketch001.MapMode = "FlatFace" self.Doc.recompute() lastGeoId = len(self.Sketch001.Geometry) self.geoList = [] self.geoList.append( Part.LineSegment( App.Vector(-33.953453, 7.680901, 0.000000), App.Vector(-33.953453, 2.543239, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(-33.953453, 2.543239, 0.000000), App.Vector(33.282925, 2.543239, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(33.282925, 2.543239, 0.000000), App.Vector(33.282925, 7.680901, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(33.282925, 7.680901, 0.000000), App.Vector(-33.953453, 7.680901, 0.000000), ) ) self.Sketch001.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) self.constraintList.append(Sketcher.Constraint("Vertical", 0)) self.constraintList.append(Sketcher.Constraint("Vertical", 2)) self.constraintList.append(Sketcher.Constraint("Horizontal", 1)) self.constraintList.append(Sketcher.Constraint("Horizontal", 3)) self.Sketch001.addConstraint(self.constraintList) del self.constraintList self.Doc.recompute() self.Pad001 = self.Body.newObject("PartDesign::Pad", "Pad001") self.Pad001.Profile = ( self.Doc.getObject("Sketch001"), [ "", ], ) self.Pad001.Length = 10 self.Doc.recompute() self.Pad001.ReferenceAxis = (self.Doc.getObject("Sketch001"), ["N_Axis"]) self.Doc.recompute() self.Pad001.UseCustomVector = 0 self.Pad001.Direction = (0, -1, 0) self.Pad001.ReferenceAxis = (self.Doc.getObject("Sketch001"), ["N_Axis"]) self.Pad001.AlongSketchNormal = 1 self.Pad001.Type = 2 self.Pad001.UpToFace = None self.Pad001.Reversed = 0 self.Pad001.Midplane = 0 self.Pad001.Offset = 0 self.Doc.recompute() self.Sketch002 = self.Body.newObject("Sketcher::SketchObject", "Sketch002") self.Sketch002.AttachmentSupport = ( self.Doc.getObject("Pad001"), [ "Face11", ], ) self.Sketch002.MapMode = "FlatFace" self.Doc.recompute() lastGeoId = len(self.Sketch002.Geometry) self.geoList = [] self.geoList.append( Part.LineSegment( App.Vector(-30.826233, 35.070259, 0.000000), App.Vector(-30.826233, 30.602728, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(-30.826233, 30.602728, 0.000000), App.Vector(30.602348, 30.602728, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(30.602348, 30.602728, 0.000000), App.Vector(30.602348, 35.070259, 0.000000), ) ) self.geoList.append( Part.LineSegment( App.Vector(30.602348, 35.070259, 0.000000), App.Vector(-30.826233, 35.070259, 0.000000), ) ) self.Sketch002.addGeometry(self.geoList, False) del self.geoList self.constraintList = [] self.constraintList.append(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 1, 2, 2, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 2, 2, 3, 1)) self.constraintList.append(Sketcher.Constraint("Coincident", 3, 2, 0, 1)) self.constraintList.append(Sketcher.Constraint("Vertical", 0)) self.constraintList.append(Sketcher.Constraint("Vertical", 2)) self.constraintList.append(Sketcher.Constraint("Horizontal", 1)) self.constraintList.append(Sketcher.Constraint("Horizontal", 3)) self.Sketch002.addConstraint(self.constraintList) del self.constraintList self.Doc.recompute() self.Pad002 = self.Body.newObject("PartDesign::Pad", "Pad002") self.Pad002.Profile = ( self.Doc.getObject("Sketch002"), [ "", ], ) self.Pad002.Length = 10 self.Doc.recompute() self.Pad002.ReferenceAxis = (self.Doc.getObject("Sketch002"), ["N_Axis"]) self.Doc.recompute() self.Pad002.Length = 10.000000 self.Pad002.TaperAngle = 0.000000 self.Pad002.UseCustomVector = 0 self.Pad002.Direction = (0, 0, 1) self.Pad002.ReferenceAxis = (self.Doc.getObject("Sketch002"), ["N_Axis"]) self.Pad002.AlongSketchNormal = 1 self.Pad002.Type = 0 self.Pad002.UpToFace = None self.Pad002.Reversed = 0 self.Pad002.Midplane = 0 self.Pad002.Offset = 0 self.Doc.recompute() self.Pad001.Type = "Length" self.Pad001.Length = "4 mm" self.Doc.recompute() """Assumption: the warning PropertyLinks.cpp(453): PartDesignTestTNP1#Sketch002.AttachmentSupport missing element reference PartDesignTestTNP1#Pad001 ;g815v1;SKT;:H976,V;:L#2;PSM; :H976:9,E;:L#8;PSM;:H976:9,F;:H-977,F.Face11 is only temporary and can be ignored.""" self.assertTrue(self.Sketch002.AttachmentSupport[0][1][0] == "Face11") self.assertGreaterEqual(self.Body.Shape.Volume, 20126) def tearDown(self): """Clean up our test, optionally preserving the test document""" # This flag allows doing something like this: # App.KeepTestDoc = True # import TestApp # TestApp.Test("TestPartDesignApp.TestTopologicalNamingProblem.testPadChange_UpToFirst_to_Dimension") # to leave the test document(s) around for further examination in an interactive setting. if hasattr(App, "KeepTestDoc") and App.KeepTestDoc: return App.closeDocument(self.Doc.Name)