def _sort_edges(edges):
        '''
        Sort a continuous path of edges
        '''

        path_shapes = []

        for path_edge in edges:
            path_shapes.append(path_edge.toShape())

        result = Part.sortEdges(path_shapes)[0]

        #if the first sorted edge is not the same as the first drawn edge,
        #reverse the sorted list
        if not path_shapes[0].Vertexes[0] in result[0].Vertexes:

            for _x in range(0, len(edges)):
                edges[_x].reverse()

            path_shapes = []

            for path_edge in edges:
                path_shapes.append(path_edge.toShape())

            result = Part.sortEdges(path_shapes)[0]

        return result
Example #2
0
    def execute(self, obj):
        e, w = self.getShape(obj)
        params = []
        if hasattr(obj, "Values"):
            params = self.parse_values(e, obj.Values)
        if params == []:
            if w:
                obj.Shape = obj.Source[0].Shape
            else:
                obj.Shape = e
            return
        if params[0] > e.FirstParameter:
            params.insert(0, e.FirstParameter)
        if params[-1] < e.LastParameter:
            params.append(e.LastParameter)

        if w:  # No subshape given, take wire 1
            edges = w.Edges
            for i in range(len(params)):
                p = e.valueAt(params[i])
                d, pts, info = Part.Vertex(p).distToShape(w)
                #print(info)
                if info[0][3] == "Edge":
                    n = info[0][4]
                    nw = w.Edges[n].split(info[0][5])
                    nw.Placement = w.Edges[n].Placement
                    if len(nw.Edges) == 2:
                        edges[n] = nw.Edges[0]
                        edges.insert(n + 1, nw.Edges[1])

                        #print([e.Length for e in edges])
                        se = Part.sortEdges(edges)
                        if len(se) > 1:
                            FreeCAD.Console.PrintError(
                                "Split curve : failed to build temp Wire !")
                            #print(se)
                        w = Part.Wire(se[0])
        else:
            edges = []
            for i in range(len(params) - 1):
                c = e.Curve.trim(params[i], params[i + 1])
                edges.append(c.toShape())

        se = Part.sortEdges(edges)
        if len(se) > 1:
            FreeCAD.Console.PrintError(
                "Split curve : failed to build final Wire !")
            wires = []
            for el in se:
                wires.append(Part.Wire(el))
            w = Part.Compound(wires)
        else:
            w = Part.Wire(se[0])
        if w.isValid():
            obj.Shape = w
        else:
            FreeCAD.Console.PrintError("Split curve : Invalid Wire !")
            obj.Shape = e
Example #3
0
    def opExecute(self, obj):
        PathLog.track(obj.Label)
        (depth, offset) = toolDepthAndOffset(obj.Width.Value,
                                             obj.ExtraDepth.Value, self.tool)
        PathLog.track(obj.Label, depth, offset)

        self.basewires = []
        self.adjusted_basewires = []
        wires = []
        for base, subs in obj.Base:
            edges = []
            basewires = []
            for f in subs:
                sub = base.Shape.getElement(f)
                if type(sub) == Part.Edge:
                    edges.append(sub)
                elif sub.Wires:
                    basewires.extend(sub.Wires)
                else:
                    basewires.append(Part.Wire(sub.Edges))
            self.edges = edges
            for edgelist in Part.sortEdges(edges):
                basewires.append(Part.Wire(edgelist))

            self.basewires.extend(basewires)

            for w in self.adjustWirePlacement(obj, base, basewires):
                self.adjusted_basewires.append(w)
                wire = PathOpTools.offsetWire(w, base.Shape, offset, True)
                if wire:
                    wires.append(wire)

        self.wires = wires
        self.buildpathocc(obj, wires, [depth], True)
Example #4
0
def get_face_boundary_rectangle(face):
    """Returns the 3D boundary wire of the 2D boundingbox of a face
    Input : Topo face
    Output : Topo Wire"""
    lines = get_face_2d_boundary(face)
    edges = [l.toShape(face.Surface) for l in lines]
    return Part.Wire(Part.sortEdges(edges)[0])
Example #5
0
def map_shape(face, shape, transfer):
    """
    mapped_shape = map_shape(face, shapes, transfer)
    Maps the shape on the target face
    transfer is a nurbs rectangle that has the same parameters as the target face.
    shape is projected onto transfer, to get the 2D geometry.
    """
    proj = transfer.project(shape.Edges)
    new_edges = []
    for e in proj.Edges:
        try:
            c2d, fp, lp = transfer.curveOnSurface(e)
            ne = c2d.toShape(face.Surface, fp, lp)
            new_edges.append(ne)
        except TypeError:
            debug("Failed to get 2D curve")
    #sorted_edges = Part.sortEdges(new_edges)
    #wirelist = [Part.Wire(el) for el in sorted_edges]
    if len(new_edges) == 0:
        return []
    else:
        se = Part.sortEdges(new_edges)
        if len(se) > 1:
            wires = []
            for el in se:
                wires.append(Part.Wire(el))
            return Part.Compound(wires)
        else:
            return Part.Wire(se[0])
Example #6
0
    def opExecute(self, obj):
        PathLog.track(obj.Label)
        (depth, offset) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool)
        PathLog.track(obj.Label, depth, offset)

        self.basewires = []
        self.adjusted_basewires = []
        wires = []
        for base, subs in obj.Base:
            edges = []
            basewires = []
            for f in subs:
                sub = base.Shape.getElement(f)
                if type(sub) == Part.Edge:
                    edges.append(sub)
                elif sub.Wires:
                    basewires.extend(sub.Wires)
                else:
                    basewires.append(Part.Wire(sub.Edges))
            self.edges = edges
            for edgelist in Part.sortEdges(edges):
                basewires.append(Part.Wire(edgelist))

            self.basewires.extend(basewires)

            for w in self.adjustWirePlacement(obj, base, basewires):
                self.adjusted_basewires.append(w)
                wire = PathOpTools.offsetWire(w, base.Shape, offset, True)
                if wire:
                    wires.append(wire)

        self.wires = wires
        self.buildpathocc(obj, wires, [depth], True)
Example #7
0
def extendWire(feature, wire, length):
    '''extendWire(wire, length) ... return a closed Wire which extends wire by length'''
    try:
        off2D = wire.makeOffset2D(length)
    except Exception as e:
        msg = "\nThe selected face cannot be used.\nYou must select the bottom face of the pocket area.\nextendWire() in PathPocketShape.py"
        PathLog.error(e)
        PathLog.error(msg)
        return False
    else:
        endPts = endPoints(wire)
        edges = [
            e for e in off2D.Edges if Part.Circle != type(e.Curve)
            or not includesPoint(e.Curve.Center, endPts)
        ]
        wires = [Part.Wire(e) for e in Part.sortEdges(edges)]
        offset = selectOffsetWire(feature, wires)
        ePts = endPoints(offset)
        l0 = (ePts[0] - endPts[0]).Length
        l1 = (ePts[1] - endPts[0]).Length
        edges = wire.Edges
        if l0 < l1:
            edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[0])))
            edges.extend(offset.Edges)
            edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[1])))
        else:
            edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
            edges.extend(offset.Edges)
            edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))
        return Part.Wire(edges)
Example #8
0
 def map_shape(self, shape, quad, face, fillfaces=False):
     if not isinstance(shape, Part.Shape):
         return []
     # proj = quad.project(shape.Edges)
     new_edges = []
     for oe in shape.Edges:
         # debug("original edge has : {} Pcurves : {}".format(_utils.nb_pcurves(oe), oe.curveOnSurface(0)))
         proj = quad.project([oe])
         for e in proj.Edges:
             # debug("edge on quad has : {} Pcurves : {}".format(_utils.nb_pcurves(e), e.curveOnSurface(0)))
             c2d, fp, lp = quad.curveOnSurface(e)
             if oe.isClosed() and not c2d.isClosed():
                 self.force_closed_bspline2d(c2d)
             ne = c2d.toShape(face.Surface, fp, lp)
             # debug("edge on face has : {} Pcurves : {}".format(_utils.nb_pcurves(ne), ne.curveOnSurface(0)))
             # debug(ne.Placement)
             # debug(face.Placement)
             # ne.Placement = face.Placement
             vt = ne.getTolerance(1, Part.Vertex)
             et = ne.getTolerance(1, Part.Edge)
             if vt < et:
                 ne.fixTolerance(et, Part.Vertex)
                 # debug("fixing tolerance : {0:e} -> {1:e}".format(vt,et))
             new_edges.append(ne)
         # else: # except TypeError:
         # error("Failed to get 2D curve")
     sorted_edges = Part.sortEdges(new_edges)
     wirelist = [Part.Wire(el) for el in sorted_edges]
     if fillfaces:
         return self.build_faces(wirelist, face)
     else:
         return wirelist
Example #9
0
def extendWire(feature, wire, length):
    '''extendWire(wire, length) ... return a closed Wire which extends wire by length'''
    try:
        off2D = wire.makeOffset2D(length)
    except Exception as e:
        PathLog.error("extendWire(): wire.makeOffset2D()")
        PathLog.error(e)
        return False
    else:
        endPts = endPoints(wire)
        edges = [e for e in off2D.Edges if not isinstance(e.Curve, Part.Circle) or not includesPoint(e.Curve.Center, endPts)]
        wires = [Part.Wire(e) for e in Part.sortEdges(edges)]
        offset = selectOffsetWire(feature, wires)
        ePts = endPoints(offset)
        try:
            l0 = (ePts[0] - endPts[0]).Length
        except Exception as ee:
            PathLog.error("extendWire(): (ePts[0] - endPts[0]).Length")
            PathLog.error(ee)
            return False
        else:
            l1 = (ePts[1] - endPts[0]).Length
            edges = wire.Edges
            if l0 < l1:
                edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[0])))
                edges.extend(offset.Edges)
                edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[1])))
            else:
                edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
                edges.extend(offset.Edges)
                edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))
            return Part.Wire(edges)
Example #10
0
def extendWire(feature, wire, length):
    '''extendWire(wire, length) ... return a closed Wire which extends wire by length'''
    PathLog.track(length)
    if length and length != 0:
        off2D = wire.makeOffset2D(length)
        endPts = endPoints(wire)
        if endPts:
            edges = [e for e in off2D.Edges if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts)]
            wires = [Part.Wire(e) for e in Part.sortEdges(edges)]
            offset = selectOffsetWire(feature, wires)
            ePts = endPoints(offset)
            if ePts and len(ePts) > 1:
                l0 = (ePts[0] - endPts[0]).Length
                l1 = (ePts[1] - endPts[0]).Length
                edges = wire.Edges
                if l0 < l1:
                    edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[0])))
                    edges.extend(offset.Edges)
                    edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[1])))
                else:
                    edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
                    edges.extend(offset.Edges)
                    edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))

                return Part.Wire(edges)
    return None
Example #11
0
 def map_shape(self, shape, quad, face, fillfaces=False):
     if not isinstance(shape, Part.Shape):
         return []
     #proj = quad.project(shape.Edges)
     new_edges = []
     for oe in shape.Edges:
         if True:
             e = quad.project([oe]).Edges[0]
             c2d, fp, lp = quad.curveOnSurface(e)
             if oe.isClosed() and not c2d.isClosed():
                 self.force_closed_bspline2d(c2d)
             ne = c2d.toShape(face.Surface, fp,
                              lp)  # toShape produces 1e-5 tolerance
             #debug(ne.Placement)
             #debug(face.Placement)
             #ne.Placement = face.Placement
             vt = ne.getTolerance(1, Part.Vertex)
             et = ne.getTolerance(1, Part.Edge)
             if vt < et:
                 ne.fixTolerance(et, Part.Vertex)
                 #debug("fixing tolerance : {0:e} -> {1:e}".format(vt,et))
             new_edges.append(ne)
         else:  #except TypeError:
             error("Failed to get 2D curve")
     sorted_edges = Part.sortEdges(new_edges)
     wirelist = [Part.Wire(el) for el in sorted_edges]
     if fillfaces:
         return self.build_faces(wirelist, face)
     else:
         return wirelist
Example #12
0
    def getWire(self):
        PathLog.track()
        if PathGeom.isRoughly(0, self.length.Value) or not self.sub:
            PathLog.debug("no extension, length=%.2f, sub=%s" % (self.length.Value, self.sub))
            return None

        feature = self.obj.Shape.getElement(self.feature)
        edges = self._getEdges()
        sub = Part.Wire(Part.sortEdges(edges)[0])

        if 1 == len(edges):
            PathLog.debug("Extending single edge wire")
            edge = edges[0]
            if Part.Circle == type(edge.Curve):
                circle = edge.Curve
                # for a circle we have to figure out if it's a hole or a cylinder
                p0 = edge.valueAt(edge.FirstParameter)
                normal = (edge.Curve.Center - p0).normalize()
                direction = self._getDirectedNormal(p0, normal)
                if direction is None:
                    return None

                if PathGeom.pointsCoincide(normal, direction):
                    r = circle.Radius - self.length.Value
                else:
                    r = circle.Radius + self.length.Value

                # assuming the offset produces a valid circle - go for it
                if r > 0:
                    e3 = Part.makeCircle(r, circle.Center, circle.Axis, edge.FirstParameter * 180 / math.pi, edge.LastParameter * 180 / math.pi)
                    if endPoints(edge):
                        # need to construct the arc slice
                        e0 = Part.makeLine(edge.valueAt(edge.FirstParameter), e3.valueAt(e3.FirstParameter))
                        e2 = Part.makeLine(edge.valueAt(edge.LastParameter), e3.valueAt(e3.LastParameter))
                        return Part.Wire([e0, edge, e2, e3])

                    return Part.Wire([e3])

                # the extension is bigger than the hole - so let's just cover the whole hole
                if endPoints(edge):
                    # if the resulting arc is smaller than the radius, create a pie slice
                    PathLog.track()
                    center = circle.Center
                    e0 = Part.makeLine(center, edge.valueAt(edge.FirstParameter))
                    e2 = Part.makeLine(edge.valueAt(edge.LastParameter), center)
                    return Part.Wire([e0, edge, e2])

                PathLog.track()
                return Part.Wire([edge])

            else:
                PathLog.track(self.feature, self.sub, type(edge.Curve), endPoints(edge))
                direction = self._getDirection(sub)
                if direction is None:
                    return None

            #    return self._extendEdge(feature, edge, direction)
            return self._extendEdge(feature, edges[0], direction)

        return extendWire(feature, sub, self.length.Value)
Example #13
0
def mergeWires(list_of_edges_wires, flag_single = False, split_connections = []):
    edges = []
    for sh in list_of_edges_wires:
        edges.extend(sh.Edges)
    if flag_single:
        return Part.Wire(edges)
    else:
        groups = splitIntoGroupsBySharing(edges, lambda sh: sh.Vertexes, split_connections)
        return Part.makeCompound([Part.Wire(Part.sortEdges(group)[0]) for group in groups])
Example #14
0
def mergeWires(list_of_edges_wires, flag_single = False, split_connections = []):
    edges = []
    for sh in list_of_edges_wires:
        edges.extend(sh.Edges)
    if flag_single:
        return Part.Wire(edges)
    else:
        groups = splitIntoGroupsBySharing(edges, lambda sh: sh.Vertexes, split_connections)
        return Part.makeCompound([Part.Wire(Part.sortEdges(group)[0]) for group in groups])
Example #15
0
    def opExecute(self, obj):
        '''opExecute(obj) ... process engraving operation'''
        PathLog.track()

        jobshapes = []

        if len(obj.Base) >= 1:  # user has selected specific subelements
            wires = []
            for base, subs in obj.Base:
                edges = []
                basewires = []
                for feature in subs:
                    sub = base.Shape.getElement(feature)
                    if type(sub) == Part.Edge:
                        edges.append(sub)
                    elif sub.Wires:
                        basewires.extend(sub.Wires)
                    else:
                        basewires.append(Part.Wire(sub.Edges))

                for edgelist in Part.sortEdges(edges):
                    basewires.append(Part.Wire(edgelist))

                wires.extend(basewires)
                jobshapes.append(Part.makeCompound(wires))

        else:  # Use the Job Base object
            for base in self.model:
                PathLog.track(base.Label)
                if base.isDerivedFrom('Part::Part2DObject'):
                    jobshapes.append(base.Shape)
                elif base.isDerivedFrom('Sketcher::SketchObject'):
                    jobshapes.append(base.Shape)
                elif hasattr(base, 'ArrayType'):
                    jobshapes.append(base.Shape)
                elif isinstance(base.Proxy, ArchPanel.PanelSheet):
                    for tag in self.model[0].Proxy.getTags(self.model[0], transform=True):
                        tagWires = []
                        for w in tag.Wires:
                            tagWires.append(Part.Wire(w.Edges))
                        jobshapes.append(Part.makeCompound(tagWires))

        if len(jobshapes) > 0:
            PathLog.debug('processing {} jobshapes'.format(len(jobshapes)))
            PathLog.track()
            wires = []
            for shape in jobshapes:
                PathLog.debug('jobshape has {} edges'.format(len(shape.Edges)))
                self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
                shapeWires = shape.Wires
                self.buildpathocc(obj, shape.Wires, self.getZValues(obj))
                wires.extend(shapeWires)
            self.wires = wires
        # the last command is a move to clearance, which is automatically added by PathOp
        if self.commandlist:
            self.commandlist.pop()
Example #16
0
    def opExecute(self, obj):
        PathLog.track(obj.Label)
        (depth, offset) = toolDepthAndOffset(obj.Width.Value,
                                             obj.ExtraDepth.Value, self.tool)
        PathLog.track(obj.Label, depth, offset)

        self.basewires = []  # pylint: disable=attribute-defined-outside-init
        self.adjusted_basewires = []  # pylint: disable=attribute-defined-outside-init
        wires = []
        for base, subs in obj.Base:
            edges = []
            basewires = []
            for f in subs:
                sub = base.Shape.getElement(f)
                if type(sub) == Part.Edge:
                    edges.append(sub)
                elif sub.Wires:
                    basewires.extend(sub.Wires)
                else:
                    basewires.append(Part.Wire(sub.Edges))
            self.edges = edges  # pylint: disable=attribute-defined-outside-init
            for edgelist in Part.sortEdges(edges):
                basewires.append(Part.Wire(edgelist))

            self.basewires.extend(basewires)

            for w in basewires:
                self.adjusted_basewires.append(w)
                wire = PathOpTools.offsetWire(w, base.Shape, offset, True)
                if wire:
                    wires.append(wire)

        forward = True
        if obj.Direction == 'CCW':
            forward = False

        zValues = []
        z = 0
        if obj.StepDown.Value != 0:
            while z + obj.StepDown.Value < depth:
                z = z + obj.StepDown.Value
                zValues.append(z)
        zValues.append(depth)
        PathLog.track(obj.Label, depth, zValues)

        self.wires = wires  # pylint: disable=attribute-defined-outside-init
        self.buildpathocc(obj, wires, zValues, True, forward)

        # the last command is a move to clearance, which is automatically added by PathOp
        if self.commandlist:
            self.commandlist.pop()
Example #17
0
 def execute(self, obj):
     edges = []
     for g in obj.Geometry:
         if hasattr(g, 'Construction') and not g.Construction:
             #try:
             edges.append(g.toShape())
             #except AttributeError:
             #debug("Failed to convert %s to BSpline"%str(g))
     if edges:
         c = Part.Compound([])
         se = Part.sortEdges(edges)
         for l in se:
             c.add(Part.Wire(l))
         obj.Shape = c
Example #18
0
    def createItemForBaseModel(self, base, sub, edges, extensions):
        PathLog.track()
        ext = _Extension(self.obj, base, sub, None)
        item = QtGui.QStandardItem()
        item.setData(sub, QtCore.Qt.EditRole)
        item.setData(ext, self.DataObject)
        item.setSelectable(False)

        extendCorners = self.form.extendCorners.isChecked()

        def createSubItem(label, ext0):
            self.switch.addChild(ext0.root)
            item0 = QtGui.QStandardItem()
            item0.setData(label, QtCore.Qt.EditRole)
            item0.setData(ext0, self.DataObject)
            item0.setCheckable(True)
            for e in extensions:
                if e.obj == base and e.sub == label:
                    item0.setCheckState(QtCore.Qt.Checked)
                    ext0.enable()
                    break
            item.appendRow([item0])

        extensionEdges = {}
        for edge in base.Shape.getElement(sub).Edges:
            for (e, label) in edges:
                if edge.isSame(e):
                    ext0 = _Extension(self.obj, base, sub, label)
                    if ext0.isValid():
                        extensionEdges[e] = label[4:]
                        if not extendCorners:
                            createSubItem(label, ext0)
                    break

        if extendCorners:
            def edgesMatchShape(e0, e1):
                return PathGeom.edgesMatch(e0, e1) or PathGeom.edgesMatch(e0, PathGeom.flipEdge(e1))

            self.extensionEdges = extensionEdges # pylint: disable=attribute-defined-outside-init
            for edgeList in Part.sortEdges(list(extensionEdges.keys())):
                self.edgeList = edgeList # pylint: disable=attribute-defined-outside-init
                if len(edgeList) == 1:
                    label = "Edge%s" % [extensionEdges[keyEdge] for keyEdge in extensionEdges.keys() if edgesMatchShape(keyEdge, edgeList[0])][0]
                else:
                    label = "Wire(%s)" % ','.join(sorted([extensionEdges[keyEdge] for e in edgeList for keyEdge in extensionEdges.keys() if edgesMatchShape(e, keyEdge)], key=lambda s: int(s))) # pylint: disable=unnecessary-lambda
                ext0 = _Extension(self.obj, base, sub, label)
                createSubItem(label, ext0)

        return item
Example #19
0
def parse(pathobj):
    """accepts a Path object.  Returns a list of wires"""

    feedcommands = PathGeom.CmdMove
    rapidcommands = PathGeom.CmdMoveRapid

    edges = []
    objlist = []

    # Gotta start somewhere.  Assume 0,0,0
    curPoint = FreeCAD.Vector(0, 0, 0)
    for c in pathobj.Path.Commands:
        PathLog.debug("{} -> {}".format(curPoint, c))
        if "Z" in c.Parameters:
            newparams = c.Parameters
            newparams.pop("Z", None)
            flatcommand = Path.Command(c.Name, newparams)
            c.Parameters = newparams
        else:
            flatcommand = c

        # ignore gcode that isn't moving
        if flatcommand.Name not in feedcommands + rapidcommands:
            PathLog.debug("non move")
            continue

        # ignore pure vertical feed and rapid
        if (flatcommand.Parameters.get("X", curPoint.x) == curPoint.x
                and flatcommand.Parameters.get("Y", curPoint.y) == curPoint.y):
            PathLog.debug("vertical")
            continue

        # feeding move.  Build an edge
        if flatcommand.Name in feedcommands:
            edges.append(PathGeom.edgeForCmd(flatcommand, curPoint))
            PathLog.debug("feeding move")

        # update the curpoint
        curPoint.x = flatcommand.Parameters.get("X", curPoint.x)
        curPoint.y = flatcommand.Parameters.get("Y", curPoint.y)

    if len(edges) > 0:
        candidates = Part.sortEdges(edges)
        for c in candidates:
            obj = FreeCAD.ActiveDocument.addObject("Part::Feature", "Wire")
            obj.Shape = Part.Wire(c)
            objlist.append(obj)

    return objlist
Example #20
0
 def shape(self):
     proj1 = self.shape1.toNurbs().extrude(self.dir1)
     proj2 = self.shape2.toNurbs().extrude(self.dir2)
     curves = list()
     for f1 in proj1.Faces:
         for f2 in proj2.Faces:
             curves += f1.Surface.intersectSS(f2.Surface)
     intersect = [c.toShape() for c in curves]
     edges = []
     for sh in intersect:
         if isinstance(sh, Part.Edge) and sh.Length > 1e-7:
             edges.append(sh)
     se = Part.sortEdges(edges)
     wires = []
     for el in se:
         wires.append(Part.Wire(el))
     return Part.Compound(wires)
Example #21
0
    def opExecute(self, obj):
        PathLog.track(obj.Label)
        (depth, offset) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool)
        PathLog.track(obj.Label, depth, offset)

        self.basewires = []
        self.adjusted_basewires = []
        wires = []
        for base, subs in obj.Base:
            edges = []
            basewires = []
            for f in subs:
                sub = base.Shape.getElement(f)
                if type(sub) == Part.Edge:
                    edges.append(sub)
                elif sub.Wires:
                    basewires.extend(sub.Wires)
                else:
                    basewires.append(Part.Wire(sub.Edges))
            self.edges = edges
            for edgelist in Part.sortEdges(edges):
                basewires.append(Part.Wire(edgelist))

            self.basewires.extend(basewires)

            for w in basewires:
                self.adjusted_basewires.append(w)
                wire = PathOpTools.offsetWire(w, base.Shape, offset, True)
                if wire:
                    wires.append(wire)

        zValues = []
        z = 0
        if obj.StepDown.Value != 0:
            while z + obj.StepDown.Value < depth:
                z = z + obj.StepDown.Value
                zValues.append(z)
        zValues.append(depth)
        PathLog.track(obj.Label, depth, zValues)

        self.wires = wires
        self.buildpathocc(obj, wires, zValues, True)

        # the last command is a move to clearance, which is automatically added by PathOp
        if self.commandlist:
            self.commandlist.pop()
 def approximate(self, obj, input_shape):
     pts = False
     input_edges = None
     if isinstance(input_shape, (list, tuple)):
         #debug(isinstance(input_shape[0],Base.Vector))
         if isinstance(input_shape[0], Base.Vector):
             pts = input_shape
         elif isinstance(input_shape[0], Part.Edge):
             input_edges = input_shape
     else:
         input_edges = input_shape.Edges
     if not obj.Active:
         return Part.Compound(input_shape)
     edges = list()
     if input_edges:
         for e in input_edges:
             pts = e.discretize(obj.Samples)
             bs = Part.BSplineCurve()
             bs.approximate(Points=pts,
                            DegMin=obj.DegreeMin,
                            DegMax=obj.DegreeMax,
                            Tolerance=obj.ApproxTolerance,
                            Continuity=obj.Continuity,
                            ParamType=obj.Parametrization)
             edges.append(bs.toShape())
         se = Part.sortEdges(edges)
         wires = []
         for el in se:
             if len(el) > 1:
                 wires.append(Part.Wire(el))
             else:
                 wires.append(el[0])
         if len(wires) > 1:
             return Part.Compound(wires)
         else:
             return wires[0]
     elif pts:
         bs = Part.BSplineCurve()
         bs.approximate(Points=pts,
                        DegMin=obj.DegreeMin,
                        DegMax=obj.DegreeMax,
                        Tolerance=obj.ApproxTolerance,
                        Continuity=obj.Continuity,
                        ParamType=obj.Parametrization)
         return bs.toShape()
    def execute(self, obj):

        # discretizza gli elementi che compongono il bordo separatamente (dopo averli ordinati)
        points = []
        # Ordino le Edges, utile per evitare problemi con le sezioni che spesso hanno le edges disordinate
        Edges = Part.sortEdges(obj.Wire.Shape.Edges)[0]
        for edges in Edges:
            # aggiungo i punti escluso l'ultimo
            if (points != []):
                points.pop()  # elimino l'ultimo punto se la lista non è vuota
            for e in (edges.discretize(Deflection=obj.Deflection)):
                points.append(e)

        # Creo la BSpline
        bspline = Part.BSplineCurve()
        bspline.interpolate(points)

        # creo la Shape
        obj.Shape = bspline.toShape()
Example #24
0
def join_multi_edges(edgelist,closed=False):
    good_edges = list()
    last = edgelist[0]
    remaining = edgelist[1:]
    res = []
    while len(remaining) > 0:
        rejected = list()
        closest_dist = 1e50
        closest_edge = None
    #    closest_pts = None
    #    closest_info = None
        for e in remaining:
            d,p,i = e.distToShape(last)
            if  closest_dist > d:
                closest_dist = d
                if closest_edge:
                    rejected.append(closest_edge)
                closest_edge = e
    #            closest_pts  = p
    #            closest_info = i
            else:
                rejected.append(e)
    
        res = join_2_edges(last,closest_edge)
        #print(last,closest_edge,res)
        last = res[-1]
        good_edges.extend(res[:-1])
        remaining = rejected
    if res:
        good_edges.append(res[-1])
    se = Part.sortEdges(good_edges)
    wires = list()
    for group in se:
        print("Wire has %d edges"%len(group))
        wires.append(Part.Wire(group))
    if closed:
        for w in wires:
            if not w.isClosed():
                ov = w.OrderedVertexes
                d,p,i = ov[0].distToShape(ov[-1])
                w.add(Part.makeLine(p[0][0],p[0][1]))
    return(Part.Compound(wires))
Example #25
0
def join_multi_edges(edgelist, closed=False):
    good_edges = list()
    last = edgelist[0]
    remaining = edgelist[1:]
    res = []
    while len(remaining) > 0:
        rejected = list()
        closest_dist = 1e50
        closest_edge = None
        #    closest_pts = None
        #    closest_info = None
        for e in remaining:
            d, p, i = e.distToShape(last)
            if closest_dist > d:
                closest_dist = d
                if closest_edge:
                    rejected.append(closest_edge)
                closest_edge = e
    #            closest_pts  = p
    #            closest_info = i
            else:
                rejected.append(e)

        res = join_2_edges(last, closest_edge)
        #print(last.distToShape(closest_edge))
        last = res[-1]
        good_edges.extend(res[:-1])
        remaining = rejected
    if res:
        good_edges.append(res[-1])
    se = Part.sortEdges(good_edges)
    wires = list()
    for group in se:
        print("Wire has %d edges" % len(group))
        wires.append(Part.Wire(group))
    if closed:
        for w in wires:
            if not w.isClosed():
                ov = w.OrderedVertexes
                d, p, i = ov[0].distToShape(ov[-1])
                w.add(Part.makeLine(p[0][0], p[0][1]))
    return Part.Compound(wires)
Example #26
0
def extendWire(feature, wire, length):
    '''extendWire(wire, length) ... return a closed Wire which extends wire by length'''
    off2D = wire.makeOffset2D(length)
    endPts = endPoints(wire)
    edges = [e for e in off2D.Edges if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts)]
    wires = [Part.Wire(e) for e in Part.sortEdges(edges)]
    offset = selectOffsetWire(feature, wires)
    ePts = endPoints(offset)
    l0 = (ePts[0] - endPts[0]).Length
    l1 = (ePts[1] - endPts[0]).Length
    edges = wire.Edges
    if l0 < l1:
        edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[0])))
        edges.extend(offset.Edges)
        edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[1])))
    else:
        edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
        edges.extend(offset.Edges)
        edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))
    return Part.Wire(edges)
Example #27
0
 def sweep_wire(self, w, solid=False):
     faces = []
     for e in w.Edges:
         faces.append(self.sweep_edge(e, solid))
     shell = Part.Shell(faces)
     shell.sewShape()
     if solid:
         cyl = Part.makeCylinder(self.max_radius * 2,
                                 self.nb_of_turns * self.lead)
         cyl.Placement = self._placement.multiply(
             FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Vector(1, 0, 0),
                               -90))
         common = cyl.common(shell)
         cut_faces = common.Faces
         new_edges = []
         for e1 in common.Edges:
             found = False
             for e2 in shell.Edges:
                 if nurbs_tools.is_same(e1.Curve,
                                        e2.Curve,
                                        tol=1e-7,
                                        full=False):
                     found = True
                     #print("found similar edges")
                     continue
             if not found:
                 new_edges.append(e1)
         #print(len(Part.sortEdges(new_edges)))
         el1, el2 = Part.sortEdges(new_edges)[0:2]
         f1 = Part.makeFace(Part.Wire(el1), 'Part::FaceMakerSimple')
         f2 = Part.makeFace(Part.Wire(el2), 'Part::FaceMakerSimple')
         cut_faces.extend([f1, f2])
         try:
             shell = Part.Shell(cut_faces)
             shell.sewShape()
             return Part.Solid(shell)
         except Part.OCCError:
             print("Failed to create solid")
             return Part.Compound(cut_faces)
     return shell
Example #28
0
    def execute(self, obj):
        debug("* trimFace execute *")
        if not obj.Tool:
            debug("No tool")
            return
        if not obj.PickedPoint:
            debug("No PickedPoint")
            return
        if not obj.Face:
            debug("No Face")
            return
        if not (obj.DirVector or obj.Direction):
            debug("No Direction")
            return

        face = self.getFace(obj.Face)
        v = self.getVector(obj)
        v.normalize()
        debug("Vector : {}".format(str(v)))
        wires = [
            Part.Wire(el) for el in Part.sortEdges(self.getEdges(obj.Tool))
        ]
        union = Part.Compound(wires + [face])
        d = 2 * union.BoundBox.DiagonalLength
        cuttool = []
        for w in wires:
            w.translate(v * d)
            cuttool.append(w.extrude(-v * d * 2))
        # Part.show(cuttool)

        bf = splitAPI.slice(face, cuttool, "Split", 1e-6)
        debug("shape has {} faces".format(len(bf.Faces)))

        u = obj.PickedPoint.x
        v = obj.PickedPoint.y
        for f in bf.Faces:
            if f.isPartOfDomain(u, v):
                obj.Shape = f
                return
Example #29
0
def extendWire(feature, wire, length):
    """extendWire(wire, length) ... return a closed Wire which extends wire by length"""
    PathLog.track(length)

    if not length or length == 0:
        return None

    try:
        off2D = wire.makeOffset2D(length)
    except FreeCAD.Base.FreeCADError as ee:
        PathLog.debug(ee)
        return None
    endPts = endPoints(wire)  # Assumes wire is NOT closed
    if endPts:
        edges = [
            e
            for e in off2D.Edges
            if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts)
        ]
        wires = [Part.Wire(e) for e in Part.sortEdges(edges)]
        offset = selectOffsetWire(feature, wires)
        ePts = endPoints(offset)
        if ePts and len(ePts) > 1:
            l0 = (ePts[0] - endPts[0]).Length
            l1 = (ePts[1] - endPts[0]).Length
            edges = wire.Edges
            if l0 < l1:
                edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[0])))
                edges.extend(offset.Edges)
                edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[1])))
            else:
                edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0])))
                edges.extend(offset.Edges)
                edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1])))

            return Part.Wire(edges)

    return None
Example #30
0
    def opExecute(self, obj):
        '''opExecute(obj) ... process engraving operation'''
        PathLog.track()

        job = PathUtils.findParentJob(obj)

        jobshapes = []
        zValues = self.getZValues(obj)

        try:
            if len(self.model) == 1 and self.model[0].isDerivedFrom('Sketcher::SketchObject') or \
                    self.model[0].isDerivedFrom('Part::Part2DObject') or \
                    hasattr(self.model[0], 'ArrayType'):
                PathLog.track()

                self.commandlist.append(
                    Path.Command('G0', {
                        'Z': obj.ClearanceHeight.Value,
                        'F': self.vertRapid
                    }))

                # we only consider the outer wire if this is a Face
                wires = []
                for w in self.model[0].Shape.Wires:
                    wires.append(Part.Wire(w.Edges))
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires

            elif len(self.model) == 1 and isinstance(
                    self.model[0].Proxy,
                    ArchPanel.PanelSheet):  # process the sheet
                PathLog.track()
                wires = []
                for tag in self.model[0].Proxy.getTags(self.model[0],
                                                       transform=True):
                    self.commandlist.append(
                        Path.Command('G0', {
                            'Z': obj.ClearanceHeight.Value,
                            'F': self.vertRapid
                        }))
                    tagWires = []
                    for w in tag.Wires:
                        tagWires.append(Part.Wire(w.Edges))
                    self.buildpathocc(obj, tagWires, zValues)
                    wires.extend(tagWires)
                self.wires = wires
            elif obj.Base:
                PathLog.track()
                wires = []
                for base, subs in obj.Base:
                    edges = []
                    basewires = []
                    for feature in subs:
                        sub = base.Shape.getElement(feature)
                        if type(sub) == Part.Edge:
                            edges.append(sub)
                        elif sub.Wires:
                            basewires.extend(sub.Wires)
                        else:
                            basewires.append(Part.Wire(sub.Edges))

                    for edgelist in Part.sortEdges(edges):
                        basewires.append(Part.Wire(edgelist))

                    wires.extend(basewires)
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires
            elif not obj.BaseShapes:
                PathLog.track()
                if not obj.Base and not obj.BaseShapes:
                    for base in self.model:
                        PathLog.track(base.Label)
                        if base.isDerivedFrom('Part::Part2DObject'):
                            jobshapes.append(base)

                if not jobshapes:
                    raise ValueError(
                        translate(
                            'PathEngrave',
                            "Unknown baseobject type for engraving (%s)") %
                        (obj.Base))

            if obj.BaseShapes or jobshapes:
                PathLog.track()
                wires = []
                for shape in obj.BaseShapes + jobshapes:
                    PathLog.track(shape.Label)
                    shapeWires = shape.Shape.Wires
                    self.buildpathocc(obj, shapeWires, zValues)
                    wires.extend(shapeWires)
                self.wires = wires
            # the last command is a move to clearance, which is automatically added by PathOp
            if self.commandlist:
                self.commandlist.pop()

        except Exception as e:
            PathLog.error(e)
            traceback.print_exc()
            PathLog.error(
                translate(
                    'PathEngrave',
                    'The Job Base Object has no engraveable element.  Engraving operation will produce no output.'
                ))
Example #31
0
    def getPath(edges=[], wires=[], pathname=None):

        svg = "<path "
        if pathname is None:
            svg += 'id="%s" ' % obj.Name
        elif pathname != "":
            svg += 'id="%s" ' % pathname
        svg += ' d="'
        if not wires:
            egroups = Part.sortEdges(edges)
        else:
            egroups = []
            first = True
            for w in wires:
                w1 = w.copy()
                if first:
                    first = False
                else:
                    # invert further wires to create holes
                    w1 = DraftGeomUtils.invert(w1)
                w1.fixWire()
                egroups.append(Part.__sortEdges__(w1.Edges))
        for egroupindex, edges in enumerate(egroups):
            edata = ""
            vs = ()  #skipped for the first edge
            for edgeindex, e in enumerate(edges):
                previousvs = vs
                # vertexes of an edge (reversed if needed)
                vs = e.Vertexes
                if previousvs:
                    if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
                        vs.reverse()
                if edgeindex == 0:
                    v = getProj(vs[0].Point, plane)
                    edata += 'M ' + str(v.x) + ' ' + str(v.y) + ' '
                else:
                    if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
                        raise ValueError('edges not ordered')
                iscircle = DraftGeomUtils.geomType(e) == "Circle"
                isellipse = DraftGeomUtils.geomType(e) == "Ellipse"
                if iscircle or isellipse:
                    import math
                    if hasattr(FreeCAD, "DraftWorkingPlane"):
                        drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
                    else:
                        drawing_plane_normal = FreeCAD.Vector(0, 0, 1)
                    if plane: drawing_plane_normal = plane.axis
                    c = e.Curve
                    if round(c.Axis.getAngle(drawing_plane_normal),
                             2) in [0, 3.14]:
                        occversion = Part.OCC_VERSION.split(".")
                        done = False
                        if (int(occversion[0]) >= 7) and (int(occversion[1]) >=
                                                          1):
                            # if using occ >= 7.1, use HLR algorithm
                            import Drawing
                            snip = Drawing.projectToSVG(
                                e, drawing_plane_normal)
                            if snip:
                                try:
                                    a = "A " + snip.split("path d=\"")[
                                        1].split("\"")[0].split("A")[1]
                                except:
                                    pass
                                else:
                                    edata += a
                                    done = True
                        if not done:
                            if len(e.Vertexes
                                   ) == 1 and iscircle:  #complete curve
                                svg = getCircle(e)
                                return svg
                            elif len(e.Vertexes) == 1 and isellipse:
                                #svg = getEllipse(e)
                                #return svg
                                endpoints = [
                                    getProj(
                                        c.value((c.LastParameter -
                                                 c.FirstParameter) / 2.0),
                                        plane),
                                    getProj(vs[-1].Point, plane)
                                ]
                            else:
                                endpoints = [getProj(vs[-1].Point, plane)]
                            # arc
                            if iscircle:
                                rx = ry = c.Radius
                                rot = 0
                            else:  #ellipse
                                rx = c.MajorRadius
                                ry = c.MinorRadius
                                rot = math.degrees(c.AngleXU * (c.Axis * \
                                    FreeCAD.Vector(0,0,1)))
                                if rot > 90:
                                    rot -= 180
                                if rot < -90:
                                    rot += 180
                                #be careful with the sweep flag
                            flag_large_arc = (((e.ParameterRange[1] - \
                                    e.ParameterRange[0]) / math.pi) % 2) > 1
                            #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \
                            #         == (e.LastParameter > e.FirstParameter)
                            #        == (e.Orientation == "Forward")
                            # other method: check the direction of the angle between tangents
                            t1 = e.tangentAt(e.FirstParameter)
                            t2 = e.tangentAt(
                                e.FirstParameter +
                                (e.LastParameter - e.FirstParameter) / 10)
                            flag_sweep = (DraftVecUtils.angle(
                                t1, t2, drawing_plane_normal) < 0)
                            for v in endpoints:
                                edata += 'A %s %s %s %s %s %s %s ' % \
                                        (str(rx),str(ry),str(rot),\
                                        str(int(flag_large_arc)),\
                                        str(int(flag_sweep)),str(v.x),str(v.y))
                    else:
                        edata += getDiscretized(e, plane)
                elif DraftGeomUtils.geomType(e) == "Line":
                    v = getProj(vs[-1].Point, plane)
                    edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
                else:
                    bspline = e.Curve.toBSpline(e.FirstParameter,
                                                e.LastParameter)
                    if bspline.Degree > 3 or bspline.isRational():
                        try:
                            bspline = bspline.approximateBSpline(
                                0.05, 50, 3, 'C0')
                        except RuntimeError:
                            print("Debug: unable to approximate bspline")
                    if bspline.Degree <= 3 and not bspline.isRational():
                        for bezierseg in bspline.toBezier():
                            if bezierseg.Degree > 3:  #should not happen
                                raise AssertionError
                            elif bezierseg.Degree == 1:
                                edata += 'L '
                            elif bezierseg.Degree == 2:
                                edata += 'Q '
                            elif bezierseg.Degree == 3:
                                edata += 'C '
                            for pole in bezierseg.getPoles()[1:]:
                                v = getProj(pole, plane)
                                edata += str(v.x) + ' ' + str(v.y) + ' '
                    else:
                        print("Debug: one edge (hash ",e.hashCode(),\
                                ") has been discretized with parameter 0.1")
                        for linepoint in bspline.discretize(0.1)[1:]:
                            v = getProj(linepoint, plane)
                            edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
            if fill != 'none':
                edata += 'Z '
            if edata in pathdata:
                # do not draw a path on another identical path
                return ""
            else:
                svg += edata
                pathdata.append(edata)
        svg += '" '
        svg += 'stroke="' + stroke + '" '
        svg += 'stroke-width="' + str(linewidth) + ' px" '
        svg += 'style="stroke-width:' + str(linewidth)
        svg += ';stroke-miterlimit:4'
        svg += ';stroke-dasharray:' + lstyle
        svg += ';fill:' + fill
        try:
            svg += ';fill-opacity:' + str(fill_opacity)
        except NameError:
            pass
        svg += ';fill-rule: evenodd "'
        svg += '/>\n'
        return svg
Example #32
0
    def opExecute(self, obj):
        '''opExecute(obj) ... process engraving operation'''
        PathLog.track()

        job = PathUtils.findParentJob(obj)

        jobshapes = []
        zValues = self.getZValues(obj)

        try:
            if len(self.model) == 1 and self.model[0].isDerivedFrom('Sketcher::SketchObject') or \
                    self.model[0].isDerivedFrom('Part::Part2DObject') or \
                    hasattr(self.model[0], 'ArrayType'):
                PathLog.track()

                self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))

                # we only consider the outer wire if this is a Face
                wires = []
                for w in self.model[0].Shape.Wires:
                    wires.append(Part.Wire(w.Edges))
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires

            elif len(self.model) == 1 and isinstance(self.model[0].Proxy, ArchPanel.PanelSheet):  # process the sheet
                PathLog.track()
                wires = []
                for tag in self.model[0].Proxy.getTags(self.model[0], transform=True):
                    self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
                    tagWires = []
                    for w in tag.Wires:
                        tagWires.append(Part.Wire(w.Edges))
                    self.buildpathocc(obj, tagWires, zValues)
                    wires.extend(tagWires)
                self.wires = wires
            elif obj.Base:
                PathLog.track()
                wires = []
                for base, subs in obj.Base:
                    edges = []
                    basewires = []
                    for feature in subs:
                        sub = base.Shape.getElement(feature)
                        if type(sub) == Part.Edge:
                            edges.append(sub)
                        elif sub.Wires:
                            basewires.extend(sub.Wires)
                        else:
                            basewires.append(Part.Wire(sub.Edges))

                    for edgelist in Part.sortEdges(edges):
                        basewires.append(Part.Wire(edgelist))

                    wires.extend(basewires)
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires
            elif not obj.BaseShapes:
                PathLog.track()
                if not obj.Base and not obj.BaseShapes:
                    for base in self.model:
                        PathLog.track(base.Label)
                        if base.isDerivedFrom('Part::Part2DObject'):
                            jobshapes.append(base)

                if not jobshapes:
                    raise ValueError(translate('PathEngrave', "Unknown baseobject type for engraving (%s)") % (obj.Base))

            if obj.BaseShapes or jobshapes:
                PathLog.track()
                wires = []
                for shape in obj.BaseShapes + jobshapes:
                    PathLog.track(shape.Label)
                    shapeWires = shape.Shape.Wires
                    self.buildpathocc(obj, shapeWires, zValues)
                    wires.extend(shapeWires)
                self.wires = wires
            # the last command is a move to clearance, which is automatically added by PathOp
            if self.commandlist:
                self.commandlist.pop()

        except Exception as e:
            PathLog.error(e)
            traceback.print_exc()
            PathLog.error(translate('PathEngrave', 'The Job Base Object has no engraveable element.  Engraving operation will produce no output.'))
Example #33
0
    def getExtrusionData(self,obj):

        """returns (shape,extrusion vector,placement) or None"""
        import Part,DraftGeomUtils
        data = ArchComponent.Component.getExtrusionData(self,obj)
        if data:
            if not isinstance(data[0],list):
                # multifuses not considered here
                return data
        length  = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        if not height:
            for p in obj.InList:
                if Draft.getType(p) in ["Floor","BuildingPart"]:
                    if p.Height.Value:
                        height = p.Height.Value
        if not height:
            return None
        if obj.Normal == Vector(0,0,0):
            normal = Vector(0,0,1)
        else:
            normal = Vector(obj.Normal)
        base = None
        placement = None
        self.basewires = None
        # build wall layers
        layers = []
        if hasattr(obj,"Material"):
            if obj.Material:
                if hasattr(obj.Material,"Materials"):
                    varwidth = 0
                    restwidth = width - sum(obj.Material.Thicknesses)
                    if restwidth > 0:
                        varwidth = [t for t in obj.Material.Thicknesses if t == 0]
                        if varwidth:
                            varwidth = restwidth/len(varwidth)
                    for t in obj.Material.Thicknesses:
                        if t:
                            layers.append(t)
                        elif varwidth:
                            layers.append(varwidth)
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Base.Shape:
                    if obj.Base.Shape.Solids:
                        return None
                    elif obj.Face > 0:
                        if len(obj.Base.Shape.Faces) >= obj.Face:
                            face = obj.Base.Shape.Faces[obj.Face-1]
                            # this wall is based on a specific face of its base object
                            normal = face.normalAt(0,0)
                            if normal.getAngle(Vector(0,0,1)) > math.pi/4:
                                normal.multiply(width)
                                base = face.extrude(normal)
                                if obj.Align == "Center":
                                    base.translate(normal.negative().multiply(0.5))
                                elif obj.Align == "Right":
                                    base.translate(normal.negative())
                            else:
                                normal.multiply(height)
                                base = face.extrude(normal)
                            base,placement = self.rebase(base)
                            return (base,normal,placement)
                    elif obj.Base.Shape.Faces:
                        if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
                            return None
                        else:
                            base,placement = self.rebase(obj.Base.Shape)
                    elif len(obj.Base.Shape.Edges) == 1:
                        self.basewires = [Part.Wire(obj.Base.Shape.Edges)]
                    else:
                        # self.basewires = obj.Base.Shape.Wires
                        self.basewires = []
                        for cluster in Part.getSortedClusters(obj.Base.Shape.Edges):
                            for c in Part.sortEdges(cluster):
                                self.basewires.append(Part.Wire(c))

                    if self.basewires and width:
                        if (len(self.basewires) == 1) and layers:
                            self.basewires = [self.basewires[0] for l in layers]
                        layeroffset = 0
                        baseface = None
                        for i,wire in enumerate(self.basewires):
                            e = wire.Edges[0]
                            if isinstance(e.Curve,Part.Circle):
                                dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
                            else:
                                dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
                            if not DraftVecUtils.isNull(dvec):
                                dvec.normalize()
                            sh = None
                            if obj.Align == "Left":
                                off = obj.Offset.Value
                                if layers:
                                    off = off+layeroffset
                                    dvec.multiply(layers[i])
                                    layeroffset += layers[i]
                                else:
                                    dvec.multiply(width)
                                if off:
                                    dvec2 = DraftVecUtils.scaleTo(dvec,off)
                                    wire = DraftGeomUtils.offsetWire(wire,dvec2)
                                w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                                sh = DraftGeomUtils.bind(w1,w2)
                            elif obj.Align == "Right":
                                dvec = dvec.negative()
                                off = obj.Offset.Value
                                if layers:
                                    off = off+layeroffset
                                    dvec.multiply(layers[i])
                                    layeroffset += layers[i]
                                else:
                                    dvec.multiply(width)
                                if off:
                                    dvec2 = DraftVecUtils.scaleTo(dvec,off)
                                    wire = DraftGeomUtils.offsetWire(wire,dvec2)
                                w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                                sh = DraftGeomUtils.bind(w1,w2)
                            elif obj.Align == "Center":
                                if layers:
                                    off = width/2-layeroffset
                                    d1 = Vector(dvec).multiply(off)
                                    w1 = DraftGeomUtils.offsetWire(wire,d1)
                                    layeroffset += layers[i]
                                    off = width/2-layeroffset
                                    d1 = Vector(dvec).multiply(off)
                                    w2 = DraftGeomUtils.offsetWire(wire,d1)
                                else:
                                    dvec.multiply(width/2)
                                    w1 = DraftGeomUtils.offsetWire(wire,dvec)
                                    dvec = dvec.negative()
                                    w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                sh = DraftGeomUtils.bind(w1,w2)
                            if sh:
                                sh.fix(0.1,0,1) # fixes self-intersecting wires
                                f = Part.Face(sh)
                                if baseface:
                                    if layers:
                                        baseface.append(f)
                                    else:
                                        baseface = baseface.fuse(f)
                                        # baseface = baseface.removeSplitter()
                                        s = DraftGeomUtils.removeSplitter(baseface)
                                        if s:
                                            baseface = s
                                else:
                                    if layers:
                                        baseface = [f]
                                    else:
                                        baseface = f
                        if baseface:
                            base,placement = self.rebase(baseface)
        else:
            if layers:
                totalwidth = sum(layers)
                offset = 0
                base = []
                for l in layers:
                    l2 = length/2 or 0.5
                    w1 = -totalwidth/2 + offset
                    w2 = w1 + l
                    v1 = Vector(-l2,w1,0)
                    v2 = Vector(l2,w1,0)
                    v3 = Vector(l2,w2,0)
                    v4 = Vector(-l2,w2,0)
                    base.append(Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])))
                    offset += l
            else:
                l2 = length/2 or 0.5
                w2 = width/2 or 0.5
                v1 = Vector(-l2,-w2,0)
                v2 = Vector(l2,-w2,0)
                v3 = Vector(l2,w2,0)
                v4 = Vector(-l2,w2,0)
                base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
            placement = FreeCAD.Placement()
        if base and placement:
            extrusion = normal.multiply(height)
            return (base,extrusion,placement)
        return None
Example #34
0
    def getExtrusionData(self,obj):

        """returns (shape,extrusion vector,placement) or None"""
        import Part,DraftGeomUtils
        data = ArchComponent.Component.getExtrusionData(self,obj)
        if data:
            if not isinstance(data[0],list):
                # multifuses not considered here
                return data
        length  = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        if not height:
            for p in obj.InList:
                if Draft.getType(p) in ["Floor","BuildingPart"]:
                    if p.Height.Value:
                        height = p.Height.Value
        if not height:
            return None
        if obj.Normal == Vector(0,0,0):
            normal = Vector(0,0,1)
        else:
            normal = Vector(obj.Normal)
        base = None
        placement = None
        self.basewires = None
        # build wall layers
        layers = []
        if hasattr(obj,"Material"):
            if obj.Material:
                if hasattr(obj.Material,"Materials"):
                    varwidth = 0
                    restwidth = width - sum(obj.Material.Thicknesses)
                    if restwidth > 0:
                        varwidth = [t for t in obj.Material.Thicknesses if t == 0]
                        if varwidth:
                            varwidth = restwidth/len(varwidth)
                    for t in obj.Material.Thicknesses:
                        if t:
                            layers.append(t)
                        elif varwidth:
                            layers.append(varwidth)
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Base.Shape:
                    if obj.Base.Shape.Solids:
                        return None
                    elif obj.Face > 0:
                        if len(obj.Base.Shape.Faces) >= obj.Face:
                            face = obj.Base.Shape.Faces[obj.Face-1]
                            # this wall is based on a specific face of its base object
                            if obj.Normal != Vector(0,0,0):
                                normal = face.normalAt(0,0)
                            if normal.getAngle(Vector(0,0,1)) > math.pi/4:
                                normal.multiply(width)
                                base = face.extrude(normal)
                                if obj.Align == "Center":
                                    base.translate(normal.negative().multiply(0.5))
                                elif obj.Align == "Right":
                                    base.translate(normal.negative())
                            else:
                                normal.multiply(height)
                                base = face.extrude(normal)
                            base,placement = self.rebase(base)
                            return (base,normal,placement)
                    elif obj.Base.Shape.Faces:
                        if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
                            return None
                        else:
                            base,placement = self.rebase(obj.Base.Shape)
                    elif len(obj.Base.Shape.Edges) == 1:
                        self.basewires = [Part.Wire(obj.Base.Shape.Edges)]
                    else:
                        # self.basewires = obj.Base.Shape.Wires
                        self.basewires = []
                        for cluster in Part.getSortedClusters(obj.Base.Shape.Edges):
                            for c in Part.sortEdges(cluster):
                                self.basewires.append(Part.Wire(c))

                    if self.basewires and width:
                        if (len(self.basewires) == 1) and layers:
                            self.basewires = [self.basewires[0] for l in layers]
                        layeroffset = 0
                        baseface = None
                        for i,wire in enumerate(self.basewires):
                            e = wire.Edges[0]
                            if isinstance(e.Curve,Part.Circle):
                                dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
                            else:
                                dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
                            if not DraftVecUtils.isNull(dvec):
                                dvec.normalize()
                            sh = None
                            if obj.Align == "Left":
                                off = obj.Offset.Value
                                if layers:
                                    off = off+layeroffset
                                    dvec.multiply(layers[i])
                                    layeroffset += layers[i]
                                else:
                                    dvec.multiply(width)
                                if off:
                                    dvec2 = DraftVecUtils.scaleTo(dvec,off)
                                    wire = DraftGeomUtils.offsetWire(wire,dvec2)
                                w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                                sh = DraftGeomUtils.bind(w1,w2)
                            elif obj.Align == "Right":
                                dvec = dvec.negative()
                                off = obj.Offset.Value
                                if layers:
                                    off = off+layeroffset
                                    dvec.multiply(layers[i])
                                    layeroffset += layers[i]
                                else:
                                    dvec.multiply(width)
                                if off:
                                    dvec2 = DraftVecUtils.scaleTo(dvec,off)
                                    wire = DraftGeomUtils.offsetWire(wire,dvec2)
                                w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                                sh = DraftGeomUtils.bind(w1,w2)
                            elif obj.Align == "Center":
                                if layers:
                                    off = width/2-layeroffset
                                    d1 = Vector(dvec).multiply(off)
                                    w1 = DraftGeomUtils.offsetWire(wire,d1)
                                    layeroffset += layers[i]
                                    off = width/2-layeroffset
                                    d1 = Vector(dvec).multiply(off)
                                    w2 = DraftGeomUtils.offsetWire(wire,d1)
                                else:
                                    dvec.multiply(width/2)
                                    w1 = DraftGeomUtils.offsetWire(wire,dvec)
                                    dvec = dvec.negative()
                                    w2 = DraftGeomUtils.offsetWire(wire,dvec)
                                sh = DraftGeomUtils.bind(w1,w2)
                            if sh:
                                sh.fix(0.1,0,1) # fixes self-intersecting wires
                                f = Part.Face(sh)
                                if baseface:
                                    if layers:
                                        baseface.append(f)
                                    else:
                                        baseface = baseface.fuse(f)
                                        # baseface = baseface.removeSplitter()
                                        s = DraftGeomUtils.removeSplitter(baseface)
                                        if s:
                                            baseface = s
                                else:
                                    if layers:
                                        baseface = [f]
                                    else:
                                        baseface = f
                        if baseface:
                            base,placement = self.rebase(baseface)
        else:
            if layers:
                totalwidth = sum(layers)
                offset = 0
                base = []
                for l in layers:
                    l2 = length/2 or 0.5
                    w1 = -totalwidth/2 + offset
                    w2 = w1 + l
                    v1 = Vector(-l2,w1,0)
                    v2 = Vector(l2,w1,0)
                    v3 = Vector(l2,w2,0)
                    v4 = Vector(-l2,w2,0)
                    base.append(Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])))
                    offset += l
            else:
                l2 = length/2 or 0.5
                w2 = width/2 or 0.5
                v1 = Vector(-l2,-w2,0)
                v2 = Vector(l2,-w2,0)
                v3 = Vector(l2,w2,0)
                v4 = Vector(-l2,w2,0)
                base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
            placement = FreeCAD.Placement()
        if base and placement:
            extrusion = normal.multiply(height)
            if placement.Rotation.Angle > 0:
                extrusion = placement.inverse().Rotation.multVec(extrusion)
            return (base,extrusion,placement)
        return None
Example #35
0
def processExtrudedSketch(extrudeObj, sketchObj, xmlVol):
    from .exportGDML import insertXMLvolume, exportPosition, addVolRef, \
              quaternion2XYZ

    sortededges = Part.sortEdges(sketchObj.Shape.Edges)
    # sort by largest area to smallest area
    sortEdgelistsByBoundingBoxArea(sortededges)
    # getCurve returns one of the sub classes of ClosedCurve that
    # knows how to export the specifc closed edges
    # Make names based on Extrude name
    # curves = [getCurve(edges, extrudeObj.Label + str(i)) for i, edges in enumerate(sortededges)]
    if extrudeObj.Symmetric is True:
        height = extrudeObj.LengthFwd.Value
    else:
        height = extrudeObj.LengthFwd.Value + extrudeObj.LengthRev.Value
    eName = extrudeObj.Label
    # get a list of curves (instances of class ClosedCurve) for each set of closed edges
    curves = [
        getExtrudedCurve(eName + str(i), edges, height)
        for i, edges in enumerate(sortededges)
    ]
    # build a generalized binary tree of closed curves.
    root = Node(curves[0], None, 0)
    for c in curves[1:]:
        root.insert(c)

    # Traverse the tree. The list returned is a list of [Node, parity], where parity = 0, says add to parent, 1 mean subtract
    lst = root.preOrderTraversal(root)
    rootnode = lst[0][0]
    rootCurve = rootnode.closedCurve
    rootCurve.export()  # a curve is created with a unique name
    firstName = rootCurve.name
    booleanName = firstName

    rootPos = rootCurve.position
    rootRot = rootCurve.rotation  # for now consider only angle of rotation about z-axis

    for c in lst[1:]:
        node = c[0]
        parity = c[1]
        curve = node.closedCurve
        curve.export()
        if parity == 0:
            boolType = 'union'
            secondName = curve.name
            secondPos = curve.position
        else:
            boolType = 'subtraction'
            secondName = curve.name + '_s'  # scale solids along z, so it punches thru
            scaleUp(secondName, curve.name, 1.10)
            secondPos = curve.position - Vector(0, 0, 0.01 * height)

        booleanName = curve.name + '_bool'
        boolSolid = ET.SubElement(solids, boolType, {'name': booleanName})
        ET.SubElement(boolSolid, 'first', {'ref': firstName})
        ET.SubElement(boolSolid, 'second', {'ref': secondName})
        relativePosition = secondPos - rootPos
        zAngle = curve.rotation[2] - rootRot[2]
        posName = curve.name + '_pos'
        rotName = curve.name + '_rot'
        exportDefine(posName,
                     relativePosition)  # position of second relative to first
        ET.SubElement(define, 'rotation', {
            'name': rotName,
            'unit': 'deg',
            'x': '0',
            'y': '0',
            'z': str(zAngle)
        })

        ET.SubElement(boolSolid, 'positionref', {'ref': posName})
        ET.SubElement(boolSolid, 'rotationref', {'ref': rotName})
        firstName = booleanName

    # now create logical and physical volumes for the last boolean.
    # Because the position of each closed curve might not be at the
    # origin, whereas primitives (tubes, cones, etc, are created centered at
    # the origin, we need to shift the position of the very first node by its
    # position, in addition to the shift by the Extrusion placement
    volName = booleanName + 'Vol'  # booleanName is name of last boolean
    newvol = insertXMLvolume(volName)

    addVolRef(newvol, volName, extrudeObj, booleanName)
    # ET.SubElement(newvol,'materialref',{'ref': 'G4_Si'})
    # ET.SubElement(newvol,'solidref',{'ref': booleanName})

    pvol = ET.SubElement(xmlVol, 'physvol', {'name': 'PV' + volName})
    ET.SubElement(pvol, 'volumeref', {'ref': volName})
    extrudePosition = extrudeObj.Placement.Base
    if extrudeObj.Symmetric is False:
        if extrudeObj.Reversed is False:
            zoffset = Vector(0, 0, extrudeObj.LengthRev.Value)
        else:
            zoffset = Vector(0, 0, extrudeObj.LengthFwd.Value)
    else:
        zoffset = Vector(0, 0, extrudeObj.LengthFwd.Value / 2)

    angles = quaternion2XYZ(extrudeObj.Placement.Rotation)
    # need to add rotations of elliptical tubes. Assume extrusion is on z-axis
    # Probably wil not work in general
    zAngle = angles[2] + rootRot[2]
    print(rootPos)
    print(rootCurve.name)
    print(rootCurve.position)
    rootPos = rotatedPos(rootCurve, extrudeObj.Placement.Rotation)
    print(rootPos)
    volPos = extrudePosition + rootPos - zoffset

    print(volPos)
    exportPosition(volName, pvol, volPos)

    rotName = booleanName + '_rot'
    ET.SubElement(
        define, 'rotation', {
            'name': rotName,
            'unit': 'deg',
            'x': str(-angles[0]),
            'y': str(-angles[1]),
            'z': str(-zAngle)
        })
    ET.SubElement(pvol, 'rotationref', {'ref': rotName})
Example #36
0
    def opExecute(self, obj):
        '''opExecute(obj) ... process engraving operation'''
        PathLog.track()

        job = PathUtils.findParentJob(obj)
        if job and job.Base:
            obj.BaseObject = job.Base

        zValues = []
        if obj.StepDown.Value != 0:
            z = obj.StartDepth.Value - obj.StepDown.Value

            while z > obj.FinalDepth.Value:
                zValues.append(z)
                z -= obj.StepDown.Value
        zValues.append(obj.FinalDepth.Value)
        self.zValues = zValues

        try:
            if self.baseobject.isDerivedFrom('Sketcher::SketchObject') or \
                    self.baseobject.isDerivedFrom('Part::Part2DObject') or \
                    hasattr(self.baseobject, 'ArrayType'):
                PathLog.track()

                self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))

                # we only consider the outer wire if this is a Face
                wires = []
                for w in self.baseobject.Shape.Wires:
                    wires.append(Part.Wire(w.Edges))
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires

            elif isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet):  # process the sheet
                PathLog.track()
                wires = []
                for tag in self.baseobject.Proxy.getTags(self.baseobject, transform=True):
                    self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
                    tagWires = []
                    for w in tag.Wires:
                        tagWires.append(Part.Wire(w.Edges))
                    self.buildpathocc(obj, tagWires, zValues)
                    wires.extend(tagWires)
                self.wires = wires
            elif obj.Base:
                PathLog.track()
                wires = []
                for base, subs in obj.Base:
                    edges = []
                    #for sub in subs:
                    #    edges.extend(base.Shape.getElement(sub).Edges)
                    #shapeWires = adjustWirePlacement(obj, base, TechDraw.edgeWalker(edges))
                    #wires.extend(shapeWires)
                    for feature in subs:
                        sub = base.Shape.getElement(feature)
                        if type(sub) == Part.Edge:
                            edges.append(sub)
                        elif sub.Wires:
                            wires.extend(sub.Wires)
                        else:
                            wires.append(Part.Wire(sub.Edges))

                    for edgelist in Part.sortEdges(edges):
                        wires.append(Part.Wire(edgelist))
                wires = adjustWirePlacement(obj, base, wires)
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires
            elif not obj.BaseShapes:
                PathLog.track()
                raise ValueError(translate('PathEngrave', "Unknown baseobject type for engraving (%s)") % (obj.Base))

            if obj.BaseShapes:
                PathLog.track()
                wires = []
                for shape in obj.BaseShapes:
                    shapeWires = adjustWirePlacement(obj, shape, shape.Shape.Wires)
                    self.buildpathocc(obj, shapeWires, zValues)
                    wires.extend(shapeWires)
                self.wires = wires

        except Exception as e:
            PathLog.error(e)
            traceback.print_exc()
            PathLog.error(translate('PathEngrave', 'The Job Base Object has no engraveable element.  Engraving operation will produce no output.'))
Example #37
0
 def getPath(edges=[],wires=[],pathname=None):
     import Part,DraftGeomUtils
     svg = "<path "
     if pathname is None:
         svg += 'id="%s" ' % obj.Name
     elif pathname != "":
         svg += 'id="%s" ' % pathname
     svg += ' d="'
     if not wires:
         egroups = Part.sortEdges(edges)
     else:
         egroups = []
         for w in wires:
             w1=w.copy()
             w1.fixWire()
             egroups.append(Part.__sortEdges__(w1.Edges))
     for egroupindex, edges in enumerate(egroups):
         edata = ""
         vs=() #skipped for the first edge
         for edgeindex,e in enumerate(edges):
             previousvs = vs
             # vertexes of an edge (reversed if needed)
             vs = e.Vertexes
             if previousvs:
                 if (vs[0].Point-previousvs[-1].Point).Length > 1e-6:
                     vs.reverse()
             if edgeindex == 0:
                 v = getProj(vs[0].Point, plane)
                 edata += 'M '+ str(v.x) +' '+ str(v.y) + ' '
             else:
                 if (vs[0].Point-previousvs[-1].Point).Length > 1e-6:
                     raise ValueError('edges not ordered')
             iscircle = DraftGeomUtils.geomType(e) == "Circle"
             isellipse = DraftGeomUtils.geomType(e) == "Ellipse"
             if iscircle or isellipse:
                 import math
                 if hasattr(FreeCAD,"DraftWorkingPlane"):
                     drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
                 else:
                     drawing_plane_normal = FreeCAD.Vector(0,0,1)
                 if plane: drawing_plane_normal = plane.axis
                 c = e.Curve
                 if round(c.Axis.getAngle(drawing_plane_normal),2) in [0,3.14]:
                     occversion = Part.OCC_VERSION.split(".")
                     done = False
                     if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1):
                         # if using occ >= 7.1, use HLR algorithm
                         import Drawing
                         snip = Drawing.projectToSVG(e,drawing_plane_normal)
                         if snip:
                             try:
                                 a = "A " + snip.split("path d=\"")[1].split("\"")[0].split("A")[1]
                             except:
                                 pass
                             else:
                                 edata += a
                                 done = True
                     if not done:
                         if len(e.Vertexes) == 1 and iscircle: #complete curve
                             svg = getCircle(e)
                             return svg
                         elif len(e.Vertexes) == 1 and isellipse:
                             #svg = getEllipse(e)
                             #return svg
                             endpoints = (getProj(c.value((c.LastParameter-\
                                     c.FirstParameter)/2.0), plane), \
                                     getProj(vs[-1].Point, plane))
                         else:
                             endpoints = (getProj(vs[-1].Point), plane)
                         # arc
                         if iscircle:
                             rx = ry = c.Radius
                             rot = 0
                         else: #ellipse
                             rx = c.MajorRadius
                             ry = c.MinorRadius
                             rot = math.degrees(c.AngleXU * (c.Axis * \
                                 FreeCAD.Vector(0,0,1)))
                             if rot > 90:
                                 rot -=180
                             if rot < -90:
                                 rot += 180
                             #be careful with the sweep flag
                         flag_large_arc = (((e.ParameterRange[1] - \
                                 e.ParameterRange[0]) / math.pi) % 2) > 1
                         #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \
                         #         == (e.LastParameter > e.FirstParameter)
                         #        == (e.Orientation == "Forward")
                         # other method: check the direction of the angle between tangents
                         t1 = e.tangentAt(e.FirstParameter)
                         t2 = e.tangentAt(e.FirstParameter + (e.LastParameter-e.FirstParameter)/10)
                         flag_sweep = (DraftVecUtils.angle(t1,t2,drawing_plane_normal) < 0)
                         for v in endpoints:
                             edata += 'A %s %s %s %s %s %s %s ' % \
                                     (str(rx),str(ry),str(rot),\
                                     str(int(flag_large_arc)),\
                                     str(int(flag_sweep)),str(v.x),str(v.y))
                 else:
                     edata += getDiscretized(e, plane)
             elif DraftGeomUtils.geomType(e) == "Line":
                 v = getProj(vs[-1].Point, plane)
                 edata += 'L '+ str(v.x) +' '+ str(v.y) + ' '
             else:
                 bspline=e.Curve.toBSpline(e.FirstParameter,e.LastParameter)
                 if bspline.Degree > 3 or bspline.isRational():
                     try:
                         bspline=bspline.approximateBSpline(0.05,50, 3,'C0')
                     except RuntimeError:
                         print("Debug: unable to approximate bspline")
                 if bspline.Degree <= 3 and not bspline.isRational():
                     for bezierseg in bspline.toBezier():
                         if bezierseg.Degree>3: #should not happen
                             raise AssertionError
                         elif bezierseg.Degree==1:
                             edata +='L '
                         elif bezierseg.Degree==2:
                             edata +='Q '
                         elif bezierseg.Degree==3:
                             edata +='C '
                         for pole in bezierseg.getPoles()[1:]:
                             v = getProj(pole, plane)
                             edata += str(v.x) +' '+ str(v.y) + ' '
                 else:
                     print("Debug: one edge (hash ",e.hashCode(),\
                             ") has been discretized with parameter 0.1")
                     for linepoint in bspline.discretize(0.1)[1:]:
                         v = getProj(linepoint, plane)
                         edata += 'L '+ str(v.x) +' '+ str(v.y) + ' '
         if fill != 'none':
             edata += 'Z '
         if edata in pathdata:
             # do not draw a path on another identical path
             return ""
         else:
             svg += edata
             pathdata.append(edata)
     svg += '" '
     svg += 'stroke="' + stroke + '" '
     svg += 'stroke-width="' + str(linewidth) + ' px" '
     svg += 'style="stroke-width:'+ str(linewidth)
     svg += ';stroke-miterlimit:4'
     svg += ';stroke-dasharray:' + lstyle
     svg += ';fill:' + fill
     try:
         svg += ';fill-opacity:' + str(fill_opacity)
     except NameError:
         pass
     svg += ';fill-rule: evenodd "'
     svg += '/>\n'
     return svg
Example #38
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

    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:
            # 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 oof the remainig 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)
Example #39
0
    def opExecute(self, obj):
        '''opExecute(obj) ... process engraving operation'''
        PathLog.track()

        job = PathUtils.findParentJob(obj)
        if job and job.Base:
            obj.BaseObject = job.Base

        zValues = []
        if obj.StepDown.Value != 0:
            z = obj.StartDepth.Value - obj.StepDown.Value

            while z > obj.FinalDepth.Value:
                zValues.append(z)
                z -= obj.StepDown.Value
        zValues.append(obj.FinalDepth.Value)
        self.zValues = zValues

        try:
            if self.baseobject.isDerivedFrom('Sketcher::SketchObject') or \
                    self.baseobject.isDerivedFrom('Part::Part2DObject') or \
                    hasattr(self.baseobject, 'ArrayType'):
                PathLog.track()

                self.commandlist.append(
                    Path.Command('G0', {
                        'Z': obj.ClearanceHeight.Value,
                        'F': self.vertRapid
                    }))

                # we only consider the outer wire if this is a Face
                wires = []
                for w in self.baseobject.Shape.Wires:
                    wires.append(Part.Wire(w.Edges))
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires

            elif isinstance(self.baseobject.Proxy,
                            ArchPanel.PanelSheet):  # process the sheet
                PathLog.track()
                wires = []
                for tag in self.baseobject.Proxy.getTags(self.baseobject,
                                                         transform=True):
                    self.commandlist.append(
                        Path.Command('G0', {
                            'Z': obj.ClearanceHeight.Value,
                            'F': self.vertRapid
                        }))
                    tagWires = []
                    for w in tag.Wires:
                        tagWires.append(Part.Wire(w.Edges))
                    self.buildpathocc(obj, tagWires, zValues)
                    wires.extend(tagWires)
                self.wires = wires
            elif obj.Base:
                PathLog.track()
                wires = []
                for base, subs in obj.Base:
                    edges = []
                    #for sub in subs:
                    #    edges.extend(base.Shape.getElement(sub).Edges)
                    #shapeWires = adjustWirePlacement(obj, base, TechDraw.edgeWalker(edges))
                    #wires.extend(shapeWires)
                    for feature in subs:
                        sub = base.Shape.getElement(feature)
                        if type(sub) == Part.Edge:
                            edges.append(sub)
                        elif sub.Wires:
                            wires.extend(sub.Wires)
                        else:
                            wires.append(Part.Wire(sub.Edges))

                    for edgelist in Part.sortEdges(edges):
                        wires.append(Part.Wire(edgelist))
                wires = adjustWirePlacement(obj, base, wires)
                self.buildpathocc(obj, wires, zValues)
                self.wires = wires
            elif not obj.BaseShapes:
                PathLog.track()
                raise ValueError(
                    translate('PathEngrave',
                              "Unknown baseobject type for engraving (%s)") %
                    (obj.Base))

            if obj.BaseShapes:
                PathLog.track()
                wires = []
                for shape in obj.BaseShapes:
                    shapeWires = adjustWirePlacement(obj, shape,
                                                     shape.Shape.Wires)
                    self.buildpathocc(obj, shapeWires, zValues)
                    wires.extend(shapeWires)
                self.wires = wires

        except Exception as e:
            PathLog.error(e)
            traceback.print_exc()
            PathLog.error(
                translate(
                    'PathEngrave',
                    'The Job Base Object has no engraveable element.  Engraving operation will produce no output.'
                ))
Example #40
0
    def Activated(self):
        b = []
        selection = FreeCADGui.Selection.getSelectionEx()
        if selection:
            if len(selection) == 4:
                base = FreeCAD.ActiveDocument.getObject(
                    (selection[0].ObjectName))
                b = base.WingPanels
                _rootRib = FreeCAD.ActiveDocument.getObject(
                    (selection[1].ObjectName))
                _path = FreeCAD.ActiveDocument.getObject(
                    (selection[2].ObjectName))
                base.WingEdges.append(_path)
                _envelope = FreeCAD.ActiveDocument.getObject(
                    (selection[3].ObjectName))
                base.WingEdges.append(_envelope)
                _leadingedge = FreeCAD.ActiveDocument.getObject(
                    (selection[3].ObjectName))  # A netoyer en doublon
                wingsketch = FreeCAD.ActiveDocument.getObject(
                    (selection[3].ObjectName))
                # Separate leadInEdge & trailingEdge
                edges = Part.sortEdges(
                    wingsketch.Shape.Edges
                )  # Separate, #edges=Part.sortEdges(wingsketch.Shape.Edges) # deprecated ?
                paths = Part.__sortEdges__(_path.Shape.Edges)
                leadInEdges = edges[0]  #id the leading edge
                trailingEdges = edges[1]  #id the trailing edge
                FreeCAD.Console.PrintMessage("Edges number : " +
                                             str(len(edges)) + "\n")
                if len(edges) != 2:
                    FreeCAD.Console.PrintMessage("Edges must be 2 and not " +
                                                 str(len(edges)) + "\n")
                    return

                nbOfPanels = len(leadInEdges)
                FreeCAD.Console.PrintMessage(
                    "-------------------- Wing Panel --------------------" +
                    "\n")
                FreeCAD.Console.PrintMessage("  Rib :" + str(_rootRib.Label) +
                                             "\n")
                FreeCAD.Console.PrintMessage("  Wing :" + str(base.Label) +
                                             "\n")
                FreeCAD.Console.PrintMessage("  Path :" + str(_path.Label) +
                                             "\n")
                FreeCAD.Console.PrintMessage("  envelope :" +
                                             str(_envelope.Label) + "\n")
                FreeCAD.Console.PrintMessage("  envelope placement:" +
                                             str(_envelope.Placement) + "\n")
                FreeCAD.Console.PrintMessage("  Number of Panels :" +
                                             str(nbOfPanels) + "\n")

                pmin = 0
                pmax = 0
                for i in range(0, nbOfPanels):  # for each panel
                    pmin = 0  #pmax
                    pmax = leadInEdges[i].Length
                    param = leadInEdges[i].getParameterByLength(pmin)
                    param2 = leadInEdges[i].getParameterByLength(pmax)
                    direction = leadInEdges[i].tangentAt(param)
                    posvec = leadInEdges[i].valueAt(param)
                    posvec2 = leadInEdges[i].valueAt(param2)

                    #normal = CurvedShapes.getNormal(obj.Base)
                    #rotaxis = normal.cross(direction)
                    #angle = math.degrees(normal.getAngle(direction))
                    bbox = leadInEdges[i].BoundBox
                    bbox2 = trailingEdges[i].BoundBox

                    FreeCAD.Console.PrintMessage("  Panel n° " + str(i) +
                                                 " ------------------------\n")
                    FreeCAD.Console.PrintMessage("  leadInEdges id        :" +
                                                 str(leadInEdges[i]) + "\n")
                    FreeCAD.Console.PrintMessage("  leadInEdges Length    :" +
                                                 str(leadInEdges[i].Length) +
                                                 "\n")
                    FreeCAD.Console.PrintMessage("  trailingEdges id      :" +
                                                 str(trailingEdges[i]) + "\n")
                    FreeCAD.Console.PrintMessage("  trailingEdges Length  :" +
                                                 str(trailingEdges[i].Length) +
                                                 "\n")
                    FreeCAD.Console.PrintMessage("  direction             :" +
                                                 str(direction) + "\n")
                    FreeCAD.Console.PrintMessage("     pmin               : " +
                                                 str(pmin) + "\n")
                    FreeCAD.Console.PrintMessage("     Param              : " +
                                                 str(param) + "\n")
                    FreeCAD.Console.PrintMessage("     Position           : " +
                                                 str(posvec) + "\n")
                    FreeCAD.Console.PrintMessage("     Position2          : " +
                                                 str(posvec2) + "\n")
                    FreeCAD.Console.PrintMessage(
                        "     BoundBox leadInEdges   : " + str(bbox) + "\n")
                    FreeCAD.Console.PrintMessage(
                        "     BoundBox trailingEdges   : " + str(bbox2) + "\n")

                    FreeCADGui.activateWorkbench("DraftWorkbench")
                    plane = WorkingPlane.plane()
                    FreeCAD.DraftWorkingPlane = plane

                    #workplane = WorkingPlane.plane()
                    workplane = FreeCAD.DraftWorkingPlane
                    v1 = FreeCAD.Vector(
                        0, 1,
                        0).normalize()  #paths[i].tangentAt(param).normalize()
                    v2 = FreeCAD.Vector(0, 0, 1).normalize()
                    #workplane.alignToPointAndAxis(v1, v2, 0)

                    #FreeCAD.DraftWorkingPlane.alignToPointAndAxis(v1, v2, 0)
                    #FreeCADGui.Snapper.toggleGrid()

                    FreeCAD.Console.PrintMessage("     V1   : " + str(v1) +
                                                 "\n")
                    FreeCAD.Console.PrintMessage("     V2   : " + str(v2) +
                                                 "\n")

                    # workplane.alignToPointAndAxis( v1, v2, 0)
                    #FreeCADGui.Snapper.toggleGrid()
                    FreeCADGui.activeDocument().activeView(
                    ).setCameraOrientation(_path.Placement.Rotation)

                    #paths[i].

                    FreeCAD.Console.PrintMessage("     pathline   : " +
                                                 str(paths[i]) + "\n")
                    #pathline=Part.Line(paths[i].Geometry)

                    myObj0 = Draft.makeSketch(paths[i], autoconstraints=True)
                    #myObj1=Part.Line(paths[i].Content)
                    myObj0.Label = "path" + str(i)

                    vec = _envelope.Placement.Rotation
                    FreeCADGui.activeDocument().activeView(
                    ).setCameraOrientation(vec)  #(0,0,0,1))
                    myObj1 = Draft.makeSketch(leadInEdges[i],
                                              name="leadInEdges" + str(i),
                                              autoconstraints=True)
                    #myObj1=Part.Line()
                    myObj1.Label = "leadInEdges" + str(i)

                    FreeCADGui.activeDocument().activeView(
                    ).setCameraOrientation(vec)
                    myObj2 = Draft.makeSketch(trailingEdges[i],
                                              autoconstraints=True)
                    myObj2.Label = "trailingEdge" + str(i)

                    obj = FreeCAD.ActiveDocument.addObject(
                        "Part::FeaturePython", "WingPanel" + str(i))

                    WingPanel(obj, _rootRib, myObj0, _envelope, myObj1, myObj2,
                              200, 100, 100, 0, 0)
                    #WingPanel(obj,_rootRib,_path,_envelope,myObj1,myObj2,200,100,100,0,0)
                    #WingPanel(obj,_rootRib,_path,_envelope,leadInEdges[i],trailingEdges[i],200,100,100,0,0)

                    #WingPanel(obj,_rootRib,_path,leadInEdges[i],trailingEdges[i],200,100,100,0,0)
                    ViewProviderPanel(obj.ViewObject)
                    b.append(obj)
                    FreeCAD.ActiveDocument.recompute()
            else:
                #---------------------création des nervures temporaires
                #_rootRib=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","RibRoot_")
                #WingRib(_rootRib,"/Users/fredericnivoix/Library/Preferences/FreeCAD/Mod/AirPlaneDesign/wingribprofil/naca/naca2412.dat",False,0,200,0,0,0,0,0,0)
                #ViewProviderWingRib(_rootRib.ViewObject)

                #_tipRib=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","RibTip_")
                #WingRib(_tipRib,"/Users/fredericnivoix/Library/Preferences/FreeCAD/Mod/AirPlaneDesign/wingribprofil/naca/naca2412.dat",False,0,200,0,500,0,0,0,0)
                #ViewProviderWingRib(_tipRib.ViewObject)

                #----------

                obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                       "WingPanel")
                WingPanel(obj, None, None, None, None, None, 200, 100, 100, 0,
                          0)
                ViewProviderPanel(obj.ViewObject)

        if selection:  #selection==None :
            try:
                #b=base.WingPanels
                #b.append(obj)
                base.WingPanels = b
            except:
                print("The selection is not a wing")
        FreeCAD.Gui.activeDocument().activeView().viewAxonometric()
        FreeCAD.Gui.SendMsgToActiveView("ViewFit")