示例#1
0
    def buildpathlibarea(self, obj, a):
        """Build the face path using libarea algorithm"""
        import PathScripts.PathAreaUtils as PathAreaUtils
        from PathScripts.PathUtils import depth_params

        FreeCAD.Console.PrintMessage(
            translate("PathFace",
                      "Generating toolpath with libarea offsets.\n"))

        depthparams = depth_params(obj.ClearanceHeight.Value,
                                   obj.SafeHeight.Value, obj.StartDepth.Value,
                                   obj.StepDown, obj.FinishDepth.Value,
                                   obj.FinalDepth.Value)

        extraoffset = 1 - obj.PassExtension.Value
        stepover = (self.radius * 2) * (float(obj.StepOver) / 100)
        use_zig_zag = obj.UseZigZag
        zig_angle = obj.ZigZagAngle
        from_center = (obj.StartAt == "Center")
        keep_tool_down = obj.KeepToolDown
        zig_unidirectional = obj.ZigUnidirectional
        start_point = None
        cut_mode = obj.CutMode

        PathAreaUtils.flush_nc()
        PathAreaUtils.output('mem')
        PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
        if obj.UseStartPoint:
            start_point = (obj.StartPoint.x, obj.StartPoint.y)

        PathAreaUtils.pocket(a, self.radius, extraoffset, stepover,
                             depthparams, from_center, keep_tool_down,
                             use_zig_zag, zig_angle, zig_unidirectional,
                             start_point, cut_mode)
        return PathAreaUtils.retrieve_gcode()
示例#2
0
    def buildpathlibarea(self, obj, a):
        """Build the pocket path using libarea algorithm"""
        import PathScripts.PathAreaUtils as PathAreaUtils
        from PathScripts.PathUtils import depth_params
        PathLog.debug("Generating toolpath with libarea offsets.\n")

        depthparams = depth_params(obj.ClearanceHeight.Value,
                                   obj.SafeHeight.Value, obj.StartDepth.Value,
                                   obj.StepDown, obj.FinishDepth.Value,
                                   obj.FinalDepth.Value)

        extraoffset = obj.MaterialAllowance.Value
        stepover = (self.radius * 2) * (float(obj.StepOver) / 100)
        use_zig_zag = obj.UseZigZag
        zig_angle = obj.ZigZagAngle
        from_center = (obj.StartAt == "Center")
        keep_tool_down = obj.KeepToolDown
        zig_unidirectional = obj.ZigUnidirectional
        start_point = None
        cut_mode = obj.CutMode

        PathAreaUtils.flush_nc()
        PathAreaUtils.output('mem')
        PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
        if obj.UseStartPoint:
            start_point = (obj.StartPoint.x, obj.StartPoint.y)

        # print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode)

        PathAreaUtils.pocket(a, self.radius, extraoffset, stepover,
                             depthparams, from_center, keep_tool_down,
                             use_zig_zag, zig_angle, zig_unidirectional,
                             start_point, cut_mode)
        return PathAreaUtils.retrieve_gcode()
示例#3
0
    def _buildPathLibarea(self, obj, edgelist):
        import PathScripts.PathKurveUtils as PathKurveUtils
        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.0

        if obj.UseComp is False:
            obj.Side = 'On'
        else:
            if obj.Direction == 'CW':
                obj.Side = 'Left'
            else:
                obj.Side = 'Right'

        PathKurveUtils.clear_tags()
        for i in range(len(obj.locs)):
            tag = obj.locs[i]
            h = obj.heights[i]
            l = obj.lengths[i]
            a = math.radians(obj.angles[i])
            PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)

        depthparams = depth_params(
            obj.ClearanceHeight.Value,
            obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 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
示例#4
0
    def _buildPathLibarea(self, obj, edgelist):
        import PathScripts.PathKurveUtils as PathKurveUtils
        # 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)
        '''The following line uses a profile function written for use with FreeCAD.  It's clean but incomplete.  It doesn't handle
print("x = " + str(point.x))
print("y - " + str(point.y))
            holding tags
            start location
            CRC
            or probably other features in heekscnc'''
        # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
        '''The following calls the original procedure from h
        toolLoad = obj.activeTCeekscnc profile function.  This, in turn, calls many other procedures to modify the profile.
            This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD.  It can probably be
            thoroughly optimized and improved but it'll take a smarter mind than mine to do it.  -sliptonic Feb16'''
        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.0

        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
示例#5
0
    def _buildPathLibarea(self, obj, edgelist):
        import PathScripts.PathKurveUtils as PathKurveUtils
        # 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)

        '''The following line uses a profile function written for use with FreeCAD.  It's clean but incomplete.  It doesn't handle
print("x = " + str(point.x))
print("y - " + str(point.y))
            holding tags
            start location
            CRC
            or probably other features in heekscnc'''
        # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)

        '''The following calls the original procedure from h
        toolLoad = obj.activeTCeekscnc profile function.  This, in turn, calls many other procedures to modify the profile.
            This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD.  It can probably be
            thoroughly optimized and improved but it'll take a smarter mind than mine to do it.  -sliptonic Feb16'''
        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.0

        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
示例#6
0
    def _buildPathArea(self, obj, baseobject, start=None):
        PathLog.track()
        profile = Path.Area()
        profile.setPlane(makeWorkplane(baseobject))
        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

        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)

        PathLog.debug('depths: {}'.format(depthparams.get_depths()))
        profile.setParams(**profileparams)
        PathLog.debug("Contour with params: {}".format(profile.getParams()))

        sections = profile.makeSections(mode=0,
                                        project=True,
                                        heights=depthparams.get_depths())
        shapelist = [sec.getShape() for sec in sections]

        params = {
            'shapes': shapelist,
            'feedrate': self.horizFeed,
            'feedrate_v': self.vertFeed,
            'verbose': True,
            'resume_height': obj.StepDown.Value,
            'retraction': obj.ClearanceHeight.Value,
            'return_end': True
        }

        if obj.Direction == 'CCW':
            params['orientation'] = 1
        else:
            params['orientation'] = 0

        if self.endVector is not None:
            params['start'] = self.endVector
        elif start is not None:
            params['start'] = start

        (pp, end_vector) = Path.fromShapes(**params)
        PathLog.debug("Generating Path with params: {}".format(params))
        PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector))
        self.endVector = end_vector

        return pp
示例#7
0
    def _buildPathLibarea(self, obj, edgelist):
        import PathScripts.PathKurveUtils as PathKurveUtils
        # 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.0

        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
示例#8
0
    def buildpathlibarea(self, obj, a):
        """Build the face path using libarea algorithm"""

        import PathScripts.PathAreaUtils as PathAreaUtils
        from PathScripts.PathUtils import depth_params

        PathLog.track()
        for p in a.getCurves():
            PathLog.debug(p.text())

        FreeCAD.Console.PrintMessage(translate("PathMillFace", "Generating toolpath with libarea offsets.\n"))

        depthparams = depth_params(
                obj.ClearanceHeight.Value,
                obj.SafeHeight.Value,
                obj.StartDepth.Value,
                obj.StepDown,
                obj.FinishDepth.Value,
                obj.FinalDepth.Value)

        extraoffset = - obj.PassExtension.Value
        stepover = (self.radius * 2) * (float(obj.StepOver)/100)
        use_zig_zag = obj.UseZigZag
        zig_angle = obj.ZigZagAngle
        from_center = (obj.StartAt == "Center")
        keep_tool_down = obj.KeepToolDown
        zig_unidirectional = obj.ZigUnidirectional
        start_point = None
        cut_mode = obj.CutMode

        PathAreaUtils.flush_nc()
        PathAreaUtils.output('mem')
        PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)
        if obj.UseStartPoint:
            start_point = (obj.StartPoint.x, obj.StartPoint.y)

        PathAreaUtils.pocket(
                a,
                self.radius,
                extraoffset,
                stepover,
                depthparams,
                from_center,
                keep_tool_down,
                use_zig_zag,
                zig_angle,
                zig_unidirectional,
                start_point,
                cut_mode)
        return PathAreaUtils.retrieve_gcode()
示例#9
0
    def buildpathlibarea(self, obj, a):
        """Build the pocket path using libarea algorithm"""
        import PathScripts.PathAreaUtils as PathAreaUtils
        from PathScripts.PathUtils import depth_params

        FreeCAD.Console.PrintMessage(translate("PathPocket", "Generating toolpath with libarea offsets.\n"))

        depthparams = depth_params(
                obj.ClearanceHeight.Value,
                obj.SafeHeight.Value,
                obj.StartDepth.Value,
                obj.StepDown,
                obj.FinishDepth.Value,
                obj.FinalDepth.Value)

        extraoffset = obj.MaterialAllowance.Value
        stepover = (self.radius * 2) * (float(obj.StepOver)/100)
        use_zig_zag = obj.UseZigZag
        zig_angle = obj.ZigZagAngle
        from_center = (obj.StartAt == "Center")
        keep_tool_down = obj.KeepToolDown
        zig_unidirectional = obj.ZigUnidirectional
        start_point = None
        cut_mode = obj.CutMode

        PathAreaUtils.flush_nc()
        PathAreaUtils.output('mem')
        PathAreaUtils.feedrate_hv(self.horizFeed, self.vertFeed)

        if obj.UseStartPoint:
            start_point = (obj.StartPoint.x, obj.StartPoint.y)

        # print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode)

        PathAreaUtils.pocket(
                a,
                self.radius,
                extraoffset,
                stepover,
                depthparams,
                from_center,
                keep_tool_down,
                use_zig_zag,
                zig_angle,
                zig_unidirectional,
                start_point,
                cut_mode)

        return PathAreaUtils.retrieve_gcode()
示例#10
0
    def _buildPathLibarea(self, obj, edgelist):
        import PathScripts.PathKurveUtils as PathKurveUtils
        import math
        import area
        output = ""

        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)
        curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint)

        '''The following line uses a profile function written for use with FreeCAD.  It's clean but incomplete.  It doesn't handle
print "x = " + str(point.x)
print "y - " + str(point.y)
            holding tags
            start location
            CRC
            or probably other features in heekscnc'''
        # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)

        '''The following calls the original procedure from heekscnc profile function.  This, in turn, calls many other procedures to modify the profile.
            This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD.  It can probably be
            thoroughly optimized and improved but it'll take a smarter mind than mine to do it.  -sliptonic Feb16'''
        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.0

        '''

        Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
        I need to access the location vector, length, angle in radians and height.

        '''
        PathKurveUtils.clear_tags()
        for i in range(len(obj.locs)):
            tag = obj.locs[i]
            h = obj.heights[i]
            l = obj.lengths[i]
            a = math.radians(obj.angles[i])
            PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)

        depthparams = depth_params(
            obj.ClearanceHeight.Value,
            obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0,
            obj.FinalDepth.Value, None)

        PathKurveUtils.profile2(
            curve, obj.Side, self.radius, self.vertFeed,
            self.horizFeed, 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
示例#11
0
    def execute(self, obj, getsim=False):
        PathLog.track()
        self.endVector = None

        if not obj.Active:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
            return

        commandlist = []
        toolLoad = obj.ToolController

        self.depthparams = depth_params(
            clearance_height=obj.ClearanceHeight.Value,
            safe_height=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)

        if toolLoad is None or toolLoad.ToolNumber == 0:
            FreeCAD.Console.PrintError(
                "No Tool Controller is selected. We need a tool to build a Path."
            )
            return
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            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
            else:
                self.radius = tool.Diameter / 2

        commandlist.append(Path.Command("(" + obj.Label + ")"))

        if obj.UseComp:
            commandlist.append(
                Path.Command("(Compensated Tool Path. Diameter: " +
                             str(self.radius * 2) + ")"))
        else:
            commandlist.append(Path.Command("(Uncompensated Tool Path)"))

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return

        # Let's always start by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        isPanel = False
        if hasattr(baseobject, "Proxy"):
            if isinstance(baseobject.Proxy,
                          ArchPanel.PanelSheet):  # process the sheet
                isPanel = True
                baseobject.Proxy.execute(baseobject)
                shapes = baseobject.Proxy.getOutlines(baseobject,
                                                      transform=True)
                for shape in shapes:
                    f = Part.makeFace([shape], 'Part::FaceMakerSimple')
                    thickness = baseobject.Group[0].Source.Thickness
                    contourshape = f.extrude(FreeCAD.Vector(0, 0, thickness))
                    try:
                        (pp, sim) = self._buildPathArea(obj,
                                                        contourshape,
                                                        start=obj.StartPoint,
                                                        getsim=getsim)
                        commandlist.extend(pp.Commands)
                    except Exception as e:
                        FreeCAD.Console.PrintError(e)
                        FreeCAD.Console.PrintError(
                            "Something unexpected happened. Unable to generate a contour path. Check project and tool config."
                        )

        if hasattr(baseobject, "Shape") and not isPanel:
            #bb = baseobject.Shape.BoundBox
            env = PathUtils.getEnvelope(partshape=baseobject.Shape,
                                        subshape=None,
                                        depthparams=self.depthparams)
            try:
                (pp, sim) = self._buildPathArea(obj,
                                                env,
                                                start=obj.StartPoint,
                                                getsim=getsim)
                commandlist.extend(pp.Commands)
            except Exception as e:
                FreeCAD.Console.PrintError(e)
                FreeCAD.Console.PrintError(
                    "Something unexpected happened. Unable to generate a contour path. Check project and tool config."
                )

        # Let's finish by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        path = Path.Path(commandlist)
        obj.Path = path
        #obj.ViewObject.Visibility = True
        return sim
示例#12
0
    def buildpathocc(self, obj, shape):
        """Build pocket Path using Native OCC algorithm."""
        import Part
        import DraftGeomUtils
        from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge, depth_params

        FreeCAD.Console.PrintMessage(translate("PathPocket", "Generating toolpath with OCC native offsets.\n"))
        extraoffset = obj.MaterialAllowance.Value

        # Build up the offset loops
        output = ""
        if obj.Comment != "":
            output += '(' + str(obj.Comment)+')\n'
        output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"

        offsets = []
        nextradius = self.radius + extraoffset
        result = DraftGeomUtils.pocket2d(shape, nextradius)
        while result:
            offsets.extend(result)
            nextradius += (self.radius * 2) * (float(obj.StepOver)/100)
            result = DraftGeomUtils.pocket2d(shape, nextradius)

        # revert the list so we start with the outer wires
        if obj.StartAt != 'Edge':
            offsets.reverse()

        plungePos = None
        rampEdge = None
        if obj.UseEntry:
            # Try to find an entry location
            toold = self.radius*2
            helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + obj.HelixSize))

            if helixBounds:
                rampD = obj.RampSize

                if obj.StartAt == 'Edge':
                    plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                else:
                    plungePos = offsets[0].Edges[0].Vertexes[0].Point

                    # If it turns out this is invalid for some reason, nuke plungePos
                    [perp, idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges)
                    if not perp or perp.Length < self.radius * (1 + obj.HelixSize):
                        plungePos = None
                        FreeCAD.Console.PrintError(translate("PathPocket", "Helical Entry location not found.\n"))
                    # FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
                    # Or some math to prove that it has to be (doubt that's true)
                    # Maybe reverse helixBounds and pick off that?

            if plungePos is None:  # If we didn't find a place to helix, how about a ramp?
                FreeCAD.Console.PrintMessage(translate("PathPocket", "Attempting ramp entry.\n"))
                if (offsets[0].Edges[0].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[0]
                # The last edge also connects with the starting location- try that
                elif (offsets[0].Edges[-1].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[-1]
                else:
                    FreeCAD.Console.PrintError(translate("PathPocket", "Ramp Entry location not found.\n"))
                    # print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
                    # FIXME: There's got to be a smarter way to find a place to ramp

        # For helix-ing/ramping, know where we were last time
        # FIXME: Can probably get this from the "machine"?
        lastZ = obj.ClearanceHeight.Value

        startPoint = None

        depthparams = depth_params(
                obj.ClearanceHeight.Value,
                obj.SafeHeight.Value,
                obj.StartDepth.Value,
                obj.StepDown,
                obj.FinishDepth.Value,
                obj.FinalDepth.Value)

        for vpos in depthparams.get_depths():

            first = True
            # loop over successive wires
            for currentWire in offsets:
                last = None
                for edge in currentWire.Edges:
                    if not last:
                        # we set the base GO to our fast move to our starting pos
                        if first:
                            # If we can helix, do so
                            if plungePos:
                                output += helicalPlunge(plungePos, obj.RampAngle, vpos, lastZ, self.radius*2, obj.HelixSize, self.horizFeed)
                                lastZ = vpos
                            # Otherwise, see if we can ramp
                            # FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
                            elif rampEdge:
                                output += rampPlunge(rampEdge, obj.RampAngle, vpos, lastZ)
                                lastZ = vpos
                            # Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
                            # FIXME: At least not with the lazy ramp programming above...
                            else:
                                print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
                                startPoint = edge.Vertexes[0].Point
                                output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
                                output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\
                                          " Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
                            first = False
                        # then move slow down to our starting point for our profile
                        last = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(last.x) + " Y" + fmt(last.y) + " Z" + fmt(vpos) + " F" + fmt(self.vertFeed) + "\n"
                    if DraftGeomUtils.geomType(edge) == "Circle":
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        center = edge.Curve.Center
                        relcenter = center.sub(last)
                        v1 = last.sub(center)
                        v2 = point.sub(center)
                        if v1.cross(v2).z < 0:
                            output += "G2"
                        else:
                            output += "G3"
                        output += " X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos)
                        output += " I" + fmt(relcenter.x) + " J" + fmt(relcenter.y) + " K" + fmt(relcenter.z)  + " F" + fmt(self.horizFeed) 
                        output += "\n"
                        last = point
                    else:
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos) + " F" + fmt(self.horizFeed)  + "\n"
                        last = point

        # move back up
        output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
        return output
示例#13
0
    def execute(self, obj, getsim=False):
        import Part

        if not obj.Active:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
            return

        self.depthparams = depth_params(
                clearance_height=obj.ClearanceHeight.Value,
                safe_height=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)

        commandlist = []
        toolLoad = obj.ToolController
        if toolLoad is None or toolLoad.ToolNumber == 0:
            FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.")
            return
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            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
            else:
                self.radius = tool.Diameter/2

        commandlist.append(Path.Command("(" + obj.Label + ")"))

        if obj.UseComp:
            commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"))
        else:
            commandlist.append(Path.Command("(Uncompensated Tool Path)"))

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return

        if obj.Base:  # The user has selected subobjects from the base.  Process each.
            holes = []
            faces = []
            for b in obj.Base:
                for sub in b[1]:
                    shape = getattr(b[0].Shape, sub)
                    if isinstance(shape, Part.Face):
                        faces.append(shape)
                        if numpy.isclose(abs(shape.normalAt(0, 0).z), 1):  # horizontal face
                            holes += shape.Wires[1:]
                    else:
                        FreeCAD.Console.PrintWarning("found a base object which is not a face.  Can't continue.")
                        return

            for wire in holes:
                f = Part.makeFace(wire, 'Part::FaceMakerSimple')
                drillable = PathUtils.isDrillable(baseobject.Shape, wire)
                if (drillable and obj.processCircles) or (not drillable and obj.processHoles):
                    env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams)
                    try:
                        (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim)
                        commandlist.extend(pp.Commands)
                    except Exception as e:
                        FreeCAD.Console.PrintError(e)
                        FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")

            if len(faces) > 0:
                profileshape = Part.makeCompound(faces)

            if obj.processPerimeter:
                env = PathUtils.getEnvelope(baseobject.Shape, subshape=profileshape, depthparams=self.depthparams)
                try:
                    (pp, sim) = self._buildPathArea(obj, baseobject=env, start=None, getsim=getsim)
                    commandlist.extend(pp.Commands)
                except Exception as e:
                    FreeCAD.Console.PrintError(e)
                    FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")

        else:  # Try to build targets from the job base
            if hasattr(baseobject, "Proxy"):
                if isinstance(baseobject.Proxy, ArchPanel.PanelSheet):  # process the sheet
                    if obj.processPerimeter:
                        shapes = baseobject.Proxy.getOutlines(baseobject, transform=True)
                        for shape in shapes:
                            for wire in shape.Wires:
                                f = Part.makeFace(wire, 'Part::FaceMakerSimple')
                                env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams)
                                try:
                                    (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=False, start=None, getsim=getsim)
                                    commandlist.extend(pp.Commands)
                                except Exception as e:
                                    FreeCAD.Console.PrintError(e)
                                    FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")

                    shapes = baseobject.Proxy.getHoles(baseobject, transform=True)
                    for shape in shapes:
                        for wire in shape.Wires:
                            drillable = PathUtils.isDrillable(baseobject.Proxy, wire)
                            if (drillable and obj.processCircles) or (not drillable and obj.processHoles):
                                f = Part.makeFace(wire, 'Part::FaceMakerSimple')
                                env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams)
                                try:
                                    (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim)
                                    commandlist.extend(pp.Commands)
                                except Exception as e:
                                    FreeCAD.Console.PrintError(e)
                                    FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")

        # Let's finish by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))

        path = Path.Path(commandlist)
        obj.Path = path
示例#14
0
    def execute(self, obj, getsim=False):
        commandlist = []
        sim = None

        if not obj.Active:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
            return

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return

        self.depthparams = depth_params(
            clearance_height=obj.ClearanceHeight.Value,
            safe_height=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)

        toolLoad = obj.ToolController
        if toolLoad is None or toolLoad.ToolNumber == 0:
            FreeCAD.Console.PrintError(
                "No Tool Controller is selected. We need a tool to build a Path."
            )
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            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
            else:
                self.radius = tool.Diameter / 2

        commandlist.append(Path.Command("(" + obj.Label + ")"))

        if obj.UseComp:
            commandlist.append(
                Path.Command("(Compensated Tool Path. Diameter: " +
                             str(self.radius * 2) + ")"))
        else:
            commandlist.append(Path.Command("(Uncompensated Tool Path)"))

        if obj.Base:
            wires = []

            for b in obj.Base:
                edgelist = []
                for sub in b[1]:
                    edgelist.append(getattr(b[0].Shape, sub))
                wires.extend(findWires(edgelist))

            for wire in wires:
                f = Part.makeFace(wire, 'Part::FaceMakerSimple')

                # shift the compound to the bottom of the base object for
                # proper sectioning
                zShift = b[0].Shape.BoundBox.ZMin - f.BoundBox.ZMin
                newPlace = FreeCAD.Placement(FreeCAD.Vector(0, 0, zShift),
                                             f.Placement.Rotation)
                f.Placement = newPlace
                env = PathUtils.getEnvelope(baseobject.Shape,
                                            subshape=f,
                                            depthparams=self.depthparams)

                try:
                    (pp, sim) = self._buildPathArea(obj,
                                                    baseobject=env,
                                                    start=obj.StartPoint,
                                                    getsim=getsim)
                    commandlist.extend(pp.Commands)

                except Exception as e:
                    FreeCAD.Console.PrintError(e)
                    FreeCAD.Console.PrintError(
                        "Something unexpected happened. Unable to generate a contour path. Check project and tool config."
                    )

        # Let's finish by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        path = Path.Path(commandlist)
        obj.Path = path
        obj.ViewObject.Visibility = True
        return sim
示例#15
0
    def execute(self, obj, getsim=False):
        PathLog.track()
        commandlist = []
        simlist = []
        commandlist.append(Path.Command("(" + obj.Label + ")"))
        if not obj.Active:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
            return

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return

        self.depthparams = depth_params(
            clearance_height=obj.ClearanceHeight.Value,
            safe_height=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)

        toolLoad = obj.ToolController
        if toolLoad is None or toolLoad.ToolNumber == 0:
            FreeCAD.Console.PrintError(
                "No Tool Controller is selected. We need a tool to build a Path."
            )
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            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
            else:
                self.radius = tool.Diameter / 2

        if obj.Base:
            PathLog.debug("base items exist.  Processing...")
            for b in obj.Base:
                PathLog.debug("Base item: {}".format(b))
                for sub in b[1]:
                    if "Face" in sub:
                        shape = Part.makeCompound([getattr(b[0].Shape, sub)])
                        #shape = getattr(b[0].Shape, sub)
                    else:
                        edges = [getattr(b[0].Shape, sub) for sub in b[1]]
                        shape = Part.makeFace(edges, 'Part::FaceMakerSimple')

                    env = PathUtils.getEnvelope(baseobject.Shape,
                                                subshape=shape,
                                                depthparams=self.depthparams)
                    removal = env.cut(baseobject.Shape)

                    if PathLog.getLevel(
                            PathLog.thisModule()) == PathLog.Level.DEBUG:
                        removalshape = FreeCAD.ActiveDocument.addObject(
                            "Part::Feature", "removalshape")
                        removalshape.Shape = removal

                    try:
                        (pp, sim) = self._buildPathArea(obj,
                                                        removal,
                                                        getsim=getsim)
                        if sim is not None:
                            simlist.append(sim)
                        commandlist.extend(pp.Commands)
                    except Exception as e:
                        FreeCAD.Console.PrintError(e)
                        FreeCAD.Console.PrintError(
                            "Something unexpected happened. Unable to generate a pocket path. Check project and tool config."
                        )
        else:  # process the job base object as a whole
            PathLog.debug("processing the whole job base object")

            env = PathUtils.getEnvelope(baseobject.Shape,
                                        subshape=None,
                                        depthparams=self.depthparams)
            removal = env.cut(baseobject.Shape)
            if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
                removalshape = FreeCAD.ActiveDocument.addObject(
                    "Part::Feature", "removalshape")
                removalshape.Shape = removal
            try:
                (pp, sim) = self._buildPathArea(obj, removal, getsim=getsim)
                commandlist.extend(pp.Commands)
                if sim is not None:
                    simlist.append(sim)

                #commandlist.extend(self._buildPathArea(obj, env.cut(baseobject.Shape)).Commands)
            except Exception as e:
                FreeCAD.Console.PrintError(e)
                FreeCAD.Console.PrintError(
                    "Something unexpected happened. Unable to generate a pocket path. Check project and tool config."
                )

        # Let's finish by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        path = Path.Path(commandlist)
        obj.Path = path
        obj.ViewObject.Visibility = True

        PathLog.debug(simlist)
        simshape = None
        if len(simlist) > 1:
            simshape = simlist[0].fuse(simlist[1:])
        elif len(simlist) == 1:
            simshape = simlist[0]

        if simshape is not None and PathLog.getLevel(
                PathLog.thisModule()) == PathLog.Level.DEBUG:
            sim = FreeCAD.ActiveDocument.addObject("Part::Feature", "simshape")
            sim.Shape = simshape
        return simshape
示例#16
0
    def _waterline(self, obj, s, bb):
        import ocl
        from PathScripts.PathUtils import depth_params, fmt
        import time

        def drawLoops(loops):
            nloop = 0
            waterlinestring = ""
            waterlinestring += "(waterline begin)"
            for loop in loops:
                p = loop[0]
                loopstring = "(loop begin)" + "\n"
                loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "\n"
                loopstring += "G0 X" + \
                    str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "\n"
                loopstring += "G1 Z" + str(fmt(p.z)) + "\n"
                for p in loop[1:]:
                    loopstring += "G1 X" + \
                        str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \
                        " Z" + str(fmt(p.z)) + "\n"
                    zheight = p.z
                p = loop[0]
                loopstring += "G1 X" + \
                    str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \
                    " Z" + str(fmt(zheight)) + "\n"
                loopstring += "(loop end)" + "\n"
                print "    loop ", nloop, " with ", len(loop), " points"
                nloop = nloop + 1
                waterlinestring += loopstring
            waterlinestring += "(waterline end)" + "\n"
            return waterlinestring

        depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value,
                                   obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value)
        # stlfile = "../../stl/gnu_tux_mod.stl"
        # surface = STLSurfaceSource(stlfile)
        surface = s

        t_before = time.time()
        zheights = depthparams.get_depths()
        wl = ocl.Waterline()
        # wl = ocl.AdaptiveWaterline() # this is slower, ca 60 seconds on i7
        # CPU
        wl.setSTL(surface)
        diam = 0.5
        length = 10.0
        # any ocl MillingCutter class should work here
        cutter = ocl.BallCutter(diam, length)
        wl.setCutter(cutter)
        # this should be smaller than the smallest details in the STL file
        wl.setSampling(obj.SampleInterval)
        # AdaptiveWaterline() also has settings for minimum sampling interval
        # (see c++ code)
        all_loops = []
        for zh in zheights:
            print "calculating Waterline at z= ", zh
            wl.reset()
            wl.setZ(zh)  # height for this waterline
            wl.run()
            all_loops.append(wl.getLoops())
        t_after = time.time()
        calctime = t_after - t_before
        n = 0
        output = ""
        for loops in all_loops:  # at each z-height, we may get many loops
            print "  %d/%d:" % (n, len(all_loops))
            output += drawLoops(loops)
            n = n + 1
        print "(" + str(calctime) + ")"
        return output
示例#17
0
    def _buildPathLibarea(self, obj, edgelist, isHole):
        import PathScripts.PathKurveUtils as PathKurveUtils
        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)

        # Reverse the direction for holes
        if isHole:
            direction = "CW" if obj.Direction == "CCW" else "CCW"
        else:
            direction = obj.Direction

        output = ""
        output += "G0 Z" + str(
            obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(
                self.vertRapid) + "\n"
        curve = PathKurveUtils.makeAreaCurve(edgelist, direction, startpoint,
                                             endpoint)
        '''The following line uses a profile function written for use with FreeCAD.  It's clean but incomplete.  It doesn't handle
print "x = " + str(point.x)
print "y - " + str(point.y)
            holding tags
            start location
            CRC
            or probably other features in heekscnc'''
        # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC)
        '''The following calls the original procedure from h
        toolLoad = obj.activeTCeekscnc profile function.  This, in turn, calls many other procedures to modify the profile.
            This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD.  It can probably be
            thoroughly optimized and improved but it'll take a smarter mind than mine to do it.  -sliptonic Feb16'''
        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.0
        '''

        Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils.
        I need to access the location vector, length, angle in radians and height.

        '''
        PathKurveUtils.clear_tags()
        for i in range(len(obj.locs)):
            tag = obj.locs[i]
            h = obj.heights[i]
            l = obj.lengths[i]
            a = math.radians(obj.angles[i])
            PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h)

        depthparams = depth_params(obj.ClearanceHeight.Value,
                                   obj.SafeHeight.Value, obj.StartDepth.Value,
                                   obj.StepDown, 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
示例#18
0
    def execute(self, obj):
        PathLog.track()
        if not obj.Active:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
            return

        commandlist = []
        toolLoad = obj.ToolController

        self.depthparams = depth_params(
            clearance_height=obj.ClearanceHeight.Value,
            safe_height=obj.SafeHeight.Value,
            start_depth=obj.StartDepth.Value,
            step_down=obj.StepDown,
            z_finish_step=obj.FinishDepth.Value,
            final_depth=obj.FinalDepth.Value,
            user_depths=None)

        if toolLoad is None or toolLoad.ToolNumber == 0:
            FreeCAD.Console.PrintError(
                "No Tool Controller is selected. We need a tool to build a Path."
            )
            return
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            tool = toolLoad.Proxy.getTool(toolLoad)

            if tool.Diameter == 0:
                FreeCAD.Console.PrintError(
                    "No Tool found or diameter is zero. We need a tool to build a Path."
                )
                return
            else:
                self.radius = tool.Diameter / 2

        commandlist.append(Path.Command("(" + obj.Label + ")"))

        # Facing is done either against base objects
        if obj.Base:
            PathLog.debug("obj.Base: {}".format(obj.Base))
            faces = []
            for b in obj.Base:
                for sub in b[1]:
                    shape = getattr(b[0].Shape, sub)
                    if isinstance(shape, Part.Face):
                        faces.append(shape)
                    else:
                        PathLog.debug('The base subobject is not a face')
                        return
            planeshape = Part.makeCompound(faces)
            PathLog.info("Working on a collection of faces {}".format(faces))

        # If no base object, do planing of top surface of entire model
        else:
            parentJob = PathUtils.findParentJob(obj)
            if parentJob is None:
                PathLog.debug("No base object. No parent job found")
                return
            baseobject = parentJob.Base
            if baseobject is None:
                PathLog.debug("Parent job exists but no Base Object")
                return
            planeshape = baseobject.Shape
            PathLog.info("Working on a shape {}".format(baseobject.Name))

        # Let's start by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        # if user wants the boundbox, calculate that
        PathLog.info("Boundary Shape: {}".format(obj.BoundaryShape))
        bb = planeshape.BoundBox
        if obj.BoundaryShape == 'Boundbox':
            bbperim = Part.makeBox(bb.XLength, bb.YLength, 1,
                                   FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin),
                                   FreeCAD.Vector(0, 0, 1))
            env = PathUtils.getEnvelope(partshape=bbperim,
                                        depthparams=self.depthparams)
        else:
            env = PathUtils.getEnvelope(partshape=planeshape,
                                        depthparams=self.depthparams)

        try:
            commandlist.extend(self._buildPathArea(obj, env).Commands)
        except Exception as e:
            FreeCAD.Console.PrintError(e)
            FreeCAD.Console.PrintError(
                translate(
                    "Path_MillFace",
                    "The selected settings did not produce a valid path.\n"))

        # Let's finish by rapid to clearance...just for safety
        commandlist.append(Path.Command("G0",
                                        {"Z": obj.ClearanceHeight.Value}))

        path = Path.Path(commandlist)
        obj.Path = path
        obj.ViewObject.Visibility = True