From 775b91d1a2e1069374c0eeb577b08718e825bb07 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Mon, 1 May 2017 23:56:36 -0500 Subject: [PATCH] PATH: conversion of PathContour to PathArea nearly complete Path: improve contour to use makeSections --- .../Path/Gui/Resources/panels/ContourEdit.ui | 40 +--- src/Mod/Path/InitGui.py | 2 +- src/Mod/Path/PathScripts/PathContour.py | 210 +++++------------- src/Mod/Path/PathScripts/PathUtils.py | 17 ++ 4 files changed, 87 insertions(+), 182 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/ContourEdit.ui b/src/Mod/Path/Gui/Resources/panels/ContourEdit.ui index 5e18b18dec..2ce88aaeee 100644 --- a/src/Mod/Path/Gui/Resources/panels/ContourEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/ContourEdit.ui @@ -30,8 +30,8 @@ 0 0 - 334 - 292 + 108 + 92 @@ -82,7 +82,7 @@ - + 0.000000000000000 @@ -97,8 +97,8 @@ 0 0 - 334 - 292 + 141 + 65 @@ -147,8 +147,8 @@ 0 0 - 334 - 292 + 336 + 303 @@ -212,13 +212,6 @@ - - - - Use End Point - - - @@ -238,19 +231,9 @@ - - - - 0.000000000000000 - - - mm - - - - + 0.000000000000000 @@ -258,13 +241,6 @@ - - - - Roll Radius - - - diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py index d375ecff65..f60387bb5c 100644 --- a/src/Mod/Path/InitGui.py +++ b/src/Mod/Path/InitGui.py @@ -140,7 +140,7 @@ class PathWorkbench (Workbench): if "Profile" or "Contour" in FreeCADGui.Selection.getSelection()[0].Name: #self.appendContextMenu("", ["Add_Tag"]) self.appendContextMenu("", ["Set_StartPoint"]) - self.appendContextMenu("", ["Set_EndPoint"]) + #self.appendContextMenu("", ["Set_EndPoint"]) if "Remote" in FreeCADGui.Selection.getSelection()[0].Name: self.appendContextMenu("", ["Refresh_Path"]) diff --git a/src/Mod/Path/PathScripts/PathContour.py b/src/Mod/Path/PathScripts/PathContour.py index 863942c4bb..6b7b78790b 100644 --- a/src/Mod/Path/PathScripts/PathContour.py +++ b/src/Mod/Path/PathScripts/PathContour.py @@ -23,19 +23,19 @@ # *************************************************************************** import FreeCAD -from FreeCAD import Vector +#from FreeCAD import Vector import Path import PathScripts.PathLog as PathLog from PathScripts import PathUtils from PathScripts.PathUtils import depth_params from PySide import QtCore -import TechDraw +#import TechDraw import ArchPanel import Part LOG_MODULE = 'PathContour' PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE) -#PathLog.trackModule('PathContour') +PathLog.trackModule('PathContour') if FreeCAD.GuiUp: import FreeCADGui @@ -80,14 +80,6 @@ class ObjectContour: # Start Point Properties obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path")) obj.addProperty("App::PropertyBool", "UseStartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying a Start Point")) - obj.addProperty("App::PropertyLength", "ExtendAtStart", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "extra length of tool path before start of part edge")) - obj.addProperty("App::PropertyLength", "LeadInLineLen", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "length of straight segment of toolpath that comes in at angle to first part edge")) - - # End Point Properties - obj.addProperty("App::PropertyBool", "UseEndPoint", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying an End Point")) - obj.addProperty("App::PropertyLength", "ExtendAtEnd", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "extra length of tool path after end of part edge")) - obj.addProperty("App::PropertyLength", "LeadOutLineLen", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "length of straight segment of toolpath that comes in at angle to last part edge")) - obj.addProperty("App::PropertyVector", "EndPoint", "End Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The end point of this path")) # Contour Properties obj.addProperty("App::PropertyEnumeration", "Direction", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")) @@ -97,7 +89,6 @@ class ObjectContour: obj.Side = ['Left', 'Right', 'On'] # side of profile that cutter is on in relation to direction of profile obj.setEditorMode('Side', 2) # hide - obj.addProperty("App::PropertyDistance", "RollRadius", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Radius at start and end")) obj.addProperty("App::PropertyDistance", "OffsetExtra", "Contour", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final Contour- good for roughing toolpath")) obj.Proxy = self @@ -132,100 +123,62 @@ class ObjectContour: obj.ClearanceHeight = 10.0 obj.SafeHeight = 8.0 - def _buildPathArea(self, obj, edgelist, start = None): + def _buildPathArea(self, obj, baseobject, start=None): + PathLog.track() - c = Part.Wire(edgelist) - f = Part.makeFace([c], 'Part::FaceMakerSimple') - - profile = Path.Area(Offset=self.radius,SectionCount=1) + profile = Path.Area() profile.setPlane(Part.makeCircle(10)) - profile.add(f) - lshapes = [profile.getShape()] + profile.add(baseobject) + + profileparams = {'Fill': 0, + 'Coplanar' : 0} + + if obj.UseComp is False: + profileparams['Offset'] = 0.0 + else: + profileparams['Offset'] = self.radius+obj.OffsetExtra.Value + + profile.setParams(**profileparams) + PathLog.debug("About to profile with params: {}".format(profileparams)) depthparams = depth_params( - clearance_height = obj.ClearanceHeight.Value, - rapid_safety_space = obj.SafeHeight.Value, - start_depth = obj.StartDepth.Value, - step_down = obj.StepDown.Value, - z_finish_step = 0.0, - final_depth = obj.FinalDepth.Value, - user_depths = None) + clearance_height=obj.ClearanceHeight.Value, + rapid_safety_space=obj.SafeHeight.Value, + start_depth=obj.StartDepth.Value, + step_down=obj.StepDown.Value, + z_finish_step=0.0, + final_depth=obj.FinalDepth.Value, + user_depths=None) - print (depthparams.get_depths()) - for l in depthparams.get_depths(): - c = lshapes[0].copy() - c.Placement.Base.z = l - lshapes.append(c) + sections = profile.makeSections(mode=0, project=True, heights=depthparams.get_depths()) + shapelist = [sec.getShape() for sec in sections] - if start is None: - pp = Path.fromShapes(lshapes, verbose=False) + params = {'shapes': shapelist, + 'feedrate': self.horizFeed, + 'feedrate_v': self.vertFeed, + 'verbose': True, + 'resume_height': obj.StepDown.Value, + 'retraction': obj.ClearanceHeight.Value} + + if obj.Direction == 'CCW': + params['orientation'] = 1 else: - pp = Path.fromShapes(lshapes, start, verbose=False) + params['orientation'] = 0 + + if obj.UseStartPoint is True and obj.StartPoint is not None: + params['start'] = obj.StartPoint + + PathLog.debug("Generating Path with params: {}".format(params)) + pp = Path.fromShapes(**params) + PathLog.debug(pp) + return pp - - # def _buildPathLibarea(self, obj, edgelist): - # import PathScripts.PathKurveUtils as PathKurveUtils - # PathLog.track() - # # import math - # # import area - # output = "" - # if obj.Comment != "": - # output += '(' + str(obj.Comment)+')\n' - - # if obj.StartPoint and obj.UseStartPoint: - # startpoint = obj.StartPoint - # else: - # startpoint = None - - # if obj.EndPoint and obj.UseEndPoint: - # endpoint = obj.EndPoint - # else: - # endpoint = None - - # PathKurveUtils.output('mem') - # PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) - - # output = "" - # output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" - # curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint) - - # roll_radius = 2.0 - # extend_at_start = 0.0 - # extend_at_end = 0.0 - # lead_in_line_len = 0.0 - # lead_out_line_len = 0 # obj.FinalDepth.Value, None) - - # PathKurveUtils.profile2( - - # if obj.UseComp is False: - # obj.Side = 'On' - # else: - # if obj.Direction == 'CW': - # obj.Side = 'Left' - # else: - # obj.Side = 'Right' - - # depthparams = depth_params( - # obj.ClearanceHeight.Value, - # obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0, - # obj.FinalDepth.Value, None) - - # PathKurveUtils.profile2( - # curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, - # self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, - # None, None, depthparams, extend_at_start, extend_at_end, - # lead_in_line_len, lead_out_line_len) - - # output += PathKurveUtils.retrieve_gcode() - # return output - def execute(self, obj): PathLog.track() - import Part # math #DraftGeomUtils - commandlist = [] - #output = "" + import Part + commandlist = [] toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: @@ -236,23 +189,18 @@ class ObjectContour: self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value - tool = toolLoad.Proxy.getTool(toolLoad) #PathUtils.getTool(obj, toolLoad.ToolNumber) + tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return - #self.radius = 0.25 else: self.radius = tool.Diameter/2 - #output += "(" + obj.Label + ")" commandlist.append(Path.Command("(" + obj.Label + ")")) if not obj.UseComp: - #output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) - else: - #output += "(Uncompensated Tool Path)" commandlist.append(Path.Command("(Uncompensated Tool Path)")) parentJob = PathUtils.findParentJob(obj) @@ -269,34 +217,27 @@ class ObjectContour: if isinstance(subobj.Proxy, ArchPanel.PanelCut): shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: - for wire in shape.Wires: - edgelist = wire.Edges - edgelist = Part.__sortEdges__(edgelist) - PathLog.debug("Processing panel perimeter. edges found: {}".format(len(edgelist))) # subobj.Proxy.execute(subobj) + f = Part.makeFace([shape], 'Part::FaceMakerSimple') + thickness = baseobject.Group[0].Source.Thickness + contourshape = f.extrude(FreeCAD.Vector(0,0, thickness)) try: - #output += self._buildPathLibarea(obj, edgelist) - commandlist.extend(self._buildPathArea(obj, edgelist).Commands) - except Exception as e: - print(e) + commandlist.extend(self._buildPathArea(obj, contourshape).Commands) + except Exception as e: + print(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") else: - fixbase = baseobject.Shape.copy() - fixbase.fix(0.00001,0.00001,0.00001) - contourwire = TechDraw.findShapeOutline(fixbase, 1, Vector(0, 0, 1)) - - edgelist = contourwire.Edges - edgelist = Part.__sortEdges__(edgelist) + #fixbase = baseobject.Shape.copy() + #fixbase.fix(0.00001, 0.00001, 0.00001) + env = PathUtils.getEnvelope(baseobject.Shape, obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, edgelist).Commands) - except Exception as e: - print(e) + commandlist.extend(self._buildPathArea(obj, env).Commands) + except Exception as e: + print(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") + if obj.Active: path = Path.Path(commandlist) - # for c in contourcommands.Commands: - # path.addCommands(c) - obj.Path = path if obj.ViewObject: obj.ViewObject.Visibility = True @@ -348,26 +289,6 @@ class _CommandSetStartPoint: obj.StartPoint.y = point.y def Activated(self): - - FreeCADGui.Snapper.getPoint(callback=self.setpoint) - - -class _CommandSetEndPoint: - def GetResources(self): - return {'Pixmap': 'Path-EndPoint', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Contour", "Pick End Point")} - - def IsActive(self): - return FreeCAD.ActiveDocument is not None - - def setpoint(self, point, o): - obj = FreeCADGui.Selection.getSelection()[0] - obj.EndPoint.x = point.x - obj.EndPoint.y = point.y - - def Activated(self): - FreeCADGui.Snapper.getPoint(callback=self.setpoint) @@ -450,14 +371,10 @@ class TaskPanel: self.obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value if hasattr(self.obj, "OffsetExtra"): self.obj.OffsetExtra = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value - if hasattr(self.obj, "RollRadius"): - self.obj.RollRadius = FreeCAD.Units.Quantity(self.form.rollRadius.text()).Value if hasattr(self.obj, "UseComp"): self.obj.UseComp = self.form.useCompensation.isChecked() if hasattr(self.obj, "UseStartPoint"): self.obj.UseStartPoint = self.form.useStartPoint.isChecked() - if hasattr(self.obj, "UseEndPoint"): - self.obj.UseEndPoint = self.form.useEndPoint.isChecked() if hasattr(self.obj, "Direction"): self.obj.Direction = str(self.form.direction.currentText()) if hasattr(self.obj, "ToolController"): @@ -473,10 +390,8 @@ class TaskPanel: self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString) self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown.Value, FreeCAD.Units.Length).UserString) self.form.extraOffset.setText(FreeCAD.Units.Quantity(self.obj.OffsetExtra.Value, FreeCAD.Units.Length).UserString) - self.form.rollRadius.setText(FreeCAD.Units.Quantity(self.obj.RollRadius.Value, FreeCAD.Units.Length).UserString) self.form.useCompensation.setChecked(self.obj.UseComp) self.form.useStartPoint.setChecked(self.obj.UseStartPoint) - self.form.useEndPoint.setChecked(self.obj.UseEndPoint) index = self.form.direction.findText( self.obj.Direction, QtCore.Qt.MatchFixedString) @@ -529,9 +444,7 @@ class TaskPanel: self.form.uiToolController.currentIndexChanged.connect(self.getFields) self.form.useCompensation.clicked.connect(self.getFields) self.form.useStartPoint.clicked.connect(self.getFields) - self.form.useEndPoint.clicked.connect(self.getFields) self.form.extraOffset.editingFinished.connect(self.getFields) - self.form.rollRadius.editingFinished.connect(self.getFields) self.setFields() @@ -554,6 +467,5 @@ if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_Contour', CommandPathContour()) FreeCADGui.addCommand('Set_StartPoint', _CommandSetStartPoint()) - FreeCADGui.addCommand('Set_EndPoint', _CommandSetEndPoint()) FreeCAD.Console.PrintLog("Loading PathContour... done\n") diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index fd6aab8be4..10f4d05d9c 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -33,6 +33,7 @@ import numpy import PathLog #from math import pi from FreeCAD import Vector +import Path LOG_MODULE = 'PathUtils' PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE) @@ -193,6 +194,22 @@ def filterArcs(arcEdge): pass return splitlist +def getEnvelope(partshape, stockheight=None): + ''' + getEnvelop(partshape, stockheight=None) + returns a shape corresponding to the partshape silhouette extruded to height. + if stockheight is given, the returned shape is extruded to that height otherwise the returned shape + is the height of the original shape boundbox + partshape = solid object + stockheight = float + ''' + area = Path.Area(Fill=1, Coplanar=0).add(partshape) + area.setPlane(Part.makeCircle(10)) + sec = area.makeSections(heights=[1.0], project=True)[0].getShape(rebuild=True) + if stockheight is not None: + return sec.extrude(FreeCAD.Vector(0, 0, stockheight)) + else: + return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZMax)) def reverseEdge(e): if geomType(e) == "Circle":