Download src/Mod/PartDesign/PartDesignTests/TestLoft.py from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 19.7 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/PartDesignTests/TestLoft.py
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/PartDesign/PartDesignTests/TestLoft.py
-
curl -L -o TestLoft.py https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/PartDesignTests/TestLoft.py
19.7 kB
| # *************************************************************************** | |
| # * Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net> * | |
| # * * | |
| # * This program is free software; you can redistribute it and/or modify * | |
| # * it under the terms of the GNU Lesser General Public License (LGPL) * | |
| # * as published by the Free Software Foundation; either version 2 of * | |
| # * the License, or (at your option) any later version. * | |
| # * for detail see the LICENCE text file. * | |
| # * * | |
| # * This program 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 Library General Public License for more details. * | |
| # * * | |
| # * You should have received a copy of the GNU Library General Public * | |
| # * License along with this program; if not, write to the Free Software * | |
| # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * | |
| # * USA * | |
| # * * | |
| # *************************************************************************** | |
| import unittest | |
| import math | |
| import FreeCAD | |
| from FreeCAD import Base | |
| from FreeCAD import Units | |
| import Part | |
| import Sketcher | |
| import TestSketcherApp | |
| class TestLoft(unittest.TestCase): | |
| """Loft Tests""" | |
| def setUp(self): | |
| self.Doc = FreeCAD.newDocument("PartDesignTestLoft") | |
| def testSimpleAdditiveLoftCase(self): | |
| self.Body = self.Doc.addObject("PartDesign::Body", "Body") | |
| self.ProfileSketch = self.Doc.addObject("Sketcher::SketchObject", "ProfileSketch") | |
| self.Body.addObject(self.ProfileSketch) | |
| TestSketcherApp.CreateRectangleSketch(self.ProfileSketch, (0, 0), (1, 1)) | |
| self.Doc.recompute() | |
| self.LoftSketch = self.Doc.addObject("Sketcher::SketchObject", "LoftSketch") | |
| self.Body.addObject(self.LoftSketch) | |
| self.LoftSketch.MapMode = "FlatFace" | |
| self.LoftSketch.AttachmentSupport = (self.Doc.XZ_Plane, [""]) | |
| self.Doc.recompute() | |
| TestSketcherApp.CreateRectangleSketch(self.LoftSketch, (0, 1), (1, 1)) | |
| self.Doc.recompute() | |
| self.AdditiveLoft = self.Doc.addObject("PartDesign::AdditiveLoft", "AdditiveLoft") | |
| self.Body.addObject(self.AdditiveLoft) | |
| self.AdditiveLoft.Profile = self.ProfileSketch | |
| self.AdditiveLoft.Sections = [self.LoftSketch] | |
| self.Doc.recompute() | |
| self.assertAlmostEqual(self.AdditiveLoft.Shape.Volume, 1) | |
| def testSimpleSubtractiveLoftCase(self): | |
| self.Body = self.Doc.addObject("PartDesign::Body", "Body") | |
| 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 = 2 | |
| self.Doc.recompute() | |
| self.ProfileSketch = self.Doc.addObject("Sketcher::SketchObject", "ProfileSketch") | |
| self.Body.addObject(self.ProfileSketch) | |
| TestSketcherApp.CreateRectangleSketch(self.ProfileSketch, (0, 0), (1, 1)) | |
| self.Doc.recompute() | |
| self.LoftSketch = self.Doc.addObject("Sketcher::SketchObject", "LoftSketch") | |
| self.Body.addObject(self.LoftSketch) | |
| self.LoftSketch.MapMode = "FlatFace" | |
| self.LoftSketch.AttachmentSupport = (self.Doc.XZ_Plane, [""]) | |
| self.Doc.recompute() | |
| TestSketcherApp.CreateRectangleSketch(self.LoftSketch, (0, 1), (1, 1)) | |
| self.Doc.recompute() | |
| self.SubtractiveLoft = self.Doc.addObject("PartDesign::SubtractiveLoft", "SubtractiveLoft") | |
| self.Body.addObject(self.SubtractiveLoft) | |
| self.SubtractiveLoft.Profile = self.ProfileSketch | |
| self.SubtractiveLoft.Sections = [self.LoftSketch] | |
| self.Doc.recompute() | |
| self.assertAlmostEqual(self.SubtractiveLoft.Shape.Volume, 1) | |
| def testClosedAdditiveLoftCase(self): | |
| """Test issue #6156: Loft tool "Closed" option not working""" | |
| body = self.Doc.addObject("PartDesign::Body", "Body") | |
| sketch1 = body.newObject("Sketcher::SketchObject", "Sketch") | |
| sketch1.AttachmentSupport = (self.Doc.XZ_Plane, [""]) | |
| sketch1.MapMode = "FlatFace" | |
| sketch1.addGeometry( | |
| Part.Circle(Base.Vector(-40.0, 0.0, 0.0), Base.Vector(0, 0, 1), 10.0), False | |
| ) | |
| sketch1.addConstraint(Sketcher.Constraint("PointOnObject", 0, 3, -1)) | |
| sketch1.addConstraint(Sketcher.Constraint("Diameter", 0, 20.0)) | |
| sketch1.setDatum(1, Units.Quantity("20.000000 mm")) | |
| sketch1.addConstraint(Sketcher.Constraint("Distance", -1, 1, 0, 3, 40.0)) | |
| sketch1.setDatum(2, Units.Quantity("40.000000 mm")) | |
| sketch2 = body.newObject("Sketcher::SketchObject", "Sketch001") | |
| sketch2.AttachmentSupport = (self.Doc.YZ_Plane, "") | |
| sketch2.MapMode = "FlatFace" | |
| sketch2.addGeometry( | |
| Part.Circle(Base.Vector(-10.0, 0.0, 0.0), Base.Vector(0, 0, 1), 10.0), False | |
| ) | |
| sketch2.addConstraint(Sketcher.Constraint("PointOnObject", 0, 3, -1)) | |
| sketch2.addConstraint(Sketcher.Constraint("Diameter", 0, 20.0)) | |
| sketch2.setDatum(1, Units.Quantity("20.000000 mm")) | |
| sketch2.addConstraint(Sketcher.Constraint("Distance", -1, 1, 0, 3, 40.0)) | |
| sketch2.setDatum(2, Units.Quantity("40.000000 mm")) | |
| sketch3 = body.newObject("Sketcher::SketchObject", "Sketch002") | |
| sketch3.AttachmentSupport = (self.Doc.getObject("YZ_Plane"), "") | |
| sketch3.MapMode = "FlatFace" | |
| sketch3.addGeometry( | |
| Part.Circle(Base.Vector(40.0, 0.0, 0.0), Base.Vector(0, 0, 1), 10.0), False | |
| ) | |
| sketch3.addConstraint(Sketcher.Constraint("PointOnObject", 0, 3, -1)) | |
| sketch3.addConstraint(Sketcher.Constraint("Distance", -1, 1, 0, 3, 40.0)) | |
| sketch3.setDatum(1, Units.Quantity("40.000000 mm")) | |
| sketch3.addConstraint(Sketcher.Constraint("Diameter", 0, 20.0)) | |
| sketch3.setDatum(2, Units.Quantity("20.000000 mm")) | |
| sketch4 = body.newObject("Sketcher::SketchObject", "Sketch003") | |
| sketch4.AttachmentSupport = (self.Doc.XZ_Plane, "") | |
| sketch4.MapMode = "FlatFace" | |
| sketch4.addGeometry( | |
| Part.Circle(Base.Vector(40.0, 0.0, 0.0), Base.Vector(0, 0, 1), 10.0), False | |
| ) | |
| sketch4.addConstraint(Sketcher.Constraint("PointOnObject", 0, 3, -1)) | |
| sketch4.addConstraint(Sketcher.Constraint("Distance", -1, 1, 0, 3, 40.0)) | |
| sketch4.setDatum(1, Units.Quantity("40.000000 mm")) | |
| sketch4.addConstraint(Sketcher.Constraint("Diameter", 0, 20.0)) | |
| sketch4.setDatum(2, Units.Quantity("20.000000 mm")) | |
| self.Doc.recompute() | |
| loft = body.newObject("PartDesign::AdditiveLoft", "AdditiveLoft") | |
| loft.Profile = sketch1 | |
| loft.Sections = [sketch2, sketch4, sketch3] | |
| loft.Closed = True | |
| sketch1.Visibility = False | |
| sketch2.Visibility = False | |
| sketch3.Visibility = False | |
| sketch4.Visibility = False | |
| self.Doc.recompute() | |
| self.assertGreater(loft.Shape.Volume, 80000.0) # 85105.5788704151 | |
| def testPadOnLoftBetweenCones(self): | |
| """Test issue #15138 adapted from a script by chennes""" | |
| body = self.Doc.addObject("PartDesign::Body", "Body") | |
| body.Label = "Body" | |
| coneBottomSketch = body.newObject("Sketcher::SketchObject", "ConeBottomSketch") | |
| coneBottomSketch.AttachmentSupport = (self.Doc.getObject("XY_Plane"), [""]) | |
| coneBottomSketch.MapMode = "FlatFace" | |
| geoList = [] | |
| geoList.append( | |
| Part.Circle( | |
| Base.Vector(0.000000, 0.000000, 0.000000), | |
| Base.Vector(0.000000, 0.000000, 1.000000), | |
| 25.000000, | |
| ) | |
| ) | |
| coneBottomSketch.addGeometry(geoList, False) | |
| del geoList | |
| constraintList = [] | |
| coneBottomSketch.addConstraint(Sketcher.Constraint("Diameter", 0, 25.000000)) | |
| coneBottomSketch.addConstraint(Sketcher.Constraint("Coincident", 0, 3, -1, 1)) | |
| geoList = [] | |
| geoList.append( | |
| Part.Circle( | |
| Base.Vector(0.000000, 0.000000, 0.000000), | |
| Base.Vector(0.000000, 0.000000, 1.000000), | |
| 40.000000, | |
| ) | |
| ) | |
| coneBottomSketch.addGeometry(geoList, False) | |
| del geoList | |
| constraintList = [] | |
| coneBottomSketch.addConstraint(Sketcher.Constraint("Diameter", 1, 40.000000)) | |
| coneBottomSketch.addConstraint(Sketcher.Constraint("Coincident", 1, 3, 0, 3)) | |
| coneTopSketch = body.newObject("Sketcher::SketchObject", "ConeTopSketch") | |
| coneTopSketch.AttachmentSupport = (self.Doc.getObject("XY_Plane"), [""]) | |
| coneTopSketch.MapMode = "FlatFace" | |
| geoList = [] | |
| geoList.append( | |
| Part.Circle( | |
| Base.Vector(0.000000, 0.000000, 0.000000), | |
| Base.Vector(0.000000, 0.000000, 1.000000), | |
| 8.000000, | |
| ) | |
| ) | |
| coneTopSketch.addGeometry(geoList, False) | |
| del geoList | |
| constraintList = [] | |
| coneTopSketch.addConstraint(Sketcher.Constraint("Diameter", 0, 8.000000)) | |
| coneTopSketch.addConstraint(Sketcher.Constraint("Coincident", 0, 3, -1, 1)) | |
| geoList = [] | |
| geoList.append( | |
| Part.Circle( | |
| Base.Vector(0.000000, 0.000000, 0.000000), | |
| Base.Vector(0.000000, 0.000000, 1.000000), | |
| 15.000000, | |
| ) | |
| ) | |
| coneTopSketch.addGeometry(geoList, False) | |
| del geoList | |
| constraintList = [] | |
| coneTopSketch.addConstraint(Sketcher.Constraint("Diameter", 1, 15.000000)) | |
| coneTopSketch.addConstraint(Sketcher.Constraint("Coincident", 1, 3, 0, 3)) | |
| coneTopSketch.AttachmentOffset = Base.Placement( | |
| Base.Vector(0, 0, 20), Base.Rotation(Base.Vector(0, 0, 1), 0) | |
| ) | |
| self.Doc.recompute() | |
| cone = body.newObject("PartDesign::AdditiveLoft", "Cone") | |
| cone.Profile = coneBottomSketch | |
| cone.Sections = [(coneTopSketch, [""])] | |
| coneBottomSketch.Visibility = False | |
| coneTopSketch.Visibility = False | |
| self.Doc.recompute() | |
| pad = body.newObject("PartDesign::Pad", "Pad") | |
| pad.Profile = ( | |
| cone, | |
| [ | |
| "Face3", | |
| ], | |
| ) | |
| pad.Length = 10.000000 | |
| pad.TaperAngle = 0.000000 | |
| pad.UseCustomVector = 0 | |
| pad.Direction = (0, 0, 1) | |
| pad.ReferenceAxis = None | |
| pad.AlongSketchNormal = 1 | |
| pad.Type = 0 | |
| pad.UpToFace = None | |
| pad.Reversed = False | |
| pad.SideType = "One side" | |
| pad.Offset = 0 | |
| cone.Visibility = True | |
| self.Doc.recompute() | |
| outerConeBottomRadius = 40 / 2 | |
| outerConeTopRadius = 15 / 2 | |
| innerConeBottomRadius = 25 / 2 | |
| innerConeTopRadius = 8 / 2 | |
| coneHeight = 20.0 | |
| padHeight = 10.0 | |
| # Frustum volumes | |
| outerConeVolume = ( | |
| 1.0 | |
| / 3.0 | |
| * math.pi | |
| * coneHeight | |
| * ( | |
| outerConeBottomRadius**2 | |
| + outerConeTopRadius**2 | |
| + outerConeBottomRadius * outerConeTopRadius | |
| ) | |
| ) | |
| innerConeVolume = ( | |
| 1.0 | |
| / 3.0 | |
| * math.pi | |
| * coneHeight | |
| * ( | |
| innerConeBottomRadius**2 | |
| + innerConeTopRadius**2 | |
| + innerConeBottomRadius * innerConeTopRadius | |
| ) | |
| ) | |
| frustumVolume = outerConeVolume - innerConeVolume | |
| topArea = math.pi * (outerConeTopRadius**2) - math.pi * (innerConeTopRadius**2) | |
| bottomArea = math.pi * (outerConeBottomRadius**2) - math.pi * (innerConeBottomRadius**2) | |
| padVolume = topArea * padHeight | |
| self.assertEqual(len(cone.Shape.Faces), 4) # Bottom, Inner, Top, Outer | |
| self.assertAlmostEqual(cone.Shape.Faces[2].Area, topArea) | |
| self.assertAlmostEqual(cone.Shape.Faces[0].Area, bottomArea) | |
| self.assertAlmostEqual(cone.Shape.Volume, frustumVolume) | |
| self.assertAlmostEqual( | |
| pad.Shape.Volume, frustumVolume + padVolume | |
| ) # contains volume of previous in Body | |
| self.assertAlmostEqual( | |
| body.Shape.Volume, frustumVolume + padVolume | |
| ) # Overall body volume matches | |
| def testTwoFacesAdditiveLoftCase(self): | |
| """Test issue #19183: Loft tool "Loft between faces no longer works""" | |
| body = self.Doc.addObject("PartDesign::Body", "Body") | |
| sketch1 = body.newObject("Sketcher::SketchObject", "Sketch") | |
| sketch1.addGeometry( | |
| Part.LineSegment( | |
| Base.Vector(-2.060394, -1.332045, 0), | |
| Base.Vector(-19.922129, -27.589359, 0), | |
| ), | |
| False, | |
| ) | |
| sketch1.addGeometry( | |
| Part.LineSegment( | |
| Base.Vector(1.940183, -1.501086, 0), | |
| Base.Vector(16.928263, -28.265512, 0), | |
| ), | |
| False, | |
| ) | |
| sketch1.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle(Base.Vector(0.418837, -1.275699, 0), Base.Vector(0, 0, 1), 32.879378), | |
| -1.751723, | |
| -1.454683, | |
| ), | |
| False, | |
| ) | |
| sketch1.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle( | |
| Base.Vector(-9.385396, -30.124937, 0), | |
| Base.Vector(0, 0, 1), | |
| 8.359959, | |
| ), | |
| 2.847554, | |
| 4.831818, | |
| ), | |
| False, | |
| ) | |
| sketch1.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle( | |
| Base.Vector(3.236143, -29.279745, 0), | |
| Base.Vector(0, 0, 1), | |
| 11.449505, | |
| ), | |
| -1.076432, | |
| 0.044306, | |
| ), | |
| False, | |
| ) | |
| sketch1.addConstraint(Sketcher.Constraint("Coincident", 0, 1, 1, 1)) | |
| sketch1.addConstraint(Sketcher.Constraint("Coincident", 0, 1, 2, 3)) | |
| sketch1.addConstraint(Sketcher.Constraint("Coincident", 0, 1, -1, 1)) | |
| sketch1.addConstraint(Sketcher.Constraint("Tangent", 0, 2, 3, 1)) | |
| sketch1.addConstraint(Sketcher.Constraint("Tangent", 1, 2, 4, 2)) | |
| sketch1.addConstraint(Sketcher.Constraint("Tangent", 2, 1, 3, 2)) | |
| sketch1.addConstraint(Sketcher.Constraint("Tangent", 2, 2, 4, 1)) | |
| sketch1.addConstraint(Sketcher.Constraint("Symmetric", 0, 2, 1, 2, -2)) | |
| sketch1.addConstraint(Sketcher.Constraint("Symmetric", 2, 1, 2, 2, -2)) | |
| sketch1.delConstraint(8) | |
| sketch1.addConstraint(Sketcher.Constraint("Radius", 2, 39.936694)) | |
| sketch1.setDatum(8, Units.Quantity("40.000000 mm")) | |
| sketch1.addConstraint(Sketcher.Constraint("DistanceX", 2, 1, 2, 2, 16.771341)) | |
| sketch1.setDatum(9, Units.Quantity("10.000000 mm")) | |
| sketch1.addConstraint(Sketcher.Constraint("Distance", 0, 30.965710)) | |
| sketch1.setDatum(10, Units.Quantity("30.000000 mm")) | |
| sketch2 = body.newObject("Sketcher::SketchObject", "Sketch001") | |
| sketch2.addGeometry( | |
| Part.LineSegment( | |
| Base.Vector(-2.060394, -1.332045, 0), | |
| Base.Vector(-19.922129, -27.589359, 0), | |
| ), | |
| False, | |
| ) | |
| sketch2.addGeometry( | |
| Part.LineSegment( | |
| Base.Vector(1.940183, -1.501086, 0), | |
| Base.Vector(16.928263, -28.265512, 0), | |
| ), | |
| False, | |
| ) | |
| sketch2.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle(Base.Vector(0.418837, -1.275699, 0), Base.Vector(0, 0, 1), 32.879378), | |
| -1.751723, | |
| -1.454683, | |
| ), | |
| False, | |
| ) | |
| sketch2.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle( | |
| Base.Vector(-9.385396, -30.124937, 0), | |
| Base.Vector(0, 0, 1), | |
| 8.359959, | |
| ), | |
| 2.847554, | |
| 4.831818, | |
| ), | |
| False, | |
| ) | |
| sketch2.addGeometry( | |
| Part.ArcOfCircle( | |
| Part.Circle( | |
| Base.Vector(3.236143, -29.279745, 0), | |
| Base.Vector(0, 0, 1), | |
| 11.449505, | |
| ), | |
| -1.076432, | |
| 0.044306, | |
| ), | |
| False, | |
| ) | |
| sketch2.addConstraint(Sketcher.Constraint("Coincident", 0, 1, 1, 1)) | |
| sketch2.addConstraint(Sketcher.Constraint("Coincident", 0, 1, 2, 3)) | |
| sketch2.addConstraint(Sketcher.Constraint("Coincident", 0, 1, -1, 1)) | |
| sketch2.addConstraint(Sketcher.Constraint("Tangent", 0, 2, 3, 1)) | |
| sketch2.addConstraint(Sketcher.Constraint("Tangent", 1, 2, 4, 2)) | |
| sketch2.addConstraint(Sketcher.Constraint("Tangent", 2, 1, 3, 2)) | |
| sketch2.addConstraint(Sketcher.Constraint("Tangent", 2, 2, 4, 1)) | |
| sketch2.addConstraint(Sketcher.Constraint("Symmetric", 0, 2, 1, 2, -2)) | |
| sketch2.addConstraint(Sketcher.Constraint("Symmetric", 2, 1, 2, 2, -2)) | |
| sketch2.delConstraint(8) | |
| sketch2.addConstraint(Sketcher.Constraint("Radius", 2, 39.936694)) | |
| sketch2.setDatum(8, Units.Quantity("30.000000 mm")) | |
| sketch2.addConstraint(Sketcher.Constraint("Radius", 3, 1.020288)) | |
| sketch2.setDatum(9, Units.Quantity("3.600000 mm")) | |
| sketch2.addConstraint(Sketcher.Constraint("DistanceX", 2, 1, 2, 2, 10.926759)) | |
| sketch2.setDatum(10, Units.Quantity("10.000000 mm")) | |
| self.Doc.recompute() | |
| pad1 = body.newObject("PartDesign::Pad", "Pad") | |
| pad1.Profile = sketch1 | |
| pad1.Length = 10.000000 | |
| pad1.TaperAngle = 0.000000 | |
| pad1.Reversed = 1 | |
| self.Doc.recompute() | |
| sketch1.Visibility = False | |
| pad2 = body.newObject("PartDesign::Pad", "Pad001") | |
| pad2.Profile = sketch2 | |
| pad2.Length = 10.000000 | |
| pad2.TaperAngle = 0.000000 | |
| self.Doc.recompute() | |
| sketch2.Visibility = False | |
| pad1.Visibility = False | |
| pad2.Visibility = True | |
| body.Tip = pad2 | |
| self.assertGreater(pad2.Shape.Volume, 8715.0) # 8720.024151557787 pre-Loft | |
| loft = body.newObject("PartDesign::AdditiveLoft", "AdditiveLoft") | |
| loft.Profile = ( | |
| self.Doc.getObject("Pad001"), | |
| [ | |
| "Face7", | |
| ], | |
| ) | |
| loft.Sections = [ | |
| ( | |
| self.Doc.getObject("Pad001"), | |
| [ | |
| "Face10", | |
| ], | |
| ) | |
| ] | |
| loft.Closed = False | |
| self.Doc.recompute() | |
| body.Tip = loft | |
| self.assertGreater(body.Shape.Volume, 9220.0) # 9221.776241582389 post-Loft | |
| self.Doc.recompute() | |
| def tearDown(self): | |
| # closing doc | |
| FreeCAD.closeDocument("PartDesignTestLoft") | |
| # print ("omit closing document for debugging") | |