コード例 #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)
コード例 #2
0
    def test45(self):
        '''Check offsetting a single inside edge not forward.'''
        obj = doc.getObjectsByLabel('offset-edge')[0]

        w = getWireInside(obj)
        length = 20 * math.cos(math.pi/6)
        for e in w.Edges:
            self.assertRoughly(length, e.Length)

        # let's offset the horizontal edge for starters
        hEdges = [e for e in w.Edges if PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)]

        x = length / 2
        y = -5
        self.assertEqual(1, len(hEdges))
        edge = hEdges[0]

        self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point)
        self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point)

        wire = PathOpTools.offsetWire(Part.Wire([edge]), obj.Shape, 2, False)
        self.assertEqual(1, len(wire.Edges))

        y = y + 2
        self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)

        # make sure we get the same result even if the edge is oriented the other way
        edge = PathGeom.flipEdge(edge)
        wire = PathOpTools.offsetWire(Part.Wire([edge]), obj.Shape, 2, False)
        self.assertEqual(1, len(wire.Edges))

        self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point)
コード例 #3
0
 def commandsForEdges(self):
     global failures
     if self.edges:
         try:
             shape = self.shell().common(self.tag.solid)
             commands = []
             rapid = None
             for e, flip in self.orderAndFlipEdges(self.cleanupEdges(shape.Edges)):
                 debugEdge(e, '++++++++ %s' % ('<' if flip else '>'), False)
                 p1 = e.valueAt(e.FirstParameter)
                 p2 = e.valueAt(e.LastParameter)
                 if self.tag.isSquare and (PathGeom.isRoughly(p1.z, self.maxZ) or p1.z > self.maxZ) and (PathGeom.isRoughly(p2.z, self.maxZ) or p2.z > self.maxZ):
                     rapid = p1 if flip else p2
                 else:
                     if rapid:
                         commands.append(Path.Command('G0', {'X': rapid.x, 'Y': rapid.y, 'Z': rapid.z}))
                         rapid = None
                     commands.extend(PathGeom.cmdsForEdge(e, False, False, self.segm))
             if rapid:
                 commands.append(Path.Command('G0', {'X': rapid.x, 'Y': rapid.y, 'Z': rapid.z}))
                 rapid = None
             return commands
         except Exception as e:
             PathLog.error("Exception during processing tag @(%.2f, %.2f) (%s) - disabling the tag" % (self.tag.x, self.tag.y, e.args[0]))
             #traceback.print_exc(e)
             self.tag.enabled = False
             commands = []
             for e in self.edges:
                 commands.extend(PathGeom.cmdsForEdge(e))
             failures.append(self)
             return commands
     return []
コード例 #4
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
    def test72(self):
        '''Flip a circle'''
        edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))

        edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
コード例 #5
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
    def test65(self):
        """Verify splitEdgeAt."""
        e = PathGeom.splitEdgeAt(Part.Edge(Part.LineSegment(Vector(), Vector(2, 4, 6))), Vector(1, 2, 3))
        self.assertLine(e[0], Vector(), Vector(1,2,3))
        self.assertLine(e[1], Vector(1,2,3), Vector(2,4,6))

        # split an arc
        p1 = Vector(10,-10,1)
        p2 = Vector(0,0,1)
        p3 = Vector(10,10,1)
        arc = Part.Edge(Part.Arc(p1, p2, p3))
        e = PathGeom.splitEdgeAt(arc, p2)
        o = 10*math.sin(math.pi/4)
        p12 = Vector(10 - o, -o, 1)
        p23 = Vector(10 - o, +o, 1)
        self.assertCurve(e[0], p1, p12, p2)
        self.assertCurve(e[1], p2, p23, p3)


        # split a helix
        p1 = Vector(10,-10,0)
        p2 = Vector(0,0,5)
        p3 = Vector(10,10,10)
        h = PathGeom.arcToHelix(arc, 0, 10)
        self.assertCurve(h, p1, p2, p3)

        e = PathGeom.splitEdgeAt(h, p2)
        o = 10*math.sin(math.pi/4)
        p12 = Vector(10 - o, -o, 2.5)
        p23 = Vector(10 - o, +o, 7.5)
        pf = e[0].valueAt((e[0].FirstParameter + e[0].LastParameter)/2)
        pl = e[1].valueAt((e[1].FirstParameter + e[1].LastParameter)/2)
        self.assertCurve(e[0], p1, p12, p2)
        self.assertCurve(e[1], p2, p23, p3)
コード例 #6
0
    def test32(self):
        '''Check offsetting a box.'''
        obj = doc.getObjectsByLabel('square-cut')[0]

        wire = PathOpTools.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True)
        self.assertEqual(8, len(wire.Edges))
        self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
        self.assertEqual(4, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
        for e in wire.Edges:
            if Part.Line == type(e.Curve):
                if PathGeom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
                    self.assertEqual(40, e.Length)
                if PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
                    self.assertEqual(60, e.Length)
            if Part.Circle == type(e.Curve):
                self.assertRoughly(3, e.Curve.Radius)
                self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis)
        self.assertTrue(PathOpTools.isWireClockwise(wire))

        # change offset orientation
        wire = PathOpTools.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False)
        self.assertEqual(8, len(wire.Edges))
        self.assertEqual(4, len([e for e in wire.Edges if Part.Line == type(e.Curve)]))
        self.assertEqual(4, len([e for e in wire.Edges if Part.Circle == type(e.Curve)]))
        for e in wire.Edges:
            if Part.Line == type(e.Curve):
                if PathGeom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x):
                    self.assertEqual(40, e.Length)
                if PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y):
                    self.assertEqual(60, e.Length)
            if Part.Circle == type(e.Curve):
                self.assertRoughly(3, e.Curve.Radius)
                self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis)
        self.assertFalse(PathOpTools.isWireClockwise(wire))
コード例 #7
0
    def test47(self):
        '''Check offsetting multiple backwards inside edges.'''
        # This is exactly the same as test36 except that the wire is flipped to make
        # sure it's orientation doesn't matter
        obj = doc.getObjectsByLabel('offset-edge')[0]

        w = getWireInside(obj)
        length = 20 * math.cos(math.pi/6)

        # let's offset the other two legs
        lEdges = [e for e in w.Edges if not PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)]
        self.assertEqual(2, len(lEdges))

        w = PathGeom.flipWire(Part.Wire(lEdges))
        wire = PathOpTools.offsetWire(w, obj.Shape, 2, True)

        x = length/2 - 2 * math.cos(math.pi/6)
        y = -5 - 2 * math.sin(math.pi/6)

        self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)

        rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
        self.assertEqual(0, len(rEdges))

        #offset the other way
        wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)

        self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)

        rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
        self.assertEqual(0, len(rEdges))
コード例 #8
0
    def orderAndFlipEdges(self, inputEdges):
        PathLog.track("entry(%.2f, %.2f, %.2f), exit(%.2f, %.2f, %.2f)" % (self.entry.x, self.entry.y, self.entry.z, self.exit.x, self.exit.y, self.exit.z))
        self.edgesOrder = []
        outputEdges = []
        p0 = self.entry
        lastP = p0
        edges = copy.copy(inputEdges)
        while edges:
            # print("(%.2f, %.2f, %.2f) %d %d" % (p0.x, p0.y, p0.z))
            for e in copy.copy(edges):
                p1 = e.valueAt(e.FirstParameter)
                p2 = e.valueAt(e.LastParameter)
                if PathGeom.pointsCoincide(p1, p0):
                    outputEdges.append((e, False))
                    edges.remove(e)
                    lastP = None
                    p0 = p2
                    debugEdge(e, ">>>>> no flip")
                    break
                elif PathGeom.pointsCoincide(p2, p0):
                    flipped = PathGeom.flipEdge(e)
                    if not flipped is None:
                        outputEdges.append((flipped, True))
                    else:
                        p0 = None
                        cnt = 0
                        for p in reversed(e.discretize(Deflection=0.01)):
                            if not p0 is None:
                                outputEdges.append((Part.Edge(Part.LineSegment(p0, p)), True))
                                cnt = cnt + 1
                            p0 = p
                        PathLog.info("replaced edge with %d straight segments" % cnt)
                    edges.remove(e)
                    lastP = None
                    p0 = p1
                    debugEdge(e, ">>>>> flip")
                    break
                else:
                    debugEdge(e, "<<<<< (%.2f, %.2f, %.2f)" % (p0.x, p0.y, p0.z))

            if lastP == p0:
                self.edgesOrder.append(outputEdges)
                self.edgesOrder.append(edges)
                print('input edges:')
                for e in inputEdges:
                    debugEdge(e, '  ', False)
                print('ordered edges:')
                for e, flip in outputEdges:
                    debugEdge(e, '  %c ' % ('<' if flip else '>'), False)
                print('remaining edges:')
                for e in edges:
                    debugEdge(e, '    ', False)
                raise ValueError("No connection to %s" % (p0))
            elif lastP:
                PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) (%.2f, %.2f, %.2f)" % (p0.x, p0.y, p0.z, lastP.x, lastP.y, lastP.z))
            else:
                PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) -" % (p0.x, p0.y, p0.z))
            lastP = p0
        PathLog.track("-")
        return outputEdges
コード例 #9
0
 def __init__(self, edge, tag, i, segm, maxZ):
     debugEdge(edge, 'MapWireToTag(%.2f, %.2f, %.2f)' % (i.x, i.y, i.z))
     self.tag = tag
     self.segm = segm
     self.maxZ = maxZ
     if PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), i):
         tail = edge
         self.commands = []
         debugEdge(tail, '.........=')
     elif PathGeom.pointsCoincide(edge.valueAt(edge.LastParameter), i):
         debugEdge(edge, '++++++++ .')
         self.commands = PathGeom.cmdsForEdge(edge, segm=segm)
         tail = None
     else:
         e, tail = PathGeom.splitEdgeAt(edge, i)
         debugEdge(e, '++++++++ .')
         self.commands = PathGeom.cmdsForEdge(e, segm=segm)
         debugEdge(tail, '.........-')
         self.initialEdge = edge
     self.tail = tail
     self.edges = []
     self.entry = i
     if tail:
         PathLog.debug("MapWireToTag(%s - %s)" % (i, tail.valueAt(tail.FirstParameter)))
     else:
         PathLog.debug("MapWireToTag(%s - )" % i)
     self.complete = False
     self.haveProblem = False
コード例 #10
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
    def test30(self):
        """Verify proper geometry for arcs with rising and fall ing Z-axis are created."""
        #print("------ rising helix -------")
        p1 = Vector(0, 1, 0)
        p2 = Vector(1, 0, 2)
        self.assertCurve(
                PathGeom.edgeForCmd(
                    Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 0, 'J': -1, 'K': 1}), p1),
                p1, Vector(1/math.sqrt(2), 1/math.sqrt(2), 1), p2)
        p1 = Vector(-1, 0, 0)
        p2 = Vector(0, -1, 2)
        self.assertCurve(
                PathGeom.edgeForCmd(
                    Path.Command('G3', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 1, 'J': 0, 'K': 1}), p1),
                p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2)

        #print("------ falling helix -------")
        p1 = Vector(0, -1, 2)
        p2 = Vector(-1, 0, 0)
        self.assertCurve(
                PathGeom.edgeForCmd(
                    Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 0, 'J': 1, 'K': -1}), p1),
                p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2)
        p1 = Vector(-1, 0, 2)
        p2 = Vector(0, -1, 0)
        self.assertCurve(
                PathGeom.edgeForCmd(
                    Path.Command('G3', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 1, 'J': 0, 'K': -1}), p1),
                p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2)
コード例 #11
0
 def isInside(edge):
     p0 = edge.firstVertex().Point
     p1 = edge.lastVertex().Point
     for p in insideEndpoints:
         if PathGeom.pointsCoincide(p, p0, 0.01) or PathGeom.pointsCoincide(p, p1, 0.01):
             return True
     return False
コード例 #12
0
def horizontalEdgeLoop(obj, edge):
    '''horizontalEdgeLoop(obj, edge) ... returns a wire in the horizontal plane, if that is the only horizontal wire the given edge is a part of.'''
    h = edge.hashCode()
    wires = [w for w in obj.Shape.Wires if any(e.hashCode() == h for e in w.Edges)]
    loops = [w for w in wires if all(PathGeom.isHorizontal(e) for e in w.Edges) and PathGeom.isHorizontal(Part.Face(w))]
    if len(loops) == 1:
        return loops[0]
    return None
コード例 #13
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
    def test75(self):
        '''Flip a B-spline'''
        spline = Part.BSplineCurve()
        spline.interpolate([Vector(1,2,3), Vector(-3,0,7), Vector(-3,1,9), Vector(1, 3, 5)])
        edge = Part.Edge(spline)
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))

        edge = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7]))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
コード例 #14
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
    def test71(self):
        '''Flip a line segment.'''
        edge = Part.Edge(Part.LineSegment(Vector(0,0,0), Vector(3, 2, 1)))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
        edge = Part.Edge(Part.LineSegment(Vector(4,2,1), Vector(-3, -7, 9)))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))

        edge = Part.makeLine(Vector(1,0,3), Vector(3, 2, 1))
        self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
コード例 #15
0
 def isRapid(self, edge):
     if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
         v0 = edge.Vertexes[0]
         v1 = edge.Vertexes[1]
         for r in self.rapid:
             r0 = r.Vertexes[0]
             r1 = r.Vertexes[1]
             if PathGeom.isRoughly(r0.X, v0.X) and PathGeom.isRoughly(r0.Y, v0.Y) and PathGeom.isRoughly(r0.Z, v0.Z) and PathGeom.isRoughly(r1.X, v1.X) and PathGeom.isRoughly(r1.Y, v1.Y) and PathGeom.isRoughly(r1.Z, v1.Z):
                 return True
     return False
コード例 #16
0
 def isValidTagStartIntersection(self, edge, i):
     if PathGeom.pointsCoincide(i, edge.valueAt(edge.LastParameter)):
         return False
     p1 = edge.valueAt(edge.FirstParameter)
     p2 = edge.valueAt(edge.LastParameter)
     if PathGeom.pointsCoincide(PathGeom.xy(p1), PathGeom.xy(p2)):
         # if this vertical goes up, it can't be the start of a tag intersection
         if p1.z < p2.z:
             return False
     return True
コード例 #17
0
    def buildpathocc(self, obj, wires, zValues, rel=False):
        '''buildpathocc(obj, wires, zValues, rel=False) ... internal helper function to generate engraving commands.'''
        PathLog.track(obj.Label, len(wires), zValues)

        for wire in wires:
            offset = wire

            # reorder the wire
            if hasattr(obj, 'StartVertex'):
                offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex)

            edges = copy.copy(offset.Edges)
            last = None

            for z in zValues:
                if last:
                    if rel:
                        self.commandlist.append(Path.Command('G1', {'X': last.x, 'Y': last.y, 'Z': last.z - z, 'F': self.vertFeed}))
                    else:
                        self.commandlist.append(Path.Command('G1', {'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed}))

                for edge in edges:
                    if not last:
                        # we set the first move to our first point
                        last = edge.Vertexes[0].Point
                        if len(offset.Edges) > 1:
                            ve = edge.Vertexes[-1]
                            e2 = offset.Edges[1]
                            if not PathGeom.pointsCoincide(ve.Point, e2.Vertexes[0].Point) and not PathGeom.pointsCoincide(ve.Point, e2.Vertexes[-1].Point):
                                PathLog.debug("flip first edge")
                                last = edge.Vertexes[-1].Point
                            else:
                                PathLog.debug("original first edge")
                        else:
                            PathLog.debug("not enough edges to flip")

                        self.commandlist.append(Path.Command('G0', {'X': last.x, 'Y': last.y, 'Z': obj.ClearanceHeight.Value, 'F': self.horizRapid}))
                        self.commandlist.append(Path.Command('G0', {'X': last.x, 'Y': last.y, 'Z': obj.SafeHeight.Value, 'F': self.vertRapid}))
                        if rel:
                            self.commandlist.append(Path.Command('G1', {'X': last.x, 'Y': last.y, 'Z': last.z - z, 'F': self.vertFeed}))
                        else:
                            self.commandlist.append(Path.Command('G1', {'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed}))

                    if PathGeom.pointsCoincide(last, edge.Vertexes[0].Point):
                        for cmd in PathGeom.cmdsForEdge(edge):
                            self.appendCommand(cmd, z, rel)
                        last = edge.Vertexes[-1].Point
                    else:
                        for cmd in PathGeom.cmdsForEdge(edge, True):
                            self.appendCommand(cmd, z, rel)
                        last = edge.Vertexes[0].Point
            self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
        if self.commandlist:
            self.commandlist.pop()
コード例 #18
0
 def isEntryOrExitStrut(self, e):
     p1 = e.valueAt(e.FirstParameter)
     p2 = e.valueAt(e.LastParameter)
     if PathGeom.pointsCoincide(p1, self.entry) and p2.z >= self.entry.z:
         return 1
     if PathGeom.pointsCoincide(p2, self.entry) and p1.z >= self.entry.z:
         return 1
     if PathGeom.pointsCoincide(p1, self.exit) and p2.z >= self.exit.z:
         return 2
     if PathGeom.pointsCoincide(p2, self.exit) and p1.z >= self.exit.z:
         return 2
     return 0
コード例 #19
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
 def test20(self):
     """Verify proper geometry for arcs in the XY-plane are created."""
     p1 = Vector(0, -1, 2)
     p2 = Vector(-1, 0, 2)
     self.assertArc(
             PathGeom.edgeForCmd(
                 Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 0, 'J': 1, 'K': 0}), p1),
             p1, p2, 'CW')
     self.assertArc(
             PathGeom.edgeForCmd(
                 Path.Command('G3', {'X': p1.x, 'Y': p1.y, 'z': p1.z, 'I': -1, 'J': 0, 'K': 0}), p2),
             p2, p1, 'CCW')
コード例 #20
0
 def isPointOnEdge(self, pt, edge):
     param = edge.Curve.parameter(pt)
     if edge.FirstParameter <= param <= edge.LastParameter:
         return True
     if edge.LastParameter <= param <= edge.FirstParameter:
         return True
     if PathGeom.isRoughly(edge.FirstParameter, param) or PathGeom.isRoughly(edge.LastParameter, param):
         return True
     # print("-------- X %.2f <= %.2f <=%.2f   (%.2f, %.2f, %.2f)   %.2f:%.2f" % (edge.FirstParameter, param, edge.LastParameter, pt.x, pt.y, pt.z, edge.Curve.parameter(edge.valueAt(edge.FirstParameter)), edge.Curve.parameter(edge.valueAt(edge.LastParameter))))
     # p1 = edge.Vertexes[0]
     # f1 = edge.Curve.parameter(FreeCAD.Vector(p1.X, p1.Y, p1.Z))
     # p2 = edge.Vertexes[1]
     # f2 = edge.Curve.parameter(FreeCAD.Vector(p2.X, p2.Y, p2.Z))
     return False
コード例 #21
0
ファイル: PathJobGui.py プロジェクト: pgilfernandez/FreeCAD
    def orientSelected(self, axis):
        def flipSel(sel):
            PathLog.debug("flip")
            p = sel.Object.Placement
            loc = sel.Object.Placement.Base
            rot = FreeCAD.Rotation(FreeCAD.Vector(1-axis.x, 1-axis.y, 1-axis.z), 180)
            sel.Object.Placement = FreeCAD.Placement(loc, p.Rotation.multiply(rot))

        def rotateSel(sel, n):
            p = sel.Object.Placement
            loc = sel.Object.Placement.Base
            r = axis.cross(n) # rotation axis
            a = DraftVecUtils.angle(n, axis, r) * 180 / math.pi
            PathLog.debug("oh boy: (%.2f, %.2f, %.2f) -> %.2f" % (r.x, r.y, r.z, a))
            Draft.rotate(sel.Object, a, axis=r)

        selObject = None
        selFeature = None
        for sel in FreeCADGui.Selection.getSelectionEx():
            selObject = sel.Object
            for feature in sel.SubElementNames:
                selFeature = feature
                sub = sel.Object.Shape.getElement(feature)
                if 'Face' == sub.ShapeType:
                    n = sub.Surface.Axis
                    if sub.Orientation == 'Reversed':
                        n = FreeCAD.Vector() - n
                        PathLog.debug("(%.2f, %.2f, %.2f) -> reversed (%s)" % (n.x, n.y, n.z, sub.Orientation))
                    else:
                        PathLog.debug("(%.2f, %.2f, %.2f) -> forward  (%s)" % (n.x, n.y, n.z, sub.Orientation))

                    if PathGeom.pointsCoincide(axis, n):
                        PathLog.debug("face properly oriented (%.2f, %.2f, %.2f)" % (n.x, n.y, n.z))
                    else:
                        if PathGeom.pointsCoincide(axis, FreeCAD.Vector() - n):
                            flipSel(sel)
                        else:
                            rotateSel(sel, n)
                if 'Edge' == sub.ShapeType:
                    n = (sub.Vertexes[1].Point - sub.Vertexes[0].Point).normalize()
                    if PathGeom.pointsCoincide(axis, n) or PathGeom.pointsCoincide(axis, FreeCAD.Vector() - n):
                        # Don't really know the orientation of an edge, so let's just flip the object
                        # and if the user doesn't like it they can flip again
                        flipSel(sel)
                    else:
                        rotateSel(sel, n)
        if selObject and selFeature:
            FreeCADGui.Selection.clearSelection()
            FreeCADGui.Selection.addSelection(selObject, selFeature)
コード例 #22
0
 def checkIgnoreAbove(self, edge):
     if self.ignoreAboveEnabled:
         p0 = edge.Vertexes[0].Point
         p1 = edge.Vertexes[1].Point
         if p0.z > self.ignoreAbove and (p1.z > self.ignoreAbove or PathGeom.isRoughly(p1.z, self.ignoreAbove.Value)):
             PathLog.debug("Whole plunge move above 'ignoreAbove', ignoring")
             return (edge, True)
         elif p0.z > self.ignoreAbove and not PathGeom.isRoughly(p0.z, self.ignoreAbove.Value):
             PathLog.debug("Plunge move partially above 'ignoreAbove', splitting into two")
             newPoint = FreeCAD.Base.Vector(p0.x, p0.y, self.ignoreAbove)
             return (Part.makeLine(p0, newPoint), False)
         else:
             return None, False
     else:
         return None, False
コード例 #23
0
 def createSolidsAt(self, z, R):
     self.z = z
     self.toolRadius = R
     r1 = self.fullWidth() / 2
     self.r1 = r1
     self.r2 = r1
     height = self.height * 1.01
     radius = 0
     if PathGeom.isRoughly(90, self.angle) and height > 0:
         # cylinder
         self.isSquare = True
         self.solid = Part.makeCylinder(r1, height)
         radius = min(min(self.radius, r1), self.height)
         PathLog.debug("Part.makeCone(%f, %f)" % (r1, height))
     elif self.angle > 0.0 and height > 0.0:
         # cone
         rad = math.radians(self.angle)
         tangens = math.tan(rad)
         dr = height / tangens
         if dr < r1:
             # with top
             r2 = r1 - dr
             s = height / math.sin(rad)
             radius = min(r2, s) * math.tan((math.pi - rad)/2) * 0.95
         else:
             # triangular
             r2 = 0
             height = r1 * tangens * 1.01
             self.actualHeight = height
         self.r2 = r2
         PathLog.debug("Part.makeCone(%f, %f, %f)" % (r1, r2, height))
         self.solid = Part.makeCone(r1, r2, height)
     else:
         # degenerated case - no tag
         PathLog.debug("Part.makeSphere(%f / 10000)" % (r1))
         self.solid = Part.makeSphere(r1 / 10000)
     if not PathGeom.isRoughly(0, R):  # testing is easier if the solid is not rotated
         angle = -PathGeom.getAngle(self.originAt(0)) * 180 / math.pi
         PathLog.debug("solid.rotate(%f)" % angle)
         self.solid.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), angle)
     orig = self.originAt(z - 0.01 * self.actualHeight)
     PathLog.debug("solid.translate(%s)" % orig)
     self.solid.translate(orig)
     radius = min(self.radius, radius)
     self.realRadius = radius
     if not PathGeom.isRoughly(0, radius.Value):
         PathLog.debug("makeFillet(%.4f)" % radius)
         self.solid = self.solid.makeFillet(radius, [self.solid.Edges[0]])
コード例 #24
0
    def execute(self, obj):
        if not obj.Base:
            return
        if not obj.Base.isDerivedFrom("Path::Feature"):
            return
        if not obj.Base.Path:
            return
        if obj.Angle >= 90:
            obj.Angle = 89.9
        elif obj.Angle <= 0:
            obj.Angle = 0.1

        if hasattr(obj, 'UseStartDepth'):
            self.ignoreAboveEnabled = obj.UseStartDepth
            self.ignoreAbove = obj.DressupStartDepth
        else:
            self.ignoreAboveEnabled = False
            self.ignoreAbove = 0

        self.angle = obj.Angle
        self.method = obj.Method
        self.wire, self.rapids = PathGeom.wireForPath(obj.Base.Path)
        if self.method in ['RampMethod1', 'RampMethod2', 'RampMethod3']:
            self.outedges = self.generateRamps()
        else:
            self.outedges = self.generateHelix()
        obj.Path = self.createCommands(obj, self.outedges)
コード例 #25
0
    def test46(self):
        '''Check offsetting multiple inside edges.'''
        obj = doc.getObjectsByLabel('offset-edge')[0]

        w = getWireInside(obj)
        length = 20 * math.cos(math.pi/6)

        # let's offset the other two legs
        lEdges = [e for e in w.Edges if not PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)]
        self.assertEqual(2, len(lEdges))

        wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True)

        x = length/2 - 2 * math.cos(math.pi/6)
        y = -5 - 2 * math.sin(math.pi/6)

        self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point)

        rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
        self.assertEqual(0, len(rEdges))

        #offset the other way
        wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False)

        self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point)
        self.assertCoincide(Vector(+x, y, 0), wire.Edges[-1].Vertexes[1].Point)

        rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)]
        self.assertEqual(0, len(rEdges))
コード例 #26
0
 def __init__(self, obj):
     PathLog.track(obj.Base.Name)
     self.obj = obj
     self.wire, rapid = PathGeom.wireForPath(obj.Base.Path)
     self.rapid = _RapidEdges(rapid)
     self.edges = self.wire.Edges
     self.baseWire = self.findBottomWire(self.edges)
コード例 #27
0
 def cloneAt(self, pos):
     clone = self.solid.copy()
     pos.z = 0
     angle = -PathGeom.getAngle(pos - self.baseCenter) * 180 / math.pi
     clone.rotate(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), angle)
     pos.z = self.z - self.actualHeight * 0.01
     clone.translate(pos)
     return clone
コード例 #28
0
ファイル: TestPathGeom.py プロジェクト: frankhardy/FreeCAD
 def test00(self):
     """Verify getAngle functionality."""
     self.assertRoughly(PathGeom.getAngle(Vector(1, 0, 0)), 0)
     self.assertRoughly(PathGeom.getAngle(Vector(1, 1, 0)), math.pi/4)
     self.assertRoughly(PathGeom.getAngle(Vector(0, 1, 0)), math.pi/2)
     self.assertRoughly(PathGeom.getAngle(Vector(-1, 1, 0)), 3*math.pi/4)
     self.assertRoughly(PathGeom.getAngle(Vector(-1, 0, 0)), math.pi)
     self.assertRoughly(PathGeom.getAngle(Vector(-1, -1, 0)), -3*math.pi/4)
     self.assertRoughly(PathGeom.getAngle(Vector(0, -1, 0)), -math.pi/2)
     self.assertRoughly(PathGeom.getAngle(Vector(1, -1, 0)), -math.pi/4)
コード例 #29
0
    def test15(self):
        '''Check offsetting a cylinder with Placement.'''
        obj = doc.getObjectsByLabel('offset-placement')[0]

        wires = [w for w in obj.Shape.Wires if 1 == len(w.Edges) and PathGeom.isRoughly(0, w.Edges[0].Vertexes[0].Point.z)]
        self.assertEqual(2, len(wires))
        w = wires[0] if wires[0].BoundBox.isInside(wires[1].BoundBox) else wires[1]

        self.assertRoughly(20, w.Edges[0].Curve.Radius)
        # make sure there is a placement and I didn't mess up the model
        self.assertFalse(PathGeom.pointsCoincide(Vector(), w.Edges[0].Placement.Base))

        wire = PathOpTools.offsetWire(w, obj.Shape, 2, True)
        self.assertIsNotNone(wire)
        self.assertEqual(1, len(wire.Edges))
        self.assertRoughly(22, wire.Edges[0].Curve.Radius)
        self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center)
        self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis)
コード例 #30
0
 def pointIsOnPath(self, p):
     v = Part.Vertex(self.pointAtBottom(p))
     PathLog.debug("pt = (%f, %f, %f)" % (v.X, v.Y, v.Z))
     for e in self.bottomEdges:
         indent = "{} ".format(e.distToShape(v)[0])
         debugEdge(e, indent, True)
         if PathGeom.isRoughly(0.0, v.distToShape(e)[0], 0.1):
             return True
     return False
コード例 #31
0
 def filterIntersections(self, pts, face):
     if type(face.Surface) == Part.Cone or type(face.Surface) == Part.Cylinder or type(face.Surface) == Part.Toroid:
         PathLog.track("it's a cone/cylinder, checking z")
         return filter(lambda pt: pt.z >= self.bottom() and pt.z <= self.top(), pts)
     if type(face.Surface) == Part.Plane:
         PathLog.track("it's a plane, checking R")
         c = face.Edges[0].Curve
         if (type(c) == Part.Circle):
             return filter(lambda pt: (pt - c.Center).Length <= c.Radius or PathGeom.isRoughly((pt - c.Center).Length, c.Radius), pts)
     print("==== we got a %s" % face.Surface)
コード例 #32
0
ファイル: TestPathGeom.py プロジェクト: zuoluo201008/FreeCAD
    def test02(self):
        """Verify isVertical/isHorizontal for Vector"""
        self.assertTrue(PathGeom.isVertical(Vector(0, 0, 1)))
        self.assertTrue(PathGeom.isVertical(Vector(0, 0, -1)))
        self.assertFalse(PathGeom.isVertical(Vector(1, 0, 1)))
        self.assertFalse(PathGeom.isVertical(Vector(1, 0, -1)))

        self.assertTrue(PathGeom.isHorizontal(Vector( 1,  0, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector(-1,  0, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector( 0,  1, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector( 0, -1, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector( 1,  1, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector(-1,  1, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector( 1, -1, 0)))
        self.assertTrue(PathGeom.isHorizontal(Vector(-1, -1, 0)))

        self.assertFalse(PathGeom.isHorizontal(Vector(0,  1,  1)))
        self.assertFalse(PathGeom.isHorizontal(Vector(0, -1,  1)))
        self.assertFalse(PathGeom.isHorizontal(Vector(0,  1, -1)))
        self.assertFalse(PathGeom.isHorizontal(Vector(0, -1, -1)))
コード例 #33
0
    def clasifySub(self, bs, sub):
        '''clasifySub(bs, sub)...
        Given a base and a sub-feature name, returns True
        if the sub-feature is a horizontally oriented flat face.
        '''
        face = bs.Shape.getElement(sub)

        if type(face.Surface) == Part.Plane:
            PathLog.debug('type() == Part.Plane')
            if PathGeom.isVertical(face.Surface.Axis):
                PathLog.debug('  -isVertical()')
                # it's a flat horizontal face
                self.horiz.append(face)
                return True

            elif PathGeom.isHorizontal(face.Surface.Axis):
                PathLog.debug('  -isHorizontal()')
                self.vert.append(face)
                return True

            else:
                return False

        elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(
                face.Surface.Axis):
            PathLog.debug('type() == Part.Cylinder')
            # vertical cylinder wall
            if any(e.isClosed() for e in face.Edges):
                PathLog.debug('  -e.isClosed()')
                # complete cylinder
                circle = Part.makeCircle(face.Surface.Radius,
                                         face.Surface.Center)
                disk = Part.Face(Part.Wire(circle))
                disk.translate(
                    FreeCAD.Vector(0, 0,
                                   face.BoundBox.ZMin - disk.BoundBox.ZMin))
                self.horiz.append(disk)
                return True

            else:
                PathLog.debug('  -none isClosed()')
                # partial cylinder wall
                self.vert.append(face)
                return True

        elif type(face.Surface) == Part.SurfaceOfExtrusion:
            # extrusion wall
            PathLog.debug('type() == Part.SurfaceOfExtrusion')
            # Save face to self.horiz for processing or display error
            if self.isVerticalExtrusionFace(face):
                self.vert.append(face)
                return True
            else:
                PathLog.error(
                    translate(
                        "Path",
                        "Failed to identify vertical face from {}.".format(
                            sub)))

        else:
            PathLog.debug('  -type(face.Surface): {}'.format(type(
                face.Surface)))
            return False
コード例 #34
0
    def createCommands(self, obj, edges):
        commands = []
        for edge in edges:
            israpid = False
            for redge in self.rapids:
                if PathGeom.edgesMatch(edge, redge):
                    israpid = True
            if israpid:
                v = edge.valueAt(edge.LastParameter)
                commands.append(Path.Command("G0", {"X": v.x, "Y": v.y, "Z": v.z}))
            else:
                commands.extend(PathGeom.cmdsForEdge(edge))

        lastCmd = Path.Command("G0", {"X": 0.0, "Y": 0.0, "Z": 0.0})

        outCommands = []

        tc = PathDressup.toolController(obj.Base)

        horizFeed = tc.HorizFeed.Value
        vertFeed = tc.VertFeed.Value

        if obj.RampFeedRate == "Horizontal Feed Rate":
            rampFeed = tc.HorizFeed.Value
        elif obj.RampFeedRate == "Vertical Feed Rate":
            rampFeed = tc.VertFeed.Value
        elif obj.RampFeedRate == "Ramp Feed Rate":
            rampFeed = math.sqrt(pow(tc.VertFeed.Value, 2) + pow(tc.HorizFeed.Value, 2))
        else:
            rampFeed = obj.CustomFeedRate.Value

        horizRapid = tc.HorizRapid.Value
        vertRapid = tc.VertRapid.Value

        for cmd in commands:
            params = cmd.Parameters
            zVal = params.get("Z", None)
            zVal2 = lastCmd.Parameters.get("Z", None)

            xVal = params.get("X", None)
            xVal2 = lastCmd.Parameters.get("X", None)

            yVal2 = lastCmd.Parameters.get("Y", None)
            yVal = params.get("Y", None)

            zVal = zVal and round(zVal, 8)
            zVal2 = zVal2 and round(zVal2, 8)

            if cmd.Name in ["G1", "G2", "G3", "G01", "G02", "G03"]:
                if zVal is not None and zVal2 != zVal:
                    if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly(
                        yVal, yVal2
                    ):
                        # this is a straight plunge
                        params["F"] = vertFeed
                    else:
                        # this is a ramp
                        params["F"] = rampFeed
                else:
                    params["F"] = horizFeed
                lastCmd = cmd

            elif cmd.Name in ["G0", "G00"]:
                if zVal is not None and zVal2 != zVal:
                    params["F"] = vertRapid
                else:
                    params["F"] = horizRapid
                lastCmd = cmd

            outCommands.append(Path.Command(cmd.Name, params))

        return Path.Path(outCommands)
コード例 #35
0
 def isCircleAt(edge, center):
     '''isCircleAt(edge, center) ... helper function returns True if edge is a circle at the given center.'''
     if Part.Circle == type(edge.Curve) or Part.ArcOfCircle == type(
             edge.Curve):
         return PathGeom.pointsCoincide(edge.Curve.Center, center)
     return False
コード例 #36
0
 def needToFlipEdge(self, edge, p):
     if PathGeom.pointsCoincide(edge.valueAt(edge.LastParameter), p):
         return True, edge.valueAt(edge.FirstParameter)
     return False, edge.valueAt(edge.LastParameter)
コード例 #37
0
 def tboneVertical(self, bone):
     angle = bone.angle()
     boneAngle = math.pi / 2
     if PathGeom.isRoughly(angle, math.pi) or angle < 0:
         boneAngle = -boneAngle
     return self.inOutBoneCommands(bone, boneAngle, self.toolRadius)
コード例 #38
0
 def connectsTo(self, chord):
     return PathGeom.pointsCoincide(self.End, chord.Start)
コード例 #39
0
    def smoothChordCommands(self,
                            bone,
                            inChord,
                            outChord,
                            edge,
                            wire,
                            corner,
                            smooth,
                            color=None):
        if smooth == 0:
            PathLog.info(" No smoothing requested")
            return [bone.lastCommand, outChord.g1Command(bone.F)]

        d = 'in'
        refPoint = inChord.Start
        if smooth == Smooth.Out:
            d = 'out'
            refPoint = outChord.End

        if DraftGeomUtils.areColinear(inChord.asEdge(), outChord.asEdge()):
            PathLog.info(" straight edge %s" % d)
            return [outChord.g1Command(bone.F)]

        pivot = None
        pivotDistance = 0

        PathLog.info("smooth:  (%.2f, %.2f)-(%.2f, %.2f)" %
                     (edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y,
                      edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y))
        for e in wire.Edges:
            self.dbg.append(e)
            if type(e.Curve) == Part.LineSegment or type(e.Curve) == Part.Line:
                PathLog.debug("         (%.2f, %.2f)-(%.2f, %.2f)" %
                              (e.Vertexes[0].Point.x, e.Vertexes[0].Point.y,
                               e.Vertexes[1].Point.x, e.Vertexes[1].Point.y))
            else:
                PathLog.debug(
                    "         (%.2f, %.2f)^%.2f" %
                    (e.Curve.Center.x, e.Curve.Center.y, e.Curve.Radius))
            for pt in DraftGeomUtils.findIntersection(edge,
                                                      e,
                                                      True,
                                                      findAll=True):
                if not PathGeom.pointsCoincide(
                        pt, corner) and self.pointIsOnEdge(pt, e):
                    # debugMarker(pt, "candidate-%d-%s" % (self.boneId, d), color, 0.05)
                    PathLog.debug("         -> candidate")
                    distance = (pt - refPoint).Length
                    if not pivot or pivotDistance > distance:
                        pivot = pt
                        pivotDistance = distance
                else:
                    PathLog.debug("         -> corner intersect")

        if pivot:
            # debugCircle(pivot, self.toolRadius, "pivot.%d-%s" % (self.boneId, d), color)

            pivotEdge = Part.Edge(
                Part.Circle(pivot, FreeCAD.Vector(0, 0, 1), self.toolRadius))
            t1 = self.findPivotIntersection(pivot, pivotEdge, inChord.asEdge(),
                                            inChord.End, d, color)
            t2 = self.findPivotIntersection(pivot, pivotEdge,
                                            outChord.asEdge(), inChord.End, d,
                                            color)

            commands = []
            if not PathGeom.pointsCoincide(t1, inChord.Start):
                PathLog.debug("  add lead in")
                commands.append(Chord(inChord.Start, t1).g1Command(bone.F))
            if bone.obj.Side == Side.Left:
                PathLog.debug("  add g3 command")
                commands.append(Chord(t1, t2).g3Command(pivot, bone.F))
            else:
                PathLog.debug(
                    "  add g2 command center=(%.2f, %.2f) -> from (%2f, %.2f) to (%.2f, %.2f"
                    % (pivot.x, pivot.y, t1.x, t1.y, t2.x, t2.y))
                commands.append(Chord(t1, t2).g2Command(pivot, bone.F))
            if not PathGeom.pointsCoincide(t2, outChord.End):
                PathLog.debug("  add lead out")
                commands.append(Chord(t2, outChord.End).g1Command(bone.F))

            # debugMarker(pivot, "pivot.%d-%s"     % (self.boneId, d), color, 0.2)
            # debugMarker(t1,    "pivot.%d-%s.in"  % (self.boneId, d), color, 0.1)
            # debugMarker(t2,    "pivot.%d-%s.out" % (self.boneId, d), color, 0.1)

            return commands

        PathLog.info(" no pivot found - straight command")
        return [inChord.g1Command(bone.F), outChord.g1Command(bone.F)]
コード例 #40
0
 def isAPlungeMove(self):
     return not PathGeom.isRoughly(self.End.z, self.Start.z)
コード例 #41
0
ファイル: PathSetupSheet.py プロジェクト: jencureboy/FreeCAD
 def hasDefaultToolRapids(self):
     return PathGeom.isRoughly(self.obj.VertRapid.Value,
                               0) and PathGeom.isRoughly(
                                   self.obj.HorizRapid.Value, 0)
コード例 #42
0
def _get_working_edges(op, obj):
    """_get_working_edges(op, obj)...
    Compile all working edges from the Base Geometry selection (obj.Base)
    for the current operation.
    Additional modifications to selected region(face), such as extensions,
    should be placed within this function.
    """
    all_regions = list()
    edge_list = list()
    avoidFeatures = list()
    rawEdges = list()

    # Get extensions and identify faces to avoid
    extensions = FeatureExtensions.getExtensions(obj)
    for e in extensions:
        if e.avoid:
            avoidFeatures.append(e.feature)

    # Get faces selected by user
    for base, subs in obj.Base:
        for sub in subs:
            if sub.startswith("Face"):
                if sub not in avoidFeatures:
                    if obj.UseOutline:
                        face = base.Shape.getElement(sub)
                        # get outline with wire_A method used in PocketShape, but it does not play nicely later
                        # wire_A = TechDraw.findShapeOutline(face, 1, FreeCAD.Vector(0.0, 0.0, 1.0))
                        wire_B = face.Wires[0]
                        shape = Part.Face(wire_B)
                    else:
                        shape = base.Shape.getElement(sub)
                    all_regions.append(shape)
            elif sub.startswith("Edge"):
                # Save edges for later processing
                rawEdges.append(base.Shape.getElement(sub))
    # Efor

    # Process selected edges
    if rawEdges:
        edgeWires = DraftGeomUtils.findWires(rawEdges)
        if edgeWires:
            for w in edgeWires:
                for e in w.Edges:
                    edge_list.append([discretize(e)])

    # Apply regular Extensions
    op.exts = []  # pylint: disable=attribute-defined-outside-init
    for ext in extensions:
        if not ext.avoid:
            wire = ext.getWire()
            if wire:
                for f in ext.getExtensionFaces(wire):
                    op.exts.append(f)
                    all_regions.append(f)

    # Second face-combining method attempted
    horizontal = PathGeom.combineHorizontalFaces(all_regions)
    if horizontal:
        obj.removalshape = Part.makeCompound(horizontal)
        for f in horizontal:
            for w in f.Wires:
                for e in w.Edges:
                    edge_list.append([discretize(e)])

    return edge_list
コード例 #43
0
    def createPath(self, obj, pathData, tags):
        PathLog.track()
        commands = []
        lastEdge = 0
        lastTag = 0
        # sameTag = None
        t = 0
        # inters = None
        edge = None

        segm = 50
        if hasattr(obj, 'SegmentationFactor'):
            segm = obj.SegmentationFactor
            if segm <= 0:
                segm = 50
                obj.SegmentationFactor = 50

        self.mappers = []
        mapper = None

        tc = PathDressup.toolController(obj.Base)
        horizFeed = tc.HorizFeed.Value
        vertFeed = tc.VertFeed.Value
        horizRapid = tc.HorizRapid.Value
        vertRapid = tc.VertRapid.Value

        while edge or lastEdge < len(pathData.edges):
            PathLog.debug("------- lastEdge = %d/%d.%d/%d" %
                          (lastEdge, lastTag, t, len(tags)))
            if not edge:
                edge = pathData.edges[lastEdge]
                debugEdge(
                    edge, "=======  new edge: %d/%d" %
                    (lastEdge, len(pathData.edges)))
                lastEdge += 1
                # sameTag = None

            if mapper:
                mapper.add(edge)
                if mapper.mappingComplete():
                    commands.extend(mapper.commands)
                    edge = mapper.tail
                    mapper = None
                else:
                    edge = None

            if edge:
                tIndex = (t + lastTag) % len(tags)
                t += 1
                i = tags[tIndex].intersects(edge, edge.FirstParameter)
                if i and self.isValidTagStartIntersection(edge, i):
                    mapper = MapWireToTag(edge,
                                          tags[tIndex],
                                          i,
                                          segm,
                                          pathData.maxZ,
                                          hSpeed=horizFeed,
                                          vSpeed=vertFeed)
                    self.mappers.append(mapper)
                    edge = mapper.tail

            if not mapper and t >= len(tags):
                # gone through all tags, consume edge and move on
                if edge:
                    debugEdge(edge, '++++++++')
                    if pathData.rapid.isRapid(edge):
                        v = edge.Vertexes[1]
                        if not commands and PathGeom.isRoughly(
                                0, v.X) and PathGeom.isRoughly(
                                    0, v.Y) and not PathGeom.isRoughly(0, v.Z):
                            # The very first move is just to move to ClearanceHeight
                            commands.append(
                                Path.Command('G0', {
                                    'Z': v.Z,
                                    'F': horizRapid
                                }))
                        else:
                            commands.append(
                                Path.Command('G0', {
                                    'X': v.X,
                                    'Y': v.Y,
                                    'Z': v.Z,
                                    'F': vertRapid
                                }))
                    else:
                        commands.extend(
                            PathGeom.cmdsForEdge(edge,
                                                 segm=segm,
                                                 hSpeed=horizFeed,
                                                 vSpeed=vertFeed))
                edge = None
                t = 0

        return Path.Path(commands)
コード例 #44
0
    def generateTags(self,
                     obj,
                     count,
                     width=None,
                     height=None,
                     angle=None,
                     radius=None,
                     spacing=None):
        # pylint: disable=unused-argument
        PathLog.track(count, width, height, angle, spacing)
        # for e in self.baseWire.Edges:
        #    debugMarker(e.Vertexes[0].Point, 'base', (0.0, 1.0, 1.0), 0.2)

        if spacing:
            tagDistance = spacing
        else:
            tagDistance = self.baseWire.Length / (count if count else 4)

        W = width if width else self.defaultTagWidth()
        H = height if height else self.defaultTagHeight()
        A = angle if angle else self.defaultTagAngle()
        R = radius if radius else self.defaultTagRadius()

        # start assigning tags on the longest segment
        (shortestEdge, longestEdge) = self.shortestAndLongestPathEdge()
        startIndex = 0
        for i in range(0, len(self.baseWire.Edges)):
            edge = self.baseWire.Edges[i]
            PathLog.debug('  %d: %.2f' % (i, edge.Length))
            if PathGeom.isRoughly(edge.Length, longestEdge.Length):
                startIndex = i
                break

        startEdge = self.baseWire.Edges[startIndex]
        startCount = int(startEdge.Length / tagDistance)
        if (longestEdge.Length - shortestEdge.Length) > shortestEdge.Length:
            startCount = int(startEdge.Length / tagDistance) + 1

        lastTagLength = (startEdge.Length + (startCount - 1) * tagDistance) / 2
        currentLength = startEdge.Length

        minLength = min(2. * W, longestEdge.Length)

        PathLog.debug(
            "length=%.2f shortestEdge=%.2f(%.2f) longestEdge=%.2f(%.2f) minLength=%.2f"
            % (self.baseWire.Length, shortestEdge.Length,
               shortestEdge.Length / self.baseWire.Length, longestEdge.Length,
               longestEdge.Length / self.baseWire.Length, minLength))
        PathLog.debug(
            "   start: index=%-2d count=%d (length=%.2f, distance=%.2f)" %
            (startIndex, startCount, startEdge.Length, tagDistance))
        PathLog.debug("               -> lastTagLength=%.2f)" % lastTagLength)
        PathLog.debug("               -> currentLength=%.2f)" % currentLength)

        edgeDict = {startIndex: startCount}

        for i in range(startIndex + 1, len(self.baseWire.Edges)):
            edge = self.baseWire.Edges[i]
            (currentLength,
             lastTagLength) = self.processEdge(i, edge, currentLength,
                                               lastTagLength, tagDistance,
                                               minLength, edgeDict)
        for i in range(0, startIndex):
            edge = self.baseWire.Edges[i]
            (currentLength,
             lastTagLength) = self.processEdge(i, edge, currentLength,
                                               lastTagLength, tagDistance,
                                               minLength, edgeDict)

        tags = []

        for (i, count) in PathUtil.keyValueIter(edgeDict):
            edge = self.baseWire.Edges[i]
            PathLog.debug(" %d: %d" % (i, count))
            # debugMarker(edge.Vertexes[0].Point, 'base', (1.0, 0.0, 0.0), 0.2)
            # debugMarker(edge.Vertexes[1].Point, 'base', (0.0, 1.0, 0.0), 0.2)
            if 0 != count:
                distance = (edge.LastParameter - edge.FirstParameter) / count
                for j in range(0, count):
                    tag = edge.Curve.value((j + 0.5) * distance)
                    tags.append(Tag(j, tag.x, tag.y, W, H, A, R, True))

        return tags
コード例 #45
0
    def orderAndFlipEdges(self, inputEdges):
        PathLog.track("entry(%.2f, %.2f, %.2f), exit(%.2f, %.2f, %.2f)" %
                      (self.entry.x, self.entry.y, self.entry.z, self.exit.x,
                       self.exit.y, self.exit.z))
        self.edgesOrder = []
        outputEdges = []
        p0 = self.entry
        lastP = p0
        edges = copy.copy(inputEdges)
        while edges:
            # print("(%.2f, %.2f, %.2f) %d %d" % (p0.x, p0.y, p0.z))
            for e in copy.copy(edges):
                p1 = e.valueAt(e.FirstParameter)
                p2 = e.valueAt(e.LastParameter)
                if PathGeom.pointsCoincide(p1, p0):
                    outputEdges.append((e, False))
                    edges.remove(e)
                    lastP = None
                    p0 = p2
                    debugEdge(e, ">>>>> no flip")
                    break
                elif PathGeom.pointsCoincide(p2, p0):
                    flipped = PathGeom.flipEdge(e)
                    if not flipped is None:
                        outputEdges.append((flipped, True))
                    else:
                        p0 = None
                        cnt = 0
                        for p in reversed(e.discretize(Deflection=0.01)):
                            if not p0 is None:
                                outputEdges.append(
                                    (Part.Edge(Part.LineSegment(p0, p)), True))
                                cnt = cnt + 1
                            p0 = p
                        PathLog.info(
                            "replaced edge with %d straight segments" % cnt)
                    edges.remove(e)
                    lastP = None
                    p0 = p1
                    debugEdge(e, ">>>>> flip")
                    break
                else:
                    debugEdge(e,
                              "<<<<< (%.2f, %.2f, %.2f)" % (p0.x, p0.y, p0.z))

            if lastP == p0:
                self.edgesOrder.append(outputEdges)
                self.edgesOrder.append(edges)
                PathLog.debug('input edges:')
                for e in inputEdges:
                    debugEdge(e, '  ', False)
                PathLog.debug('ordered edges:')
                for e, flip in outputEdges:
                    debugEdge(e, '  %c ' % ('<' if flip else '>'), False)
                PathLog.debug('remaining edges:')
                for e in edges:
                    debugEdge(e, '    ', False)
                raise ValueError("No connection to %s" % (p0))
            elif lastP:
                PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) (%.2f, %.2f, %.2f)" %
                              (p0.x, p0.y, p0.z, lastP.x, lastP.y, lastP.z))
            else:
                PathLog.debug("xxxxxx (%.2f, %.2f, %.2f) -" %
                              (p0.x, p0.y, p0.z))
            lastP = p0
        PathLog.track("-")
        return outputEdges
コード例 #46
0
 def minZmax(z):
     if hasattr(obj, 'StepDown') and not PathGeom.isRoughly(
             obj.StepDown.Value, 0):
         return z + obj.StepDown.Value
     else:
         return z + 1
コード例 #47
0
    def cleanupEdges(self, edges):
        # want to remove all edges from the wire itself, and all internal struts
        PathLog.track("+cleanupEdges")
        PathLog.debug(" edges:")
        if not edges:
            return edges
        for e in edges:
            debugEdge(e, '   ')
        PathLog.debug(":")
        self.edgesCleanup = [copy.copy(edges)]

        # remove any edge that has a point inside the tag solid
        # and collect all edges that are connected to the entry and/or exit
        self.entryEdges = []
        self.exitEdges = []
        self.edgePoints = []
        for e in copy.copy(edges):
            p1 = e.valueAt(e.FirstParameter)
            p2 = e.valueAt(e.LastParameter)
            self.edgePoints.append(p1)
            self.edgePoints.append(p2)
            if self.tag.solid.isInside(p1, PathGeom.Tolerance,
                                       False) or self.tag.solid.isInside(
                                           p2, PathGeom.Tolerance, False):
                edges.remove(e)
                debugEdge(e, '......... X0', False)
            else:
                if PathGeom.pointsCoincide(
                        p1, self.entry) or PathGeom.pointsCoincide(
                            p2, self.entry):
                    self.entryEdges.append(e)
                if PathGeom.pointsCoincide(
                        p1, self.exit) or PathGeom.pointsCoincide(
                            p2, self.exit):
                    self.exitEdges.append(e)
        self.edgesCleanup.append(copy.copy(edges))

        # if there are no edges connected to entry/exit, it means the plunge in/out is vertical
        # we need to add in the missing segment and collect the new entry/exit edges.
        if not self.entryEdges:
            PathLog.debug("fill entryEdges ...")
            self.realEntry = sorted(self.edgePoints,
                                    key=lambda p: (p - self.entry).Length)[0]
            self.entryEdges = list([
                e for e in edges if PathGeom.edgeConnectsTo(e, self.realEntry)
            ])
            edges.append(
                Part.Edge(Part.LineSegment(self.entry, self.realEntry)))
        else:
            self.realEntry = None
        if not self.exitEdges:
            PathLog.debug("fill exitEdges ...")
            self.realExit = sorted(self.edgePoints,
                                   key=lambda p: (p - self.exit).Length)[0]
            self.exitEdges = list([
                e for e in edges if PathGeom.edgeConnectsTo(e, self.realExit)
            ])
            edges.append(Part.Edge(Part.LineSegment(self.realExit, self.exit)))
        else:
            self.realExit = None
        self.edgesCleanup.append(copy.copy(edges))

        # if there are 2 edges attached to entry/exit, throw away the one that is "lower"
        if len(self.entryEdges) > 1:
            debugEdge(self.entryEdges[0], ' entry[0]', False)
            debugEdge(self.entryEdges[1], ' entry[1]', False)
            if self.entryEdges[0].BoundBox.ZMax < self.entryEdges[
                    1].BoundBox.ZMax:
                edges.remove(self.entryEdges[0])
                debugEdge(e, '......... X1', False)
            else:
                edges.remove(self.entryEdges[1])
                debugEdge(e, '......... X2', False)
        if len(self.exitEdges) > 1:
            debugEdge(self.exitEdges[0], ' exit[0]', False)
            debugEdge(self.exitEdges[1], ' exit[1]', False)
            if self.exitEdges[0].BoundBox.ZMax < self.exitEdges[
                    1].BoundBox.ZMax:
                if self.exitEdges[0] in edges:
                    edges.remove(self.exitEdges[0])
                debugEdge(e, '......... X3', False)
            else:
                if self.exitEdges[1] in edges:
                    edges.remove(self.exitEdges[1])
                debugEdge(e, '......... X4', False)

        self.edgesCleanup.append(copy.copy(edges))
        return edges
コード例 #48
0
    def generateRamps(self, allowBounce=True):
        edges = self.wire.Edges
        outedges = []
        for edge in edges:
            israpid = False
            for redge in self.rapids:
                if PathGeom.edgesMatch(edge, redge):
                    israpid = True
            if not israpid:
                bb = edge.BoundBox
                p0 = edge.Vertexes[0].Point
                p1 = edge.Vertexes[1].Point
                rampangle = self.angle
                if bb.XLength < 1e-6 and bb.YLength < 1e-6 and bb.ZLength > 0 and p0.z > p1.z:

                    # check if above ignoreAbove parameter - do not generate ramp if it is
                    newEdge, cont = self.checkIgnoreAbove(edge)
                    if newEdge is not None:
                        outedges.append(newEdge)
                        p0.z = self.ignoreAbove
                    if cont:
                        continue

                    plungelen = abs(p0.z - p1.z)
                    projectionlen = plungelen * math.tan(
                        math.radians(rampangle)
                    )  # length of the forthcoming ramp projected to XY plane
                    PathLog.debug(
                        "Found plunge move at X:{} Y:{} From Z:{} to Z{}, length of ramp: {}"
                        .format(p0.x, p0.y, p0.z, p1.z, projectionlen))
                    if self.method == 'RampMethod3':
                        projectionlen = projectionlen / 2

                    # next need to determine how many edges in the path after
                    # plunge are needed to cover the length:
                    covered = False
                    coveredlen = 0
                    rampedges = []
                    i = edges.index(edge) + 1
                    while not covered:
                        candidate = edges[i]
                        cp0 = candidate.Vertexes[0].Point
                        cp1 = candidate.Vertexes[1].Point
                        if abs(cp0.z - cp1.z) > 1e-6:
                            # this edge is not parallel to XY plane, not qualified for ramping.
                            break
                        # PathLog.debug("Next edge length {}".format(candidate.Length))
                        rampedges.append(candidate)
                        coveredlen = coveredlen + candidate.Length

                        if coveredlen > projectionlen:
                            covered = True
                        i = i + 1
                        if i >= len(edges):
                            break
                    if len(rampedges) == 0:
                        PathLog.debug(
                            "No suitable edges for ramping, plunge will remain as such"
                        )
                        outedges.append(edge)
                    else:
                        if not covered:
                            if (not allowBounce
                                ) or self.method == 'RampMethod2':
                                l = 0
                                for redge in rampedges:
                                    l = l + redge.Length
                                if self.method == 'RampMethod3':
                                    rampangle = math.degrees(
                                        math.atan(l / (plungelen / 2)))
                                else:
                                    rampangle = math.degrees(
                                        math.atan(l / plungelen))
                                PathLog.warning(
                                    "Cannot cover with desired angle, tightening angle to: {}"
                                    .format(rampangle))

                        # PathLog.debug("Doing ramp to edges: {}".format(rampedges))
                        if self.method == 'RampMethod1':
                            outedges.extend(
                                self.createRampMethod1(rampedges, p0,
                                                       projectionlen,
                                                       rampangle))
                        elif self.method == 'RampMethod2':
                            outedges.extend(
                                self.createRampMethod2(rampedges, p0,
                                                       projectionlen,
                                                       rampangle))
                        else:
                            # if the ramp cannot be covered with Method3, revert to Method1
                            # because Method1 support going back-and-forth and thus results in same path as Method3 when
                            # length of the ramp is smaller than needed for single ramp.
                            if (not covered) and allowBounce:
                                projectionlen = projectionlen * 2
                                outedges.extend(
                                    self.createRampMethod1(
                                        rampedges, p0, projectionlen,
                                        rampangle))
                            else:
                                outedges.extend(
                                    self.createRampMethod3(
                                        rampedges, p0, projectionlen,
                                        rampangle))
                else:
                    outedges.append(edge)
            else:
                outedges.append(edge)
        return outedges
コード例 #49
0
 def isDefinitelySmaller(z, zRef):
     # Eliminate false positives of edges that just brush along the top of the tag
     return z < zRef and not PathGeom.isRoughly(z, zRef, 0.01)
コード例 #50
0
    def generateHelix(self):
        edges = self.wire.Edges
        minZ = self.findMinZ(edges)
        PathLog.debug("Minimum Z in this path is {}".format(minZ))
        outedges = []
        i = 0
        while i < len(edges):
            edge = edges[i]
            israpid = False
            for redge in self.rapids:
                if PathGeom.edgesMatch(edge, redge):
                    israpid = True
            if not israpid:
                bb = edge.BoundBox
                p0 = edge.Vertexes[0].Point
                p1 = edge.Vertexes[1].Point
                if bb.XLength < 1e-6 and bb.YLength < 1e-6 and bb.ZLength > 0 and p0.z > p1.z:
                    # plungelen = abs(p0.z-p1.z)
                    PathLog.debug(
                        "Found plunge move at X:{} Y:{} From Z:{} to Z{}, Searching for closed loop"
                        .format(p0.x, p0.y, p0.z, p1.z))
                    # check if above ignoreAbove parameter - do not generate helix if it is
                    newEdge, cont = self.checkIgnoreAbove(edge)
                    if newEdge is not None:
                        outedges.append(newEdge)
                        p0.z = self.ignoreAbove
                    if cont:
                        i = i + 1
                        continue
                    # next need to determine how many edges in the path after plunge are needed to cover the length:
                    loopFound = False
                    rampedges = []
                    j = i + 1
                    while not loopFound:
                        candidate = edges[j]
                        cp0 = candidate.Vertexes[0].Point
                        cp1 = candidate.Vertexes[1].Point
                        if PathGeom.pointsCoincide(p1, cp1):
                            # found closed loop
                            loopFound = True
                            rampedges.append(candidate)
                            break
                        if abs(cp0.z - cp1.z) > 1e-6:
                            # this edge is not parallel to XY plane, not qualified for ramping.
                            break
                        # PathLog.debug("Next edge length {}".format(candidate.Length))
                        rampedges.append(candidate)
                        j = j + 1
                        if j >= len(edges):
                            break
                    if len(rampedges) == 0 or not loopFound:
                        PathLog.debug("No suitable helix found")
                        outedges.append(edge)
                    else:
                        outedges.extend(self.createHelix(rampedges, p0, p1))
                        if not PathGeom.isRoughly(p1.z, minZ):
                            # the edges covered by the helix not handled again,
                            # unless reached the bottom height
                            i = j

                else:
                    outedges.append(edge)
            else:
                outedges.append(edge)
            i = i + 1
        return outedges
コード例 #51
0
def offsetWire(wire, base, offset, forward):
    '''offsetWire(wire, base, offset, forward) ... offsets the wire away from base and orients the wire accordingly.
    The function tries to avoid most of the pitfalls of Part.makeOffset2D which is possible because all offsetting
    happens in the XY plane.
    '''
    PathLog.track('offsetWire')

    if 1 == len(wire.Edges):
        edge = wire.Edges[0]
        curve = edge.Curve
        if Part.Circle == type(curve) and wire.isClosed():
            # it's a full circle and there are some problems with that, see
            # http://www.freecadweb.org/wiki/Part%20Offset2D
            # it's easy to construct them manually though
            z = -1 if forward else 1
            edge = Part.makeCircle(curve.Radius + offset, curve.Center,
                                   FreeCAD.Vector(0, 0, z))
            if base.isInside(edge.Vertexes[0].Point, offset / 2, True):
                if offset > curve.Radius or PathGeom.isRoughly(
                        offset, curve.Radius):
                    # offsetting a hole by its own radius (or more) makes the hole vanish
                    return None
                edge = Part.makeCircle(curve.Radius - offset, curve.Center,
                                       FreeCAD.Vector(0, 0, -z))
            w = Part.Wire([edge])
            return w
        if Part.Line == type(curve) or Part.LineSegment == type(curve):
            # offsetting a single edge doesn't work because there is an infinite
            # possible planes into which the edge could be offset
            # luckily, the plane here must be the XY-plane ...
            p0 = edge.Vertexes[0].Point
            v0 = edge.Vertexes[1].Point - p0
            n = v0.cross(FreeCAD.Vector(0, 0, 1))
            o = n.normalize() * offset
            edge.translate(o)

            # offset edde the other way if the result is inside
            if base.isInside(
                    edge.valueAt(
                        (edge.FirstParameter + edge.LastParameter) / 2),
                    offset / 2, True):
                edge.translate(-2 * o)

            # flip the edge if it's not on the right side of the original edge
            if forward is not None:
                v1 = edge.Vertexes[1].Point - p0
                left = PathGeom.Side.Left == PathGeom.Side.of(v0, v1)
                if left != forward:
                    edge = PathGeom.flipEdge(edge)
            return Part.Wire([edge])

        # if we get to this point the assumption is that makeOffset2D can deal with the edge
        pass  # pylint: disable=unnecessary-pass

    owire = orientWire(wire.makeOffset2D(offset), True)
    debugWire('makeOffset2D_%d' % len(wire.Edges), owire)

    if wire.isClosed():
        if not base.isInside(owire.Edges[0].Vertexes[0].Point, offset / 2,
                             True):
            PathLog.track('closed - outside')
            return orientWire(owire, forward)
        PathLog.track('closed - inside')
        try:
            owire = wire.makeOffset2D(-offset)
        except Exception:  # pylint: disable=broad-except
            # most likely offsetting didn't work because the wire is a hole
            # and the offset is too big - making the hole vanish
            return None
        # For negative offsets (holes) 'forward' is the other way
        if forward is None:
            return orientWire(owire, None)
        return orientWire(owire, not forward)

    # An edge is considered to be inside of shape if the mid point is inside
    # Of the remaining edges we take the longest wire to be the engraving side
    # Looking for a circle with the start vertex as center marks and end
    #  starting from there follow the edges until a circle with the end vertex as center is found
    #  if the traversed edges include any of the remaining from above, all those edges are remaining
    #  this is to also include edges which might partially be inside shape
    #  if they need to be discarded, split, that should happen in a post process
    # Depending on the Axis of the circle, and which side remains we know if the wire needs to be flipped

    # first, let's make sure all edges are oriented the proper way
    edges = _orientEdges(wire.Edges)

    # determine the start and end point
    start = edges[0].firstVertex().Point
    end = edges[-1].lastVertex().Point
    debugWire('wire', wire)
    debugWire('wedges', Part.Wire(edges))

    # find edges that are not inside the shape
    common = base.common(owire)
    insideEndpoints = [e.lastVertex().Point for e in common.Edges]
    insideEndpoints.append(common.Edges[0].firstVertex().Point)

    def isInside(edge):
        p0 = edge.firstVertex().Point
        p1 = edge.lastVertex().Point
        for p in insideEndpoints:
            if PathGeom.pointsCoincide(p, p0, 0.01) or PathGeom.pointsCoincide(
                    p, p1, 0.01):
                return True
        return False

    outside = [e for e in owire.Edges if not isInside(e)]
    # discard all edges that are not part of the longest wire
    longestWire = None
    for w in [Part.Wire(el) for el in Part.sortEdges(outside)]:
        if not longestWire or longestWire.Length < w.Length:
            longestWire = w

    debugWire('outside', Part.Wire(outside))
    debugWire('longest', longestWire)

    def isCircleAt(edge, center):
        '''isCircleAt(edge, center) ... helper function returns True if edge is a circle at the given center.'''
        if Part.Circle == type(edge.Curve) or Part.ArcOfCircle == type(
                edge.Curve):
            return PathGeom.pointsCoincide(edge.Curve.Center, center)
        return False

    # split offset wire into edges to the left side and edges to the right side
    collectLeft = False
    collectRight = False
    leftSideEdges = []
    rightSideEdges = []

    # traverse through all edges in order and start collecting them when we encounter
    # an end point (circle centered at one of the end points of the original wire).
    # should we come to an end point and determine that we've already collected the
    # next side, we're done
    for e in (owire.Edges + owire.Edges):
        if isCircleAt(e, start):
            if PathGeom.pointsCoincide(e.Curve.Axis, FreeCAD.Vector(0, 0, 1)):
                if not collectLeft and leftSideEdges:
                    break
                collectLeft = True
                collectRight = False
            else:
                if not collectRight and rightSideEdges:
                    break
                collectLeft = False
                collectRight = True
        elif isCircleAt(e, end):
            if PathGeom.pointsCoincide(e.Curve.Axis, FreeCAD.Vector(0, 0, 1)):
                if not collectRight and rightSideEdges:
                    break
                collectLeft = False
                collectRight = True
            else:
                if not collectLeft and leftSideEdges:
                    break
                collectLeft = True
                collectRight = False
        elif collectLeft:
            leftSideEdges.append(e)
        elif collectRight:
            rightSideEdges.append(e)

    debugWire('left', Part.Wire(leftSideEdges))
    debugWire('right', Part.Wire(rightSideEdges))

    # figure out if all the left sided edges or the right sided edges are the ones
    # that are 'outside'. However, we return the full side.
    edges = leftSideEdges
    for e in longestWire.Edges:
        for e0 in rightSideEdges:
            if PathGeom.edgesMatch(e, e0):
                edges = rightSideEdges
                PathLog.debug("#use right side edges")
                if not forward:
                    PathLog.debug("#reverse")
                    edges.reverse()
                return orientWire(Part.Wire(edges), None)

    # at this point we have the correct edges and they are in the order for forward
    # traversal (climb milling). If that's not what we want just reverse the order,
    # orientWire takes care of orienting the edges appropriately.
    PathLog.debug("#use left side edges")
    if not forward:
        PathLog.debug("#reverse")
        edges.reverse()

    return orientWire(Part.Wire(edges), None)
コード例 #52
0
    def createRampMethod1(self, rampedges, p0, projectionlen, rampangle):
        """
        This method generates ramp with following pattern:
        1. Start from the original startpoint of the plunge
        2. Ramp down along the path that comes after the plunge
        3. When reaching the Z level of the original plunge, return back to the beginning
           by going the path backwards until the original plunge end point is reached
        4. Continue with the original path

        This method causes many unnecessary moves with tool down.
        """
        outedges = []
        rampremaining = projectionlen
        curPoint = p0  # start from the upper point of plunge
        done = False
        goingForward = True
        i = 0
        while not done:
            for i, redge in enumerate(rampedges):
                if redge.Length >= rampremaining:
                    # will reach end of ramp within this edge, needs to be split
                    p1 = self.getSplitPoint(redge, rampremaining)
                    splitEdge = PathGeom.splitEdgeAt(redge, p1)
                    PathLog.debug("Ramp remaining: {}".format(rampremaining))
                    PathLog.debug(
                        "Got split edge (index: {}) (total len: {}) with lengths: {}, {}"
                        .format(i, redge.Length, splitEdge[0].Length,
                                splitEdge[1].Length))
                    # ramp ends to the last point of first edge
                    p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
                    outedges.append(
                        self.createRampEdge(splitEdge[0], curPoint, p1))
                    # now we have reached the end of the ramp. Go back to plunge position with constant Z
                    # start that by going to the beginning of this splitEdge
                    if goingForward:
                        outedges.append(
                            self.createRampEdge(
                                splitEdge[0], p1,
                                redge.valueAt(redge.FirstParameter)))
                    else:
                        # if we were reversing, we continue to the same direction as the ramp
                        outedges.append(
                            self.createRampEdge(
                                splitEdge[0], p1,
                                redge.valueAt(redge.LastParameter)))
                    done = True
                    break
                else:
                    deltaZ = redge.Length / math.tan(math.radians(rampangle))
                    newPoint = FreeCAD.Base.Vector(
                        redge.valueAt(redge.LastParameter).x,
                        redge.valueAt(redge.LastParameter).y,
                        curPoint.z - deltaZ)
                    outedges.append(
                        self.createRampEdge(redge, curPoint, newPoint))
                    curPoint = newPoint
                    rampremaining = rampremaining - redge.Length

            if not done:
                # we did not reach the end of the ramp going this direction, lets reverse.
                rampedges = self.getreversed(rampedges)
                PathLog.debug("Reversing")
                if goingForward:
                    goingForward = False
                else:
                    goingForward = True
        # now we need to return to original position.
        if goingForward:
            # if the ramp was going forward, the return edges are the edges we already covered in ramping,
            # except the last one, which was already covered inside for loop. Direction needs to be reversed also
            returnedges = self.getreversed(rampedges[:i])
        else:
            # if the ramp was already reversing, the edges needed for return are the ones
            # which were not covered in ramp
            returnedges = rampedges[(i + 1):]

        # add the return edges:
        outedges.extend(returnedges)

        return outedges
コード例 #53
0
def generate(center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator,
             start):
    """generate(center, cmd, zStart, zFinal, pitch, radius, leadInOut, elevator, start) ... returns the g-code to mill the given internal thread"""
    thread = _Thread(cmd, zStart, zFinal, pitch, radius > elevator)

    yMin = center.y - radius
    yMax = center.y + radius

    path = []
    # at this point the tool is at a safe heiht (depending on the previous thread), so we can move
    # into position first, and then drop to the start height. If there is any material in the way this
    # op hasn't been setup properly.
    if leadInOut:
        _comment(path, "lead-in")
        if start is None:
            path.append(
                Path.Command("G0", {
                    "X": center.x,
                    "Y": center.y + elevator
                }))
            path.append(Path.Command("G0", {"Z": thread.zStart}))
        else:
            path.append(
                Path.Command(
                    thread.g4Start2Elevator(),
                    {
                        "X": center.x,
                        "Y": center.y + elevator,
                        "Z": thread.zStart,
                        "I": (center.x - start.x) / 2,
                        "J": (center.y + elevator - start.y) / 2,
                        "K": (thread.zStart - start.z) / 2,
                    },
                ))
        path.append(
            Path.Command(
                thread.g4LeadInOut(),
                {
                    "Y": yMax,
                    "J": (yMax - (center.y + elevator)) / 2
                },
            ))
        _comment(path, "lead-in")
    else:
        if start is None:
            path.append(
                Path.Command("G0", {
                    "X": center.x,
                    "Y": center.y + elevator
                }))
            path.append(Path.Command("G0", {"Z": thread.zStart}))
        else:
            path.append(
                Path.Command("G0", {
                    "X": center.x,
                    "Y": center.y + elevator,
                    "Z": thread.zStart
                }))
        path.append(Path.Command("G1", {"Y": yMax}))

    z = thread.zStart
    r = -radius
    i = 0
    while not PathGeom.isRoughly(z, thread.zFinal):
        if thread.overshoots(z):
            break
        if 0 == (i & 0x01):
            y = yMin
        else:
            y = yMax
        path.append(
            Path.Command(thread.cmd, {
                "Y": y,
                "Z": z + thread.hPitch,
                "J": r
            }))
        r = -r
        i = i + 1
        z = z + thread.hPitch

    if PathGeom.isRoughly(z, thread.zFinal):
        x = center.x
        y = yMin if (i & 0x01) else yMax
    else:
        n = math.fabs(thread.zFinal - thread.zStart) / thread.hPitch
        k = n - int(n)
        dy = math.cos(k * math.pi)
        dx = math.sin(k * math.pi)
        y = thread.adjustY(center.y, r * dy)
        x = thread.adjustX(center.x, r * dx)
        _comment(path, "finish-thread")
        path.append(
            Path.Command(thread.cmd, {
                "X": x,
                "Y": y,
                "Z": thread.zFinal,
                "J": r
            }))
        _comment(path, "finish-thread")

    a = math.atan2(y - center.y, x - center.x)
    dx = math.cos(a) * (radius - elevator)
    dy = math.sin(a) * (radius - elevator)
    PathLog.debug("")
    PathLog.debug("a={}: dx={:.2f}, dy={:.2f}".format(a / math.pi * 180, dx,
                                                      dy))

    elevatorX = x - dx
    elevatorY = y - dy
    PathLog.debug("({:.2f}, {:.2f}) -> ({:.2f}, {:.2f})".format(
        x, y, elevatorX, elevatorY))

    if leadInOut:
        _comment(path, "lead-out")
        path.append(
            Path.Command(
                thread.g4LeadInOut(),
                {
                    "X": elevatorX,
                    "Y": elevatorY,
                    "I": -dx / 2,
                    "J": -dy / 2
                },
            ))
        _comment(path, "lead-out")
    else:
        path.append(Path.Command("G1", {"X": elevatorX, "Y": elevatorY}))

    return (path, FreeCAD.Vector(elevatorX, elevatorY, thread.zFinal))
コード例 #54
0
    def createRampMethod3(self, rampedges, p0, projectionlen, rampangle):
        """
        This method generates ramp with following pattern:
        1. Start from the original startpoint of the plunge
        2. Ramp down along the path that comes after the plunge until
           traveled half of the Z distance
        3. Change direction and ramp backwards to the original plunge end point
        4. Continue with the original path

        This method causes many unnecessary moves with tool down.
        """
        outedges = []
        rampremaining = projectionlen
        curPoint = p0  # start from the upper point of plunge
        done = False

        i = 0
        while not done:
            for i, redge in enumerate(rampedges):
                if redge.Length >= rampremaining:
                    # will reach end of ramp within this edge, needs to be split
                    p1 = self.getSplitPoint(redge, rampremaining)
                    splitEdge = PathGeom.splitEdgeAt(redge, p1)
                    PathLog.debug(
                        "Got split edge (index: {}) with lengths: {}, {}".
                        format(i, splitEdge[0].Length, splitEdge[1].Length))
                    # ramp ends to the last point of first edge
                    p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
                    deltaZ = splitEdge[0].Length / math.tan(
                        math.radians(rampangle))
                    p1.z = curPoint.z - deltaZ
                    outedges.append(
                        self.createRampEdge(splitEdge[0], curPoint, p1))
                    curPoint.z = p1.z - deltaZ
                    # now we have reached the end of the ramp. Reverse direction of ramp
                    # start that by going back to the beginning of this splitEdge
                    outedges.append(
                        self.createRampEdge(splitEdge[0], p1, curPoint))

                    done = True
                    break
                elif i == len(rampedges) - 1:
                    # last ramp element but still did not reach the full length?
                    # Probably a rounding issue on floats.
                    p1 = redge.valueAt(redge.LastParameter)
                    deltaZ = redge.Length / math.tan(math.radians(rampangle))
                    p1.z = curPoint.z - deltaZ
                    outedges.append(self.createRampEdge(redge, curPoint, p1))
                    # and go back that edge
                    newPoint = FreeCAD.Base.Vector(
                        redge.valueAt(redge.FirstParameter).x,
                        redge.valueAt(redge.FirstParameter).y, p1.z - deltaZ)
                    outedges.append(self.createRampEdge(redge, p1, newPoint))
                    curPoint = newPoint
                    done = True
                else:
                    deltaZ = redge.Length / math.tan(math.radians(rampangle))
                    newPoint = FreeCAD.Base.Vector(
                        redge.valueAt(redge.LastParameter).x,
                        redge.valueAt(redge.LastParameter).y,
                        curPoint.z - deltaZ)
                    outedges.append(
                        self.createRampEdge(redge, curPoint, newPoint))
                    curPoint = newPoint
                    rampremaining = rampremaining - redge.Length

        returnedges = self.getreversed(rampedges[:i])

        # ramp backwards to the plunge position
        for i, redge in enumerate(returnedges):
            deltaZ = redge.Length / math.tan(math.radians(rampangle))
            newPoint = FreeCAD.Base.Vector(
                redge.valueAt(redge.LastParameter).x,
                redge.valueAt(redge.LastParameter).y, curPoint.z - deltaZ)
            if i == len(rampedges) - 1:
                # make sure that the last point of the ramps ends to the original position
                newPoint = redge.valueAt(redge.LastParameter)
            outedges.append(self.createRampEdge(redge, curPoint, newPoint))
            curPoint = newPoint

        return outedges
コード例 #55
0
    def areaOpShapes(self, obj):
        '''areaOpShapes(obj) ... return shapes representing the solids to be removed.'''
        PathLog.track()

        # self.isDebug = True if PathLog.getLevel(PathLog.thisModule()) == 4 else False
        self.removalshapes = []
        avoidFeatures = list()

        # Get extensions and identify faces to avoid
        extensions = FeatureExtensions.getExtensions(obj)
        for e in extensions:
            if e.avoid:
                avoidFeatures.append(e.feature)

        if obj.Base:
            PathLog.debug('base items exist.  Processing...')
            self.horiz = []
            self.vert = []
            for (base, subList) in obj.Base:
                for sub in subList:
                    if 'Face' in sub:
                        if sub not in avoidFeatures and not self.clasifySub(
                                base, sub):
                            PathLog.error(
                                translate(
                                    'PathPocket',
                                    'Pocket does not support shape %s.%s') %
                                (base.Label, sub))

            # Convert horizontal faces to use outline only if requested
            if obj.UseOutline and self.horiz:
                horiz = [Part.Face(f.Wire1) for f in self.horiz]
                self.horiz = horiz

            # Check if selected vertical faces form a loop
            if len(self.vert) > 0:
                self.vertical = PathGeom.combineConnectedShapes(self.vert)
                self.vWires = [
                    TechDraw.findShapeOutline(shape, 1,
                                              FreeCAD.Vector(0, 0, 1))
                    for shape in self.vertical
                ]
                for wire in self.vWires:
                    w = PathGeom.removeDuplicateEdges(wire)
                    face = Part.Face(w)
                    # face.tessellate(0.1)
                    if PathGeom.isRoughly(face.Area, 0):
                        PathLog.error(
                            translate(
                                'PathPocket',
                                'Vertical faces do not form a loop - ignoring')
                        )
                    else:
                        self.horiz.append(face)

            # Add faces for extensions
            self.exts = []  # pylint: disable=attribute-defined-outside-init
            for ext in extensions:
                if not ext.avoid:
                    wire = ext.getWire()
                    if wire:
                        faces = ext.getExtensionFaces(wire)
                        for f in faces:
                            self.horiz.append(f)
                            self.exts.append(f)

            # check all faces and see if they are touching/overlapping and combine and simplify
            self.horizontal = PathGeom.combineHorizontalFaces(self.horiz)

            # Move all faces to final depth before extrusion
            for h in self.horizontal:
                h.translate(
                    FreeCAD.Vector(0.0, 0.0,
                                   obj.FinalDepth.Value - h.BoundBox.ZMin))

            # extrude all faces up to StartDepth and those are the removal shapes
            extent = FreeCAD.Vector(
                0, 0, obj.StartDepth.Value - obj.FinalDepth.Value)
            self.removalshapes = [(face.removeSplitter().extrude(extent),
                                   False) for face in self.horizontal]

        else:  # process the job base object as a whole
            PathLog.debug("processing the whole job base object")
            self.outlines = [
                Part.Face(
                    TechDraw.findShapeOutline(base.Shape, 1,
                                              FreeCAD.Vector(0, 0, 1)))
                for base in self.model
            ]
            stockBB = self.stock.Shape.BoundBox

            self.bodies = []
            for outline in self.outlines:
                outline.translate(FreeCAD.Vector(0, 0, stockBB.ZMin - 1))
                body = outline.extrude(
                    FreeCAD.Vector(0, 0, stockBB.ZLength + 2))
                self.bodies.append(body)
                self.removalshapes.append((self.stock.Shape.cut(body), False))

        # Tessellate all working faces
        # for (shape, hole) in self.removalshapes:
        #    shape.tessellate(0.05)  # originally 0.1

        if self.removalshapes:
            obj.removalshape = self.removalshapes[0][0]
        return self.removalshapes
コード例 #56
0
    def createRampMethod2(self, rampedges, p0, projectionlen, rampangle):
        """
        This method generates ramp with following pattern:
        1. Start from the original startpoint of the plunge
        2. Calculate the distance on the path which is needed to implement the ramp
           and travel that distance while maintaining start depth
        3. Start ramping while traveling the original path backwards until reaching the
           original plunge end point
        4. Continue with the original path
        """
        outedges = []
        rampremaining = projectionlen
        curPoint = p0  # start from the upper point of plunge
        if PathGeom.pointsCoincide(
                PathGeom.xy(p0),
                PathGeom.xy(rampedges[-1].valueAt(
                    rampedges[-1].LastParameter))):
            PathLog.debug(
                "The ramp forms a closed wire, needless to move on original Z height"
            )
        else:
            for i, redge in enumerate(rampedges):
                if redge.Length >= rampremaining:
                    # this edge needs to be split
                    p1 = self.getSplitPoint(redge, rampremaining)
                    splitEdge = PathGeom.splitEdgeAt(redge, p1)
                    PathLog.debug(
                        "Got split edges with lengths: {}, {}".format(
                            splitEdge[0].Length, splitEdge[1].Length))
                    # ramp starts at the last point of first edge
                    p1 = splitEdge[0].valueAt(splitEdge[0].LastParameter)
                    p1.z = p0.z
                    outedges.append(
                        self.createRampEdge(splitEdge[0], curPoint, p1))
                    # now we have reached the beginning of the ramp.
                    # start that by going to the beginning of this splitEdge
                    deltaZ = splitEdge[0].Length / math.tan(
                        math.radians(rampangle))
                    newPoint = FreeCAD.Base.Vector(
                        splitEdge[0].valueAt(splitEdge[0].FirstParameter).x,
                        splitEdge[0].valueAt(splitEdge[0].FirstParameter).y,
                        p1.z - deltaZ)
                    outedges.append(
                        self.createRampEdge(splitEdge[0], p1, newPoint))
                    curPoint = newPoint
                elif i == len(rampedges) - 1:
                    # last ramp element but still did not reach the full length?
                    # Probably a rounding issue on floats.
                    # Lets start the ramp anyway
                    p1 = redge.valueAt(redge.LastParameter)
                    p1.z = p0.z
                    outedges.append(self.createRampEdge(redge, curPoint, p1))
                    # and go back that edge
                    deltaZ = redge.Length / math.tan(math.radians(rampangle))
                    newPoint = FreeCAD.Base.Vector(
                        redge.valueAt(redge.FirstParameter).x,
                        redge.valueAt(redge.FirstParameter).y, p1.z - deltaZ)
                    outedges.append(self.createRampEdge(redge, p1, newPoint))
                    curPoint = newPoint

                else:
                    # we are traveling on start depth
                    newPoint = FreeCAD.Base.Vector(
                        redge.valueAt(redge.LastParameter).x,
                        redge.valueAt(redge.LastParameter).y, p0.z)
                    outedges.append(
                        self.createRampEdge(redge, curPoint, newPoint))
                    curPoint = newPoint
                    rampremaining = rampremaining - redge.Length

            # the last edge got handled previously
            rampedges.pop()
        # ramp backwards to the plunge position
        for i, redge in enumerate(reversed(rampedges)):
            deltaZ = redge.Length / math.tan(math.radians(rampangle))
            newPoint = FreeCAD.Base.Vector(
                redge.valueAt(redge.FirstParameter).x,
                redge.valueAt(redge.FirstParameter).y, curPoint.z - deltaZ)
            if i == len(rampedges) - 1:
                # make sure that the last point of the ramps ends to the original position
                newPoint = redge.valueAt(redge.FirstParameter)
            outedges.append(self.createRampEdge(redge, curPoint, newPoint))
            curPoint = newPoint

        return outedges
コード例 #57
0
ファイル: TestPathGeom.py プロジェクト: zuoluo201008/FreeCAD
    def test03(self):
        """Verify isVertical/isHorizontal for Edges"""

        # lines
        self.assertTrue(PathGeom.isVertical(Part.Edge(Part.LineSegment(Vector(-1, -1, -1), Vector(-1, -1, 8)))))
        self.assertFalse(PathGeom.isVertical(Part.Edge(Part.LineSegment(Vector(-1, -1, -1), Vector(1, -1, 8)))))
        self.assertFalse(PathGeom.isVertical(Part.Edge(Part.LineSegment(Vector(-1, -1, -1), Vector(-1, 1, 8)))))

        self.assertTrue(PathGeom.isHorizontal(Part.Edge(Part.LineSegment(Vector(1, -1, -1), Vector(-1, -1, -1)))))
        self.assertTrue(PathGeom.isHorizontal(Part.Edge(Part.LineSegment(Vector(-1, 1, -1), Vector(-1, -1, -1)))))
        self.assertTrue(PathGeom.isHorizontal(Part.Edge(Part.LineSegment(Vector(1, 1, -1), Vector(-1, -1, -1)))))
        self.assertFalse(PathGeom.isHorizontal(Part.Edge(Part.LineSegment(Vector(1, -1, -1), Vector(1, -1, 8)))))
        self.assertFalse(PathGeom.isHorizontal(Part.Edge(Part.LineSegment(Vector(-1, 1, -1), Vector(-1, 1, 8)))))

        # circles
        self.assertTrue(PathGeom.isVertical(Part.Edge(Part.makeCircle(4, Vector(), Vector(0, 1, 0)))))
        self.assertTrue(PathGeom.isVertical(Part.Edge(Part.makeCircle(4, Vector(), Vector(1, 0, 0)))))
        self.assertTrue(PathGeom.isVertical(Part.Edge(Part.makeCircle(4, Vector(), Vector(1, 1, 0)))))
        self.assertFalse(PathGeom.isVertical(Part.Edge(Part.makeCircle(4, Vector(), Vector(1, 1, 1)))))

        self.assertTrue(PathGeom.isHorizontal(Part.Edge(Part.makeCircle(4, Vector(), Vector(0, 0, 1)))))
        self.assertFalse(PathGeom.isHorizontal(Part.Edge(Part.makeCircle(4, Vector(), Vector(0, 1, 1)))))
        self.assertFalse(PathGeom.isHorizontal(Part.Edge(Part.makeCircle(4, Vector(), Vector(1, 0, 1)))))
        self.assertFalse(PathGeom.isHorizontal(Part.Edge(Part.makeCircle(4, Vector(), Vector(1, 1, 1)))))
コード例 #58
0
 def isStrut(self, edge):
     p1 = PathGeom.xy(edge.valueAt(edge.FirstParameter))
     p2 = PathGeom.xy(edge.valueAt(edge.LastParameter))
     return PathGeom.pointsCoincide(p1, p2)
コード例 #59
0
    def createCommands(self, obj, edges):
        commands = []
        for edge in edges:
            israpid = False
            for redge in self.rapids:
                if PathGeom.edgesMatch(edge, redge):
                    israpid = True
            if israpid:
                v = edge.valueAt(edge.LastParameter)
                commands.append(
                    Path.Command('G0', {
                        'X': v.x,
                        'Y': v.y,
                        'Z': v.z
                    }))
            else:
                commands.extend(PathGeom.cmdsForEdge(edge))

        lastCmd = Path.Command('G0', {'X': 0.0, 'Y': 0.0, 'Z': 0.0})

        outCommands = []

        tc = PathDressup.toolController(obj.Base)

        horizFeed = tc.HorizFeed.Value
        vertFeed = tc.VertFeed.Value
        if obj.RampFeedRate == "Horizontal Feed Rate":
            rampFeed = tc.HorizFeed.Value
        elif obj.RampFeedRate == "Vertical Feed Rate":
            rampFeed = tc.VertFeed.Value
        else:
            rampFeed = obj.CustomFeedRate.Value
        horizRapid = tc.HorizRapid.Value
        vertRapid = tc.VertRapid.Value

        for cmd in commands:
            params = cmd.Parameters
            zVal = params.get('Z', None)
            zVal2 = lastCmd.Parameters.get('Z', None)

            xVal = params.get('X', None)
            xVal2 = lastCmd.Parameters.get('X', None)

            yVal2 = lastCmd.Parameters.get('Y', None)
            yVal = params.get('Y', None)

            zVal = zVal and round(zVal, 8)
            zVal2 = zVal2 and round(zVal2, 8)

            if cmd.Name in ['G1', 'G2', 'G3', 'G01', 'G02', 'G03']:
                if zVal is not None and zVal2 != zVal:
                    if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly(
                            yVal, yVal2):
                        # this is a straight plunge
                        params['F'] = vertFeed
                    else:
                        # this is a ramp
                        params['F'] = rampFeed
                else:
                    params['F'] = horizFeed
                lastCmd = cmd

            elif cmd.Name in ['G0', 'G00']:
                if zVal is not None and zVal2 != zVal:
                    params['F'] = vertRapid
                else:
                    params['F'] = horizRapid
                lastCmd = cmd

            outCommands.append(Path.Command(cmd.Name, params))

        return Path.Path(outCommands)
コード例 #60
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...")
            self.removalshapes = []
            self.horiz = []
            vertical = []
            for o in obj.Base:
                PathLog.debug("Base item: {}".format(o))
                base = o[0]
                for sub in o[1]:
                    if "Face" in sub:
                        face = base.Shape.getElement(sub)
                        if type(face.Surface) == Part.Plane and PathGeom.isVertical(face.Surface.Axis):
                            # it's a flat horizontal face
                            self.horiz.append(face)
                        elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(face.Surface.Axis):
                            # vertical cylinder wall
                            if any(e.isClosed() for e in face.Edges):
                                # complete cylinder
                                circle = Part.makeCircle(face.Surface.Radius, face.Surface.Center)
                                disk = Part.Face(Part.Wire(circle))
                                self.horiz.append(disk)
                            else:
                                # partial cylinder wall
                                vertical.append(face)
                        elif type(face.Surface) == Part.Plane and PathGeom.isHorizontal(face.Surface.Axis):
                            vertical.append(face)
                        else:
                            PathLog.error(translate('PathPocket', "Pocket does not support shape %s.%s") % (base.Label, sub))

            self.vertical = PathGeom.combineConnectedShapes(vertical)
            self.vWires = [TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1)) for shape in self.vertical]
            for wire in self.vWires:
                w = PathGeom.removeDuplicateEdges(wire)
                face = Part.Face(w)
                face.tessellate(0.1)
                if PathGeom.isRoughly(face.Area, 0):
                    PathLog.error(translate('PathPocket', 'Vertical faces do not form a loop - ignoring'))
                else:
                    self.horiz.append(face)


            # move all horizontal faces to FinalDepth
            for f in self.horiz:
                f.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - f.BoundBox.ZMin))

            # check all faces and see if they are touching/overlapping and combine those into a compound
            self.horizontal = []
            for shape in PathGeom.combineConnectedShapes(self.horiz):
                shape.sewShape()
                shape.tessellate(0.1)
                if obj.UseOutline:
                    wire = TechDraw.findShapeOutline(shape, 1, FreeCAD.Vector(0, 0, 1))
                    wire.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - wire.BoundBox.ZMin))
                    self.horizontal.append(Part.Face(wire))
                else:
                    self.horizontal.append(shape)

            # extrude all faces up to StartDepth and those are the removal shapes
            extent = FreeCAD.Vector(0, 0, obj.StartDepth.Value - obj.FinalDepth.Value)
            self.removalshapes = [(face.extrude(extent), False) for face in self.horizontal]

        else:  # process the job base object as a whole
            PathLog.debug("processing the whole job base object")
            self.outlines = [Part.Face(TechDraw.findShapeOutline(base.Shape, 1, FreeCAD.Vector(0, 0, 1))) for base in self.model]
            stockBB = self.stock.Shape.BoundBox

            self.removalshapes = []
            self.bodies = []
            for outline in self.outlines:
                outline.translate(FreeCAD.Vector(0, 0, stockBB.ZMin - 1))
                body = outline.extrude(FreeCAD.Vector(0, 0, stockBB.ZLength + 2))
                self.bodies.append(body)
                self.removalshapes.append((self.stock.Shape.cut(body), False))

        for (shape,hole) in self.removalshapes:
            shape.tessellate(0.1)

        if self.removalshapes:
            obj.removalshape = self.removalshapes[0][0]
        return self.removalshapes