| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import Part |
| | import Path.Op.Adaptive as PathAdaptive |
| | import Path.Main.Job as PathJob |
| | from CAMTests.PathTestUtils import PathTestBase |
| |
|
| | if FreeCAD.GuiUp: |
| | import Path.Main.Gui.Job as PathJobGui |
| | import Path.Op.Gui.Adaptive as PathAdaptiveGui |
| |
|
| |
|
| | class TestPathAdaptive(PathTestBase): |
| | """Unit tests for the Adaptive operation.""" |
| |
|
| | @classmethod |
| | def setUpClass(cls): |
| | """setUpClass()... |
| | This method is called upon instantiation of this test class. Add code and objects here |
| | that are needed for the duration of the test() methods in this class. In other words, |
| | set up the 'global' test environment here; use the `setUp()` method to set up a 'local' |
| | test environment. |
| | This method does not have access to the class `self` reference, but it |
| | is able to call static methods within this same class. |
| | """ |
| | cls.needsInit = True |
| |
|
| | @classmethod |
| | def initClass(cls): |
| | |
| | cls.needsInit = False |
| | FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "True") |
| | cls.doc = FreeCAD.open(FreeCAD.getHomePath() + "Mod/CAM/CAMTests/test_adaptive.fcstd") |
| | FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "") |
| |
|
| | |
| | cls.job = PathJob.Create("Job", [cls.doc.Fusion], None) |
| | cls.job.GeometryTolerance.Value = 0.001 |
| | if FreeCAD.GuiUp: |
| | cls.job.ViewObject.Proxy = PathJobGui.ViewProvider(cls.job.ViewObject) |
| |
|
| | |
| | cls.prototype = PathAdaptive.Create("Adaptive") |
| | cls.prototype.Base = [(cls.doc.Fusion, ["Face3"])] |
| | cls.prototype.Label = "Prototype" |
| | _addViewProvider(cls.prototype) |
| |
|
| | cls.doc.recompute() |
| |
|
| | @classmethod |
| | def tearDownClass(cls): |
| | """tearDownClass()... |
| | This method is called prior to destruction of this test class. Add code and objects here |
| | that cleanup the test environment after the test() methods in this class have been executed. |
| | This method does not have access to the class `self` reference. This method |
| | is able to call static methods within this same class. |
| | """ |
| | |
| |
|
| | |
| | if not cls.needsInit: |
| | FreeCAD.closeDocument(cls.doc.Name) |
| |
|
| | |
| | def setUp(self): |
| | """setUp()... |
| | This method is called prior to each `test()` method. Add code and objects here |
| | that are needed for multiple `test()` methods. |
| | """ |
| | if self.needsInit: |
| | self.initClass() |
| |
|
| | def tearDown(self): |
| | """tearDown()... |
| | This method is called after each test() method. Add cleanup instructions here. |
| | Such cleanup instructions will likely undo those in the setUp() method. |
| | """ |
| | pass |
| |
|
| | |
| | def testFaceSingleSimple(self): |
| | """testFaceSingleSimple() Verify path generated on Face3.""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face3"])] |
| | adaptive.Label = "testFaceSingleSimple+" |
| | adaptive.Comment = "testFaceSingleSimple() Verify path generated on Face3." |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | def testFacesMergedDifferentZ(self): |
| | """testFacesMergedDifferentZ() Verify path generated on adjacent, combined |
| | Face3 and Face10. The Z heights are different.""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] |
| | adaptive.Label = "testFacesMergedDifferentZ+" |
| | adaptive.Comment = "testFacesMergedDifferentZ() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different. UseOutline = False" |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | def testFacesMergedDifferentZUseOutline(self): |
| | """testFacesMergedDifferentZUseOutline() Verify path generated on adjacent, combined Face3 and Face10. |
| | The Z heights are different.""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] |
| | adaptive.Label = "testFacesMergedDifferentZUseOutline+" |
| | adaptive.Comment = "testFacesMergedDifferentZUseOutline() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different. UseOutline = True." |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = True |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | def testOutlineDifferentZDiscontinuousEdges(self): |
| | """testOutlineDifferentZDiscontinuous() Verify path generated non-closed edges with differing Z-heights that are closed with Z=1 projection: "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [ |
| | ( |
| | self.doc.Fusion, |
| | [ |
| | "Edge9", |
| | "Edge2", |
| | "Edge8", |
| | "Edge15", |
| | "Edge30", |
| | "Edge31", |
| | "Edge29", |
| | "Edge19", |
| | ], |
| | ) |
| | ] |
| | adaptive.Label = "testOutlineDifferentZDiscontinuous+" |
| | adaptive.Comment = 'testOutlineDifferentZDiscontinuous() Verify path generated non-closed edges with differing Z-heights that are closed with Z=1 projection: "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".' |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | def testOutlineDifferentZContinuousEdges(self): |
| | """test05() Verify path generated closed wire with differing Z-heights: "Edge13", "Edge7", "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [ |
| | ( |
| | self.doc.Fusion, |
| | [ |
| | "Edge13", |
| | "Edge7", |
| | "Edge9", |
| | "Edge2", |
| | "Edge8", |
| | "Edge15", |
| | "Edge30", |
| | "Edge31", |
| | "Edge29", |
| | "Edge19", |
| | ], |
| | ) |
| | ] |
| | adaptive.Label = "testOutlineDifferentZContinuous+" |
| | adaptive.Comment = 'testOutlineDifferentZContinuous() Verify path generated closed wire with differing Z-heights: "Edge13", "Edge7", "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".' |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | def testOutlineWithCutout(self): |
| | """testOutlineWithCutout() Verify path generated with outer and inner edge loops at same Z height: "Edge15", "Edge30", "Edge31", "Edge29", "Edge19", "Edge18", "Edge35", "Edge32", "Edge34", "Edge33".""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [ |
| | ( |
| | self.doc.Fusion, |
| | [ |
| | "Edge15", |
| | "Edge30", |
| | "Edge31", |
| | "Edge29", |
| | "Edge19", |
| | "Edge18", |
| | "Edge35", |
| | "Edge32", |
| | "Edge34", |
| | "Edge33", |
| | ], |
| | ) |
| | ] |
| | adaptive.Label = "testOutlineWithCutout+" |
| | adaptive.Comment = 'testOutlineWithCutout() Verify path generated with outer and inner edge loops at same Z height: "Edge15", "Edge30", "Edge31", "Edge29", "Edge19", "Edge18", "Edge35", "Edge32", "Edge34", "Edge33".' |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | |
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | |
| | isInBox = False |
| | edges = [ |
| | self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"] |
| | ] |
| | square = Part.Wire(edges) |
| | sqrBB = square.BoundBox |
| | minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0) |
| | maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0) |
| | for c in adaptive.Path.Commands: |
| | if pathOriginatesInBox(c, minPoint, maxPoint): |
| | isInBox = True |
| | break |
| | self.assertFalse(isInBox, "Paths originating within the inner hole.") |
| |
|
| | def testFaceWithCutout(self): |
| | """testFaceWithCutout() Verify path generated on donut-shaped Face10.""" |
| |
|
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face10"])] |
| | adaptive.Label = "testFaceWithCutout+" |
| | adaptive.Comment = "testFaceWithCutout() Verify path generated on donut-shaped Face10." |
| |
|
| | |
| | |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 20.0 |
| | ) |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.") |
| |
|
| | |
| | isInBox = False |
| | edges = [ |
| | self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"] |
| | ] |
| | square = Part.Wire(edges) |
| | sqrBB = square.BoundBox |
| | minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0) |
| | maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0) |
| | for c in adaptive.Path.Commands: |
| | if pathOriginatesInBox(c, minPoint, maxPoint): |
| | isInBox = True |
| | break |
| | self.assertFalse(isInBox, "Paths originating within the inner hole.") |
| |
|
| | |
| | adaptive.UseOutline = True |
| | self.doc.recompute() |
| |
|
| | |
| | isInBox = False |
| | edges = [ |
| | self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"] |
| | ] |
| | square = Part.Wire(edges) |
| | sqrBB = square.BoundBox |
| | minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0) |
| | maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0) |
| | for c in adaptive.Path.Commands: |
| | if pathOriginatesInBox(c, minPoint, maxPoint): |
| | isInBox = True |
| | break |
| | self.assertTrue(isInBox, "No paths originating within the inner hole.") |
| |
|
| | def testModelStockAwareness(self): |
| | """testModelStockAwareness() Tests stock awareness- avoids cutting into the model regardless |
| | of bounding box selected.""" |
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] |
| | adaptive.Label = "testModelStockAwareness+" |
| | adaptive.Comment = "testModelStockAwareness() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different. Result should be the combination at Z=10 (faces from (0,0) to (40,25), minus tool radius), and only the lower face at Z=5: (15,0) to (40,25)." |
| |
|
| | |
| | setDepthsAndHeights(adaptive, 15, 0) |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.ModelAwareExperiment = True |
| | adaptive.StepDown.Value = ( |
| | 5.0 |
| | ) |
| | |
| | |
| | |
| | adaptive.UseHelixArcs = False |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | paths = [c for c in adaptive.Path.Commands if c.Name in ["G0", "G00", "G1", "G01"]] |
| | toolr = adaptive.OpToolDiameter.Value / 2 |
| | tol = adaptive.Tolerance |
| |
|
| | |
| | |
| | moffset = toolr - tol |
| |
|
| | zDict = getPathBoundaries(paths, [10, 5, 0]) |
| |
|
| | |
| | bbf3 = self.doc.Fusion.Shape.getElement("Face3").BoundBox |
| | bbf10 = self.doc.Fusion.Shape.getElement("Face10").BoundBox |
| |
|
| | okAt10 = ( |
| | zDict[10] is not None |
| | and zDict[10]["min"][0] >= bbf3.XMin + moffset |
| | and zDict[10]["min"][1] >= bbf10.YMin + moffset |
| | and zDict[10]["max"][0] <= bbf10.XMax - moffset |
| | and zDict[10]["max"][1] <= bbf10.YMax - moffset |
| | ) |
| |
|
| | okAt5 = ( |
| | zDict[5] is not None |
| | and zDict[5]["min"][0] >= bbf10.XMin + moffset |
| | and zDict[5]["min"][1] >= bbf10.YMin + moffset |
| | and zDict[5]["max"][0] < bbf10.XMax - moffset |
| | and zDict[5]["max"][1] < bbf10.YMax - moffset |
| | ) |
| |
|
| | okAt0 = not zDict[0] |
| |
|
| | self.assertTrue(okAt10 and okAt5 and okAt0, "Path boundaries outside of expected regions") |
| |
|
| | def testZStockToLeave(self): |
| | """testZStockToLeave() Tests Z stock to leave- with 1mm Z stock to leave, machining |
| | at the top of the model should not touch the top model face""" |
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] |
| | adaptive.Label = "testZStockToLeave+" |
| | adaptive.Comment = "testZStockToLeave() Verify Z stock is left as requested" |
| |
|
| | |
| | setDepthsAndHeights(adaptive, 15, 10) |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.StepDown.Value = ( |
| | 5.0 |
| | ) |
| | |
| | adaptive.setExpression("ZStockToLeave", None) |
| | adaptive.ZStockToLeave.Value = 1 |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | |
| | |
| | toolr = adaptive.OpToolDiameter.Value / 2 |
| | tol = adaptive.Tolerance |
| |
|
| | |
| | |
| | moffset = toolr - tol |
| |
|
| | |
| | |
| | |
| | |
| | |
| | noPathTouchesFace3 = True |
| | foffset = self.doc.Fusion.Shape.getElement("Face3").makeOffset2D(moffset) |
| | |
| | lastpt = FreeCAD.Vector(0, 0, 10) |
| | for p in [c.Parameters for c in adaptive.Path.Commands if c.Name in ["G1", "G01"]]: |
| | pt = FreeCAD.Vector(lastpt) |
| | if "X" in p: |
| | pt.x = p.get("X") |
| | if "Y" in p: |
| | pt.x = p.get("Y") |
| |
|
| | if foffset.isInside(pt, 0.001, True): |
| | noPathTouchesFace3 = False |
| | break |
| |
|
| | lastpt = pt |
| |
|
| | self.assertTrue(noPathTouchesFace3, "No feed moves within the top face.") |
| |
|
| | def testFullModelAdaptiveRoughing(self): |
| | """testFullModelAdaptiveRoughing() Tests full roughing- should machine entire model with no inputs""" |
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, [])] |
| | adaptive.Label = "testFullModelAdaptiveRoughing+" |
| | adaptive.Comment = ( |
| | "testFullModelAdaptiveRoughing() Verify path generated with no subs roughs entire model" |
| | ) |
| |
|
| | |
| | setDepthsAndHeights(adaptive, 15, 0) |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.ModelAwareExperiment = True |
| | adaptive.StepDown.Value = ( |
| | 5.0 |
| | ) |
| | |
| | |
| | |
| | adaptive.UseHelixArcs = False |
| |
|
| | _addViewProvider(adaptive) |
| | self.doc.recompute() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | paths = [c for c in adaptive.Path.Commands if c.Name in ["G0", "G00", "G1", "G01"]] |
| | toolr = adaptive.OpToolDiameter.Value / 2 |
| | tol = adaptive.Tolerance |
| |
|
| | |
| | |
| | moffset = toolr - tol |
| |
|
| | zDict = getPathBoundaries(paths, [10, 5, 0]) |
| | mbb = self.doc.Fusion.Shape.BoundBox |
| | sbb = adaptive.Document.Stock.Shape.BoundBox |
| |
|
| | okAt10 = ( |
| | zDict[10] is not None |
| | and zDict[10]["min"][0] <= sbb.XMin + moffset |
| | and zDict[10]["min"][1] <= sbb.YMin + moffset |
| | and zDict[10]["max"][0] >= sbb.XMax - moffset |
| | and zDict[10]["max"][1] >= sbb.YMax - moffset |
| | ) |
| |
|
| | okAt5 = ( |
| | zDict[5] is not None |
| | and zDict[5]["min"][0] <= mbb.XMin - moffset |
| | and zDict[5]["min"][1] <= sbb.YMin + moffset |
| | and zDict[5]["max"][0] >= sbb.XMax - moffset |
| | and zDict[5]["max"][1] >= sbb.YMax - moffset |
| | ) |
| |
|
| | okAt0 = ( |
| | zDict[0] is not None |
| | and zDict[0]["min"][0] <= mbb.XMin - moffset |
| | and zDict[0]["min"][1] <= mbb.YMin - moffset |
| | and zDict[0]["max"][0] >= mbb.XMax + moffset |
| | and zDict[0]["max"][1] >= mbb.YMax + moffset |
| | ) |
| |
|
| | self.assertTrue( |
| | okAt10 and okAt5 and okAt0, "Path boundaries don't include expected regions" |
| | ) |
| |
|
| | def testStockLimitsAwareness(self): |
| | """testStockLimitsAwareness() Tests stock handling- should rough full model, but not cut |
| | air excessively where there's not stock""" |
| | |
| | adaptive = PathAdaptive.Create("Adaptive") |
| | adaptive.Base = [(self.doc.Fusion, [])] |
| | adaptive.Label = "testStockLimitsAwareness+" |
| | adaptive.Comment = ( |
| | "testStockLimitsAwareness() Verify machining region is limited to the stock" |
| | ) |
| |
|
| | |
| | setDepthsAndHeights(adaptive, 15, 5) |
| | adaptive.FinishingProfile = False |
| | adaptive.HelixAngle = 75.0 |
| | adaptive.LiftDistance.Value = 1.0 |
| | adaptive.StepOver = 75 |
| | adaptive.UseOutline = False |
| | adaptive.setExpression("StepDown", None) |
| | adaptive.ModelAwareExperiment = True |
| | adaptive.StepDown.Value = ( |
| | 5.0 |
| | ) |
| | |
| | |
| | |
| | adaptive.UseHelixArcs = False |
| |
|
| | |
| | |
| | btall = Part.makeBox(17, 27, 11, FreeCAD.Vector(-1, -1, 0)) |
| | bshort = Part.makeBox(42, 27, 6, FreeCAD.Vector(-1, -1, 0)) |
| | adaptive.Document.Job.Stock.Shape = btall.fuse(bshort) |
| |
|
| | _addViewProvider(adaptive) |
| | |
| | adaptive.recompute() |
| |
|
| | |
| | |
| | |
| |
|
| | paths = [c for c in adaptive.Path.Commands if c.Name in ["G1", "G01"]] |
| | toolr = adaptive.OpToolDiameter.Value / 2 |
| | tol = adaptive.Tolerance |
| |
|
| | |
| | |
| | |
| | |
| | moffset = toolr + tol |
| |
|
| | zDict = getPathBoundaries(paths, [10, 5]) |
| | sbb = adaptive.Document.Stock.Shape.BoundBox |
| | sbb10 = btall.BoundBox |
| |
|
| | |
| | |
| | okAt10 = ( |
| | zDict[10] is not None |
| | and zDict[10]["min"][0] >= sbb10.XMin - moffset |
| | and zDict[10]["min"][1] >= sbb10.YMin - moffset |
| | and zDict[10]["max"][0] <= sbb10.XMax + moffset |
| | and zDict[10]["max"][1] <= sbb10.YMax + moffset |
| | ) |
| |
|
| | |
| | |
| | okAt5 = ( |
| | zDict[5] is not None |
| | and zDict[5]["min"][0] >= sbb.XMin - moffset |
| | and zDict[5]["min"][1] >= sbb.YMin - moffset |
| | and zDict[5]["max"][0] <= sbb.XMax + moffset |
| | and zDict[5]["max"][1] <= sbb.YMax + moffset |
| | ) |
| |
|
| | self.assertTrue(okAt10 and okAt5, "Path feeds extend excessively in +X") |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | |
| |
|
| |
|
| | def getPathBoundaries(paths, zLevels): |
| | """getPathBoundaries(paths, zLevels): Takes the list of paths and list of Z |
| | depths of interest, and finds the bounding box of the paths at each depth. |
| | A dictionary of depth: {"min": (x,y), "max": (x,y)} entries is returned. |
| | |
| | NOTE: You'd think that using Path.BoundBox would give us what we want, |
| | but... no, for whatever reason it appears to always extend to (0,0,0) |
| | """ |
| | last = FreeCAD.Vector(0.0, 0.0, 0.0) |
| | |
| | for p in paths: |
| | params = p.Parameters |
| | last.x = p.X if "X" in params else last.x |
| | last.y = p.Y if "Y" in params else last.y |
| | last.z = p.Z if "Z" in params else last.z |
| |
|
| | p.X = last.x |
| | p.Y = last.y |
| | p.Z = last.z |
| |
|
| | zDict = {} |
| | for z in zLevels: |
| | zpaths = [k for k in paths if k.Z == z] |
| | if not zpaths: |
| | zDict[z] = None |
| | continue |
| | xmin = min([k.X for k in zpaths]) |
| | xmax = max([k.X for k in zpaths]) |
| | ymin = min([k.Y for k in zpaths]) |
| | ymax = max([k.Y for k in zpaths]) |
| | zDict[z] = {"min": (xmin, ymin), "max": (xmax, ymax)} |
| |
|
| | return zDict |
| |
|
| |
|
| | def setDepthsAndHeights(op, strDep=20.0, finDep=0.0): |
| | """setDepthsAndHeights(op, strDep=20.0, finDep=0.0)... Sets default depths and heights for `op` passed to it""" |
| |
|
| | |
| | op.setExpression("StartDepth", None) |
| | op.StartDepth.Value = strDep |
| | op.setExpression("FinalDepth", None) |
| | op.FinalDepth.Value = finDep |
| |
|
| | |
| | op.setExpression("StepDown", None) |
| | op.StepDown.Value = 20.0 |
| |
|
| | |
| | |
| |
|
| |
|
| | def getGcodeMoves(cmdList, includeRapids=True, includeLines=True, includeArcs=True): |
| | """getGcodeMoves(cmdList, includeRapids=True, includeLines=True, includeArcs=True)... |
| | Accepts command dict and returns point string coordinate. |
| | """ |
| |
|
| | |
| | |
| | |
| | gcode_list = list() |
| | last = FreeCAD.Vector(0.0, 0.0, 0.0) |
| | for c in cmdList: |
| | p = c.Parameters |
| | name = c.Name |
| | if (includeRapids and name in ["G0", "G00"]) or (includeLines and name in ["G1", "G01"]): |
| | gcode = name |
| | x = last.x |
| | y = last.y |
| | z = last.z |
| | if "X" in p: |
| | x = round(p["X"], 2) |
| | gcode += " X" + str(x) |
| | if "Y" in p: |
| | y = round(p["Y"], 2) |
| | gcode += " Y" + str(y) |
| | if "Z" in p: |
| | z = round(p["Z"], 2) |
| | gcode += " Z" + str(z) |
| | last.x = x |
| | last.y = y |
| | last.z = z |
| | gcode_list.append(gcode) |
| | elif includeArcs and name in ["G2", "G3", "G02", "G03"]: |
| | gcode = name |
| | x = last.x |
| | y = last.y |
| | z = last.z |
| | i = 0.0 |
| | j = 0.0 |
| | k = 0.0 |
| | if "I" in p: |
| | i = round(p["I"], 2) |
| | gcode += " I" + str(i) |
| | if "J" in p: |
| | j = round(p["J"], 2) |
| | gcode += " J" + str(j) |
| | if "K" in p: |
| | k = round(p["K"], 2) |
| | gcode += " K" + str(k) |
| |
|
| | if "X" in p: |
| | x = round(p["X"], 2) |
| | gcode += " X" + str(x) |
| | if "Y" in p: |
| | y = round(p["Y"], 2) |
| | gcode += " Y" + str(y) |
| | if "Z" in p: |
| | z = round(p["Z"], 2) |
| | gcode += " Z" + str(z) |
| |
|
| | gcode_list.append(gcode) |
| | last.x = x |
| | last.y = y |
| | last.z = z |
| | return gcode_list |
| |
|
| |
|
| | def pathOriginatesInBox(cmd, minPoint, maxPoint): |
| | p = cmd.Parameters |
| | name = cmd.Name |
| | if name in ["G0", "G00", "G1", "G01"]: |
| | if "X" in p and "Y" in p: |
| | x = p.get("X") |
| | y = p.get("Y") |
| | if x > minPoint.x and y > minPoint.y and x < maxPoint.x and y < maxPoint.y: |
| | return True |
| | return False |
| |
|
| |
|
| | def _addViewProvider(adaptiveOp): |
| | if FreeCAD.GuiUp: |
| | PathOpGui = PathAdaptiveGui.PathOpGui |
| | cmdRes = PathAdaptiveGui.Command.res |
| | adaptiveOp.ViewObject.Proxy = PathOpGui.ViewProvider(adaptiveOp.ViewObject, cmdRes) |
| |
|
| |
|
| | |
| | |
| | expected_moves_test01 = "G1 X32.5 Y32.5 Z5.0; \ |
| | G1 X17.5 Y32.5 Z5.0; \ |
| | G1 X17.5 Y30.0 Z5.0; \ |
| | G1 X32.5 Y30.0 Z5.0; \ |
| | G1 X32.5 Y27.5 Z5.0; \ |
| | G1 X17.5 Y27.5 Z5.0; \ |
| | G1 X17.5 Y25.0 Z5.0; \ |
| | G1 X32.5 Y25.0 Z5.0; \ |
| | G1 X32.5 Y22.5 Z5.0; \ |
| | G1 X17.5 Y22.5 Z5.0; \ |
| | G1 X17.5 Y20.0 Z5.0; \ |
| | G1 X32.5 Y20.0 Z5.0; \ |
| | G1 X32.5 Y17.5 Z5.0; \ |
| | G1 X17.5 Y17.5 Z5.0" |
| |
|