Exemple #1
1
    def updateDepths(self, obj, ignoreErrors=False):
        '''updateDepths(obj) ... base implementation calculating depths depending on base geometry.
        Should not be overwritten.'''
        def faceZmin(bb, fbb):
            if fbb.ZMax == fbb.ZMin and fbb.ZMax == bb.ZMax:  # top face
                return fbb.ZMin
            elif fbb.ZMax > fbb.ZMin and fbb.ZMax == bb.ZMax:  # vertical face, full cut
                return fbb.ZMin
            elif fbb.ZMax > fbb.ZMin and fbb.ZMin > bb.ZMin:  # internal vertical wall
                return fbb.ZMin
            elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin:  # face/shelf
                return fbb.ZMin
            return bb.ZMin

        if not self._setBaseAndStock(obj, ignoreErrors):
            return False

        stockBB = self.stock.Shape.BoundBox
        zmin = stockBB.ZMin
        zmax = stockBB.ZMax

        obj.OpStockZMin = zmin
        obj.OpStockZMax = zmax

        if hasattr(obj, 'Base') and obj.Base:
            for base, sublist in obj.Base:
                bb = base.Shape.BoundBox
                zmax = max(zmax, bb.ZMax)
                for sub in sublist:
                    try:
                        fbb = base.Shape.getElement(sub).BoundBox
                        zmin = max(zmin, faceZmin(bb, fbb))
                        zmax = max(zmax, fbb.ZMax)
                    except Part.OCCError as e:
                        PathLog.error(e)

        else:
            # clearing with stock boundaries
            job = PathUtils.findParentJob(obj)
            zmax = stockBB.ZMax
            zmin = job.Proxy.modelBoundBox(job).ZMax

        if FeatureDepths & self.opFeatures(obj):
            # first set update final depth, it's value is not negotiable
            if not PathGeom.isRoughly(obj.OpFinalDepth.Value, zmin):
                obj.OpFinalDepth = zmin
            zmin = obj.OpFinalDepth.Value

            def minZmax(z):
                if hasattr(obj, 'StepDown') and not PathGeom.isRoughly(
                        obj.StepDown.Value, 0):
                    return z + obj.StepDown.Value
                else:
                    return z + 1

            # ensure zmax is higher than zmin
            if (zmax - 0.0001) <= zmin:
                zmax = minZmax(zmin)

            # update start depth if requested and required
            if not PathGeom.isRoughly(obj.OpStartDepth.Value, zmax):
                obj.OpStartDepth = zmax
        else:
            # every obj has a StartDepth
            if obj.StartDepth.Value != zmax:
                obj.StartDepth = zmax

        self.opUpdateDepths(obj)
    def test20(self):
        '''Start and end are equal or start lower than finish '''
        clearance_height = 15
        rapid_safety_space = 12

        start_depth = 10
        step_down = 2
        z_finish_step = 0
        final_depth = 10
        user_depths = None

        expected = []

        d = PU.depth_params(clearance_height, rapid_safety_space, start_depth,
                            step_down, z_finish_step, final_depth, user_depths)
        r = d.get_depths()
        self.assertListEqual(r, expected)

        start_depth = 10
        final_depth = 15

        expected = []

        d = PU.depth_params(clearance_height, rapid_safety_space, start_depth,
                            step_down, z_finish_step, final_depth, user_depths)
        r = d.get_depths()
        self.assertListEqual(r, expected)
Exemple #3
0
    def setDefaultValues(self, obj):
        '''setDefaultValues(obj) ... base implementation.
        Do not overwrite, overwrite opSetDefaultValues() instead.'''
        PathUtils.addToJob(obj)

        obj.Active = True

        features = self.opFeatures(obj)

        if FeatureTool & features:
            obj.ToolController = PathUtils.findToolController(obj)

        if FeatureDepths & features:
            obj.StartDepth      =  1.0
            obj.FinalDepth      =  0.0

        if FeatureStepDown & features:
            obj.StepDown        =  1.0

        if FeatureHeights & features:
            obj.ClearanceHeight = 10.0
            obj.SafeHeight      =  8.0

        if FeatureStartPoint & features:
            obj.UseStartPoint = False

        self.opSetDefaultValues(obj)
Exemple #4
0
    def execute(self, obj):
        output = ""

        toolLoad = PathUtils.getLastToolLoad(obj)
        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            self.radius = tool.Diameter/2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " (" + obj.ToolDescription + ")"
        else:
            obj.Label = obj.UserLabel + " (" + obj.ToolDescription + ")"

        output += "(remote gcode goes here)"
        path = Path.Path(output)
        obj.Path = path
    def test20(self):
        '''Start and end are equal or start lower than finish '''
        clearance_height= 15
        safe_height = 12

        start_depth = 10
        step_down = 2
        z_finish_step = 0
        final_depth = 10
        user_depths =  None

        expected =[10]

        d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths)
        r = [i for i in d]
        self.assertListEqual (r, expected)

        start_depth = 10
        final_depth = 15

        expected =[]

        d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths)
        r = [i for i in d]
        self.assertListEqual (r, expected)
Exemple #6
0
    def areaOpShapes(self, obj):
        '''areaOpShapes(obj) ... return shapes representing the solids to be removed.'''
        PathLog.track()

        if obj.Base:
            PathLog.debug("base items exist.  Processing...")
            removalshapes = []
            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)])
                    else:
                        edges = [getattr(b[0].Shape, sub) for sub in b[1]]
                        shape = Part.makeFace(edges, 'Part::FaceMakerSimple')

                    env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=shape, depthparams=self.depthparams)
                    obj.removalshape = env.cut(self.baseobject.Shape)
                    removalshapes.append((obj.removalshape, False))
        else:  # process the job base object as a whole
            PathLog.debug("processing the whole job base object")

            env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=None, depthparams=self.depthparams)
            obj.removalshape = env.cut(self.baseobject.Shape)
            removalshapes = [(obj.removalshape, False)]
        return removalshapes
Exemple #7
0
    def findHoles(self, obj, shape):
        import DraftGeomUtils as dgu
        PathLog.track('obj: {} shape: {}'.format(obj, shape))
        holelist = []
        tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter
        PathLog.debug('search for holes larger than tooldiameter: {}: '.format(tooldiameter))
        if dgu.isPlanar(shape):
            PathLog.debug("shape is planar")
            for i in range(len(shape.Edges)):
                candidateEdgeName = "Edge" + str(i + 1)
                e = shape.getElement(candidateEdgeName)
                if PathUtils.isDrillable(shape, e, tooldiameter):
                    PathLog.debug('edge candidate: {} (hash {})is drillable '.format(e, e.hashCode()))
                    x = e.Curve.Center.x
                    y = e.Curve.Center.y
                    diameter = e.BoundBox.XLength
                    holelist.append({'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True})
        else:
            PathLog.debug("shape is not planar")
            for i in range(len(shape.Faces)):
                candidateFaceName = "Face" + str(i + 1)
                f = shape.getElement(candidateFaceName)
                if PathUtils.isDrillable(shape, f, tooldiameter):
                    PathLog.debug('face candidate: {} is drillable '.format(f))
                    x = f.Surface.Center.x
                    y = f.Surface.Center.y
                    diameter = f.BoundBox.XLength
                    holelist.append({'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True})

        PathLog.debug("holes found: {}".format(holelist))
        return holelist
 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) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
         loopstring += "G0 X" + \
             str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "F " + PathUtils.fmt(self.horizRapid) + "\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
    def areaOpShapes(self, obj):
        '''areaOpShapes(obj) ... return top face'''
        # 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.debug("Working on a collection of faces {}".format(faces))

        # If no base object, do planing of top surface of entire model
        else:
            planeshape = self.baseobject.Shape
            PathLog.debug("Working on a shape {}".format(self.baseobject.Name))

        # Find the correct shape depending on Boundary shape.
        PathLog.debug("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)
        elif obj.BoundaryShape == 'Stock':
            stock = PathUtils.findParentJob(obj).Stock.Shape
            env = stock
        else:
            env = PathUtils.getEnvelope(partshape=planeshape, depthparams=self.depthparams)

        return [(env, False)]
Exemple #10
0
    def setDefaultValues(self, obj):
        '''setDefaultValues(obj) ... base implementation.
        Do not overwrite, overwrite opSetDefaultValues() instead.'''
        job = PathUtils.addToJob(obj)

        obj.Active = True

        features = self.opFeatures(obj)

        if FeatureTool & features:
            obj.ToolController = PathUtils.findToolController(obj)
            obj.OpToolDiameter  =  1.0

        if FeatureDepths & features:
            obj.setExpression('StartDepth', job.SetupSheet.StartDepthExpression)
            obj.setExpression('FinalDepth', job.SetupSheet.FinalDepthExpression)
            obj.OpStartDepth    =  1.0
            obj.OpFinalDepth    =  0.0

        if FeatureStepDown & features:
            obj.setExpression('StepDown', job.SetupSheet.StepDownExpression)

        if FeatureHeights & features:
            if job.SetupSheet.SafeHeightExpression:
                obj.setExpression('SafeHeight', job.SetupSheet.SafeHeightExpression)
            if job.SetupSheet.ClearanceHeightExpression:
                obj.setExpression('ClearanceHeight', job.SetupSheet.ClearanceHeightExpression)

        if FeatureStartPoint & features:
            obj.UseStartPoint = False

        self.opSetDefaultValues(obj)
        obj.recompute()
Exemple #11
0
    def setup(self, obj):
        debugPrint("Here we go ... ")
        if hasattr(obj.Base, "BoneBlacklist"):
            # dressing up a bone dressup
            obj.Side = obj.Base.Side
        else:
            # otherwise dogbones are opposite of the base path's side
            if obj.Base.Side == Side.Left:
                obj.Side = Side.Right
            elif obj.Base.Side == Side.Right:
                obj.Side = Side.Left
            else:
                # This will cause an error, which is fine for now 'cause I don't know what to do here
                obj.Side = 'On'

        self.toolRadius = 5
        toolLoad = PathUtils.getLastToolLoad(obj)
        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.toolRadius = 5
        else:
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            if not tool or tool.Diameter == 0:
                self.toolRadius = 5
            else:
                self.toolRadius = tool.Diameter / 2

        self.shapes = {}
        self.dbg = []
Exemple #12
0
    def setFields(self):
        self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finishDepth.setText(FreeCAD.Units.Quantity(self.obj.FinishDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown, FreeCAD.Units.Length).UserString)
        self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
        self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value,  FreeCAD.Units.Length).UserString)

        controllers = PathUtils.getToolControllers(self.obj)
        labels = [c.Label for c in controllers]
        self.form.uiToolController.blockSignals(True)
        self.form.uiToolController.addItems(labels)
        self.form.uiToolController.blockSignals(False)
        if self.obj.ToolController is not None:
            index = self.form.uiToolController.findText(
                self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
            PathLog.debug("searching for TC label {}. Found Index: {}".format(self.obj.ToolController.Label, index))
            if index >= 0:
                self.form.uiToolController.blockSignals(True)
                self.form.uiToolController.setCurrentIndex(index)
                self.form.uiToolController.blockSignals(False)
        else:
            self.obj.ToolController = PathUtils.findToolController(self.obj)

        for i in self.obj.Base:
            self.form.baseList.addItem(i[0].Name)

        index = self.form.algorithmSelect.findText(
                self.obj.Algorithm, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.algorithmSelect.blockSignals(True)
            self.form.algorithmSelect.setCurrentIndex(index)
            self.form.algorithmSelect.blockSignals(False)
Exemple #13
0
    def execute(self, obj):
        import Part  # math #DraftGeomUtils
        output = ""

        toolLoad = PathUtils.getLastToolLoad(obj)

        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.vertRapid = 100
            self.horizRapid = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            if not tool or tool.Diameter == 0:
                self.radius = 0.25
            else:
                self.radius = tool.Diameter/2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        self.setLabel(obj)

        output += "(" + obj.Label + ")"
        if not obj.UseComp:
            output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
        else:
            output += "(Uncompensated Tool Path)"

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return
        contourwire = TechDraw.findShapeOutline(baseobject.Shape,1, Vector(0,0,1))

        edgelist = contourwire.Edges
        edgelist = Part.__sortEdges__(edgelist)
        try:
            output += self._buildPathLibarea(obj, edgelist)
        except:
            FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            if obj.ViewObject:
                obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
    def _dropcutter(self, obj, s, bb):
        import ocl
        import time

        cutter = ocl.CylCutter(self.radius * 2, 5)
        pdc = ocl.PathDropCutter()   # create a pdc
        pdc.setSTL(s)
        pdc.setCutter(cutter)
        pdc.minimumZ = 0.25
        pdc.setSampling(obj.SampleInterval)

        # some parameters for this "zigzig" pattern
        xmin = bb.XMin - cutter.getDiameter()
        xmax = bb.XMax + cutter.getDiameter()
        ymin = bb.YMin - cutter.getDiameter()
        ymax = bb.YMax + cutter.getDiameter()

        # number of lines in the y-direction
        Ny = int(bb.YLength / cutter.getDiameter())
        dy = float(ymax - ymin) / Ny  # the y step-over

        path = ocl.Path()                   # create an empty path object

        # add Line objects to the path in this loop
        for n in xrange(0, Ny):
            y = ymin + n * dy
            p1 = ocl.Point(xmin, y, 0)   # start-point of line
            p2 = ocl.Point(xmax, y, 0)   # end-point of line
            if (n % 2 == 0):  # even
                l = ocl.Line(p1, p2)     # line-object
            else:  # odd
                l = ocl.Line(p2, p1)     # line-object

            path.append(l)        # add the line to the path

        pdc.setPath(path)

        # run drop-cutter on the path
        t_before = time.time()
        pdc.run()
        t_after = time.time()
        print "calculation took ", t_after - t_before, " s"

        # retrieve the points
        clp = pdc.getCLPoints()
        print "points received: " + str(len(clp))

        # generate the path commands
        output = ""
        output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
        output += "G0 X" + str(clp[0].x) + " Y" + str(clp[0].y) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
        output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\n"

        for c in clp:
            output += "G1 X" + str(c.x) + " Y" + \
                str(c.y) + " Z" + str(c.z) + "\n"

        return output
Exemple #15
0
    def execute(self,obj):

        if obj.Base:
            
            # tie the toolnumber to the PathLoadTool object ToolNumber
            if len(obj.InList)>0: #check to see if obj is in the Project group yet
                project = obj.InList[0]
                tl = int(PathUtils.changeTool(obj,project))
                obj.ToolNumber= tl   
            
            tool = PathUtils.getTool(obj,obj.ToolNumber)
            if tool:
                self.radius = tool.Diameter/2
            else:
                # temporary value,in case we don't have any tools defined already
                self.radius = 0.25
#            self.radius = 0.25
            self.clearance = obj.ClearanceHeight.Value
            self.step_down=obj.StepDown.Value
            self.start_depth=obj.StartDepth.Value
            self.final_depth=obj.FinalDepth.Value
            self.rapid_safety_space=obj.RetractHeight.Value
            self.side=obj.Side
            self.offset_extra=obj.OffsetExtra.Value
            self.use_CRC=obj.UseComp
            self.vf=obj.VertFeed.Value
            self.hf=obj.HorizFeed.Value


            edgelist = []

            if obj.StartPtName and obj.UseStartPt:             
                self.startpt = FreeCAD.ActiveDocument.getObject(obj.StartPtName).Shape
            else:
                self.startpt = None

            if obj.EndPtName and obj.UseEndPt:
                self.endpt = FreeCAD.ActiveDocument.getObject(obj.EndPtName).Shape
            else:
                self.endpt = None
                
            for e in obj.Edgelist:
                edgelist.append(FreeCAD.ActiveDocument.getObject(obj.Base[0].Name).Shape.Edges[e-1])

            output=PathKurveUtils.makePath(edgelist,self.side,self.radius,self.vf,self.hf,self.offset_extra, \
                   self.rapid_safety_space,self.clearance,self.start_depth,self.step_down, \
                   self.final_depth,self.use_CRC,obj.Direction,self.startpt,self.endpt)

            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True

            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
    def areaOpSetDefaultValues(self, obj):
        '''areaOpSetDefaultValues(obj) ... initialize mill facing properties'''
       # obj.StepOver = 50
       # obj.ZigZagAngle = 45.0

        # need to overwrite the default depth calculations for facing
        job = PathUtils.findParentJob(obj)
        if job and job.Base:
            d = PathUtils.guessDepths(job.Base.Shape, None)
            obj.OpStartDepth = d.safe_height
            obj.OpFinalDepth = d.start_depth
    def execute(self, obj):
        output = ""
        if obj.Comment != "":
            output += '(' + str(obj.Comment)+')\n'

        toolLoad = PathUtils.getLastToolLoad(obj)
        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            self.radius = tool.Diameter/2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " :" + obj.ToolDescription
        else:
            obj.Label = obj.UserLabel + " :" + obj.ToolDescription

        if obj.Base:
            output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n"

            wires = []
            for o in obj.Base:
                # we only consider the outer wire if this is a Face
                for w in o[0].Shape.Wires:
                    tempedges = PathUtils.cleanedges(w.Edges, 0.5)
                    wires.append (Part.Wire(tempedges))

                if obj.Algorithm == "OCC Native":
                    output += self.buildpathocc(obj, wires)

            output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n"


        # print output
        if output == "":
            output += "(No commands processed)"

        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
Exemple #18
0
    def setupToolController(self, obj, combo):
        '''setupToolController(obj, combo) ... helper function to setup obj's ToolController in the given combo box.'''
        controllers = PathUtils.getToolControllers(self.obj)
        labels = [c.Label for c in controllers]
        combo.blockSignals(True)
        combo.addItems(labels)
        combo.blockSignals(False)

        if obj.ToolController is None:
            obj.ToolController = PathUtils.findToolController(obj)
        if obj.ToolController is not None:
            self.selectInComboBox(obj.ToolController.Label, combo)
Exemple #19
0
    def opSetDefaultValues(self, obj, job):
        '''opSetDefaultValues(obj, job) ... initialize defaults'''

        # obj.ZigZagAngle = 45.0
        obj.StepOver = 50
        obj.Optimize = True
        # need to overwrite the default depth calculations for facing
        job = PathUtils.findParentJob(obj)
        if job and job.Stock:
            d = PathUtils.guessDepths(job.Stock.Shape, None)
            obj.OpStartDepth = d.start_depth
            obj.OpFinalDepth = d.final_depth
Exemple #20
0
    def opExecute(self, obj, getsim=False):
        '''opExecute(obj, getsim=False) ... implementation of Path.Area ops.
        determines the parameters for _buildPathArea().
        Do not overwrite, implement
            areaOpAreaParams(obj, isHole) ... op specific area param dictionary
            areaOpPathParams(obj, isHole) ... op specific path param dictionary
            areaOpShapes(obj)             ... the shape for path area to process
            areaOpUseProjection(obj)      ... return true if operation can use projection
        instead.'''
        PathLog.track()
        self.endVector = None

        finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
        self.depthparams = PathUtils.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=finish_step,
                final_depth=obj.FinalDepth.Value,
                user_depths=None)

        if PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint:
            start = obj.StartPoint
        else:
            start = None

        shapes = self.areaOpShapes(obj)

        jobs = [{
            'x': s[0].BoundBox.XMax,
            'y': s[0].BoundBox.YMax,
            'shape': s
        } for s in shapes]

        jobs = PathUtils.sort_jobs(jobs, ['x', 'y'])

        shapes = [j['shape'] for j in jobs]

        sims = []
        for (shape, isHole) in shapes:
            try:
                (pp, sim) = self._buildPathArea(obj, shape, isHole, start, getsim)
                self.commandlist.extend(pp.Commands)
                sims.append(sim)
            except Exception as e:
                FreeCAD.Console.PrintError(e)
                FreeCAD.Console.PrintError("Something unexpected happened. Check project and tool config.")

            if self.areaOpRetractTool(obj):
                self.endVector = None

        return sims
Exemple #21
0
    def setFields(self):
        self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
        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)
        self.form.processHoles.setChecked(self.obj.processHoles)
        self.form.processPerimeter.setChecked(self.obj.processPerimeter)
        self.form.processCircles.setChecked(self.obj.processCircles)

        index = self.form.cutSide.findText(
                self.obj.Side, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.cutSide.blockSignals(True)
            self.form.cutSide.setCurrentIndex(index)
            self.form.cutSide.blockSignals(False)

        index = self.form.direction.findText(
                self.obj.Direction, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.direction.blockSignals(True)
            self.form.direction.setCurrentIndex(index)
            self.form.direction.blockSignals(False)

        controllers = PathUtils.getToolControllers(self.obj)
        labels = [c.Label for c in controllers]
        self.form.uiToolController.blockSignals(True)
        self.form.uiToolController.addItems(labels)
        self.form.uiToolController.blockSignals(False)
        if self.obj.ToolController is not None:
            index = self.form.uiToolController.findText(
                self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
            PathLog.debug("searching for TC label {}. Found Index: {}".format(self.obj.ToolController.Label, index))
            if index >= 0:
                self.form.uiToolController.blockSignals(True)
                self.form.uiToolController.setCurrentIndex(index)
                self.form.uiToolController.blockSignals(False)
        else:
            self.obj.ToolController = PathUtils.findToolController(self.obj)

        self.form.baseList.blockSignals(True)
        for i in self.obj.Base:
            for sub in i[1]:
                self.form.baseList.addItem(i[0].Name + "." + sub)
        self.form.baseList.blockSignals(False)

        self.form.update()
Exemple #22
0
    def setFields(self):
        self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
        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.MaterialAllowance, FreeCAD.Units.Length).UserString)
        self.form.useStartPoint.setChecked(self.obj.UseStartPoint)
        self.form.useZigZag.setChecked(self.obj.UseZigZag)
        self.form.zigZagUnidirectional.setChecked(self.obj.ZigUnidirectional)
        self.form.zigZagAngle.setText(FreeCAD.Units.Quantity(self.obj.ZigZagAngle, FreeCAD.Units.Angle).UserString)
        self.form.stepOverPercent.setValue(self.obj.StepOver)

        index = self.form.algorithmSelect.findText(self.obj.Algorithm, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.algorithmSelect.blockSignals(True)
            self.form.algorithmSelect.setCurrentIndex(index)
            self.form.algorithmSelect.blockSignals(False)

        index = self.form.cutMode.findText(
                self.obj.CutMode, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.cutMode.blockSignals(True)
            self.form.cutMode.setCurrentIndex(index)
            self.form.cutMode.blockSignals(False)

        # for i in self.obj.Base:
        #     self.form.baseList.addItem(i[0].Name + "." + i[1][0])
        self.form.baseList.blockSignals(True)
        for i in self.obj.Base:
            for sub in i[1]:
                self.form.baseList.addItem(i[0].Name + "." + sub)
        self.form.baseList.blockSignals(False)

        controllers = PathUtils.getToolControllers(self.obj)
        labels = [c.Label for c in controllers]
        self.form.uiToolController.blockSignals(True)
        self.form.uiToolController.addItems(labels)
        self.form.uiToolController.blockSignals(False)
        if self.obj.ToolController is not None:
            index = self.form.uiToolController.findText(
                self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
            PathLog.debug("searching for TC label {}. Found Index: {}".format(self.obj.ToolController.Label, index))
            if index >= 0:
                self.form.uiToolController.blockSignals(True)
                self.form.uiToolController.setCurrentIndex(index)
                self.form.uiToolController.blockSignals(False)
        else:
            self.obj.ToolController = PathUtils.findToolController(self.obj)
Exemple #23
0
    def setFields(self):
        self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.finishDepth.setText(FreeCAD.Units.Quantity(self.obj.FinishDepth.Value, FreeCAD.Units.Length).UserString)
        self.form.stepDown.setText(FreeCAD.Units.Quantity(self.obj.StepDown, FreeCAD.Units.Length).UserString)
        self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
        self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value,  FreeCAD.Units.Length).UserString)

        self.form.stepOverPercent.setValue(self.obj.StepOver)
        self.form.useZigZag.setChecked(self.obj.UseZigZag)
        self.form.zigZagUnidirectional.setChecked(self.obj.ZigUnidirectional)
        self.form.zigZagAngle.setValue(FreeCAD.Units.Quantity(self.obj.ZigZagAngle, FreeCAD.Units.Angle))
        self.form.extraOffset.setValue(self.obj.PassExtension.Value)

        index = self.form.cutMode.findText(
                self.obj.CutMode, QtCore.Qt.MatchFixedString)
        if index >= 0:

            self.form.cutMode.blockSignals(True)
            self.form.cutMode.setCurrentIndex(index)
            self.form.cutMode.blockSignals(False)

        index = self.form.boundaryShape.findText(
                self.obj.BoundaryShape, QtCore.Qt.MatchFixedString)
        if index >= 0:
            self.form.boundaryShape.blockSignals(True)
            self.form.boundaryShape.setCurrentIndex(index)
            self.form.boundaryShape.blockSignals(False)

        for i in self.obj.Base:
            for sub in i[1]:
                self.form.baseList.addItem(i[0].Name + "." + sub)

        controllers = PathUtils.getToolControllers(self.obj)
        labels = [c.Label for c in controllers]
        self.form.uiToolController.blockSignals(True)
        self.form.uiToolController.addItems(labels)
        self.form.uiToolController.blockSignals(False)

        if self.obj.ToolController is None:
            self.obj.ToolController = PathUtils.findToolController(self.obj)

        if self.obj.ToolController is not None:
            index = self.form.uiToolController.findText(
                self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
            if index >= 0:
                self.form.uiToolController.blockSignals(True)
                self.form.uiToolController.setCurrentIndex(index)
                self.form.uiToolController.blockSignals(False)
Exemple #24
0
 def onDelete(self, arg1=None, arg2=None):
     '''this makes sure that the base operation is added back to the project and visible'''
     FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True
     job = PathUtils.findParentJob(arg1.Object)
     job.Proxy.addOperation(arg1.Object.Base)
     arg1.Object.Base = None
     return True
    def addBaseGeometry(self, selection):
        added = False
        shapes = self.obj.BaseShapes
        for sel in selection:
            job = PathUtils.findParentJob(self.obj)
            base = job.Proxy.resourceClone(job, sel.Object)
            if not base:
                PathLog.notice((translate("Path", "%s is not a Base Model object of the job %s")+"\n") % (sel.Object.Label, job.Label))
                continue
            if base in shapes:
                PathLog.notice((translate("Path", "Base shape %s already in the list")+"\n") % (sel.Object.Label))
                continue
            if base.isDerivedFrom('Part::Part2DObject'):
                if sel.HasSubObjects:
                    # selectively add some elements of the drawing to the Base
                    for sub in sel.SubElementNames:
                        if 'Vertex' in sub:
                            PathLog.info(translate("Path", "Ignoring vertex"))
                        else:
                            self.obj.Proxy.addBase(self.obj, base, sub)
                else:
                    # when adding an entire shape to BaseShapes we can take its sub shapes out of Base
                    self.obj.Base = [(p,el) for p,el in self.obj.Base if p != base]
                    shapes.append(base)
                    self.obj.BaseShapes = shapes
                added = True
            else:
                # user wants us to engrave an edge of face of a base model
                base = self.super().addBaseGeometry(selection)
                added = added or base

        return added
    def Create():
        obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Machine")
        Machine(obj)
        _ViewProviderMachine(obj.ViewObject)

        PathUtils.addToProject(obj)

        UnitParams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units")
        if UnitParams.GetInt('UserSchema') == 0:
            obj.MachineUnits = 'Metric'
            #metric mode
        else:
            obj.MachineUnits = 'Inch'

        obj.ViewObject.ShowFirstRapid = False
        return obj
Exemple #27
0
def _OpenCloseResourceEditor(obj, vobj, edit):
    job = PathUtils.findParentJob(obj)
    if job and job.ViewObject and job.ViewObject.Proxy:
        if edit:
            job.ViewObject.Proxy.editObject(obj)
        else:
            job.ViewObject.Proxy.uneditObject(obj)
    def onChanged(self,obj,prop):
        mode = 2
        obj.setEditorMode('Placement',mode)

        if prop == "PostProcessor":
            sys.path.append(os.path.split(obj.PostProcessor)[0])
            lessextn = os.path.splitext(obj.PostProcessor)[0]
            postname = os.path.split(lessextn)[1]

            exec "import %s as current_post" % postname
            if hasattr (current_post, "UNITS"): 
                if current_post.UNITS == "G21":
                    obj.MachineUnits = "Metric"
                else:
                    obj.MachineUnits = "Inch"
            if hasattr (current_post, "MACHINE_NAME"): obj.MachineName = current_post.MACHINE_NAME

            if hasattr (current_post, "CORNER_MAX"):
                obj.X_Max = current_post.CORNER_MAX['x']
                obj.Y_Max = current_post.CORNER_MAX['y']
                obj.Z_Max = current_post.CORNER_MAX['z']

            if hasattr (current_post, "CORNER_MIN"): 
                obj.X_Min = current_post.CORNER_MIN['x']
                obj.Y_Min = current_post.CORNER_MIN['y']
                obj.Z_Min = current_post.CORNER_MIN['z']

        if prop == "Tooltable":
            proj = PathUtils.findProj()            
            for g in proj.Group:
                if not(isinstance(g.Proxy, PathScripts.PathMachine.Machine)):
                    g.touch()
Exemple #29
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
Exemple #30
0
    def execute(self,obj):
        output = "G90 G98\n"
        # rapid to first hole location, with spindle still retracted:
        p0 = obj.locations[0]
        output += "G0 X"+str(p0.x) + " Y" + str(p0.y)+ "\n"
        # move tool to clearance plane
        output += "G0 Z" + str(obj.ClearanceHeight.Value) + "\n"
        if obj.PeckDepth.Value > 0:
            cmd = "G83"
            qword = " Q"+ str(obj.PeckDepth.Value)
        else:
            cmd = "G81"
            qword = ""
            
        for p in obj.locations:
            output += cmd + " X" + str(p.x) + " Y" + str(p.y) + " Z" + str(obj.FinalDepth.Value) + qword + " R" + str(obj.RetractHeight.Value) + " F" + str(obj.VertFeed.Value) + "\n"

        output += "G80\n"

        print output
        path = Path.Path(output)
        obj.Path = path

        # tie the toolnumber to the PathLoadTool object ToolNumber
        if len(obj.InList)>0: #check to see if obj is in the Project group yet
            project = obj.InList[0]
            tl = int(PathUtils.changeTool(obj,project))
            obj.ToolNumber= tl   
    def areaOpShapes(self, obj):
        '''areaOpShapes(obj) ... returns envelope for all wires formed by the base edges.'''
        PathLog.track()

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

        shapes = []
        if obj.Base:
            basewires = []

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

            for base,wires in basewires:
                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(base.Shape, subshape=f, depthparams=self.depthparams)
                    shapes.append((env, False))
        return shapes
Exemple #32
0
def export(objectslist, filename, argstring):
    if not processArguments(argstring):
        return None
    global UNITS
    global UNIT_SPEED_FORMAT

    for obj in objectslist:
        if not hasattr(obj, "Path"):
            print("the object " + obj.Name +
                  " is not a path. Please select only path and Compounds.")
            return None

    print("postprocessing...")
    gcode = ""

    # write header
    if OUTPUT_HEADER:
        gcode += linenumber() + "(Exported by FreeCAD)\n"
        gcode += linenumber() + "(Post Processor: " + __name__ + ")\n"
        gcode += linenumber() + "(Output Time:" + str(now) + ")\n"

    # Write the preamble
    if OUTPUT_COMMENTS:
        gcode += linenumber() + "(begin preamble)\n"
    for line in PREAMBLE.splitlines(False):
        gcode += linenumber() + line + "\n"
    gcode += linenumber() + UNITS + "\n"

    for obj in objectslist:

        # fetch machine details
        job = PathUtils.findParentJob(obj)

        myMachine = 'not set'

        if hasattr(job, "MachineName"):
            myMachine = job.MachineName

        if hasattr(job, "MachineUnits"):
            if job.MachineUnits == "Metric":
                UNITS = "G21"
                UNIT_SPEED_FORMAT = 'mm/min'
            else:
                UNITS = "G20"
                UNIT_SPEED_FORMAT = 'in/min'

        # do the pre_op
        if OUTPUT_COMMENTS:
            gcode += linenumber() + "(begin operation: %s)\n" % obj.Label
            gcode += linenumber() + "(machine: %s, %s)\n" % (myMachine,
                                                             UNIT_SPEED_FORMAT)
        for line in PRE_OPERATION.splitlines(True):
            gcode += linenumber() + line

        gcode += parse(obj)

        # do the post_op
        if OUTPUT_COMMENTS:
            gcode += linenumber() + "(finish operation: %s)\n" % obj.Label
        for line in POST_OPERATION.splitlines(True):
            gcode += linenumber() + line

    # do the post_amble

    if OUTPUT_COMMENTS:
        gcode += "(begin postamble)\n"
    for line in POSTAMBLE.splitlines(True):
        gcode += linenumber() + line

    if FreeCAD.GuiUp and SHOW_EDITOR:
        dia = PostUtils.GCodeEditorDialog()
        dia.editor.setText(gcode)
        result = dia.exec_()
        if result:
            final = dia.editor.toPlainText()
        else:
            final = gcode
    else:
        final = gcode

    print("done postprocessing.")

    if not filename == '-':
        gfile = pythonopen(filename, "wb")
        gfile.write(final)
        gfile.close()

    return final
    def execute(self, obj):
        if obj.Base:

            # tie the toolnumber to the PathLoadTool object ToolNumber
            if len(obj.InList
                   ) > 0:  #check to see if obj is in the Project group yet
                project = obj.InList[0]
                tl = int(PathUtils.changeTool(obj, project))
                obj.ToolNumber = tl

            tool = PathUtils.getTool(obj, obj.ToolNumber)
            if tool:
                radius = tool.Diameter / 2
            else:
                # temporary value, to be taken from the properties later on
                radius = 0.001
            if obj.Base[0].Shape.ShapeType == "Wire":  #a pure wire was picked
                wire = obj.Base[0].Shape
            else:  #we are dealing with a face and it's edges or just a face
                if obj.Edge1:
                    e1 = FreeCAD.ActiveDocument.getObject(
                        obj.Base[0].Name).Shape.Edges[
                            eval(obj.Edge1[1][0].lstrip('Edge')) - 1]
                    if e1.BoundBox.ZMax <> e1.BoundBox.ZMin:
                        FreeCAD.Console.PrintError(
                            'vertical edges not valid yet\n')
                        return
                    if obj.Base[0].Shape.ShapeType == 'Wire':
                        wire = obj.Base[0].Shape
                    if obj.Base[0].Shape.ShapeType == 'Solid' or obj.Base[
                            0].Shape.ShapeType == 'Compound':
                        shape = obj.Base[0].Shape
                        for fw in shape.Wires:
                            if (fw.BoundBox.ZMax == e1.BoundBox.ZMax) and (
                                    fw.BoundBox.ZMin == e1.BoundBox.ZMin):
                                for e in fw.Edges:
                                    if e.isSame(e1):
                                        #FreeCAD.Console.PrintMessage('found the same objects\n')
                                        wire = fw
                elif obj.Face1:  # we are only dealing with a face or faces
                    f1 = FreeCAD.ActiveDocument.getObject(
                        obj.Base[0].Name).Shape.Faces[
                            eval(obj.Face1[1][0].lstrip('Face')) - 1]
                    # make the side Left and direction CW for normal cnc milling
                    obj.Direction = 'CW'
                    obj.Side = "Left"
                    # we only consider the outer wire if this is a single Face
                    wire = f1.OuterWire

            if obj.Direction == 'CCW':
                clockwise = False
            else:
                clockwise = True
            output = ""
            output += '(' + str(obj.Comment) + ')\n'

            FirstEdge = None
            if obj.Edge1:
                ename = obj.Edge1[1][0]
                edgeNumber = int(ename[4:]) - 1
                FirstEdge = obj.Base[0].Shape.Edges[edgeNumber]
            ZMax = obj.Base[0].Shape.BoundBox.ZMax

            ZCurrent = obj.ClearanceHeight.Value

            if obj.UseStartDepth:
                output += PathUtils.MakePath(
                    wire, obj.Side, radius, clockwise,
                    obj.ClearanceHeight.Value, obj.StepDown.Value,
                    obj.StartDepth.Value, obj.FinalDepth.Value, FirstEdge,
                    obj.PathClosed, obj.SegLen.Value, obj.VertFeed.Value,
                    obj.HorizFeed.Value)
            else:
                output += PathUtils.MakePath(
                    wire, obj.Side, radius, clockwise,
                    obj.ClearanceHeight.Value, obj.StepDown.Value, ZMax,
                    obj.FinalDepth.Value, FirstEdge, obj.PathClosed,
                    obj.SegLen.Value, obj.VertFeed.Value, obj.HorizFeed.Value)

            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True

            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
Exemple #34
0
    def execute(self, obj):
        import Part  # math #DraftGeomUtils
        output = ""

        toolLoad = PathUtils.getLastToolLoad(obj)

        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.vertRapid = 100
            self.horizRapid = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            if not tool or tool.Diameter == 0:
                self.radius = 0.25
            else:
                self.radius = tool.Diameter / 2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " :" + obj.ToolDescription
        else:
            obj.Label = obj.UserLabel + " :" + obj.ToolDescription

        output += "(" + obj.Label + ")"
        if not obj.UseComp:
            output += "(Compensated Tool Path. Diameter: " + str(
                self.radius * 2) + ")"
        else:
            output += "(Uncompensated Tool Path)"

        parentJob = PathUtils.findParentJob(obj)
        if parentJob is None:
            return
        baseobject = parentJob.Base
        if baseobject is None:
            return
        contourwire = TechDraw.findShapeOutline(baseobject.Shape, 1,
                                                Vector(0, 0, 1))

        edgelist = contourwire.Edges
        edgelist = Part.__sortEdges__(edgelist)
        try:
            output += self._buildPathLibarea(obj, edgelist)
        except:
            FreeCAD.Console.PrintError(
                "Something unexpected happened. Unable to generate a contour path. Check project and tool config."
            )
        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            if obj.ViewObject:
                obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
    def execute(self, obj):
        import Part  # math #DraftGeomUtils
        output = ""

        toolLoad = PathUtils.getLastToolLoad(obj)

        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.vertRapid = 100
            self.horizRapid = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            if tool.Diameter == 0:
                self.radius = 0.25
            else:
                self.radius = tool.Diameter/2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " :" + obj.ToolDescription
        else:
            obj.Label = obj.UserLabel + " :" + obj.ToolDescription

        output += "(" + obj.Label + ")"
        if obj.Side != "On":
            output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")"
        else:
            output += "(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:
                edgelist = wire.Edges
                edgelist = Part.__sortEdges__(edgelist)
                output += self._buildPathLibarea(obj, edgelist)

        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
Exemple #36
0
    def _buildPathArea(self, obj, baseobject, isHole, start, getsim):
        """_buildPathArea(obj, baseobject, isHole, start, getsim) ... internal function."""
        PathLog.track()
        area = Path.Area()
        area.setPlane(PathUtils.makeWorkplane(baseobject))
        area.add(baseobject)

        areaParams = self.areaOpAreaParams(obj, isHole)

        heights = [i for i in self.depthparams]
        PathLog.debug("depths: {}".format(heights))
        area.setParams(**areaParams)
        obj.AreaParams = str(area.getParams())

        PathLog.debug("Area with params: {}".format(area.getParams()))

        sections = area.makeSections(
            mode=0, project=self.areaOpUseProjection(obj), heights=heights
        )
        PathLog.debug("sections = %s" % sections)
        shapelist = [sec.getShape() for sec in sections]
        PathLog.debug("shapelist = %s" % shapelist)

        pathParams = self.areaOpPathParams(obj, isHole)
        pathParams["shapes"] = shapelist
        pathParams["feedrate"] = self.horizFeed
        pathParams["feedrate_v"] = self.vertFeed
        pathParams["verbose"] = True
        pathParams["resume_height"] = obj.SafeHeight.Value
        pathParams["retraction"] = obj.ClearanceHeight.Value
        pathParams["return_end"] = True
        # Note that emitting preambles between moves breaks some dressups and prevents path optimization on some controllers
        pathParams["preamble"] = False

        if not self.areaOpRetractTool(obj):
            pathParams["threshold"] = 2.001 * self.radius

        if self.endVector is not None:
            pathParams["start"] = self.endVector
        elif PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint:
            pathParams["start"] = obj.StartPoint

        obj.PathParams = str(
            {key: value for key, value in pathParams.items() if key != "shapes"}
        )
        PathLog.debug("Path with params: {}".format(obj.PathParams))

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

        simobj = None
        if getsim:
            areaParams["Thicken"] = True
            areaParams["ToolRadius"] = self.radius - self.radius * 0.005
            area.setParams(**areaParams)
            sec = area.makeSections(mode=0, project=False, heights=heights)[
                -1
            ].getShape()
            simobj = sec.extrude(FreeCAD.Vector(0, 0, baseobject.BoundBox.ZMax))

        return pp, simobj
Exemple #37
0
 def updateToolController(self, obj, combo):
     '''updateToolController(obj, combo) ... helper function to update obj's ToolController property if a different one has been selected in the combo box.'''
     tc = PathUtils.findToolController(obj, combo.currentText())
     if obj.ToolController != tc:
         obj.ToolController = tc
Exemple #38
0
    def execute(self, obj):
        output = ""
        if obj.Comment != "":
            output += '(' + str(obj.Comment)+')\n'

        toolLoad = PathUtils.getLastToolLoad(obj)
        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.vertRapid = 100
            self.horizRapid = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            self.vertRapid = toolLoad.VertRapid.Value
            self.horizRapid = toolLoad.HorizRapid.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            if tool.Diameter == 0:
                self.radius = 0.25
            else:
                self.radius = tool.Diameter/2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " :" + obj.ToolDescription
        else:
            obj.Label = obj.UserLabel + " :" + obj.ToolDescription

        locations = []
        output = "(Begin Drilling)\n"
        if obj.Base:
            for loc in obj.Base:
                #print loc
                for sub in loc[1]:
                    #locations.append(self._findDrillingVector(loc))

                    if "Face" in sub or "Edge" in sub:
                        s = getattr(loc[0].Shape, sub)
                    else:
                        s = loc[0].Shape

                    if s.ShapeType in ['Wire', 'Edge']:
                        X = s.Edges[0].Curve.Center.x
                        Y = s.Edges[0].Curve.Center.y
                        Z = s.Edges[0].Curve.Center.z
                    elif s.ShapeType in ['Vertex']:
                        X = s.Point.x
                        Y = s.Point.y
                        Z = s.Point.z
                    elif s.ShapeType in ['Face']:
                        #if abs(s.normalAt(0, 0).z) == 1:  # horizontal face
                        X = s.CenterOfMass.x
                        Y = s.CenterOfMass.y
                        Z = s.CenterOfMass.z
                    locations.append(FreeCAD.Vector(X, Y, Z))


            output += "G90 G98\n"
            # rapid to clearance height
            output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
            # rapid to first hole location, with spindle still retracted:
            p0 = locations[0]
            output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y)  + "F " + PathUtils.fmt(self.horizRapid) + "\n"
            # move tool to clearance plane
            output += "G0 Z" + fmt(obj.ClearanceHeight.Value)  + "F " + PathUtils.fmt(self.vertRapid) + "\n"
            pword = ""
            qword = ""
            if obj.PeckDepth.Value > 0:
                cmd = "G83"
                qword = " Q" + fmt(obj.PeckDepth.Value)
            elif obj.DwellTime > 0:
                cmd = "G82"
                pword = " P" + fmt(obj.DwellTime)
            else:
                cmd = "G81"
            for p in locations:
                output += cmd + \
                    " X" + fmt(p.x) + \
                    " Y" + fmt(p.y) + \
                    " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \
                    " R" + str(obj.RetractHeight.Value) + \
                    " F" + str(self.vertFeed) + "\n" \

            output += "G80\n"

#         path = Path.Path(output)
#         obj.Path = path

        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False
Exemple #39
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.SafeHeight.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))

        # 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)

        # save the envelope for reference
        obj.removalshape = env

        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
Exemple #40
0
    def findHoles(self, obj, baseobject):
        '''findHoles(obj, baseobject) ... inspect baseobject and identify all features that resemble a straight cricular hole.'''
        shape = baseobject.Shape
        PathLog.track('obj: {} shape: {}'.format(obj, shape))
        holelist = []
        features = []
        # tooldiameter = float(obj.ToolController.Proxy.getTool(obj.ToolController).Diameter)
        tooldiameter = None
        PathLog.debug('search for holes larger than tooldiameter: {}: '.format(
            tooldiameter))
        if DraftGeomUtils.isPlanar(shape):
            PathLog.debug("shape is planar")
            for i in range(len(shape.Edges)):
                candidateEdgeName = "Edge" + str(i + 1)
                e = shape.getElement(candidateEdgeName)
                if PathUtils.isDrillable(shape, e, tooldiameter):
                    PathLog.debug(
                        'edge candidate: {} (hash {})is drillable '.format(
                            e, e.hashCode()))
                    x = e.Curve.Center.x
                    y = e.Curve.Center.y
                    diameter = e.BoundBox.XLength
                    holelist.append({
                        'featureName': candidateEdgeName,
                        'feature': e,
                        'x': x,
                        'y': y,
                        'd': diameter,
                        'enabled': True
                    })
                    features.append((baseobject, candidateEdgeName))
                    PathLog.debug("Found hole feature %s.%s" %
                                  (baseobject.Label, candidateEdgeName))
        else:
            PathLog.debug("shape is not planar")
            for i in range(len(shape.Faces)):
                candidateFaceName = "Face" + str(i + 1)
                f = shape.getElement(candidateFaceName)
                if PathUtils.isDrillable(shape, f, tooldiameter):
                    PathLog.debug('face candidate: {} is drillable '.format(f))
                    if hasattr(f.Surface, 'Center'):
                        x = f.Surface.Center.x
                        y = f.Surface.Center.y
                        diameter = f.BoundBox.XLength
                    else:
                        center = f.Edges[0].Curve.Center
                        x = center.x
                        y = center.y
                        diameter = f.Edges[0].Curve.Radius * 2
                    holelist.append({
                        'featureName': candidateFaceName,
                        'feature': f,
                        'x': x,
                        'y': y,
                        'd': diameter,
                        'enabled': True
                    })
                    features.append((baseobject, candidateFaceName))
                    PathLog.debug("Found hole feature %s.%s" %
                                  (baseobject.Label, candidateFaceName))

        PathLog.debug("holes found: {}".format(holelist))
        return features
Exemple #41
0
    def opExecute(self, obj):
        '''opExecute(obj) ... processes all Base features and Locations and collects
        them in a list of positions and radii which is then passed to circularHoleExecute(obj, holes).
        If no Base geometries and no Locations are present, the job's Base is inspected and all
        drillable features are added to Base. In this case appropriate values for depths are also
        calculated and assigned.
        Do not overwrite, implement circularHoleExecute(obj, holes) instead.'''
        PathLog.track()

        holes = []
        baseSubsTuples = []
        subCount = 0
        allTuples = []
        self.cloneNames = []  # pylint: disable=attribute-defined-outside-init
        self.guiMsgs = []  # pylint: disable=attribute-defined-outside-init
        self.rotateFlag = False  # pylint: disable=attribute-defined-outside-init
        self.useTempJobClones('Delete')  # pylint: disable=attribute-defined-outside-init
        self.stockBB = PathUtils.findParentJob(obj).Stock.Shape.BoundBox  # pylint: disable=attribute-defined-outside-init
        self.clearHeight = obj.ClearanceHeight.Value  # pylint: disable=attribute-defined-outside-init
        self.safeHeight = obj.SafeHeight.Value  # pylint: disable=attribute-defined-outside-init
        self.axialFeed = 0.0  # pylint: disable=attribute-defined-outside-init
        self.axialRapid = 0.0  # pylint: disable=attribute-defined-outside-init

        def haveLocations(self, obj):
            if PathOp.FeatureLocations & self.opFeatures(obj):
                return len(obj.Locations) != 0
            return False

        if obj.EnableRotation == 'Off':
            strDep = obj.StartDepth.Value
            finDep = obj.FinalDepth.Value
        else:
            # Calculate operation heights based upon rotation radii
            opHeights = self.opDetermineRotationRadii(obj)
            (self.xRotRad, self.yRotRad, self.zRotRad) = opHeights[0]  # pylint: disable=attribute-defined-outside-init
            (clrOfset, safOfst) = opHeights[1]
            PathLog.debug("Exec. opHeights[0]: " + str(opHeights[0]))
            PathLog.debug("Exec. opHeights[1]: " + str(opHeights[1]))

            # Set clearance and safe heights based upon rotation radii
            if obj.EnableRotation == 'A(x)':
                strDep = self.xRotRad
            elif obj.EnableRotation == 'B(y)':
                strDep = self.yRotRad
            else:
                strDep = max(self.xRotRad, self.yRotRad)
            finDep = -1 * strDep

            obj.ClearanceHeight.Value = strDep + clrOfset
            obj.SafeHeight.Value = strDep + safOfst

            # Create visual axes when debugging.
            if PathLog.getLevel(PathLog.thisModule()) == 4:
                self.visualAxis()

            # Set axial feed rates based upon horizontal feed rates
            safeCircum = 2 * math.pi * obj.SafeHeight.Value
            self.axialFeed = 360 / safeCircum * self.horizFeed  # pylint: disable=attribute-defined-outside-init
            self.axialRapid = 360 / safeCircum * self.horizRapid  # pylint: disable=attribute-defined-outside-init

        # Complete rotational analysis and temp clone creation as needed
        if obj.EnableRotation == 'Off':
            PathLog.debug("Enable Rotation setting is 'Off' for {}.".format(
                obj.Name))
            stock = PathUtils.findParentJob(obj).Stock
            for (base, subList) in obj.Base:
                baseSubsTuples.append((base, subList, 0.0, 'A', stock))
        else:
            for p in range(0, len(obj.Base)):
                (base, subsList) = obj.Base[p]
                for sub in subsList:
                    if self.isHoleEnabled(obj, base, sub):
                        shape = getattr(base.Shape, sub)
                        rtn = False
                        (norm, surf) = self.getFaceNormAndSurf(shape)
                        (rtn, angle, axis,
                         praInfo) = self.faceRotationAnalysis(obj, norm, surf)  # pylint: disable=unused-variable
                        if rtn is True:
                            (clnBase, angle, clnStock,
                             tag) = self.applyRotationalAnalysis(
                                 obj, base, angle, axis, subCount)
                            # Verify faces are correctly oriented - InverseAngle might be necessary
                            PathLog.debug(
                                "Verifying {} orientation: running faceRotationAnalysis() again."
                                .format(sub))
                            faceIA = getattr(clnBase.Shape, sub)
                            (norm, surf) = self.getFaceNormAndSurf(faceIA)
                            (rtn, praAngle, praAxis,
                             praInfo) = self.faceRotationAnalysis(
                                 obj, norm, surf)  # pylint: disable=unused-variable
                            if rtn is True:
                                msg = obj.Name + ":: "
                                msg += translate(
                                    "Path",
                                    "{} might be misaligned after initial rotation."
                                    .format(sub)) + "  "
                                if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
                                    (clnBase, clnStock,
                                     angle) = self.applyInverseAngle(
                                         obj, clnBase, clnStock, axis, angle)
                                    msg += translate(
                                        "Path",
                                        "Rotated to 'InverseAngle' to attempt access."
                                    )
                                else:
                                    if len(subsList) == 1:
                                        msg += translate(
                                            "Path",
                                            "Consider toggling the 'InverseAngle' property and recomputing."
                                        )
                                    else:
                                        msg += translate(
                                            "Path",
                                            "Consider transferring '{}' to independent operation."
                                            .format(sub))
                                PathLog.warning(msg)
                                # title = translate("Path", 'Rotation Warning')
                                # self.guiMessage(title, msg, False)
                            else:
                                PathLog.debug(
                                    "Face appears to be oriented correctly.")

                            cmnt = "{}: {} @ {};  ".format(
                                sub, axis, str(round(angle, 5)))
                            if cmnt not in obj.Comment:
                                obj.Comment += cmnt

                            tup = clnBase, sub, tag, angle, axis, clnStock
                            allTuples.append(tup)
                        else:
                            if self.warnDisabledAxis(obj, axis, sub) is True:
                                pass  # Skip drill feature due to access issue
                            else:
                                PathLog.debug(str(sub) + ": No rotation used")
                                axis = 'X'
                                angle = 0.0
                                tag = base.Name + '_' + axis + str(
                                    angle).replace('.', '_')
                                stock = PathUtils.findParentJob(obj).Stock
                                tup = base, sub, tag, angle, axis, stock
                                allTuples.append(tup)
                        # Eif
                    # Eif
                    subCount += 1
                # Efor
            # Efor
            (Tags,
             Grps) = self.sortTuplesByIndex(allTuples,
                                            2)  # return (TagList, GroupList)
            subList = []
            for o in range(0, len(Tags)):
                PathLog.debug('hTag: {}'.format(Tags[o]))
                subList = []
                for (base, sub, tag, angle, axis, stock) in Grps[o]:
                    subList.append(sub)
                pair = base, subList, angle, axis, stock
                baseSubsTuples.append(pair)
            # Efor

        for base, subs, angle, axis, stock in baseSubsTuples:
            for sub in subs:
                if self.isHoleEnabled(obj, base, sub):
                    pos = self.holePosition(obj, base, sub)
                    if pos:
                        # Default is treat selection as 'Face' shape
                        holeBtm = base.Shape.getElement(sub).BoundBox.ZMin
                        if base.Shape.getElement(sub).ShapeType == 'Edge':
                            msg = translate(
                                "Path",
                                "Verify Final Depth of holes based on edges. {} depth is: {} mm"
                                .format(sub, round(holeBtm, 4))) + "  "
                            msg += translate(
                                "Path",
                                "Always select the bottom edge of the hole when using an edge."
                            )
                            PathLog.warning(msg)

                        # Warn user if Final Depth set lower than bottom of hole
                        if finDep < holeBtm:
                            msg = translate(
                                "Path",
                                "Final Depth setting is below the hole bottom for {}."
                                .format(sub)) + '  '
                            msg += translate(
                                "Path",
                                "{} depth is calculated at {} mm".format(
                                    sub, round(holeBtm, 4)))
                            PathLog.warning(msg)

                        holes.append({
                            'x': pos.x,
                            'y': pos.y,
                            'r': self.holeDiameter(obj, base, sub),
                            'angle': angle,
                            'axis': axis,
                            'trgtDep': finDep,
                            'stkTop': stock.Shape.BoundBox.ZMax
                        })

        if haveLocations(self, obj):
            for location in obj.Locations:
                # holes.append({'x': location.x, 'y': location.y, 'r': 0, 'angle': 0.0, 'axis': 'X', 'holeBtm': obj.FinalDepth.Value})
                holes.append({
                    'x':
                    location.x,
                    'y':
                    location.y,
                    'r':
                    0,
                    'angle':
                    0.0,
                    'axis':
                    'X',
                    'trgtDep':
                    finDep,
                    'stkTop':
                    PathUtils.findParentJob(obj).stock.Shape.BoundBox.ZMax
                })

        if len(holes) > 0:
            self.circularHoleExecute(
                obj, holes)  # circularHoleExecute() located in PathDrilling.py

        self.useTempJobClones(
            'Delete')  # Delete temp job clone group and contents
        self.guiMessage('title', None,
                        show=True)  # Process GUI messages to user
        PathLog.debug("obj.Name: " + str(obj.Name))
Exemple #42
0
    def execute(self,obj):
        if obj.Base:
            tool = PathUtils.getLastTool(obj)

            if tool:
                radius = tool.Diameter/2
                if radius < 0:# safe guard
                    radius -= radius
            else:
                # temporary value, to be taken from the properties later on
                radius = 1

            import Part, DraftGeomUtils
            if "Face" in obj.Base[1][0]:
                shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
            else:
                edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
                shape = Part.Wire(edges)
                print len(edges)

            # absolute coords, millimeters, cancel offsets
            output = "G90\nG21\nG40\n"
            # save tool
            if obj.ToolNumber > 0 and tool.ToolNumber != obj.ToolNumber:
                output += "M06 T" + str(tool.ToolNumber) + "\n"
            
            # build offsets
            offsets = []
            nextradius = radius
            result = DraftGeomUtils.pocket2d(shape,nextradius)
            while result:
                #print "Adding " + str(len(result)) + " wires"
                offsets.extend(result)
                nextradius += radius
                result = DraftGeomUtils.pocket2d(shape,nextradius)
            
            # first move will be rapid, subsequent will be at feed rate
            first = True
            startPoint = None
            fastZPos = max(obj.StartDepth + 2, obj.RetractHeight)
            
            # revert the list so we start with the outer wires
            if obj.StartAt != 'Edge':
                offsets.reverse()

#            print "startDepth: " + str(obj.StartDepth)
#            print "finalDepth: " + str(obj.FinalDepth)
#            print "stepDown: " + str(obj.StepDown)
#            print "finishDepth" + str(obj.FinishDepth)
#            print "offsets:", len(offsets)

            def prnt(vlu): return str("%.4f" % round(vlu, 4))
            
            #Fraction of tool radius our plunge helix is to be
            #FIXME: This should be configurable
            plungeR = 0.75
            
            #(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging
            #FIXME: This should be configurable
            #FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best
            rampD = 0.75
            
            
            #Total offset from the desired pocket edge is tool radius plus the plunge helix radius
            #Any point on these curves could be the center of a plunge
            helixBounds = DraftGeomUtils.pocket2d(shape, tool.Diameter / 2. * (1 + plungeR))
            
            
            #Try to find a location to nicely plunge, starting with a helix, then ramp
            #Can't do it without knowledge of a tool
            plungePos = None
            rampEdge = None
            if not tool:
                    raise Error("Ramp plunge location-finding requires a tool")
                    return
            else:
                #Since we're going to start machining either the inner-most
                #edge or the outer (depending on StartAt setting), try to
                #plunge near that location
                
                if helixBounds:
                    #Edge is easy- pick a point on helixBounds and go with it
                    if obj.StartAt == 'Edge':
                        plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                    #Center is harder- use a point from the first offset, check if it works
                    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 < tool.Diameter / 2. * (1 + plungeR):
                            plungePos = None
                        #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 we didn't find a place to helix, how about a ramp?
                if not plungePos:
                    #Check first edge of our offsets
                    if (offsets[0].Edges[0].Length >= tool.Diameter * 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 >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
                        rampEdge = offsets[0].Edges[-1]
                    else:
                        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
                
            
            #Returns gcode to perform a rapid move
            def rapid(x=None, y=None, z=None):
                retstr = "G00"
                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"
                
            #Returns gcode to perform a linear feed
            def feed(x=None, y=None, z=None):
                global feedxy
                retstr = "G01 F"
                if(x == None) and (y == None):
                    retstr += str("%.4f" % obj.HorizFeed)
                else:
                    retstr += str("%.4f" % obj.VertFeed)
                
                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"
            
            #Returns gcode to perform an arc
            #Assumes XY plane or helix around Z
            #Don't worry about starting Z- assume that's dealt with elsewhere
            def arc(cx, cy, sx, sy, ex, ey, ez=None, ccw=False):
                #If start/end radii aren't within eps, abort
                eps = 0.01
                if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps:
                    print "ERROR: Illegal arc: Stand and end radii not equal"
                    return ""
                
                #Set [C]CW and feed
                retstr = ""
                if ccw:
                    retstr += "G03 F"
                else:
                    retstr += "G02 F"
                retstr += str(obj.HorizFeed)
                
                #End location
                retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
                
                #Helix if requested
                if ez != None:
                    retstr += " Z" + str("%.4f" % ez)
                
                #Append center offsets
                retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy))
                
                return retstr + "\n"

            #Returns gcode to helically plunge
            #destZ is the milling level
            #startZ is the height we can safely feed down to before helix-ing
            def helicalPlunge(plungePos, rampangle, destZ, startZ):
                helixCmds = "(START HELICAL PLUNGE)\n"
                if(plungePos == None):
                    raise Error("Helical plunging requires a position!")
                    return None
                if(not tool):
                    raise Error("Helical plunging requires a tool!")
                    return None

                helixX = plungePos.x + tool.Diameter/2. * plungeR
                helixY = plungePos.y;
                
                helixCirc = math.pi * tool.Diameter * plungeR
                dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc

                #Go to the start of the helix position
                helixCmds += rapid(helixX, helixY)
                helixCmds += rapid(z=startZ)
                
                #Helix as required to get to the requested depth
                lastZ = startZ
                curZ = max(startZ-dzPerRev, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)
                    #NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid
                    #helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True)
                    
                    #Use two half-helixes; FreeCAD renders that correctly,
                    #and it fits with the other code breaking up 360-degree arcs
                    helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - tool.Diameter * plungeR, helixY, ez = (curZ + lastZ)/2., ccw=True)
                    helixCmds += arc(plungePos.x, plungePos.y, helixX - tool.Diameter * plungeR, helixY, helixX, helixY, ez = curZ, ccw=True)
                    lastZ = curZ
                    curZ = max(curZ - dzPerRev, destZ)
                
                return helixCmds
                
                
            #Returns commands to linearly ramp into a cut
            #FIXME: This ramps along the first edge, assuming it's long
            #enough, NOT just wiggling back and forth by ~0.75 * toolD.
            #Not sure if that's any worse, but it's simpler
            #FIXME: This code is untested
            def rampPlunge(edge, rampangle, destZ, startZ):
                rampCmds = "(START RAMP PLUNGE)\n"
                if(edge == None):
                    raise Error("Ramp plunging requires an edge!")
                    return None
                if(not tool):
                    raise Error("Ramp plunging requires a tool!")
                
                
                sPoint = edge.Vertexes[0].Point
                ePoint = edge.Vertexes[1].Point
                #Evidently edges can get flipped- pick the right one in this case
                #FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below
                if ePoint == sPoint:
                    #print "FLIP"
                    ePoint = edge.Vertexes[-1].Point
                #print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ)
                
                rampDist = edge.Length
                rampDZ = math.sin(rampangle/180. * math.pi) * rampDist
                
                rampCmds += rapid(sPoint.x, sPoint.y)
                rampCmds += rapid(z=startZ)
                
                #Ramp down to the requested depth
                #FIXME: This might be an arc, so handle that as well
                lastZ = startZ
                curZ = max(startZ-rampDZ, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)
                    
                    #If it's an arc, handle it!
                    if isinstance(edge.Curve,Part.Circle):
                        raise Error("rampPlunge: Screw it, not handling an arc.")
                    #Straight feed! Easy!
                    else:
                        rampCmds += feed(ePoint.x, ePoint.y, curZ)
                        rampCmds += feed(sPoint.x, sPoint.y)

                    lastZ = curZ
                    curZ = max(curZ - rampDZ, destZ)
                
                return rampCmds
                    
            
            
            
            #For helix-ing/ramping, know where we were last time
            #FIXME: Can probably get this from the "machine"?
            lastZ = fastZPos

            for vpos in frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth):
#                print "vpos: " + str(vpos)
                #Every for every depth we should helix down
                first = True
                # loop over successive wires
                for currentWire in offsets:
#                    print "new line (offset)"
                    last = None
                    for edge in currentWire.Edges:
#                        print "new edge"
                        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, 3, vpos, lastZ)
                                    #print output
                                    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, 3, 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 X" + prnt(startPoint.x) + " Y" + prnt(startPoint.y) +\
                                              " Z" + prnt(fastZPos) + "\n"
                                first = False
                            #then move slow down to our starting point for our profile
                            last = edge.Vertexes[0].Point
                            output += "G1 X" + prnt(last.x) + " Y" + prnt(last.y) + " Z" + prnt(vpos) + "\n"
                        #if isinstance(edge.Curve,Part.Circle):
                        if DraftGeomUtils.geomType(edge) == "Circle":
                            point = edge.Vertexes[-1].Point
                            if point == last: # edges can come flipped
                                point = edge.Vertexes[0].Point
#                                print "flipped"
                            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" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos)
                            output += " I" + prnt(relcenter.x) + " J" +prnt(relcenter.y) + " K" + prnt(relcenter.z)
                            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" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) + "\n"
                            last = point

            #move back up
            output += "G0 Z" + prnt(fastZPos) + "\n"
#            print output
#            path = Path.Path(output)
#            obj.Path = path
            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True
            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
Exemple #43
0
 def opUpdateDepths(self, obj):
     '''updateDepths(obj) ... engraving is always done at the top most z-value'''
     job = PathUtils.findParentJob(obj)
     self.opSetDefaultValues(obj, job)
Exemple #44
0
    def buildpathocc(self, obj, wires):
        import Part
        import DraftGeomUtils
        output = ""

        # absolute coords, millimeters, cancel offsets

        for wire in wires:
            offset = wire

            # reorder the wire
            offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex)

            # we create the path from the offset shape
            last = None
            for edge in offset.Edges:
                if not last:
                    # we set the first move to our first point
                    last = edge.Vertexes[0].Point
                    output += "G0" + " X" + PathUtils.fmt(
                        last.x
                    ) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(
                        obj.SafeHeight.Value)  # Rapid sto starting position
                    output += "G1" + " X" + PathUtils.fmt(
                        last.x
                    ) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(
                        obj.FinalDepth.Value) + "F " + PathUtils.fmt(
                            self.vertFeed) + "\n"  # Vertical feed to depth
                if isinstance(edge.Curve, Part.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" + PathUtils.fmt(
                        point.x) + " Y" + PathUtils.fmt(
                            point.y) + " Z" + PathUtils.fmt(
                                obj.FinalDepth.Value)
                    output += " I" + PathUtils.fmt(
                        relcenter.x) + " J" + PathUtils.fmt(
                            relcenter.y) + " K" + PathUtils.fmt(relcenter.z)
                    output += " F " + PathUtils.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" + PathUtils.fmt(
                        point.x) + " Y" + PathUtils.fmt(
                            point.y) + " Z" + PathUtils.fmt(
                                obj.FinalDepth.Value)
                    output += " F " + PathUtils.fmt(self.horizFeed)
                    output += "\n"
                    last = point
            output += "G0 Z " + PathUtils.fmt(obj.SafeHeight.Value)
        return output
Exemple #45
0
    def areaOpShapes(self, obj):
        """areaOpShapes(obj) ... return top face"""
        # Facing is done either against base objects
        holeShape = None

        PathLog.debug("depthparams: {}".format([i for i in self.depthparams]))

        if obj.Base:
            PathLog.debug("obj.Base: {}".format(obj.Base))
            self.removalshapes = []
            faces = []
            holes = []
            holeEnvs = []
            oneBase = [obj.Base[0][0], True]
            sub0 = getattr(obj.Base[0][0].Shape, obj.Base[0][1][0])
            minHeight = sub0.BoundBox.ZMax

            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 shape.BoundBox.ZMin < minHeight:
                            minHeight = shape.BoundBox.ZMin
                        # Limit to one model base per operation
                        if oneBase[0] is not b[0]:
                            oneBase[1] = False
                        if numpy.isclose(
                            abs(shape.normalAt(0, 0).z), 1
                        ):  # horizontal face
                            # Analyze internal closed wires to determine if raised or a recess
                            for wire in shape.Wires[1:]:
                                if obj.ExcludeRaisedAreas:
                                    ip = self.isPocket(b[0], shape, wire)
                                    if ip is False:
                                        holes.append((b[0].Shape, wire))
                                else:
                                    holes.append((b[0].Shape, wire))
                    else:
                        PathLog.warning(
                            'The base subobject, "{0}," is not a face. Ignoring "{0}."'.format(
                                sub
                            )
                        )

            if obj.ExcludeRaisedAreas and len(holes) > 0:
                for shape, wire in holes:
                    f = Part.makeFace(wire, "Part::FaceMakerSimple")
                    env = PathUtils.getEnvelope(
                        shape, subshape=f, depthparams=self.depthparams
                    )
                    holeEnvs.append(env)
                    holeShape = Part.makeCompound(holeEnvs)

            PathLog.debug("Working on a collection of faces {}".format(faces))
            planeshape = Part.makeCompound(faces)

        # If no base object, do planing of top surface of entire model
        else:
            planeshape = Part.makeCompound([base.Shape for base in self.model])
            PathLog.debug("Working on a shape {}".format(obj.Label))

        # Find the correct shape depending on Boundary shape.
        PathLog.debug("Boundary Shape: {}".format(obj.BoundaryShape))
        bb = planeshape.BoundBox

        # Apply offset for clearing edges
        offset = 0
        if obj.ClearEdges:
            offset = self.radius + 0.1

        bb.XMin = bb.XMin - offset
        bb.YMin = bb.YMin - offset
        bb.XMax = bb.XMax + offset
        bb.YMax = bb.YMax + offset

        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)
            if obj.ExcludeRaisedAreas and oneBase[1]:
                includedFaces = self.getAllIncludedFaces(
                    oneBase[0], env, faceZ=minHeight
                )
                if len(includedFaces) > 0:
                    includedShape = Part.makeCompound(includedFaces)
                    includedEnv = PathUtils.getEnvelope(
                        oneBase[0].Shape,
                        subshape=includedShape,
                        depthparams=self.depthparams,
                    )
                    env = env.cut(includedEnv)
        elif obj.BoundaryShape == "Stock":
            stock = PathUtils.findParentJob(obj).Stock.Shape
            env = stock

            if obj.ExcludeRaisedAreas and oneBase[1]:
                includedFaces = self.getAllIncludedFaces(
                    oneBase[0], stock, faceZ=minHeight
                )
                if len(includedFaces) > 0:
                    stockEnv = PathUtils.getEnvelope(
                        partshape=stock, depthparams=self.depthparams
                    )
                    includedShape = Part.makeCompound(includedFaces)
                    includedEnv = PathUtils.getEnvelope(
                        oneBase[0].Shape,
                        subshape=includedShape,
                        depthparams=self.depthparams,
                    )
                    env = stockEnv.cut(includedEnv)
        elif obj.BoundaryShape == "Perimeter":
            if obj.ClearEdges:
                psZMin = planeshape.BoundBox.ZMin
                ofstShape = PathUtils.getOffsetArea(
                    planeshape, self.radius * 1.25, plane=planeshape
                )
                ofstShape.translate(
                    FreeCAD.Vector(0.0, 0.0, psZMin - ofstShape.BoundBox.ZMin)
                )
                env = PathUtils.getEnvelope(
                    partshape=ofstShape, depthparams=self.depthparams
                )
            else:
                env = PathUtils.getEnvelope(
                    partshape=planeshape, depthparams=self.depthparams
                )
        elif obj.BoundaryShape == "Face Region":
            baseShape = oneBase[0].Shape
            psZMin = planeshape.BoundBox.ZMin
            ofst = 0.0
            if obj.ClearEdges:
                ofst = self.tool.Diameter * 0.51
            ofstShape = PathUtils.getOffsetArea(planeshape, ofst, plane=planeshape)
            ofstShape.translate(
                FreeCAD.Vector(0.0, 0.0, psZMin - ofstShape.BoundBox.ZMin)
            )

            # Calculate custom depth params for removal shape envelope, with start and final depth buffers
            custDepthparams = self._customDepthParams(
                obj, obj.StartDepth.Value + 0.2, obj.FinalDepth.Value - 0.1
            )  # only an envelope
            ofstShapeEnv = PathUtils.getEnvelope(
                partshape=ofstShape, depthparams=custDepthparams
            )
            if obj.ExcludeRaisedAreas:
                env = ofstShapeEnv.cut(baseShape)
                env.translate(
                    FreeCAD.Vector(0.0, 0.0, -0.00001)
                )  # lower removal shape into buffer zone
            else:
                env = ofstShapeEnv

        if holeShape:
            PathLog.debug("Processing holes and face ...")
            holeEnv = PathUtils.getEnvelope(
                partshape=holeShape, depthparams=self.depthparams
            )
            newEnv = env.cut(holeEnv)
            tup = newEnv, False, "pathMillFace"
        else:
            PathLog.debug("Processing solid face ...")
            tup = env, False, "pathMillFace"

        self.removalshapes.append(tup)
        obj.removalshape = self.removalshapes[0][0]  # save removal shape

        return self.removalshapes
Exemple #46
0
def GenerateGCode(op, obj, adaptiveResults, helixDiameter):
    # pylint: disable=unused-argument
    if len(adaptiveResults) == 0 or len(adaptiveResults[0]["AdaptivePaths"]) == 0:
        return

    # minLiftDistance = op.tool.Diameter
    helixRadius = 0
    for region in adaptiveResults:
        p1 = region["HelixCenterPoint"]
        p2 = region["StartPoint"]
        r = math.sqrt(
            (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])
        )
        if r > helixRadius:
            helixRadius = r

    stepDown = obj.StepDown.Value
    passStartDepth = obj.StartDepth.Value

    if stepDown < 0.1:
        stepDown = 0.1

    length = 2 * math.pi * helixRadius

    if float(obj.HelixAngle) < 1:
        obj.HelixAngle = 1
    if float(obj.HelixAngle) > 89:
        obj.HelixAngle = 89

    if float(obj.HelixConeAngle) < 0:
        obj.HelixConeAngle = 0

    helixAngleRad = math.pi * float(obj.HelixAngle) / 180.0
    depthPerOneCircle = length * math.tan(helixAngleRad)
    # print("Helix circle depth: {}".format(depthPerOneCircle))

    stepUp = obj.LiftDistance.Value
    if stepUp < 0:
        stepUp = 0

    finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0
    if finish_step > stepDown:
        finish_step = stepDown

    depth_params = PathUtils.depth_params(
        clearance_height=obj.ClearanceHeight.Value,
        safe_height=obj.SafeHeight.Value,
        start_depth=obj.StartDepth.Value,
        step_down=stepDown,
        z_finish_step=finish_step,
        final_depth=obj.FinalDepth.Value,
        user_depths=None,
    )

    # ml: this is dangerous because it'll hide all unused variables hence forward
    #     however, I don't know what lx and ly signify so I'll leave them for now
    # pylint: disable=unused-variable
    # lx = adaptiveResults[0]["HelixCenterPoint"][0]
    # ly = adaptiveResults[0]["HelixCenterPoint"][1]
    lz = passStartDepth
    step = 0

    for passEndDepth in depth_params.data:
        step = step + 1

        for region in adaptiveResults:
            startAngle = math.atan2(
                region["StartPoint"][1] - region["HelixCenterPoint"][1],
                region["StartPoint"][0] - region["HelixCenterPoint"][0],
            )

            # lx = region["HelixCenterPoint"][0]
            # ly = region["HelixCenterPoint"][1]

            passDepth = passStartDepth - passEndDepth

            p1 = region["HelixCenterPoint"]
            p2 = region["StartPoint"]
            helixRadius = math.sqrt(
                (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])
            )

            # Helix ramp
            if helixRadius > 0.01:
                r = helixRadius - 0.01

                maxfi = passDepth / depthPerOneCircle * 2 * math.pi
                fi = 0
                offsetFi = -maxfi + startAngle - math.pi / 16

                helixStart = [
                    region["HelixCenterPoint"][0] + r * math.cos(offsetFi),
                    region["HelixCenterPoint"][1] + r * math.sin(offsetFi),
                ]

                op.commandlist.append(
                    Path.Command("(Helix to depth: %f)" % passEndDepth)
                )

                if obj.UseHelixArcs is False:
                    # rapid move to start point
                    op.commandlist.append(
                        Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
                    )
                    op.commandlist.append(
                        Path.Command(
                            "G0",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": obj.ClearanceHeight.Value,
                            },
                        )
                    )

                    # rapid move to safe height
                    op.commandlist.append(
                        Path.Command(
                            "G0",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": obj.SafeHeight.Value,
                            },
                        )
                    )

                    # move to start depth
                    op.commandlist.append(
                        Path.Command(
                            "G1",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": passStartDepth,
                                "F": op.vertFeed,
                            },
                        )
                    )

                    if obj.HelixConeAngle == 0:
                        while fi < maxfi:
                            x = region["HelixCenterPoint"][0] + r * math.cos(
                                fi + offsetFi
                            )
                            y = region["HelixCenterPoint"][1] + r * math.sin(
                                fi + offsetFi
                            )
                            z = passStartDepth - fi / maxfi * (
                                passStartDepth - passEndDepth
                            )
                            op.commandlist.append(
                                Path.Command(
                                    "G1", {"X": x, "Y": y, "Z": z, "F": op.vertFeed}
                                )
                            )
                            # lx = x
                            # ly = y
                            fi = fi + math.pi / 16

                        # one more circle at target depth to make sure center is cleared
                        maxfi = maxfi + 2 * math.pi
                        while fi < maxfi:
                            x = region["HelixCenterPoint"][0] + r * math.cos(
                                fi + offsetFi
                            )
                            y = region["HelixCenterPoint"][1] + r * math.sin(
                                fi + offsetFi
                            )
                            z = passEndDepth
                            op.commandlist.append(
                                Path.Command(
                                    "G1", {"X": x, "Y": y, "Z": z, "F": op.horizFeed}
                                )
                            )
                            # lx = x
                            # ly = y
                            fi = fi + math.pi / 16

                    else:
                        # Cone
                        _HelixAngle = 360 - (float(obj.HelixAngle) * 4)

                        if obj.HelixConeAngle > 6:
                            obj.HelixConeAngle = 6

                        helixRadius *= 0.9

                        # Calculate everything
                        helix_height = passStartDepth - passEndDepth
                        r_extra = helix_height * math.tan(
                            math.radians(obj.HelixConeAngle)
                        )
                        HelixTopRadius = helixRadius + r_extra
                        helix_full_height = HelixTopRadius * (
                            math.cos(math.radians(obj.HelixConeAngle))
                            / math.sin(math.radians(obj.HelixConeAngle))
                        )

                        # Start height
                        z = passStartDepth
                        i = 0

                        # Default step down
                        z_step = 0.05

                        # Bigger angle, smaller step down
                        if _HelixAngle > 120:
                            z_step = 0.025
                        if _HelixAngle > 240:
                            z_step = 0.015

                        p = None
                        # Calculate conical helix
                        while z >= passEndDepth:
                            if z < passEndDepth:
                                z = passEndDepth

                            p = CalcHelixConePoint(
                                helix_full_height, i, HelixTopRadius, _HelixAngle
                            )
                            op.commandlist.append(
                                Path.Command(
                                    "G1",
                                    {
                                        "X": p["X"] + region["HelixCenterPoint"][0],
                                        "Y": p["Y"] + region["HelixCenterPoint"][1],
                                        "Z": z,
                                        "F": op.vertFeed,
                                    },
                                )
                            )
                            z = z - z_step
                            i = i + z_step

                        # Calculate some stuff for arcs at bottom
                        p["X"] = p["X"] + region["HelixCenterPoint"][0]
                        p["Y"] = p["Y"] + region["HelixCenterPoint"][1]
                        x_m = (
                            region["HelixCenterPoint"][0]
                            - p["X"]
                            + region["HelixCenterPoint"][0]
                        )
                        y_m = (
                            region["HelixCenterPoint"][1]
                            - p["Y"]
                            + region["HelixCenterPoint"][1]
                        )
                        i_off = (x_m - p["X"]) / 2
                        j_off = (y_m - p["Y"]) / 2

                        # One more circle at target depth to make sure center is cleared
                        op.commandlist.append(
                            Path.Command(
                                "G3",
                                {
                                    "X": x_m,
                                    "Y": y_m,
                                    "Z": passEndDepth,
                                    "I": i_off,
                                    "J": j_off,
                                    "F": op.horizFeed,
                                },
                            )
                        )
                        op.commandlist.append(
                            Path.Command(
                                "G3",
                                {
                                    "X": p["X"],
                                    "Y": p["Y"],
                                    "Z": passEndDepth,
                                    "I": -i_off,
                                    "J": -j_off,
                                    "F": op.horizFeed,
                                },
                            )
                        )

                else:
                    # Use arcs for helix - no conical shape support
                    helixStart = [
                        region["HelixCenterPoint"][0] + r,
                        region["HelixCenterPoint"][1],
                    ]

                    # rapid move to start point
                    op.commandlist.append(
                        Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
                    )
                    op.commandlist.append(
                        Path.Command(
                            "G0",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": obj.ClearanceHeight.Value,
                            },
                        )
                    )

                    # rapid move to safe height
                    op.commandlist.append(
                        Path.Command(
                            "G0",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": obj.SafeHeight.Value,
                            },
                        )
                    )

                    # move to start depth
                    op.commandlist.append(
                        Path.Command(
                            "G1",
                            {
                                "X": helixStart[0],
                                "Y": helixStart[1],
                                "Z": passStartDepth,
                                "F": op.vertFeed,
                            },
                        )
                    )

                    x = region["HelixCenterPoint"][0] + r
                    y = region["HelixCenterPoint"][1]

                    curDep = passStartDepth
                    while curDep > (passEndDepth + depthPerOneCircle):
                        op.commandlist.append(
                            Path.Command(
                                "G2",
                                {
                                    "X": x - (2 * r),
                                    "Y": y,
                                    "Z": curDep - (depthPerOneCircle / 2),
                                    "I": -r,
                                    "F": op.vertFeed,
                                },
                            )
                        )
                        op.commandlist.append(
                            Path.Command(
                                "G2",
                                {
                                    "X": x,
                                    "Y": y,
                                    "Z": curDep - depthPerOneCircle,
                                    "I": r,
                                    "F": op.vertFeed,
                                },
                            )
                        )
                        curDep = curDep - depthPerOneCircle

                    lastStep = curDep - passEndDepth
                    if lastStep > (depthPerOneCircle / 2):
                        op.commandlist.append(
                            Path.Command(
                                "G2",
                                {
                                    "X": x - (2 * r),
                                    "Y": y,
                                    "Z": curDep - (lastStep / 2),
                                    "I": -r,
                                    "F": op.vertFeed,
                                },
                            )
                        )
                        op.commandlist.append(
                            Path.Command(
                                "G2",
                                {
                                    "X": x,
                                    "Y": y,
                                    "Z": passEndDepth,
                                    "I": r,
                                    "F": op.vertFeed,
                                },
                            )
                        )
                    else:
                        op.commandlist.append(
                            Path.Command(
                                "G2",
                                {
                                    "X": x - (2 * r),
                                    "Y": y,
                                    "Z": passEndDepth,
                                    "I": -r,
                                    "F": op.vertFeed,
                                },
                            )
                        )
                        op.commandlist.append(
                            Path.Command(
                                "G1",
                                {"X": x, "Y": y, "Z": passEndDepth, "F": op.vertFeed},
                            )
                        )

                    # one more circle at target depth to make sure center is cleared
                    op.commandlist.append(
                        Path.Command(
                            "G2",
                            {
                                "X": x - (2 * r),
                                "Y": y,
                                "Z": passEndDepth,
                                "I": -r,
                                "F": op.horizFeed,
                            },
                        )
                    )
                    op.commandlist.append(
                        Path.Command(
                            "G2",
                            {
                                "X": x,
                                "Y": y,
                                "Z": passEndDepth,
                                "I": r,
                                "F": op.horizFeed,
                            },
                        )
                    )
                    # lx = x
                    # ly = y

            else:  # no helix entry
                # rapid move to clearance height
                op.commandlist.append(
                    Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
                )
                op.commandlist.append(
                    Path.Command(
                        "G0",
                        {
                            "X": region["StartPoint"][0],
                            "Y": region["StartPoint"][1],
                            "Z": obj.ClearanceHeight.Value,
                        },
                    )
                )
                # straight plunge to target depth
                op.commandlist.append(
                    Path.Command(
                        "G1",
                        {
                            "X": region["StartPoint"][0],
                            "Y": region["StartPoint"][1],
                            "Z": passEndDepth,
                            "F": op.vertFeed,
                        },
                    )
                )

            lz = passEndDepth
            z = obj.ClearanceHeight.Value
            op.commandlist.append(Path.Command("(Adaptive - depth: %f)" % passEndDepth))

            # add adaptive paths
            for pth in region["AdaptivePaths"]:
                motionType = pth[0]  # [0] contains motion type

                for pt in pth[1]:  # [1] contains list of points
                    x = pt[0]
                    y = pt[1]

                    # dist = math.sqrt((x-lx)*(x-lx) + (y-ly)*(y-ly))

                    if motionType == area.AdaptiveMotionType.Cutting:
                        z = passEndDepth
                        if z != lz:
                            op.commandlist.append(
                                Path.Command("G1", {"Z": z, "F": op.vertFeed})
                            )

                        op.commandlist.append(
                            Path.Command("G1", {"X": x, "Y": y, "F": op.horizFeed})
                        )

                    elif motionType == area.AdaptiveMotionType.LinkClear:
                        z = passEndDepth + stepUp
                        if z != lz:
                            op.commandlist.append(Path.Command("G0", {"Z": z}))

                        op.commandlist.append(Path.Command("G0", {"X": x, "Y": y}))

                    elif motionType == area.AdaptiveMotionType.LinkNotClear:
                        z = obj.ClearanceHeight.Value
                        if z != lz:
                            op.commandlist.append(Path.Command("G0", {"Z": z}))

                        op.commandlist.append(Path.Command("G0", {"X": x, "Y": y}))

                    # elif motionType == area.AdaptiveMotionType.LinkClearAtPrevPass:
                    #     if lx!=x or ly!=y:
                    #         op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":passStartDepth+stepUp}))
                    #     op.commandlist.append(Path.Command("G0", { "X": x, "Y":y, "Z":passStartDepth+stepUp}))

                    # lx = x
                    # ly = y
                    lz = z

            # return to safe height in this Z pass
            z = obj.ClearanceHeight.Value
            if z != lz:
                op.commandlist.append(Path.Command("G0", {"Z": z}))

            lz = z

        passStartDepth = passEndDepth

        # return to safe height in this Z pass
        z = obj.ClearanceHeight.Value
        if z != lz:
            op.commandlist.append(Path.Command("G0", {"Z": z}))

        lz = z

    z = obj.ClearanceHeight.Value
    if z != lz:
        op.commandlist.append(Path.Command("G0", {"Z": z}))
Exemple #47
0
    def opExecute(self, obj, getsim=False):
        """opExecute(obj, getsim=False) ... implementation of Path.Area ops.
        determines the parameters for _buildPathArea().
        Do not overwrite, implement
            areaOpAreaParams(obj, isHole) ... op specific area param dictionary
            areaOpPathParams(obj, isHole) ... op specific path param dictionary
            areaOpShapes(obj)             ... the shape for path area to process
            areaOpUseProjection(obj)      ... return true if operation can use projection
        instead."""
        PathLog.track()

        # Instantiate class variables for operation reference
        self.endVector = None
        self.leadIn = 2.0

        # Initiate depthparams and calculate operation heights for operation
        self.depthparams = self._customDepthParams(
            obj, obj.StartDepth.Value, obj.FinalDepth.Value
        )

        # Set start point
        if PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint:
            start = obj.StartPoint
        else:
            start = None

        aOS = self.areaOpShapes(obj)

        # Adjust tuples length received from other PathWB tools/operations
        shapes = []
        for shp in aOS:
            if len(shp) == 2:
                (fc, iH) = shp
                #     fc, iH,  sub or description
                tup = fc, iH, "otherOp"
                shapes.append(tup)
            else:
                shapes.append(shp)

        if len(shapes) > 1:
            locations = []
            for s in shapes:
                if s[2] == "OpenEdge":
                    shp = Part.makeCompound(s[0])
                else:
                    shp = s[0]
                locations.append(
                    {"x": shp.BoundBox.XMax, "y": shp.BoundBox.YMax, "shape": s}
                )

            locations = PathUtils.sort_locations(locations, ["x", "y"])

            shapes = [j["shape"] for j in locations]

        sims = []
        for shape, isHole, sub in shapes:
            profileEdgesIsOpen = False

            if sub == "OpenEdge":
                profileEdgesIsOpen = True
                if (
                    PathOp.FeatureStartPoint & self.opFeatures(obj)
                    and obj.UseStartPoint
                ):
                    osp = obj.StartPoint
                    self.commandlist.append(
                        Path.Command(
                            "G0", {"X": osp.x, "Y": osp.y, "F": self.horizRapid}
                        )
                    )

            try:
                if profileEdgesIsOpen:
                    (pp, sim) = self._buildProfileOpenEdges(
                        obj, shape, isHole, start, getsim
                    )
                else:
                    (pp, sim) = self._buildPathArea(obj, shape, isHole, start, getsim)
            except Exception as e:
                FreeCAD.Console.PrintError(e)
                FreeCAD.Console.PrintError(
                    "Something unexpected happened. Check project and tool config."
                )
            else:
                if profileEdgesIsOpen:
                    ppCmds = pp
                else:
                    ppCmds = pp.Commands

                # Save gcode commands to object command list
                self.commandlist.extend(ppCmds)
                sims.append(sim)
            # Eif

            if (
                self.areaOpRetractTool(obj)
                and self.endVector is not None
                and len(self.commandlist) > 1
            ):
                self.endVector[2] = obj.ClearanceHeight.Value
                self.commandlist.append(
                    Path.Command(
                        "G0", {"Z": obj.ClearanceHeight.Value, "F": self.vertRapid}
                    )
                )

        PathLog.debug("obj.Name: " + str(obj.Name) + "\n\n")
        return sims
Exemple #48
0
def profile(curve,
            side_of_line,
            radius=1.0,
            vertfeed=0.0,
            horizfeed=0.0,
            offset_extra=0.0,
            rapid_safety_space=None,
            clearance=None,
            start_depth=None,
            stepdown=None,
            final_depth=None,
            use_CRC=False,
            roll_on=None,
            roll_off=None,
            roll_start=False,
            roll_end=True,
            roll_radius=None,
            roll_start_pt=None,
            roll_end_pt=None):

    output = ""
    output += "G0 Z" + str(clearance) + "\n"
    print "in profile: 151"
    offset_curve = area.Curve(curve)
    if offset_curve.getNumVertices() <= 1:
        raise Exception, "Sketch has no elements!"
    if side_of_line == "On":
        use_CRC = False

    elif (side_of_line == "Left") or (side_of_line == "Right"):
        # get tool radius plus little bit of extra offset, if needed to clean
        # up profile a little more
        offset = radius + offset_extra
        if side_of_line == 'Left':
            offset_curve.Offset(offset)

        else:
            offset_curve.Offset(-offset)

        if offset_curve is False:
            raise Exception, "couldn't offset kurve " + str(offset_curve)
    else:
        raise Exception, "Side must be 'Left','Right', or 'On'"


# =========================================================================
#     #roll_on roll_off section
#     roll_on_curve = area.Curve()
#     if offset_curve.getNumVertices() <= 1: return
#     first_span = offset_curve.GetFirstSpan()
#     if roll_on == None:
#         rollstart = first_span.p
#     elif roll_on == 'auto':
#         if roll_radius < 0.0000000001:
#             rollstart = first_span.p
#         v = first_span.GetVector(0.0)
#         if direction == 'right':
#             off_v = area.Point(v.y, -v.x)
#         else:
#             off_v = area.Point(-v.y, v.x)
#         rollstart = first_span.p + off_v * roll_radius
#     else:
#         rollstart = roll_on
#
#     rvertex = area.Vertex(first_span.p)
#
#     if first_span.p == rollstart:
#         rvertex.type = 0
#     else:
#         v = first_span.GetVector(0.0) # get start direction
#         rvertex.c, rvertex.type = area.TangentialArc(first_span.p, rollstart, -v)
#         rvertex.type = -rvertex.type # because TangentialArc was used in reverse
#     # add a start roll on point
#     roll_on_curve.append(rollstart)
#
#     # add the roll on arc
#     roll_on_curve.append(rvertex)
#     #end of roll_on roll_off section
# =========================================================================

# do multiple depths
    layer_count = int((start_depth - final_depth) / stepdown)
    if layer_count * stepdown + 0.00001 < start_depth - final_depth:
        layer_count += 1
    current_start_depth = start_depth
    prev_depth = start_depth
    for i in range(1, layer_count + 1):
        if i == layer_count:
            depth = final_depth
        else:
            depth = start_depth - i * stepdown
        mat_depth = prev_depth
        start_z = mat_depth
        # first move
        output += "G0 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\
            " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) +\
            " Z" + str(PathUtils.fmt(mat_depth + rapid_safety_space)) + "\n"
        # feed down to depth
        mat_depth = depth
        if start_z > mat_depth:
            mat_depth = start_z
        # feed down in Z
        output += "G1 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\
            " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) + " Z" + str(PathUtils.fmt(depth)) +\
            " F" + str(PathUtils.fmt(vertfeed)) + "\n"
        if use_CRC:
            if side_of_line == 'left':
                output += "G41" + "\n"
            else:
                output += "G42" + "\n"
        # cut the main kurve
        current_perim = 0.0
        lastx = offset_curve.GetFirstSpan().p.x
        lasty = offset_curve.GetFirstSpan().p.y
        for span in offset_curve.GetSpans():
            current_perim += span.Length()
            if span.v.type == 0:  # line
                # feed(span.v.p.x, span.v.p.y, ez)
                output += "G1 X" + str(PathUtils.fmt(span.v.p.x)) + " Y" + str(PathUtils.fmt(span.v.p.y)) +\
                    " Z" + str(PathUtils.fmt(depth)) + " F" + \
                    str(PathUtils.fmt(horizfeed)) + "\n"
                lastx = span.v.p.x
                lasty = span.v.p.y
            elif (span.v.type == 1) or (span.v.type == -1):
                if span.v.type == 1:  # anti-clockwise arc
                    command = 'G3'
                elif span.v.type == -1:  # clockwise arc
                    command = 'G2'
                arc_I = span.v.c.x - lastx
                arc_J = span.v.c.y - lasty
                output += command + "X" + str(PathUtils.fmt(
                    span.v.p.x)) + " Y" + str(PathUtils.fmt(
                        span.v.p.y))  # +" Z"+ str(PathUtils.fmt(depth))
                output += " I" + str(PathUtils.fmt(arc_I)) + " J" + str(
                    PathUtils.fmt(arc_J)) + " F" + str(
                        PathUtils.fmt(horizfeed)
                    ) + '\n'  # " K"+str(PathUtils.fmt(depth)) +"\n"
                lastx = span.v.p.x
                lasty = span.v.p.y
            else:
                raise Exception, "valid geometry identifier needed"
        if use_CRC:
            # end_CRC()
            output += "G40" + "\n"
        # rapid up to the clearance height
        output += "G0 Z" + str(PathUtils.fmt(clearance)) + "\n"

    del offset_curve

    return output
Exemple #49
0
    def _buildPathArea(self, obj, baseobject, isHole, start, getsim):
        '''_buildPathArea(obj, baseobject, isHole, start, getsim) ... internal function.'''
        # pylint: disable=unused-argument
        PathLog.track()
        area = Path.Area()
        area.setPlane(PathUtils.makeWorkplane(baseobject))
        area.add(baseobject)

        areaParams = self.areaOpAreaParams(obj, isHole)  # pylint: disable=assignment-from-no-return
        if hasattr(obj, 'ExpandProfile') and obj.ExpandProfile != 0:
            areaParams = self.areaOpAreaParamsExpandProfile(obj, isHole)  # pylint: disable=assignment-from-no-return

        heights = [i for i in self.depthparams]
        PathLog.debug('depths: {}'.format(heights))
        area.setParams(**areaParams)
        obj.AreaParams = str(area.getParams())

        PathLog.debug("Area with params: {}".format(area.getParams()))

        sections = area.makeSections(mode=0,
                                     project=self.areaOpUseProjection(obj),
                                     heights=heights)
        PathLog.debug("sections = %s" % sections)
        shapelist = [sec.getShape() for sec in sections]
        PathLog.debug("shapelist = %s" % shapelist)

        pathParams = self.areaOpPathParams(obj, isHole)  # pylint: disable=assignment-from-no-return
        pathParams['shapes'] = shapelist
        pathParams['feedrate'] = self.horizFeed
        pathParams['feedrate_v'] = self.vertFeed
        pathParams['verbose'] = True
        pathParams['resume_height'] = obj.SafeHeight.Value
        pathParams['retraction'] = obj.ClearanceHeight.Value
        pathParams['return_end'] = True
        # Note that emitting preambles between moves breaks some dressups and prevents path optimization on some controllers
        pathParams['preamble'] = False

        if not self.areaOpRetractTool(obj):
            pathParams['threshold'] = 2.001 * self.radius

        if self.endVector is not None:
            pathParams['start'] = self.endVector
        elif PathOp.FeatureStartPoint & self.opFeatures(
                obj) and obj.UseStartPoint:
            pathParams['start'] = obj.StartPoint

        obj.PathParams = str({
            key: value
            for key, value in pathParams.items() if key != 'shapes'
        })
        PathLog.debug("Path with params: {}".format(obj.PathParams))

        (pp, end_vector) = Path.fromShapes(**pathParams)
        PathLog.debug('pp: {}, end vector: {}'.format(pp, end_vector))
        self.endVector = end_vector  # pylint: disable=attribute-defined-outside-init

        simobj = None
        if getsim:
            areaParams['Thicken'] = True
            areaParams['ToolRadius'] = self.radius - self.radius * .005
            area.setParams(**areaParams)
            sec = area.makeSections(mode=0, project=False,
                                    heights=heights)[-1].getShape()
            simobj = sec.extrude(FreeCAD.Vector(0, 0,
                                                baseobject.BoundBox.ZMax))

        return pp, simobj
Exemple #50
0
def review(obj):
    limits = False
    "checks the selected project for common errors"
    toolcontrolcount = 0
    for item in obj.Group:
        print "Checking: " + item.Label
        if item.Name[:2] == "TC":
            toolcontrolcount += 1
            if item.ToolNumber == 0:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity", "Tool Controller: " + str(item.Label) +
                        " is using ID 0 which the undefined default. Please set a real tool.\n"
                    ))
            else:
                tool = PU.getTool(item, item.ToolNumber)
                if tool is None:
                    FreeCAD.Console.PrintError(
                        translate(
                            "Path_Sanity", "Tool Controller: " +
                            str(item.Label) + " is using tool: " +
                            str(item.ToolNumber) + " which is invalid\n"))
                elif tool.Diameter == 0:
                    FreeCAD.Console.PrintError(
                        translate(
                            "Path_Sanity",
                            "Tool Controller: " + str(item.Label) +
                            " is using tool: " + str(item.ToolNumber) +
                            " which has a zero diameter\n"))
            if item.HorizFeed == 0:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity", "Tool Controller: " + str(item.Label) +
                        " has a 0 value for the Horizontal feed rate\n"))
            if item.VertFeed == 0:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity", "Tool Controller: " + str(item.Label) +
                        " has a 0 value for the Vertical feed rate\n"))
            if item.SpindleSpeed == 0:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity", "Tool Controller: " + str(item.Label) +
                        " has a 0 value for the spindle speed\n"))

        if item.Name[:7] == "Machine":
            if len(item.Tooltable.Tools) == 0:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity", "Machine: " + str(item.Label) +
                        " has no tools defined in the tool table\n"))

            if item.X_Max == item.X_Min or item.Y_Max == item.Y_Min:
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Path_Sanity",
                        "It appears the machine limits haven't been set.  Not able to check path extents.\n"
                    ))
            else:
                limits = True

    if toolcontrolcount == 0:
        FreeCAD.Console.PrintWarning(
            translate(
                "Path_Sanity",
                "A Tool Controller was not found. Default values are used which is dangerous.  Please add a Tool Controller.\n"
            ))
Exemple #51
0
    def opExecute(self, obj, getsim=False):  # pylint: disable=arguments-differ
        '''opExecute(obj, getsim=False) ... implementation of Path.Area ops.
        determines the parameters for _buildPathArea().
        Do not overwrite, implement
            areaOpAreaParams(obj, isHole) ... op specific area param dictionary
            areaOpPathParams(obj, isHole) ... op specific path param dictionary
            areaOpShapes(obj)             ... the shape for path area to process
            areaOpUseProjection(obj)      ... return true if operation can use projection
        instead.'''
        PathLog.track()

        # Instantiate class variables for operation reference
        self.endVector = None  # pylint: disable=attribute-defined-outside-init
        self.rotateFlag = False  # pylint: disable=attribute-defined-outside-init
        self.leadIn = 2.0  # pylint: disable=attribute-defined-outside-init
        self.cloneNames = []  # pylint: disable=attribute-defined-outside-init
        self.guiMsgs = []  # pylint: disable=attribute-defined-outside-init
        self.tempObjectNames = []  # pylint: disable=attribute-defined-outside-init
        self.stockBB = PathUtils.findParentJob(obj).Stock.Shape.BoundBox  # pylint: disable=attribute-defined-outside-init
        self.useTempJobClones(
            'Delete')  # Clear temporary group and recreate for temp job clones
        self.rotStartDepth = None  # pylint: disable=attribute-defined-outside-init

        start_depth = obj.StartDepth.Value
        final_depth = obj.FinalDepth.Value
        if obj.EnableRotation != 'Off':
            # Calculate operation heights based upon rotation radii
            opHeights = self.opDetermineRotationRadii(obj)
            (self.xRotRad, self.yRotRad, self.zRotRad) = opHeights[0]  # pylint: disable=attribute-defined-outside-init
            (self.clrOfset, self.safOfst) = opHeights[1]  # pylint: disable=attribute-defined-outside-init

            # Set clearance and safe heights based upon rotation radii
            if obj.EnableRotation == 'A(x)':
                start_depth = self.xRotRad
            elif obj.EnableRotation == 'B(y)':
                start_depth = self.yRotRad
            else:
                start_depth = max(self.xRotRad, self.yRotRad)
            final_depth = -1 * start_depth

            self.rotStartDepth = start_depth
            # The next two lines are improper code.
            # The ClearanceHeight and SafeHeight need to be set in opSetDefaultValues() method.
            # They should not be redefined here, so this entire `if...:` statement needs relocated.
            obj.ClearanceHeight.Value = start_depth + self.clrOfset
            obj.SafeHeight.Value = start_depth + self.safOfst

            # Create visual axes when debugging.
            if PathLog.getLevel(PathLog.thisModule()) == 4:
                self.visualAxis()

            # Set axial feed rates based upon horizontal feed rates
            safeCircum = 2 * math.pi * obj.SafeHeight.Value
            self.axialFeed = 360 / safeCircum * self.horizFeed  # pylint: disable=attribute-defined-outside-init
            self.axialRapid = 360 / safeCircum * self.horizRapid  # pylint: disable=attribute-defined-outside-init

        # Initiate depthparams and calculate operation heights for rotational operation
        self.depthparams = self._customDepthParams(obj, obj.StartDepth.Value,
                                                   obj.FinalDepth.Value)

        # Set start point
        if PathOp.FeatureStartPoint & self.opFeatures(
                obj) and obj.UseStartPoint:
            start = obj.StartPoint
        else:
            start = None

        aOS = self.areaOpShapes(obj)  # pylint: disable=assignment-from-no-return

        # Adjust tuples length received from other PathWB tools/operations beside PathPocketShape
        shapes = []
        for shp in aOS:
            if len(shp) == 2:
                (fc, iH) = shp
                #     fc, iH,   sub,   angle, axis,  strtDep,     finDep
                tup = fc, iH, 'otherOp', 0.0, 'S', start_depth, final_depth
                shapes.append(tup)
            else:
                shapes.append(shp)

        if len(shapes) > 1:
            jobs = list()
            for s in shapes:
                if s[2] == 'OpenEdge':
                    shp = Part.makeCompound(s[0])
                else:
                    shp = s[0]
                jobs.append({
                    'x': shp.BoundBox.XMax,
                    'y': shp.BoundBox.YMax,
                    'shape': s
                })

            jobs = PathUtils.sort_jobs(jobs, ['x', 'y'])

            shapes = [j['shape'] for j in jobs]

        sims = []
        numShapes = len(shapes)
        for ns in range(0, numShapes):
            profileEdgesIsOpen = False
            (shape, isHole, sub, angle, axis, strDep, finDep) = shapes[ns]  # pylint: disable=unused-variable
            if sub == 'OpenEdge':
                profileEdgesIsOpen = True
                if PathOp.FeatureStartPoint & self.opFeatures(
                        obj) and obj.UseStartPoint:
                    osp = obj.StartPoint
                    self.commandlist.append(
                        Path.Command('G0', {
                            'X': osp.x,
                            'Y': osp.y,
                            'F': self.horizRapid
                        }))

            if ns < numShapes - 1:
                nextAxis = shapes[ns + 1][4]
            else:
                nextAxis = 'L'

            self.depthparams = self._customDepthParams(obj, strDep, finDep)

            try:
                if profileEdgesIsOpen:
                    (pp, sim) = self._buildProfileOpenEdges(
                        obj, shape, isHole, start, getsim)
                else:
                    (pp, sim) = self._buildPathArea(obj, shape, isHole, start,
                                                    getsim)
            except Exception as e:  # pylint: disable=broad-except
                FreeCAD.Console.PrintError(e)
                FreeCAD.Console.PrintError(
                    "Something unexpected happened. Check project and tool config."
                )
            else:
                if profileEdgesIsOpen:
                    ppCmds = pp
                else:
                    ppCmds = pp.Commands
                if obj.EnableRotation != 'Off' and self.rotateFlag is True:
                    # Rotate model to index for cut
                    if axis == 'X':
                        axisOfRot = 'A'
                    elif axis == 'Y':
                        axisOfRot = 'B'
                    elif axis == 'Z':
                        axisOfRot = 'C'
                    else:
                        axisOfRot = 'A'
                    # Rotate Model to correct angle
                    ppCmds.insert(
                        0,
                        Path.Command('G0', {
                            axisOfRot: angle,
                            'F': self.axialRapid
                        }))

                    # Raise cutter to safe height
                    ppCmds.insert(
                        0,
                        Path.Command('G0', {
                            'Z': obj.SafeHeight.Value,
                            'F': self.vertRapid
                        }))

                    # Return index to starting position if axis of rotation changes.
                    if numShapes > 1:
                        if ns != numShapes - 1:
                            if axis != nextAxis:
                                ppCmds.append(
                                    Path.Command('G0', {
                                        axisOfRot: 0.0,
                                        'F': self.axialRapid
                                    }))
                # Eif

                # Save gcode commands to object command list
                self.commandlist.extend(ppCmds)
                sims.append(sim)
            # Eif

            if self.areaOpRetractTool(
                    obj) and self.endVector is not None and len(
                        self.commandlist) > 1:
                self.endVector[2] = obj.ClearanceHeight.Value
                self.commandlist.append(
                    Path.Command('G0', {
                        'Z': obj.ClearanceHeight.Value,
                        'F': self.vertRapid
                    }))

        # Raise cutter to safe height and rotate back to original orientation
        #    based on next rotational operation in job
        if self.rotateFlag is True:
            resetAxis = False
            lastJobOp = None
            nextJobOp = None
            opIdx = 0
            JOB = PathUtils.findParentJob(obj)
            jobOps = JOB.Operations.Group
            numJobOps = len(jobOps)

            for joi in range(0, numJobOps):
                jo = jobOps[joi]
                if jo.Name == obj.Name:
                    opIdx = joi
            lastOpIdx = opIdx - 1
            nextOpIdx = opIdx + 1
            if lastOpIdx > -1:
                lastJobOp = jobOps[lastOpIdx]
            if nextOpIdx < numJobOps:
                nextJobOp = jobOps[nextOpIdx]

            if lastJobOp is not None:
                if hasattr(lastJobOp, 'EnableRotation'):
                    PathLog.debug(
                        'Last Op, {}, has `EnableRotation` set to {}'.format(
                            lastJobOp.Label, lastJobOp.EnableRotation))
                    if lastJobOp.EnableRotation != obj.EnableRotation:
                        resetAxis = True
            # if ns == numShapes - 1:  # If last shape, check next op EnableRotation setting
            if nextJobOp is not None:
                if hasattr(nextJobOp, 'EnableRotation'):
                    PathLog.debug(
                        'Next Op, {}, has `EnableRotation` set to {}'.format(
                            nextJobOp.Label, nextJobOp.EnableRotation))
                    if nextJobOp.EnableRotation != obj.EnableRotation:
                        resetAxis = True

            # Raise to safe height if rotation activated
            self.commandlist.append(
                Path.Command('G0', {
                    'Z': obj.SafeHeight.Value,
                    'F': self.vertRapid
                }))
            # reset rotational axes if necessary
            if resetAxis is True:
                self.commandlist.append(
                    Path.Command('G0', {
                        'A': 0.0,
                        'F': self.axialRapid
                    }))
                self.commandlist.append(
                    Path.Command('G0', {
                        'B': 0.0,
                        'F': self.axialRapid
                    }))

        self.useTempJobClones(
            'Delete')  # Delete temp job clone group and contents
        self.guiMessage('title', None,
                        show=True)  # Process GUI messages to user
        for ton in self.tempObjectNames:  # remove temporary objects by name
            FreeCAD.ActiveDocument.removeObject(ton)
        PathLog.debug("obj.Name: " + str(obj.Name) + "\n\n")
        return sims
    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

        '''

        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.

        '''
        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
Exemple #53
0
def makeAreaCurve(edges, direction, startpt=None, endpt=None):
    curveobj = area.Curve()

    cleanededges = Part.__sortEdges__(PathUtils.cleanedges(edges, 0.01))

    # for e in cleanededges:
    # print str(e.valueAt(e.FirstParameter)) + "," +
    # str(e.valueAt(e.LastParameter))
    edgelist = []

    if len(cleanededges) == 1:  # user selected a single edge.
        edgelist = cleanededges
    else:
        # edgelist = [] #Multiple edges.  Need to sequence the vetexes.
        # First get the first segment oriented correctly.

        # We first compare the last parameter of the first segment to see if it
        # matches either end of the second segment. If not, it must need
        # flipping.
        if cleanededges[0].valueAt(cleanededges[0].LastParameter) in [
                cleanededges[1].valueAt(cleanededges[1].FirstParameter),
                cleanededges[1].valueAt(cleanededges[1].LastParameter)
        ]:
            edge0 = cleanededges[0]
        else:
            edge0 = PathUtils.reverseEdge(cleanededges[0])

        edgelist.append(edge0)

        # Now iterate the rest of the edges matching the last parameter of the
        # previous segment.
        for edge in cleanededges[1:]:

            if edge.valueAt(edge.FirstParameter) == edgelist[-1].valueAt(
                    edgelist[-1].LastParameter):
                nextedge = edge
            else:
                nextedge = PathUtils.reverseEdge(edge)
            edgelist.append(nextedge)
    # print "makeareacurve 87: " + "area.Point(" +
    # str(edgelist[0].Vertexes[0].X) + ", " +
    # str(edgelist[0].Vertexes[0].Y)+")"
    curveobj.append(
        area.Point(edgelist[0].Vertexes[0].X, edgelist[0].Vertexes[0].Y))
    #     seglist =[]
    #     if direction=='CW':
    #         edgelist.reverse()
    #         for e in edgelist:
    #             seglist.append(PathUtils.reverseEdge(e)) #swap end points on every segment
    #     else:
    #         for e in edgelist:
    #             seglist.append(e)

    for s in edgelist:
        curveobj.append(makeAreaVertex(s))

    if startpt:
        # future nearest point code yet to be worked out -fixme
        #         v1 = Vector(startpt.X,startpt.Y,startpt.Z)
        #         perppoint1 = DraftGeomUtils.findPerpendicular(v1,firstedge)
        #         perppoint1 = DraftGeomUtils.findDistance(v1,firstedge)
        #         if  perppoint1:
        #             curveobj.ChangeStart(area.Point(perppoint1[0].x,perppoint1[0].y))
        #         else:
        #             curveobj.ChangeStart(area.Point(startpt.X,startpt.Y))
        curveobj.ChangeStart(area.Point(startpt.x, startpt.y))
    if endpt:
        # future nearest point code yet to be worked out -fixme
        #         v2 = Vector(endpt.X,endpt.Y,endpt.Z)
        #         perppoint2 = DraftGeomUtils.findPerpendicular(v2,lastedge)
        #         if perppoint2:
        #             curveobj.ChangeEnd(area.Point(perppoint2[0].x,perppoint2[0].y))
        #         else:
        #             curveobj.ChangeEnd(area.Point(endpt.X,endpt.Y))
        curveobj.ChangeEnd(area.Point(endpt.x, endpt.y))

    if curveobj.IsClockwise() and direction == 'CCW':
        curveobj.Reverse()
    elif not curveobj.IsClockwise() and direction == 'CW':
        curveobj.Reverse()
    return curveobj
    def Activated(self):
        import Path
        from PathScripts import PathUtils, PathProfile, PathProject
        prjexists = False
        selection = PathSelection.multiSelect()

        if not selection:
            return

        # if everything is ok, execute and register the transaction in the undo/redo stack
        FreeCAD.ActiveDocument.openTransaction(
            translate("PathProfile", "Create Profile"))
        FreeCADGui.addModule("PathScripts.PathProfile")

        obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython",
                                               "Profile")
        PathProfile.ObjectProfile(obj)
        PathProfile.ViewProviderProfile(obj.ViewObject)

        obj.Base = (FreeCAD.ActiveDocument.getObject(selection['objname']))

        if selection['facenames']:
            #FreeCAD.Console.PrintMessage('There are edges selected\n')
            obj.Face1 = (FreeCAD.ActiveDocument.getObject(
                selection['objname']), selection['facenames'][0])
            if len(selection['facenames']) > 1:
                obj.Face2 = (FreeCAD.ActiveDocument.getObject(
                    selection['objname']), selection['facenames'][-1])

        if selection['edgenames']:
            #FreeCAD.Console.PrintMessage('There are edges selected\n')

            obj.Edge1 = (FreeCAD.ActiveDocument.getObject(
                selection['objname']), (selection['edgenames'][0]))
            if len(selection['edgenames']) > 1:
                obj.Edge2 = (FreeCAD.ActiveDocument.getObject(
                    selection['objname']), (selection['edgenames'][-1]))

        if selection['pointlist']:
            FreeCADGui.doCommand('from FreeCAD import Vector')
            stptX, stptY, stptZ = selection['pointlist'][0].X, selection[
                'pointlist'][0].Y, selection['pointlist'][0].Z
            obj.StartPoint = Vector((stptX), (stptY), (stptZ))
            if len(
                    selection['pointlist']
            ) > 1:  # we have more than one point so we have an end point
                endptX, endptY, endptZ = selection['pointlist'][
                    -1].X, selection['pointlist'][-1].Y, selection[
                        'pointlist'][-1].Z
                obj.EndPoint = Vector(endptX, endptY, endptZ)
        if selection['pathwire'].isClosed():
            obj.PathClosed = True
            if selection['clockwise']:
                obj.Side = "Left"
                obj.Direction = "CW"
            elif selection['clockwise'] == False:
                obj.Side = "Right"
                obj.Direction = "CCW"
        else:
            obj.Side = "On"
            obj.Direction = "CCW"
            obj.PathClosed = False

        ZMax = obj.Base[0].Shape.BoundBox.ZMax
        ZMin = obj.Base[0].Shape.BoundBox.ZMin
        obj.StepDown.Value = 1.0
        obj.StartDepth.Value = ZMax - obj.StepDown.Value
        obj.FinalDepth.Value = ZMin - 1.0
        obj.ClearanceHeight.Value = ZMax + 5.0
        obj.SegLen.Value = 0.5
        obj.Active = True
        obj.ViewObject.ShowFirstRapid = False

        project = PathUtils.addToProject(obj)

        tl = PathUtils.changeTool(obj, project)
        if tl:
            obj.ToolNumber = tl

        FreeCAD.ActiveDocument.commitTransaction()
        FreeCAD.ActiveDocument.recompute()
 def onDelete(self, arg1=None, arg2=None):
     '''this makes sure that the base operation is added back to the project and visible'''
     FreeCADGui.ActiveDocument.getObject(
         arg1.Object.Base.Name).Visibility = True
     PathUtils.addToJob(arg1.Object.Base)
     return True
Exemple #56
0
 def onChanged(self, obj, prop):
     if not 'Restore' in obj.State and prop == "Radius":
         job = PathUtils.findParentJob(obj)
         if job:
             job.Proxy.setCenterOfRotation(self.center(obj))
Exemple #57
0
    def opSetDefaultValues(self, obj, job):
        '''opSetDefaultValues(obj) ... base implementation, do not overwrite.
        The base implementation sets the depths and heights based on the
        areaOpShapeForDepths() return value.
        Do not overwrite, overwrite areaOpSetDefaultValues(obj, job) instead.'''
        PathLog.debug("opSetDefaultValues(%s, %s)" % (obj.Label, job.Label))

        # Initial setting for EnableRotation is taken from Job settings/SetupSheet
        # User may override on per-operation basis as needed.
        if hasattr(job.SetupSheet, 'SetupEnableRotation'):
            obj.EnableRotation = job.SetupSheet.SetupEnableRotation
        else:
            obj.EnableRotation = 'Off'
        PathLog.debug("opSetDefaultValues(): Enable Rotation: {}".format(
            obj.EnableRotation))

        if PathOp.FeatureDepths & self.opFeatures(obj):
            try:
                shape = self.areaOpShapeForDepths(obj, job)
            except Exception as ee:  # pylint: disable=broad-except
                PathLog.error(ee)
                shape = None

            # Set initial start and final depths
            if shape is None:
                PathLog.debug("shape is None")
                startDepth = 1.0
                finalDepth = 0.0
            else:
                bb = job.Stock.Shape.BoundBox
                startDepth = bb.ZMax
                finalDepth = bb.ZMin

            # Adjust start and final depths if rotation is enabled
            if obj.EnableRotation != 'Off':
                self.initWithRotation = True
                self.stockBB = PathUtils.findParentJob(
                    obj).Stock.Shape.BoundBox  # pylint: disable=attribute-defined-outside-init
                # Calculate rotational distances/radii
                opHeights = self.opDetermineRotationRadii(
                    obj
                )  # return is list with tuples [(xRotRad, yRotRad, zRotRad), (clrOfst, safOfset)]
                (xRotRad, yRotRad, zRotRad) = opHeights[0]  # pylint: disable=unused-variable
                PathLog.debug("opHeights[0]: " + str(opHeights[0]))
                PathLog.debug("opHeights[1]: " + str(opHeights[1]))

                if obj.EnableRotation == 'A(x)':
                    startDepth = xRotRad
                if obj.EnableRotation == 'B(y)':
                    startDepth = yRotRad
                else:
                    startDepth = max(xRotRad, yRotRad)
                finalDepth = -1 * startDepth

            obj.StartDepth.Value = startDepth
            obj.FinalDepth.Value = finalDepth
            obj.OpStartDepth.Value = startDepth
            obj.OpFinalDepth.Value = finalDepth

            PathLog.debug(
                "Default OpDepths are Start: {}, and Final: {}".format(
                    obj.OpStartDepth.Value, obj.OpFinalDepth.Value))
            PathLog.debug("Default Depths are Start: {}, and Final: {}".format(
                startDepth, finalDepth))

        self.areaOpSetDefaultValues(obj, job)
Exemple #58
0
    def circularHoleExecute(self, obj, holes):
        """circularHoleExecute(obj, holes) ... generate drill operation for each hole in holes."""
        PathLog.track()
        machine = PathMachineState.MachineState()

        self.commandlist.append(Path.Command("(Begin Drilling)"))

        # rapid to clearance height
        command = Path.Command("G0", {"Z": obj.ClearanceHeight.Value})
        machine.addCommand(command)
        self.commandlist.append(command)

        self.commandlist.append(Path.Command("G90"))  # Absolute distance mode

        # Calculate offsets to add to target edge
        endoffset = 0.0
        if obj.ExtraOffset == "Drill Tip":
            endoffset = PathUtils.drillTipLength(self.tool)
        elif obj.ExtraOffset == "2x Drill Tip":
            endoffset = PathUtils.drillTipLength(self.tool) * 2

        # http://linuxcnc.org/docs/html/gcode/g-code.html#gcode:g98-g99
        self.commandlist.append(Path.Command(obj.ReturnLevel))

        holes = PathUtils.sort_locations(holes, ["x", "y"])

        # This section is technical debt. The computation of the
        # target shapes should be factored out for re-use.
        # This will likely mean refactoring upstream CircularHoleBase to pass
        # spotshapes instead of holes.

        startHeight = obj.StartDepth.Value + self.job.SetupSheet.SafeHeightOffset.Value

        edgelist = []
        for hole in holes:
            v1 = FreeCAD.Vector(hole["x"], hole["y"], obj.StartDepth.Value)
            v2 = FreeCAD.Vector(hole["x"], hole["y"],
                                obj.FinalDepth.Value - endoffset)
            edgelist.append(Part.makeLine(v1, v2))

        # iterate the edgelist and generate gcode
        for edge in edgelist:

            PathLog.debug(edge)

            # move to hole location

            startPoint = edge.Vertexes[0].Point

            command = Path.Command("G0", {
                "X": startPoint.x,
                "Y": startPoint.y
            })
            self.commandlist.append(command)
            machine.addCommand(command)

            command = Path.Command("G0", {"Z": startHeight})
            self.commandlist.append(command)
            machine.addCommand(command)

            # command = Path.Command("G1", {"Z": obj.StartDepth.Value})
            # self.commandlist.append(command)
            # machine.addCommand(command)

            # Technical Debt:  We are assuming the edges are aligned.
            # This assumption should be corrected and the necessary rotations
            # performed to align the edge with the Z axis for drilling

            # Perform drilling
            dwelltime = obj.DwellTime if obj.DwellEnabled else 0.0
            peckdepth = obj.PeckDepth.Value if obj.PeckEnabled else 0.0
            repeat = 1  # technical debt:  Add a repeat property for user control
            chipBreak = (obj.chipBreakEnabled and obj.PeckEnabled)

            try:
                drillcommands = generator.generate(edge,
                                                   dwelltime,
                                                   peckdepth,
                                                   repeat,
                                                   obj.RetractHeight.Value,
                                                   chipBreak=chipBreak)

            except ValueError as e:  # any targets that fail the generator are ignored
                PathLog.info(e)
                continue

            for command in drillcommands:
                self.commandlist.append(command)
                machine.addCommand(command)

        # Cancel canned drilling cycle
        self.commandlist.append(Path.Command("G80"))
        command = Path.Command("G0", {"Z": obj.SafeHeight.Value})
        self.commandlist.append(command)
        machine.addCommand(command)

        # Apply feedrates to commands
        PathFeedRate.setFeedRate(self.commandlist, obj.ToolController)
Exemple #59
0
    def _waterline(self, obj, s, bb):
        import time
        import ocl

        def drawLoops(loops):
            nloop = 0
            pp = []
            pp.append(Path.Command("(waterline begin)"))

            for loop in loops:
                p = loop[0]
                pp.append(Path.Command("(loop begin)"))
                pp.append(
                    Path.Command('G0', {
                        "Z": obj.SafeHeight.Value,
                        'F': self.vertRapid
                    }))
                pp.append(
                    Path.Command('G0', {
                        'X': p.x,
                        "Y": p.y,
                        'F': self.horizRapid
                    }))
                pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed}))

                for p in loop[1:]:
                    pp.append(
                        Path.Command('G1', {
                            'X': p.x,
                            "Y": p.y,
                            "Z": p.z,
                            'F': self.horizFeed
                        }))
                # zheight = p.z
                p = loop[0]
                pp.append(
                    Path.Command('G1', {
                        'X': p.x,
                        "Y": p.y,
                        "Z": p.z,
                        'F': self.horizFeed
                    }))
                pp.append(Path.Command("(loop end)"))

                print("    loop ", nloop, " with ", len(loop), " points")
                nloop = nloop + 1
            pp.append(Path.Command("(waterline end)"))

            return pp

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

        t_before = time.time()
        zheights = [i for i in depthparams]

        wl = ocl.Waterline()
        wl.setSTL(s)
        cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5)
        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 = []
        print("zheights: {}".format(zheights))
        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.extend(drawLoops(loops))
            n = n + 1
        print("(" + str(calctime) + ")")
        return output
Exemple #60
0
    def execute(self, obj):
        import MeshPart
        FreeCAD.Console.PrintWarning(
            translate("PathSurface", "Hold on.  This might take a minute.\n"))
        output = ""
        if obj.Comment != "":
            output += '(' + str(obj.Comment) + ')\n'

        toolLoad = PathUtils.getLastToolLoad(obj)
        if toolLoad is None or toolLoad.ToolNumber == 0:
            self.vertFeed = 100
            self.horizFeed = 100
            self.radius = 0.25
            obj.ToolNumber = 0
            obj.ToolDescription = "UNDEFINED"
        else:
            self.vertFeed = toolLoad.VertFeed.Value
            self.horizFeed = toolLoad.HorizFeed.Value
            tool = PathUtils.getTool(obj, toolLoad.ToolNumber)
            self.radius = tool.Diameter / 2
            obj.ToolNumber = toolLoad.ToolNumber
            obj.ToolDescription = toolLoad.Name

        if obj.UserLabel == "":
            obj.Label = obj.Name + " :" + obj.ToolDescription
        else:
            obj.Label = obj.UserLabel + " :" + obj.ToolDescription

        output += "(" + obj.Label + ")"
        output += "(Compensated Tool Path. Diameter: " + str(
            self.radius * 2) + ")"

        if obj.Base:
            for b in obj.Base:

                if obj.Algorithm in ['OCL Dropcutter', 'OCL Waterline']:
                    try:
                        import ocl
                    except:
                        FreeCAD.Console.PrintError(
                            translate(
                                "PathSurface",
                                "This operation requires OpenCamLib to be installed.\n"
                            ))
                        return

                mesh = b[0]
                if mesh.TypeId.startswith('Mesh'):
                    mesh = mesh.Mesh
                    bb = mesh.BoundBox
                else:
                    bb = mesh.Shape.BoundBox
                    mesh = MeshPart.meshFromShape(mesh.Shape, MaxLength=2)

                s = ocl.STLSurf()
                for f in mesh.Facets:
                    p = f.Points[0]
                    q = f.Points[1]
                    r = f.Points[2]
                    t = ocl.Triangle(ocl.Point(p[0], p[1], p[2]),
                                     ocl.Point(q[0], q[1], q[2]),
                                     ocl.Point(r[0], r[1], r[2]))
                    s.addTriangle(t)

                if obj.Algorithm == 'OCL Dropcutter':
                    output = self._dropcutter(obj, s, bb)
                elif obj.Algorithm == 'OCL Waterline':
                    output = self._waterline(obj, s, bb)

        if obj.Active:
            path = Path.Path(output)
            obj.Path = path
            obj.ViewObject.Visibility = True

        else:
            path = Path.Path("(inactive operation)")
            obj.Path = path
            obj.ViewObject.Visibility = False