Example #1
0
 def getbase(wire):
     "returns a full shape from a base wire"
     dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
     dvec.normalize()
     if obj.Align == "Left":
         dvec = dvec.multiply(width)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Right":
         dvec = dvec.multiply(width)
         dvec = DraftVecUtils.neg(dvec)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Center":
         dvec = dvec.multiply(width/2)
         w1 = DraftGeomUtils.offsetWire(wire,dvec)
         dvec = DraftVecUtils.neg(dvec)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         sh = DraftGeomUtils.bind(w1,w2)
     # fixing self-intersections
     sh.fix(0.1,0,1)
     if height and (not flat):
         norm = Vector(normal).multiply(height)
         sh = sh.extrude(norm)
     return sh
Example #2
0
    def backHigher(self, i):
        import DraftGeomUtils

        profilCurrent = self.findProfil(i)
        profilBack1 = self.findProfil(i - 1)
        dec = profilCurrent["height"] / math.tan(math.radians(profilBack1["angle"]))
        edgeRidgeOnPane = DraftGeomUtils.offset(
            profilBack1["edge"], self.getPerpendicular(profilBack1["vec"], profilBack1["rot"], dec)
        )
        ptInterRidges = DraftGeomUtils.findIntersection(
            edgeRidgeOnPane, profilCurrent["ridge"], infinite1=True, infinite2=True
        )
        self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
        edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]), profilCurrent["edge"].Vertexes[0].Point)
        ptInterHipEave = DraftGeomUtils.findIntersection(
            edgeHip, profilCurrent["eave"], infinite1=True, infinite2=False
        )
        if ptInterHipEave:
            self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0]))
        else:
            ptInterHipEave = DraftGeomUtils.findIntersection(
                edgeHip, profilBack1["eaveD"], infinite1=True, infinite2=True
            )
            self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0]))
            self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point[0]))
Example #3
0
    def update(self, line=None, normal=None):
        import WorkingPlane, DraftGeomUtils

        if not normal:
            normal = FreeCAD.DraftWorkingPlane.axis
        if line:
            if isinstance(line, list):
                bp = line[0]
                lvec = line[1].sub(line[0])
            else:
                lvec = DraftGeomUtils.vec(line.Shape.Edges[0])
                bp = line.Shape.Edges[0].Vertexes[0].Point
        elif self.baseline:
            lvec = DraftGeomUtils.vec(self.baseline.Shape.Edges[0])
            bp = self.baseline.Shape.Edges[0].Vertexes[0].Point
        else:
            return
        right = lvec.cross(normal)
        self.cube.width.setValue(lvec.Length)
        p = WorkingPlane.getPlacementFromPoints([bp, bp.add(lvec), bp.add(right)])
        if p:
            self.trans.rotation.setValue(p.Rotation.Q)
        bp = bp.add(lvec.multiply(0.5))
        bp = bp.add(DraftVecUtils.scaleTo(normal, self.cube.depth.getValue() / 2))
        self.pos(bp)
Example #4
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    for v in shape.Vertexes:
        vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
    if not shape.Faces:
        for e in shape.Edges:
            if DraftGeomUtils.geomType(e) == "Line":
                ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                elist.append(ei)
    for f in shape.Faces:
        if len(f.Wires) > 1:
            # if we have holes, we triangulate
            tris = f.tessellate(1)
            for fdata in tris[1]:
                fi = ""
                for vi in fdata:
                    vdata = Part.Vertex(tris[0][vi])
                    fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                flist.append(fi)
        else:
            fi = ""
            # OCC vertices are unsorted. We need to sort in the right order...
            edges = DraftGeomUtils.sortEdges(f.Wire.Edges)
            #print edges
            for e in edges:
                #print e.Vertexes[0].Point,e.Vertexes[1].Point
                v = e.Vertexes[0]
                fi += " " + str(findVert(v,shape.Vertexes) + offset)
            flist.append(fi)
    return vlist,elist,flist
Example #5
0
 def findPivotIntersection(self, pivot, pivotEdge, edge, refPt, d, color):
     debugPrint(
         "Intersection (%.2f, %.2f)^%.2f  - [(%.2f, %.2f), (%.2f, %.2f)]"
         % (
             pivotEdge.Curve.Center.x,
             pivotEdge.Curve.Center.y,
             pivotEdge.Curve.Radius,
             edge.Vertexes[0].Point.x,
             edge.Vertexes[0].Point.y,
             edge.Vertexes[1].Point.x,
             edge.Vertexes[1].Point.y,
         )
     )
     ppt = None
     pptDistance = 0
     for pt in DraftGeomUtils.findIntersection(edge, pivotEdge, dts=False):
         # debugMarker(pt, "pti.%d-%s.in" % (self.boneId, d), color, 0.2)
         distance = (pt - refPt).Length
         debugPrint("        -->  (%.2f, %.2f): %.2f" % (pt.x, pt.y, distance))
         if not ppt or pptDistance < distance:
             ppt = pt
             pptDistance = distance
     if not ppt:
         tangent = DraftGeomUtils.findDistance(pivot, edge)
         if tangent:
             debugPrint("Taking tangent as intersect %s" % tangent)
             ppt = pivot + tangent
         else:
             debugPrint("Taking chord start as intersect %s" % inChordStart)
             ppt = inChord.Start
         # debugMarker(ppt, "ptt.%d-%s.in" % (self.boneId, d), color, 0.2)
         debugPrint("        -->  (%.2f, %.2f)" % (ppt.x, ppt.y))
     return ppt
Example #6
0
 def getBase(self,obj,wire,normal,width,height):
     "returns a full shape from a base wire"
     import DraftGeomUtils,Part
     flat = False
     if hasattr(obj.ViewObject,"DisplayMode"):
         flat = (obj.ViewObject.DisplayMode == "Flat 2D")
     dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
     if not DraftVecUtils.isNull(dvec):
         dvec.normalize()
     if obj.Align == "Left":
         dvec = dvec.multiply(width)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Right":
         dvec = dvec.multiply(width)
         dvec = DraftVecUtils.neg(dvec)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Center":
         dvec = dvec.multiply(width/2)
         w1 = DraftGeomUtils.offsetWire(wire,dvec)
         dvec = DraftVecUtils.neg(dvec)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         sh = DraftGeomUtils.bind(w1,w2)
     # fixing self-intersections
     sh.fix(0.1,0,1)
     if height and (not flat):
         norm = Vector(normal).multiply(height)
         sh = sh.extrude(norm)
     return sh
Example #7
0
    def calcEave(self, i):

        import DraftGeomUtils
        pt0Eave1 = DraftGeomUtils.findIntersection(self.findProfil(i-1)["eaveD"],self.findProfil(i)["eaveD"],infinite1=True,infinite2=True,)
        pt1Eave1 = DraftGeomUtils.findIntersection(self.findProfil(i)["eaveD"],self.findProfil(i+1)["eaveD"],infinite1=True,infinite2=True,)
        eave = DraftGeomUtils.edg(FreeCAD.Vector(pt0Eave1[0]),FreeCAD.Vector(pt1Eave1[0]))
        self.profilsDico[i]["eave"] = eave
Example #8
0
def removeShape(objs, mark=True):
    """takes an arch object (wall or structure) built on a cubic shape, and removes
    the inner shape, keeping its length, width and height as parameters."""
    import DraftGeomUtils

    if not isinstance(objs, list):
        objs = [objs]
    for obj in objs:
        if DraftGeomUtils.isCubic(obj.Shape):
            dims = DraftGeomUtils.getCubicDimensions(obj.Shape)
            if dims:
                name = obj.Name
                tp = Draft.getType(obj)
                print tp
                if tp == "Structure":
                    FreeCAD.ActiveDocument.removeObject(name)
                    import ArchStructure

                    str = ArchStructure.makeStructure(length=dims[1], width=dims[2], height=dims[3], name=name)
                    str.Placement = dims[0]
                elif tp == "Wall":
                    FreeCAD.ActiveDocument.removeObject(name)
                    import ArchWall

                    length = dims[1]
                    width = dims[2]
                    v1 = Vector(length / 2, 0, 0)
                    v2 = v1.negative()
                    v1 = dims[0].multVec(v1)
                    v2 = dims[0].multVec(v2)
                    line = Draft.makeLine(v1, v2)
                    wal = ArchWall.makeWall(line, width=width, height=dims[3], name=name)
        else:
            if mark:
                obj.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
Example #9
0
 def connectNodes(self,other=None):
     if not other:
         self.observer = StructSelectionObserver(self.connectNodes)
         FreeCADGui.Selection.addObserver(self.observer)
         FreeCAD.Console.PrintMessage(translate("Arch","Pick another Structure object: "))
     else:
         FreeCADGui.Selection.removeObserver(self.observer)
         self.observer = None
         if Draft.getType(other) != "Structure":
             FreeCAD.Console.PrintError(translate("Arch","The picked object is not a Structure\n"))
         else:
             if not other.Nodes:
                 FreeCAD.Console.PrintError(translate("Arch","The picked object has no structural nodes\n"))
             else:
                 if (len(self.Object.Nodes) != 2) or (len(other.Nodes) != 2):
                     FreeCAD.Console.PrintError(translate("Arch","One of these objects has more than 2 nodes\n"))
                 else:
                     import DraftGeomUtils
                     nodes1 = [self.Object.Placement.multVec(v) for v in self.Object.Nodes]
                     nodes2 = [other.Placement.multVec(v) for v in other.Nodes]
                     intersect = DraftGeomUtils.findIntersection(nodes1[0],nodes1[1],nodes2[0],nodes2[1],True,True)
                     if not intersect:
                         FreeCAD.Console.PrintError(translate("Arch","Unable to find a suitable intersection point\n"))
                     else:
                         intersect = intersect[0]
                         FreeCAD.Console.PrintMessage(translate("Arch","Intersection found.\n"))
                         if DraftGeomUtils.findClosest(intersect,nodes1) == 0:
                             self.Object.Nodes = [self.Object.Placement.inverse().multVec(intersect),self.Object.Nodes[1]]
                         else:
                             self.Object.Nodes = [self.Object.Nodes[0],self.Object.Placement.inverse().multVec(intersect)]
                         if DraftGeomUtils.findClosest(intersect,nodes2) == 0:
                             other.Nodes = [other.Placement.inverse().multVec(intersect),other.Nodes[1]]
                         else:
                             other.Nodes = [other.Nodes[0],other.Placement.inverse().multVec(intersect)]
Example #10
0
    def backPignon(self, i):
        import DraftGeomUtils

        profilCurrent = self.findProfil(i)
        profilBack1 = self.findProfil(i - 1)
        profilBack2 = self.findProfil(i - 2)
        pt1 = DraftGeomUtils.findIntersection(
            profilCurrent["edge"], profilBack1["eave"], infinite1=True, infinite2=True
        )
        pt2 = DraftGeomUtils.findIntersection(profilBack2["edge"], profilBack1["eave"], infinite1=True, infinite2=True)
        eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0], pt2[0])
        if profilCurrent["run"] + profilBack2["run"] != eaveWithoutOverhang.Length:
            points = [FreeCAD.Vector(0.0, 0.0, 0.0)]
            points.append(FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0))
            rampantCurrent = DraftGeomUtils.edg(points[0], points[1])
            points = [FreeCAD.Vector(eaveWithoutOverhang.Length, 0.0, 0.0)]
            points.append(FreeCAD.Vector(eaveWithoutOverhang.Length - profilBack2["run"], profilBack2["height"], 0.0))
            rampantBack2 = DraftGeomUtils.edg(points[0], points[1])
            point = DraftGeomUtils.findIntersection(rampantCurrent, rampantBack2, infinite1=True, infinite2=True)
            ridgeCurrent = DraftGeomUtils.offset(
                profilCurrent["edge"], self.getPerpendicular(profilCurrent["vec"], profilCurrent["rot"], point[0].x)
            )
            point = DraftGeomUtils.findIntersection(ridgeCurrent, profilBack1["eave"], infinite1=True, infinite2=True)
        else:
            point = DraftGeomUtils.findIntersection(
                profilCurrent["ridge"], profilBack1["eave"], infinite1=True, infinite2=True
            )
        self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
        point = DraftGeomUtils.findIntersection(
            profilCurrent["eave"], profilBack1["eave"], infinite1=True, infinite2=True
        )
        self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
Example #11
0
 def nextPignon(self, i):
     print("Next : pignon")
     profilCurrent = self.findProfil(i)
     profilNext1 = self.findProfil(i+1)
     profilNext2 = self.findProfil(i+2)
     point = DraftGeomUtils.findIntersection(profilCurrent["eave"],profilNext1["eave"],infinite1=True,infinite2=True,)
     print "a ",FreeCAD.Vector(point[0])
     self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
     pt1 = DraftGeomUtils.findIntersection(profilCurrent["edge"],profilNext1["eave"],infinite1=True,infinite2=True,)
     pt2 = DraftGeomUtils.findIntersection(profilNext2["edge"],profilNext1["eave"],infinite1=True,infinite2=True,)
     eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0],pt2[0])
     if profilCurrent["run"]+profilNext2["run"] != eaveWithoutOverhang.Length :
         points = [FreeCAD.Vector(0.0,0.0,0.0),]
         points.append(FreeCAD.Vector(profilCurrent["run"],profilCurrent["height"],0.0))
         rampantCurrent = DraftGeomUtils.edg(points[0],points[1])
         points = [FreeCAD.Vector(eaveWithoutOverhang.Length,0.0,0.0),]
         points.append(FreeCAD.Vector(eaveWithoutOverhang.Length-profilNext2["run"],profilNext2["height"],0.0))
         rampantNext2 = DraftGeomUtils.edg(points[0],points[1])
         point = DraftGeomUtils.findIntersection(rampantCurrent,rampantNext2,infinite1=True,infinite2=True,)
         ridgeCurrent = DraftGeomUtils.offset(profilCurrent["edge"],self.getPerpendicular(profilCurrent["vec"],profilCurrent["rot"],point[0].x))
         point = DraftGeomUtils.findIntersection(ridgeCurrent,profilNext1["eave"],infinite1=True,infinite2=True,)
     else:
         point = DraftGeomUtils.findIntersection(profilCurrent["ridge"],profilNext1["eaveD"],infinite1=True,infinite2=True,)
     print "b ",FreeCAD.Vector(point[0])
     self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
Example #12
0
def SortPath(wire, Side, radius, clockwise, firstedge=None, SegLen=0.5):
    """SortPath(wire,Side,radius,clockwise,firstedge=None,SegLen =0.5) Sorts the wire and reverses it, if needed. Splits arcs over 180 degrees in two. Returns the reordered offset of the wire. """
    if firstedge:
        edgelist = wire.Edges[:]
        if wire.isClosed():
            elindex = None
            n = 0
            for e in edgelist:
                if isSameEdge(e, firstedge):
                    #                    FreeCAD.Console.PrintMessage('found first edge\n')
                    elindex = n
                n = n + 1
            l1 = edgelist[:elindex]
            l2 = edgelist[elindex:]
            newedgelist = l2 + l1

            if clockwise:
                newedgelist.reverse()
                last = newedgelist.pop(-1)
                newedgelist.insert(0, last)

            preoffset = []
            for e in newedgelist:
                if clockwise:
                    r = reverseEdge(e)
                    preoffset.append(r)
                else:
                    preoffset.append(e)

            sortedpreoff = DraftGeomUtils.sortEdgesOld(preoffset)
            wire = Part.Wire(sortedpreoff)
        else:
            sortedpreoff = DraftGeomUtils.sortEdgesOld(edgelist)
            wire = Part.Wire(sortedpreoff)

    edgelist = []
    for e in wire.Edges:
        if geomType(e) == "Circle":
            arclist = filterArcs(e)
            for a in arclist:
                edgelist.append(a)
        elif geomType(e) == "Line":
            edgelist.append(e)
        elif geomType(e) == "BSplineCurve" or geomType(e) == "BezierCurve" or geomType(e) == "Ellipse":
            edgelist.append(Part.Wire(curvetowire(e, (SegLen))))

    newwire = Part.Wire(edgelist)
    if Side == "Left":
        # we use the OCC offset feature
        offset = newwire.makeOffset(radius)  # tool is outside line
    elif Side == "Right":
        offset = newwire.makeOffset(-radius)  # tool is inside line
    else:
        if wire.isClosed():
            offset = newwire.makeOffset(0.0)
        else:
            offset = newwire

    return offset
def export(exportList,filename):
    "called when freecad exports a file"
    faces = []
    edges = []
    
    # getting faces and edges
    for ob in exportList:
        if ob.Shape.Faces:
            for f in ob.Shape.Faces:
                faces.append(f)
        else:
            for e in ob.Shape.Edges:
                edges.append(e)
    if not (edges or faces):
        print("oca: found no data to export")
        return
    
    # writing file
    oca = pythonopen(filename,'wb')
    oca.write("#oca file generated from FreeCAD\r\n")
    oca.write("# edges\r\n")
    count = 1
    for e in edges:
        if DraftGeomUtils.geomType(e) == "Line":
            oca.write("L"+str(count)+"=")
            oca.write(writepoint(e.Vertexes[0].Point))
            oca.write(" ")
            oca.write(writepoint(e.Vertexes[-1].Point))
            oca.write("\r\n")
        elif DraftGeomUtils.geomType(e) == "Circle":
            if (len(e.Vertexes) > 1):
                oca.write("C"+str(count)+"=ARC ")
                oca.write(writepoint(e.Vertexes[0].Point))
                oca.write(" ")
                oca.write(writepoint(DraftGeomUtils.findMidpoint(e)))
                oca.write(" ")
                oca.write(writepoint(e.Vertexes[-1].Point))
            else:
                oca.write("C"+str(count)+"= ")
                oca.write(writepoint(e.Curve.Center))
                oca.write(" ")
                oca.write(str(e.Curve.Radius))
            oca.write("\r\n")
        count += 1
    oca.write("# faces\r\n")
    for f in faces:
        oca.write("A"+str(count)+"=S(POL")
        for v in f.Vertexes:
            oca.write(" ")
            oca.write(writepoint(v.Point))
        oca.write(" ")
        oca.write(writepoint(f.Vertexes[0].Point))
        oca.write(")\r\n")
        count += 1

    # closing
    oca.close()
    FreeCAD.Console.PrintMessage("successfully exported "+filename)
Example #14
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    for e in shape.Edges:
        try:
            if not isinstance(e.Curve,Part.Line):
                if not curves:
                    curves = shape.tessellate(1)
                    FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n"))
                    break
        except: # unimplemented curve type
            curves = shape.tessellate(1)
            FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n"))
            break
    if curves:
        for v in curves[0]:
            vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                    ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                # OCC vertices are unsorted. We need to sort in the right order...
                edges = DraftGeomUtils.sortEdges(f.OuterWire.Edges)
                #print edges
                for e in edges:
                    #print e.Vertexes[0].Point,e.Vertexes[1].Point
                    v = e.Vertexes[0]
                    fi += " " + str(findVert(v,shape.Vertexes) + offset)
                flist.append(fi)
    return vlist,elist,flist
Example #15
0
 def calcDraftEdges(self, i):
     edge = self.profilsDico[i]["edge"]
     vec = self.profilsDico[i]["vec"]
     rot = self.profilsDico[i]["rot"]
     overhang = self.profilsDico[i]["overhang"]
     run = self.profilsDico[i]["run"]
     perpendicular = self.getPerpendicular(vec,rot,self.profilsDico[i]["overhang"]).negative()
     eave = DraftGeomUtils.offset(edge,perpendicular)
     self.profilsDico[i]["eaveD"] = eave
     perpendicular = self.getPerpendicular(vec,rot,self.profilsDico[i]["run"])
     ridge = DraftGeomUtils.offset(edge,perpendicular)
     self.profilsDico[i]["ridge"] = ridge
Example #16
0
 def backSameHeight(self, i):
     import DraftGeomUtils
     profilCurrent = self.findProfil(i)
     profilBack1 = self.findProfil(i-1)
     ptInterRidges = DraftGeomUtils.findIntersection(profilCurrent["ridge"],profilBack1["ridge"],infinite1=True,infinite2=True,)
     self.ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
     edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),profilCurrent["edge"].Vertexes[0].Point)
     ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilCurrent["eave"],infinite1=True,infinite2=False,)
     if ptInterHipEave:
         self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0]))
     else:
         ptInterHipEave = DraftGeomUtils.findIntersection(edgeHip,profilBack1["eaveD"],infinite1=True,infinite2=True,)
         self.ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave[0]))
         self.ptsPaneProject.append(FreeCAD.Vector(profilCurrent["eave"].Vertexes[0].Point))
Example #17
0
 def getBaseAndAxis(self,wire):
     "returns a base point and orientation axis from the base wire"
     import DraftGeomUtils
     if wire:
         e = wire.Edges[0]
         v = DraftGeomUtils.vec(e).normalize()
         return e.Vertexes[0].Point,v
     if obj.Base:
         if obj.Base.Shape:
             if obj.Base.Shape.Wires:
                 e = obj.Base.Shape.Wires[0].Edges[0]
                 v = DraftGeomUtils.vec(e).normalize()
                 return e.Vertexes[0].Point,v
     return None,None
Example #18
0
def intersectionCLines(thing1=None, thing2=None):
  '''
  intersectionCLines(thing1=None, thing2=None)
  Returns the intersection (vector) of the center lines of thing1 and thing2.
  Things can be any combination of intersecting beams, pipes or edges.
  If less than 2 arguments are given, thing1 and thing2 are the first 2 beams
  or pipes found in the selection set.
  '''
  if not (thing1 and thing2):
    try:
      thing1,thing2=beams()[:2]
    except:
      FreeCAD.Console.PrintError('Insufficient arguments for intersectionCLines\n')
      return None
  edges=[]
  for thing in [thing1,thing2]:
    if beams([thing]):
      edges.append(vec2edge(thing.Placement.Base,beamAx(thing)))
    elif hasattr(thing,'ShapeType') and thing.ShapeType=='Edge':
      edges.append(thing)
  intersections=dgu.findIntersection(*edges, infinite1=True, infinite2=True)
  if len(intersections):
    return rounded(intersections[0])
  else:
    FreeCAD.Console.PrintError('No intersection found\n')
    return None
Example #19
0
    def findHoles(self, obj, shape):
        import DraftGeomUtils as dgu
        PathLog.track('obj: {} shape: {}'.format(obj, shape))
        holelist = []
        tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter
        PathLog.debug('search for holes larger than tooldiameter: {}: '.format(tooldiameter))
        if dgu.isPlanar(shape):
            PathLog.debug("shape is planar")
            for i in range(len(shape.Edges)):
                candidateEdgeName = "Edge" + str(i + 1)
                e = shape.getElement(candidateEdgeName)
                if PathUtils.isDrillable(shape, e, tooldiameter):
                    PathLog.debug('edge candidate: {} (hash {})is drillable '.format(e, e.hashCode()))
                    x = e.Curve.Center.x
                    y = e.Curve.Center.y
                    diameter = e.BoundBox.XLength
                    holelist.append({'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True})
        else:
            PathLog.debug("shape is not planar")
            for i in range(len(shape.Faces)):
                candidateFaceName = "Face" + str(i + 1)
                f = shape.getElement(candidateFaceName)
                if PathUtils.isDrillable(shape, f, tooldiameter):
                    PathLog.debug('face candidate: {} is drillable '.format(f))
                    x = f.Surface.Center.x
                    y = f.Surface.Center.y
                    diameter = f.BoundBox.XLength
                    holelist.append({'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True})

        PathLog.debug("holes found: {}".format(holelist))
        return holelist
Example #20
0
 def rebase(self,shape):
     import DraftGeomUtils,math
     if not isinstance(shape,list):
         shape = [shape]
     if hasattr(shape[0],"CenterOfMass"):
         v = shape[0].CenterOfMass
     else:
         v = shape[0].BoundBox.Center
     n = DraftGeomUtils.getNormal(shape[0])
     r = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),n)
     if round(r.Angle,8) == round(math.pi,8):
         r = FreeCAD.Rotation()
     shapes = []
     for s in shape:
         s = s.copy()
         s.translate(v.negative())
         s.rotate(FreeCAD.Vector(0,0,0),r.inverted().Axis,math.degrees(r.inverted().Angle))
         shapes.append(s)
     p = FreeCAD.Placement()
     p.Base = v
     p.Rotation = r
     if len(shapes) == 1:
         return (shapes[0],p)
     else:
         return(shapes,p)
Example #21
0
    def calc(self):
        import Part

        if (self.p1 != None) and (self.p2 != None):
            points = [
                DraftVecUtils.tup(self.p1, True),
                DraftVecUtils.tup(self.p2, True),
                DraftVecUtils.tup(self.p1, True),
                DraftVecUtils.tup(self.p2, True),
            ]
            if self.p3 != None:
                p1 = self.p1
                p4 = self.p2
                if DraftVecUtils.equals(p1, p4):
                    proj = None
                else:
                    base = Part.Line(p1, p4).toShape()
                    proj = DraftGeomUtils.findDistance(self.p3, base)
                if not proj:
                    p2 = p1
                    p3 = p4
                else:
                    p2 = p1.add(proj.negative())
                    p3 = p4.add(proj.negative())
                points = [DraftVecUtils.tup(p1), DraftVecUtils.tup(p2), DraftVecUtils.tup(p3), DraftVecUtils.tup(p4)]
            self.coords.point.setValues(0, 4, points)
Example #22
0
 def rebase(self,shape):
     """returns a shape that is a copy of the original shape
     but centered on the (0,0) origin, and a placement that is needed to
     reposition that shape to its original location/orientation"""
     import DraftGeomUtils,math
     if not isinstance(shape,list):
         shape = [shape]
     if hasattr(shape[0],"CenterOfMass"):
         v = shape[0].CenterOfMass
     else:
         v = shape[0].BoundBox.Center
     n = DraftGeomUtils.getNormal(shape[0])
     r = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),n)
     if round(abs(r.Angle),8) == round(math.pi,8):
         r = FreeCAD.Rotation()
     shapes = []
     for s in shape:
         s = s.copy()
         s.translate(v.negative())
         s.rotate(FreeCAD.Vector(0,0,0),r.Axis,math.degrees(-r.Angle))
         shapes.append(s)
     p = FreeCAD.Placement()
     p.Base = v
     p.Rotation = r
     if len(shapes) == 1:
         return (shapes[0],p)
     else:
         return(shapes,p)
Example #23
0
def getTuples(data, scale=1, placement=None):
    """getTuples(data,[scale,placement]): returns a tuple or a list of tuples from a vector
    or from the vertices of a shape. Scale can indicate a scale factor"""
    import Part

    if isinstance(data, FreeCAD.Vector):
        if placement:
            data = placement.multVec(data)
        return (data.x * scale, data.y * scale, data.z * scale)
    elif isinstance(data, Part.Shape):
        t = []
        if len(data.Wires) == 1:
            import Part, DraftGeomUtils

            data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges))
            verts = data.Vertexes
            # verts.reverse()
            for v in verts:
                pt = v.Point
                if placement:
                    pt = placement.multVec(pt)
                t.append((pt.x * scale, pt.y * scale, pt.z * scale))
            t.append(t[0])  # for IFC verts lists must be closed
        else:
            print "Arch.getTuples(): Wrong profile data"
        return t
Example #24
0
    def makeStraightStairsWithLanding(self,obj,edge):
        
        "builds a straight staircase with a landing in the middle"

        if obj.NumberOfSteps < 3:
            return
        import Part,DraftGeomUtils
        v = DraftGeomUtils.vec(edge)
        reslength = edge.Length - obj.Width.Value
        vLength = DraftVecUtils.scaleTo(v,float(reslength)/(obj.NumberOfSteps-2))
        vLength = Vector(vLength.x,vLength.y,0)
        vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value)
        p1 = edge.Vertexes[0].Point
        if round(v.z,Draft.precision()) != 0:
            h = v.z
        else:
            h = obj.Height.Value
        hstep = h/obj.NumberOfSteps
        landing = obj.NumberOfSteps/2
        p2 = p1.add(DraftVecUtils.scale(vLength,landing-1).add(Vector(0,0,landing*hstep)))
        p3 = p2.add(DraftVecUtils.scaleTo(vLength,obj.Width.Value))
        p4 = p3.add(DraftVecUtils.scale(vLength,obj.NumberOfSteps-(landing+1)).add(Vector(0,0,(obj.NumberOfSteps-landing)*hstep)))
        self.makeStraightStairs(obj,Part.Line(p1,p2).toShape(),landing)
        self.makeStraightLanding(obj,Part.Line(p2,p3).toShape())
        self.makeStraightStairs(obj,Part.Line(p3,p4).toShape(),obj.NumberOfSteps-landing)
Example #25
0
 def projectFace(self,face):
     "projects a single face on the WP"
     #print "VRM: projectFace start: ",len(face[0].Vertexes)," verts, ",len(face[0].Edges)," edges"
     wires = []
     if not face[0].Wires:
         if DEBUG: print "Error: Unable to project face on the WP"
         return None
     norm = face[0].normalAt(0,0)
     for w in face[0].Wires:
         verts = []
         edges = DraftGeomUtils.sortEdges(w.Edges)
         #print len(edges)," edges after sorting"
         for e in edges:
             v = e.Vertexes[0].Point
             #print v
             v = self.wp.getLocalCoords(v)
             verts.append(v)
         verts.append(verts[0])
         if len(verts) > 2:
             #print "new wire with ",len(verts)
             wires.append(Part.makePolygon(verts))
     try:
         sh = ArchCommands.makeFace(wires)
     except:
         if DEBUG: print "Error: Unable to project face on the WP"
         return None
     else:
         # restoring flipped normals
         vnorm = self.wp.getLocalCoords(norm)
         if vnorm.getAngle(sh.normalAt(0,0)) > 1:
             sh.reverse()
         #print "VRM: projectFace end: ",len(sh.Vertexes)," verts"
         return [sh]+face[1:]
Example #26
0
 def getAxisPoints(self,obj):
     "returns the gridpoints of linked axes"
     import DraftGeomUtils
     pts = []
     if len(obj.Axes) == 1:
         if hasattr(obj,"Align"):
             if obj.Align == True :
                 p0 = obj.Axes[0].Shape.Edges[0].Vertexes[1].Point
                 for e in obj.Axes[0].Shape.Edges:
                     p = e.Vertexes[1].Point
                     p = p.sub(p0)
                     pts.append(p)
             else:
                 for e in obj.Axes[0].Shape.Edges:
                     pts.append(e.Vertexes[0].Point)
         else:
             for e in obj.Axes[0].Shape.Edges:
                     pts.append(e.Vertexes[0].Point)
     elif len(obj.Axes) >= 2:
         set1 = obj.Axes[0].Shape.Edges
         set2 = obj.Axes[1].Shape.Edges
         for e1 in set1:
             for e2 in set2:
                 pts.extend(DraftGeomUtils.findIntersection(e1,e2))
     return pts
Example #27
0
def mergeShapes(w1,w2):

    "returns a Shape built on two walls that share same properties and have a coincident endpoint"

    if not areSameWallTypes([w1,w2]):
        return None
    if (not hasattr(w1.Base,"Shape")) or (not hasattr(w2.Base,"Shape")):
        return None
    if w1.Base.Shape.Faces or w2.Base.Shape.Faces:
        return None

    # TODO fix this
    return None

    eds = w1.Base.Shape.Edges + w2.Base.Shape.Edges
    import DraftGeomUtils
    w = DraftGeomUtils.findWires(eds)
    if len(w) == 1:
        #print("found common wire")
        normal,length,width,height = w1.Proxy.getDefaultValues(w1)
        print(w[0].Edges)
        sh = w1.Proxy.getBase(w1,w[0],normal,width,height)
        print(sh)
        return sh
    return None
Example #28
0
 def projectFace(self,face):
     "projects a single face on the WP"
     wires = []
     norm = face[0].normalAt(0,0)
     for w in face[0].Wires:
         verts = []
         edges = DraftGeomUtils.sortEdges(w.Edges)
         for e in edges:
             v = e.Vertexes[0].Point
             v = self.wp.getLocalCoords(v)
             verts.append(v)
         verts.append(verts[0])
         if len(verts) > 2:
             wires.append(Part.makePolygon(verts))
     try:
         sh = ArchCommands.makeFace(wires)
     except:
         if DEBUG: print "Error: Unable to project face on the WP"
         return None
     else:
         # restoring flipped normals
         vnorm = self.wp.getLocalCoords(norm)
         if vnorm.getAngle(sh.normalAt(0,0)) > 1:
             sh.reverse()
         return [sh]+face[1:]
Example #29
0
def closeHole(shape):
    """closeHole(shape): closes a hole in an open shape"""
    import DraftGeomUtils, Part

    # creating an edges lookup table
    lut = {}
    for face in shape.Faces:
        for edge in face.Edges:
            hc = edge.hashCode()
            if lut.has_key(hc):
                lut[hc] = lut[hc] + 1
            else:
                lut[hc] = 1
    # filter out the edges shared by more than one face
    bound = []
    for e in shape.Edges:
        if lut[e.hashCode()] == 1:
            bound.append(e)
    bound = DraftGeomUtils.sortEdges(bound)
    try:
        nface = Part.Face(Part.Wire(bound))
        shell = Part.makeShell(shape.Faces + [nface])
        solid = Part.Solid(shell)
    except:
        raise
    else:
        return solid
Example #30
0
    def execute(self,obj):
        import Part, math, DraftGeomUtils
        pl = obj.Placement
        self.baseface = None

        base = None
        if obj.Base and obj.Angle:
            w = None
            if obj.Base.isDerivedFrom("Part::Feature"):
                if (obj.Base.Shape.Faces and obj.Face):
                    w = obj.Base.Shape.Faces[obj.Face-1].Wires[0]
                elif obj.Base.Shape.Wires:
                    w = obj.Base.Shape.Wires[0]
            if w:
                if w.isClosed():
                    f = Part.Face(w)
                    self.baseface = f.copy()
                    norm = f.normalAt(0,0)
                    c = round(math.tan(math.radians(obj.Angle)),Draft.precision())
                    d = f.BoundBox.DiagonalLength
                    edges = DraftGeomUtils.sortEdges(f.Edges)
                    l = len(edges)
                    edges.append(edges[0])
                    shps = []
                    for i in range(l):
                        v = DraftGeomUtils.vec(DraftGeomUtils.angleBisection(edges[i],edges[i+1]))
                        v.normalize()
                        bis = v.getAngle(DraftGeomUtils.vec(edges[i]))
                        delta = 1/math.cos(bis)
                        v.multiply(delta)
                        n = (FreeCAD.Vector(norm)).multiply(c)
                        dv = v.add(n)
                        dv.normalize()
                        dv.scale(d,d,d)
                        shps.append(f.extrude(dv))
                    base = shps.pop()
                    for s in shps:
                        base = base.common(s)
                    base = base.removeSplitter()
                    if not base.isNull():
                        if not DraftGeomUtils.isNull(pl):
                            base.Placement = pl
                            
        base = self.processSubShapes(obj,base)
        if base:
            if not base.isNull():
                obj.Shape = base
Example #31
0
    def execute(self, obj):

        if self.clone(obj):
            return

        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return

        pl = obj.Placement
        if obj.Base.Shape.Solids:
            obj.Shape = obj.Base.Shape.copy()
            if not pl.isNull():
                obj.Placement = obj.Shape.Placement.multiply(pl)
        else:
            if not obj.Profile:
                return
            if not obj.Profile.isDerivedFrom("Part::Part2DObject"):
                return
            if not obj.Profile.Shape:
                return
            if not obj.Profile.Shape.Wires:
                return
            if not obj.Profile.Shape.Faces:
                for w in obj.Profile.Shape.Wires:
                    if not w.isClosed():
                        return
            import DraftGeomUtils, Part, math
            baseprofile = obj.Profile.Shape.copy()
            if hasattr(obj, "ProfilePlacement"):
                if not obj.ProfilePlacement.isNull():
                    baseprofile.Placement = obj.ProfilePlacement.multiply(
                        baseprofile.Placement)
            if not baseprofile.Faces:
                f = []
                for w in baseprofile.Wires:
                    f.append(Part.Face(w))
                if len(f) == 1:
                    baseprofile = f[0]
                else:
                    baseprofile = Part.makeCompound(f)
            shapes = []
            normal = DraftGeomUtils.getNormal(obj.Base.Shape)
            #for wire in obj.Base.Shape.Wires:
            edges = obj.Base.Shape.Edges
            if hasattr(obj, "Edges"):
                if obj.Edges == "Vertical edges":
                    rv = obj.Base.Placement.Rotation.multVec(
                        FreeCAD.Vector(0, 1, 0))
                    edges = [
                        e for e in edges
                        if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4)
                        in [0, 3.1416]
                    ]
                elif obj.Edges == "Horizontal edges":
                    rv = obj.Base.Placement.Rotation.multVec(
                        FreeCAD.Vector(1, 0, 0))
                    edges = [
                        e for e in edges
                        if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4)
                        in [0, 3.1416]
                    ]
                elif obj.Edges == "Top Horizontal edges":
                    rv = obj.Base.Placement.Rotation.multVec(
                        FreeCAD.Vector(1, 0, 0))
                    edges = [
                        e for e in edges
                        if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4)
                        in [0, 3.1416]
                    ]
                    edges = sorted(edges,
                                   key=lambda x: x.CenterOfMass.z,
                                   reverse=True)
                    z = edges[0].CenterOfMass.z
                    edges = [
                        e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001
                    ]
                elif obj.Edges == "Bottom Horizontal edges":
                    rv = obj.Base.Placement.Rotation.multVec(
                        FreeCAD.Vector(1, 0, 0))
                    edges = [
                        e for e in edges
                        if round(rv.getAngle(e.tangentAt(e.FirstParameter)), 4)
                        in [0, 3.1416]
                    ]
                    edges = sorted(edges, key=lambda x: x.CenterOfMass.z)
                    z = edges[0].CenterOfMass.z
                    edges = [
                        e for e in edges if abs(e.CenterOfMass.z - z) < 0.00001
                    ]
            for e in edges:
                #e = wire.Edges[0]
                bvec = DraftGeomUtils.vec(e)
                bpoint = e.Vertexes[0].Point
                profile = baseprofile.copy()
                #basepoint = profile.Placement.Base
                if hasattr(obj, "BasePoint"):
                    edges = Part.__sortEdges__(profile.Edges)
                    basepointliste = [profile.CenterOfMass]
                    for edge in edges:
                        basepointliste.append(
                            DraftGeomUtils.findMidpoint(edge))
                        basepointliste.append(edge.Vertexes[-1].Point)
                    try:
                        basepoint = basepointliste[obj.BasePoint]
                    except IndexError:
                        FreeCAD.Console.PrintMessage(
                            translate(
                                "Arch",
                                "Crossing point not found in profile.\n"))
                        basepoint = basepointliste[0]
                else:
                    basepoint = profile.CenterOfMass
                profile.translate(bpoint.sub(basepoint))
                if obj.Align:
                    axis = profile.Placement.Rotation.multVec(
                        FreeCAD.Vector(0, 0, 1))
                    angle = bvec.getAngle(axis)
                    if round(angle, Draft.precision()) != 0:
                        if round(angle, Draft.precision()) != round(
                                math.pi, Draft.precision()):
                            rotaxis = axis.cross(bvec)
                            profile.rotate(DraftVecUtils.tup(bpoint),
                                           DraftVecUtils.tup(rotaxis),
                                           math.degrees(angle))
                if obj.Rotation:
                    profile.rotate(
                        DraftVecUtils.tup(bpoint),
                        DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()),
                        obj.Rotation)
                #profile = wire.makePipeShell([profile],True,False,2) TODO buggy
                profile = profile.extrude(bvec)
                if obj.Offset:
                    if not DraftVecUtils.isNull(obj.Offset):
                        profile.translate(obj.Offset)
                shapes.append(profile)
            if shapes:
                if hasattr(obj, "Fuse"):
                    if obj.Fuse:
                        if len(shapes) > 1:
                            s = shapes[0].multiFuse(shapes[1:])
                            s = s.removeSplitter()
                            obj.Shape = s
                            obj.Placement = pl
                            return
                obj.Shape = Part.makeCompound(shapes)
                obj.Placement = pl
Example #32
0
    def execute(self, obj):

        if self.clone(obj):
            return

        import Part, math, DraftGeomUtils
        pl = obj.Placement
        #self.baseface = None

        base = None
        w = None
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Base.Shape.Solids:
                    base = obj.Base.Shape
                    #pl = obj.Base.Placement
                else:
                    if (obj.Base.Shape.Faces and obj.Face):
                        w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0]
                    elif obj.Base.Shape.Wires:
                        w = obj.Base.Shape.Wires[0]
        if w:
            if w.isClosed():
                self.profilsDico = []
                self.shps = []
                self.subVolshps = []
                heights = []
                edges = Part.__sortEdges__(w.Edges)
                l = len(edges)
                for i in range(l):
                    self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i],
                                            obj.IdRel[i], obj.Overhang[i],
                                            obj.Thickness[i])
                for i in range(l):
                    self.calcMissingData(i)
                for i in range(l):
                    self.calcEdgeGeometry(edges, i)
                for i in range(l):
                    self.calcDraftEdges(i)
                for i in range(l):
                    self.calcEave(i)
                for p in self.profilsDico:
                    heights.append(p["height"])
                obj.Heights = heights
                for i in range(l):
                    self.getRoofPaneProject(i)
                    profilCurrent = self.findProfil(i)
                    midpoint = DraftGeomUtils.findMidpoint(
                        profilCurrent["edge"])
                    ptsPaneProject = profilCurrent["points"]
                    lp = len(ptsPaneProject)
                    if lp != 0:
                        ptsPaneProject.append(ptsPaneProject[0])
                        edgesWire = []
                        for p in range(lp):
                            edge = Part.makeLine(ptsPaneProject[p],
                                                 ptsPaneProject[p + 1])
                            edgesWire.append(edge)
                        wire = Part.Wire(edgesWire)
                        d = wire.BoundBox.DiagonalLength
                        thicknessV = profilCurrent["thickness"] / (math.cos(
                            math.radians(profilCurrent["angle"])))
                        overhangV = profilCurrent["overhang"] * math.tan(
                            math.radians(profilCurrent["angle"]))
                        if wire.isClosed():
                            f = Part.Face(wire)
                            f = f.extrude(
                                FreeCAD.Vector(
                                    0, 0, profilCurrent["height"] + 1000000.0))
                            f.translate(
                                FreeCAD.Vector(0.0, 0.0, -2 * overhangV))
                        ptsPaneProfil = [
                            FreeCAD.Vector(-profilCurrent["overhang"],
                                           -overhangV, 0.0),
                            FreeCAD.Vector(profilCurrent["run"],
                                           profilCurrent["height"], 0.0),
                            FreeCAD.Vector(
                                profilCurrent["run"],
                                profilCurrent["height"] + thicknessV, 0.0),
                            FreeCAD.Vector(-profilCurrent["overhang"],
                                           -overhangV + thicknessV, 0.0)
                        ]
                        self.shps.append(
                            self.createProfilShape(ptsPaneProfil, midpoint,
                                                   profilCurrent["rot"],
                                                   profilCurrent["vec"],
                                                   profilCurrent["run"], d, f))
                        ## subVolume shape
                        ptsSubVolumeProfil = [
                            FreeCAD.Vector(-profilCurrent["overhang"],
                                           -overhangV, 0.0),
                            FreeCAD.Vector(profilCurrent["run"],
                                           profilCurrent["height"], 0.0),
                            FreeCAD.Vector(profilCurrent["run"],
                                           profilCurrent["height"] + 900000.0,
                                           0.0),
                            FreeCAD.Vector(-profilCurrent["overhang"],
                                           profilCurrent["height"] + 900000.0,
                                           0.0)
                        ]
                        self.subVolshps.append(
                            self.createProfilShape(ptsSubVolumeProfil,
                                                   midpoint,
                                                   profilCurrent["rot"],
                                                   profilCurrent["vec"],
                                                   profilCurrent["run"], d, f))
                ## SubVolume
                self.sub = self.subVolshps.pop()
                for s in self.subVolshps:
                    self.sub = self.sub.fuse(s)
                self.sub = self.sub.removeSplitter()
                if not self.sub.isNull():
                    if not DraftGeomUtils.isNull(pl):
                        self.sub.Placement = pl
                ## BaseVolume
                base = self.shps.pop()
                for s in self.shps:
                    base = base.fuse(s)
                base = self.processSubShapes(obj, base)
                self.applyShape(obj, base, pl, allownosolid=True)
        elif base:
            base = self.processSubShapes(obj, base)
            self.applyShape(obj, base, pl, allownosolid=True)
        else:
            FreeCAD.Console.PrintMessage(
                translate("Arch", "Unable to create a roof"))
Example #33
0
    def buildpathocc(self, obj, shape):
        """Build pocket Path using Native OCC algorithm."""
        import Part
        import DraftGeomUtils
        from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge, depth_params

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

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

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

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

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

            if helixBounds:
                rampD = obj.RampSize

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

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

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

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

        startPoint = None

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

        for vpos in depthparams.get_depths():

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

        # move back up
        output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
        return output
Example #34
0
    def getRebarData(self, obj):

        if not obj.Host:
            return
        if Draft.getType(obj.Host) != "Structure":
            return
        if not obj.Host.Shape:
            return
        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return
        if not obj.Diameter.Value:
            return
        if not obj.Amount:
            return
        father = obj.Host
        wire = obj.Base.Shape.Wires[0]
        if Draft.getType(
                obj.Base) == "Wire":  # Draft Wires can have "wrong" placement
            import DraftGeomUtils
            axis = DraftGeomUtils.getNormal(obj.Base.Shape)
        else:
            axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(
                0, 0, -1))
        size = (ArchCommands.projectToVector(father.Shape.copy(), axis)).Length
        if hasattr(obj, "Direction"):
            if not DraftVecUtils.isNull(obj.Direction):
                axis = FreeCAD.Vector(obj.Direction)
                axis.normalize()
        if hasattr(obj, "Distance"):
            if obj.Distance.Value:
                size = obj.Distance.Value
        if hasattr(obj, "Rounding"):
            if obj.Rounding:
                radius = obj.Rounding * obj.Diameter.Value
                import DraftGeomUtils
                wire = DraftGeomUtils.filletWire(wire, radius)
        wires = []
        if obj.Amount == 1:
            offset = DraftVecUtils.scaleTo(axis, size / 2)
            wire.translate(offset)
            wires.append(wire)
        else:
            if obj.OffsetStart.Value:
                baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value)
            else:
                baseoffset = None
            if obj.ViewObject.RebarShape == "Stirrup":
                interval = size - (obj.OffsetStart.Value +
                                   obj.OffsetEnd.Value + obj.Diameter.Value)
            else:
                interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value)
            interval = interval / (obj.Amount - 1)
            vinterval = DraftVecUtils.scaleTo(axis, interval)
            for i in range(obj.Amount):
                if i == 0:
                    if baseoffset:
                        wire.translate(baseoffset)
                    wires.append(wire)
                else:
                    wire = wire.copy()
                    wire.translate(vinterval)
                    wires.append(wire)
        return [wires, obj.Diameter.Value / 2]
Example #35
0
    def buildpathocc(self, obj, wires, zValues):
        '''buildpathocc(obj, wires, zValues) ... internal helper function to generate engraving commands.'''
        PathLog.track(obj.Label, len(wires), zValues)

        for wire in wires:
            offset = wire

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

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

                for edge in offset.Edges:
                    if not last:
                        # we set the first move to our first point
                        last = edge.Vertexes[0].Point
                        if len(offset.Edges) > 1:
                            e2 = offset.Edges[1]
                            if not PathGeom.pointsCoincide(
                                    edge.Vertexes[-1].Point, e2.Vertexes[0].
                                    Point) and not PathGeom.pointsCoincide(
                                        edge.Vertexes[-1].Point,
                                        e2.Vertexes[-1].Point):
                                PathLog.debug("flip first edge")
                                last = edge.Vertexes[-1].Point
                            else:
                                PathLog.debug("original first edge")
                        else:
                            PathLog.debug("not enough edges to flip")
                        self.commandlist.append(
                            Path.Command(
                                'G0', {
                                    'X': last.x,
                                    'Y': last.y,
                                    'Z': obj.ClearanceHeight.Value,
                                    'F': self.horizRapid
                                }))
                        self.commandlist.append(
                            Path.Command(
                                'G0', {
                                    'X': last.x,
                                    'Y': last.y,
                                    'Z': obj.SafeHeight.Value,
                                    'F': self.vertRapid
                                }))
                        self.commandlist.append(
                            Path.Command(
                                'G0', {
                                    'X': last.x,
                                    'Y': last.y,
                                    'Z': z,
                                    'F': self.vertFeed
                                }))

                    if PathGeom.pointsCoincide(last, edge.Vertexes[0].Point):
                        for cmd in PathGeom.cmdsForEdge(edge):
                            params = cmd.Parameters
                            params.update({'Z': z, 'F': self.horizFeed})
                            self.commandlist.append(
                                Path.Command(cmd.Name, params))
                        last = edge.Vertexes[-1].Point
                    else:
                        for cmd in PathGeom.cmdsForEdge(edge, True):
                            params = cmd.Parameters
                            params.update({'Z': z, 'F': self.horizFeed})
                            self.commandlist.append(
                                Path.Command(cmd.Name, params))
                        last = edge.Vertexes[0].Point
            self.commandlist.append(
                Path.Command('G0', {
                    'Z': obj.ClearanceHeight.Value,
                    'F': self.vertRapid
                }))
        if self.commandlist:
            self.commandlist.pop()
Example #36
0
    def execute(self,obj):
        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return

        pl = obj.Placement
        if obj.Base.Shape.Solids:
            obj.Shape = obj.Base.Shape.copy()
            if not pl.isNull():
                obj.Placement = obj.Shape.Placement.multiply(pl)
        else:
            if not obj.Profile:
                return
            if not obj.Profile.isDerivedFrom("Part::Part2DObject"):
                return
            if not obj.Profile.Shape:
                return
            if not obj.Profile.Shape.Wires:
                return
            if not obj.Profile.Shape.Faces:
                for w in obj.Profile.Shape.Wires:
                    if not w.isClosed():
                        return
            import DraftGeomUtils, Part, math
            baseprofile = obj.Profile.Shape.copy()
            if not baseprofile.Faces:
                f = []
                for w in baseprofile.Wires:
                    f.append(Part.Face(w))
                if len(f) == 1:
                    baseprofile = f[0]
                else:
                    baseprofile = Part.makeCompound(f)
            shapes = []
            normal = DraftGeomUtils.getNormal(obj.Base.Shape)
            #for wire in obj.Base.Shape.Wires:
            for e in obj.Base.Shape.Edges:
                #e = wire.Edges[0]
                bvec = DraftGeomUtils.vec(e)
                bpoint = e.Vertexes[0].Point
                profile = baseprofile.copy()
                #basepoint = profile.Placement.Base
                basepoint = profile.CenterOfMass
                profile.translate(bpoint.sub(basepoint))
                if obj.Align:
                    axis = profile.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1))
                    angle = bvec.getAngle(axis)
                    if round(angle,Draft.precision()) != 0:
                        if round(angle,Draft.precision()) != round(math.pi,Draft.precision()):
                            rotaxis = axis.cross(bvec)
                            profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle))
                if obj.Rotation:
                    profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation)
                #profile = wire.makePipeShell([profile],True,False,2) TODO buggy
                profile = profile.extrude(bvec)
                if obj.Offset:
                    if not DraftVecUtils.isNull(obj.Offset):
                        profile.translate(obj.Offset)
                shapes.append(profile)
            if shapes:
                obj.Shape = Part.makeCompound(shapes)
                obj.Placement = pl
Example #37
0
def getSVG(obj,
           scale=1,
           linewidth=0.35,
           fontsize=12,
           fillstyle="shape color",
           direction=None,
           linestyle=None,
           color=None,
           linespacing=None,
           techdraw=False,
           rotation=0,
           fillSpaces=False,
           override=True):
    '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle],[color],[linespacing]):
    returns a string containing a SVG representation of the given object,
    with the given linewidth and fontsize (used if the given object contains
    any text). You can also supply an arbitrary projection vector. the
    scale parameter allows to scale linewidths down, so they are resolution-independant.'''

    import Part, DraftGeomUtils

    # if this is a group, gather all the svg views of its children
    if hasattr(obj, "isDerivedFrom"):
        if obj.isDerivedFrom("App::DocumentObjectGroup") or getType(
                obj) == "Layer":
            svg = ""
            for child in obj.Group:
                svg += getSVG(child, scale, linewidth, fontsize, fillstyle,
                              direction, linestyle, color, linespacing,
                              techdraw, rotation, fillSpaces, override)
            return svg

    pathdata = []
    svg = ""
    linewidth = float(linewidth) / scale
    if not override:
        if hasattr(obj, "ViewObject"):
            if hasattr(obj.ViewObject, "LineWidth"):
                if hasattr(obj.ViewObject.LineWidth, "Value"):
                    lw = obj.ViewObject.LineWidth.Value
                else:
                    lw = obj.ViewObject.LineWidth
                linewidth = lw * linewidth
    fontsize = (float(fontsize) / scale) / 2
    if linespacing:
        linespacing = float(linespacing) / scale
    else:
        linespacing = 0.5
    #print obj.Label," line spacing ",linespacing,"scale ",scale
    pointratio = .75  # the number of times the dots are smaller than the arrow size
    plane = None
    if direction:
        if isinstance(direction, FreeCAD.Vector):
            if direction != Vector(0, 0, 0):
                plane = WorkingPlane.plane()
                plane.alignToPointAndAxis_SVG(Vector(0, 0, 0),
                                              direction.negative().negative(),
                                              0)
        elif isinstance(direction, WorkingPlane.plane):
            plane = direction
    stroke = "#000000"
    if color and override:
        if "#" in color:
            stroke = color
        else:
            stroke = getrgb(color)
    elif gui:
        if hasattr(obj, "ViewObject"):
            if hasattr(obj.ViewObject, "LineColor"):
                stroke = getrgb(obj.ViewObject.LineColor)
            elif hasattr(obj.ViewObject, "TextColor"):
                stroke = getrgb(obj.ViewObject.TextColor)
    lstyle = "none"
    if override:
        lstyle = getLineStyle(linestyle, scale)
    else:
        if hasattr(obj, "ViewObject"):
            if hasattr(obj.ViewObject, "DrawStyle"):
                lstyle = getLineStyle(obj.ViewObject.DrawStyle, scale)

    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

    def getCircle(edge):
        cen = getProj(edge.Curve.Center, plane)
        rad = edge.Curve.Radius
        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
        if round(edge.Curve.Axis.getAngle(drawing_plane_normal),
                 2) in [0, 3.14]:
            # perpendicular projection: circle
            svg = '<circle cx="' + str(cen.x)
            svg += '" cy="' + str(cen.y)
            svg += '" r="' + str(rad) + '" '
        else:
            # any other projection: ellipse
            svg = '<path d="'
            svg += getDiscretized(edge, plane)
            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 + '"'
        svg += '/>\n'
        return svg

    def getEllipse(edge):
        cen = getProj(edge.Curve.Center, plane)
        mir = edge.Curve.MinorRadius
        mar = edge.Curve.MajorRadius
        svg = '<ellipse cx="' + str(cen.x)
        svg += '" cy="' + str(cen.y)
        svg += '" rx="' + str(mar)
        svg += '" ry="' + str(mir) + '" '
        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 + '"'
        svg += '/>\n'
        return svg

    def getArrow(arrowtype, point, arrowsize, color, linewidth, angle=0):
        svg = ""
        if gui:
            if not obj.ViewObject:
                return svg
            if obj.ViewObject.ArrowType == "Circle":
                svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y)
                svg += '" r="' + str(arrowsize) + '" '
                svg += 'fill="none" stroke="' + color + '" '
                svg += 'style="stroke-width:' + str(
                    linewidth) + ';stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'freecad:skip="1"'
                svg += '/>\n'
            elif obj.ViewObject.ArrowType == "Dot":
                svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y)
                svg += '" r="' + str(arrowsize) + '" '
                svg += 'fill="' + color + '" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'freecad:skip="1"'
                svg += '/>\n'
            elif obj.ViewObject.ArrowType == "Arrow":
                svg += '<path transform="rotate(' + str(math.degrees(angle))
                svg += ',' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'scale(' + str(arrowsize) + ',' + str(
                    arrowsize) + ')" freecad:skip="1" '
                svg += 'fill="' + color + '" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'd="M 0 0 L 4 1 L 4 -1 Z"/>\n'
            elif obj.ViewObject.ArrowType == "Tick":
                svg += '<path transform="rotate(' + str(math.degrees(angle))
                svg += ',' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'scale(' + str(arrowsize) + ',' + str(
                    arrowsize) + ')" freecad:skip="1" '
                svg += 'fill="' + color + '" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"/>\n'
            elif obj.ViewObject.ArrowType == "Tick-2":
                svg += '<line transform="rotate(' + str(
                    math.degrees(angle) + 45)
                svg += ',' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += '" freecad:skip="1" '
                svg += 'fill="none" stroke="' + color + '" '
                svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
                svg += 'stroke-width:' + str(linewidth) + '" '
                svg += 'x1="-' + str(arrowsize * 2) + '" y1="0" '
                svg += 'x2="' + str(arrowsize * 2) + '" y2="0" />\n'
            else:
                print("getSVG: arrow type not implemented")
        return svg

    def getOvershoot(point, shootsize, color, linewidth, angle=0):
        svg = '<line transform="rotate(' + str(math.degrees(angle))
        svg += ',' + str(point.x) + ',' + str(point.y) + ') '
        svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
        svg += '" freecad:skip="1" '
        svg += 'fill="none" stroke="' + color + '" '
        svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
        svg += 'stroke-width:' + str(linewidth) + '" '
        svg += 'x1="0" y1="0" '
        svg += 'x2="' + str(shootsize * -1) + '" y2="0" />\n'
        return svg

    def getText(tcolor,
                fontsize,
                fontname,
                angle,
                base,
                text,
                linespacing=0.5,
                align="center",
                flip=True):
        if isinstance(angle, FreeCAD.Rotation):
            if not plane:
                angle = angle.Angle
            else:
                if plane.axis.getAngle(angle.Axis) < 0.001:
                    angle = angle.Angle
                elif abs(plane.axis.getAngle(angle.Axis) - math.pi) < 0.001:
                    if abs(angle.Angle) > 0.1:
                        angle = -angle.Angle
                    else:
                        angle = angle.Angle
                elif abs(plane.axis.getAngle(angle.Axis) -
                         math.pi / 2) < 0.001:
                    return ""  # text is perpendicular to view, so it shouldn't appear
                else:
                    angle = 0  #TODO maybe there is something better to do here?
        if not isinstance(text, list):
            text = text.split("\n")
        if align.lower() == "center":
            anchor = "middle"
        elif align.lower() == "left":
            anchor = "start"
        else:
            anchor = "end"
        if techdraw:
            svg = ""
            for i in range(len(text)):
                t = text[i].replace("&", "&amp;").replace("<", "&lt;").replace(
                    ">", "&gt;")
                if six.PY2 and not isinstance(t, six.text_type):
                    t = t.decode("utf8")
                # possible workaround if UTF8 is unsupported
                #    import unicodedata
                #    t = u"".join([c for c in unicodedata.normalize("NFKD",t) if not unicodedata.combining(c)]).encode("utf8")
                svg += '<text stroke-width="0" stroke="' + tcolor + '" fill="' + tcolor + '" font-size="' + str(
                    fontsize) + '" '
                svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower(
                ) + ';'
                svg += 'font-family:' + fontname + '" '
                svg += 'transform="rotate(' + str(math.degrees(angle))
                svg += ',' + str(
                    base.x) + ',' + str(base.y - linespacing * i) + ') '
                svg += 'translate(' + str(
                    base.x) + ',' + str(base.y - linespacing * i) + ') '
                svg += 'scale(1,-1)" '
                #svg += '" freecad:skip="1"'
                svg += '>\n' + t + '</text>\n'
        else:
            svg = '<text stroke-width="0" stroke="' + tcolor + '" fill="'
            svg += tcolor + '" font-size="'
            svg += str(fontsize) + '" '
            svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower(
            ) + ';'
            svg += 'font-family:' + fontname + '" '
            svg += 'transform="rotate(' + str(math.degrees(angle))
            svg += ',' + str(base.x) + ',' + str(base.y) + ') '
            if flip:
                svg += 'translate(' + str(base.x) + ',' + str(base.y) + ')'
            else:
                svg += 'translate(' + str(base.x) + ',' + str(-base.y) + ')'
            #svg += 'scale('+str(tmod/2000)+',-'+str(tmod/2000)+') '
            if flip:
                svg += ' scale(1,-1) '
            else:
                svg += ' scale(1,1) '
            svg += '" freecad:skip="1"'
            svg += '>\n'
            if len(text) == 1:
                try:
                    svg += text[0].replace("&", "&amp;").replace(
                        "<", "&lt;").replace(">", "&gt;")
                except:
                    svg += text[0].decode("utf8").replace(
                        "&", "&amp;").replace("<",
                                              "&lt;").replace(">", "&gt;")
            else:
                for i in range(len(text)):
                    if i == 0:
                        svg += '<tspan>'
                    else:
                        svg += '<tspan x="0" dy="' + str(linespacing) + '">'
                    try:
                        svg += text[i].replace("&", "&amp;").replace(
                            "<", "&lt;").replace(">", "&gt;")
                    except:
                        svg += text[i].decode("utf8").replace(
                            "&", "&amp;").replace("<",
                                                  "&lt;").replace(">", "&gt;")
                    svg += '</tspan>\n'
            svg += '</text>\n'
        return svg

    if not obj:
        pass

    elif isinstance(obj, Part.Shape):
        if "#" in fillstyle:
            fill = fillstyle
        elif fillstyle == "shape color":
            fill = "#888888"
        else:
            fill = 'url(#' + fillstyle + ')'
        svg += getPath(obj.Edges, pathname="")

    elif getType(obj) in ["Dimension", "LinearDimension"]:
        if gui:
            if not obj.ViewObject:
                print(
                    "export of dimensions to SVG is only available in GUI mode"
                )
            elif obj.ViewObject.Proxy:
                if hasattr(obj.ViewObject.Proxy, "p1"):
                    prx = obj.ViewObject.Proxy
                    ts = (len(prx.string) *
                          obj.ViewObject.FontSize.Value) / 4.0
                    rm = ((prx.p3.sub(prx.p2)).Length / 2.0) - ts
                    p2a = getProj(
                        prx.p2.add(
                            DraftVecUtils.scaleTo(prx.p3.sub(prx.p2), rm)),
                        plane)
                    p2b = getProj(
                        prx.p3.add(
                            DraftVecUtils.scaleTo(prx.p2.sub(prx.p3), rm)),
                        plane)
                    p1 = getProj(prx.p1, plane)
                    p2 = getProj(prx.p2, plane)
                    p3 = getProj(prx.p3, plane)
                    p4 = getProj(prx.p4, plane)
                    tbase = getProj(prx.tbase, plane)
                    r = prx.textpos.rotation.getValue().getValue()
                    rv = FreeCAD.Rotation(r[0], r[1], r[2], r[3]).multVec(
                        FreeCAD.Vector(1, 0, 0))
                    angle = -DraftVecUtils.angle(getProj(rv, plane))
                    #angle = -DraftVecUtils.angle(p3.sub(p2))

                    svg = ''
                    nolines = False
                    if hasattr(obj.ViewObject, "ShowLine"):
                        if not obj.ViewObject.ShowLine:
                            nolines = True

                    # drawing lines
                    if not nolines:
                        svg += '<path '
                    if obj.ViewObject.DisplayMode == "2D":
                        tangle = angle
                        if tangle > math.pi / 2:
                            tangle = tangle - math.pi
                        #elif (tangle <= -math.pi/2) or (tangle > math.pi/2):
                        #    tangle = tangle+math.pi
                        #tbase = tbase.add(DraftVecUtils.rotate(Vector(0,2/scale,0),tangle))
                        if rotation != 0:
                            #print "dim: tangle:",tangle," rot: ",rotation," text: ",prx.string
                            if abs(tangle + math.radians(rotation)) < 0.0001:
                                tangle += math.pi
                                tbase = tbase.add(
                                    DraftVecUtils.rotate(
                                        Vector(0, 2 / scale, 0), tangle))
                        if not nolines:
                            svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' '
                            svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' '
                            svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' '
                            svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" '
                    else:
                        tangle = 0
                        if rotation != 0:
                            tangle = -math.radians(rotation)
                        tbase = tbase.add(Vector(0, -2.0 / scale, 0))
                        if not nolines:
                            svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' '
                            svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' '
                            svg += 'L ' + str(p2a.x) + ' ' + str(p2a.y) + ' '
                            svg += 'M ' + str(p2b.x) + ' ' + str(p2b.y) + ' '
                            svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' '
                            svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" '

                    if not nolines:
                        svg += 'fill="none" stroke="'
                        svg += stroke + '" '
                        svg += 'stroke-width="' + str(linewidth) + ' px" '
                        svg += 'style="stroke-width:' + str(linewidth)
                        svg += ';stroke-miterlimit:4;stroke-dasharray:none" '
                        svg += 'freecad:basepoint1="' + str(p1.x) + ' ' + str(
                            p1.y) + '" '
                        svg += 'freecad:basepoint2="' + str(p4.x) + ' ' + str(
                            p4.y) + '" '
                        svg += 'freecad:dimpoint="' + str(p2.x) + ' ' + str(
                            p2.y) + '"'
                        svg += '/>\n'

                        # drawing dimension and extension lines overshoots
                        if hasattr(obj.ViewObject, "DimOvershoot"
                                   ) and obj.ViewObject.DimOvershoot.Value:
                            shootsize = obj.ViewObject.DimOvershoot.Value / pointratio
                            svg += getOvershoot(p2, shootsize, stroke,
                                                linewidth, angle)
                            svg += getOvershoot(p3, shootsize, stroke,
                                                linewidth, angle + math.pi)
                        if hasattr(obj.ViewObject, "ExtOvershoot"
                                   ) and obj.ViewObject.ExtOvershoot.Value:
                            shootsize = obj.ViewObject.ExtOvershoot.Value / pointratio
                            shootangle = -DraftVecUtils.angle(p1.sub(p2))
                            svg += getOvershoot(p2, shootsize, stroke,
                                                linewidth, shootangle)
                            svg += getOvershoot(p3, shootsize, stroke,
                                                linewidth, shootangle)

                        # drawing arrows
                        if hasattr(obj.ViewObject, "ArrowType"):
                            arrowsize = obj.ViewObject.ArrowSize.Value / pointratio
                            if hasattr(obj.ViewObject, "FlipArrows"):
                                if obj.ViewObject.FlipArrows:
                                    angle = angle + math.pi
                            svg += getArrow(obj.ViewObject.ArrowType, p2,
                                            arrowsize, stroke, linewidth,
                                            angle)
                            svg += getArrow(obj.ViewObject.ArrowType, p3,
                                            arrowsize, stroke, linewidth,
                                            angle + math.pi)

                    # drawing text
                    svg += getText(stroke, fontsize, obj.ViewObject.FontName,
                                   tangle, tbase, prx.string)

    elif getType(obj) == "AngularDimension":
        if gui:
            if not obj.ViewObject:
                print(
                    "export of dimensions to SVG is only available in GUI mode"
                )
            elif obj.ViewObject.Proxy:
                if hasattr(obj.ViewObject.Proxy, "circle"):
                    prx = obj.ViewObject.Proxy

                    # drawing arc
                    fill = "none"
                    if obj.ViewObject.DisplayMode == "2D":
                        svg += getPath([prx.circle])
                    else:
                        if hasattr(prx, "circle1"):
                            svg += getPath([prx.circle1])
                            svg += getPath([prx.circle2])
                        else:
                            svg += getPath([prx.circle])

                    # drawing arrows
                    if hasattr(obj.ViewObject, "ArrowType"):
                        p2 = getProj(prx.p2, plane)
                        p3 = getProj(prx.p3, plane)
                        arrowsize = obj.ViewObject.ArrowSize.Value / pointratio
                        arrowlength = 4 * obj.ViewObject.ArrowSize.Value
                        u1 = getProj(
                            (prx.circle.valueAt(prx.circle.FirstParameter +
                                                arrowlength)
                             ).sub(
                                 prx.circle.valueAt(
                                     prx.circle.FirstParameter)), plane)
                        u2 = getProj(
                            (prx.circle.valueAt(prx.circle.LastParameter -
                                                arrowlength)
                             ).sub(prx.circle.valueAt(
                                 prx.circle.LastParameter)), plane)
                        angle1 = -DraftVecUtils.angle(u1)
                        angle2 = -DraftVecUtils.angle(u2)
                        if hasattr(obj.ViewObject, "FlipArrows"):
                            if obj.ViewObject.FlipArrows:
                                angle1 = angle1 + math.pi
                                angle2 = angle2 + math.pi
                        svg += getArrow(obj.ViewObject.ArrowType, p2,
                                        arrowsize, stroke, linewidth, angle1)
                        svg += getArrow(obj.ViewObject.ArrowType, p3,
                                        arrowsize, stroke, linewidth, angle2)

                    # drawing text
                    if obj.ViewObject.DisplayMode == "2D":
                        t = prx.circle.tangentAt(prx.circle.FirstParameter +
                                                 (prx.circle.LastParameter -
                                                  prx.circle.FirstParameter) /
                                                 2.0)
                        t = getProj(t, plane)
                        tangle = DraftVecUtils.angle(t)
                        if (tangle <= -math.pi / 2) or (tangle > math.pi / 2):
                            tangle = tangle + math.pi
                        tbase = getProj(
                            prx.circle.valueAt(prx.circle.FirstParameter +
                                               (prx.circle.LastParameter -
                                                prx.circle.FirstParameter) /
                                               2.0), plane)
                        tbase = tbase.add(
                            DraftVecUtils.rotate(Vector(0, 2.0 / scale, 0),
                                                 tangle))
                        #print(tbase)
                    else:
                        tangle = 0
                        tbase = getProj(prx.tbase, plane)
                    svg += getText(stroke, fontsize, obj.ViewObject.FontName,
                                   tangle, tbase, prx.string)

    elif getType(obj) == "Label":
        if getattr(obj.ViewObject, "Line",
                   True):  # some Labels may have no Line property

            def format_point(coords, action='L'):
                return "{action}{x},{y}".format(x=coords.x,
                                                y=coords.y,
                                                action=action)

            # Draw multisegment line
            proj_points = list(map(lambda x: getProj(x, plane), obj.Points))
            path_dir_list = [format_point(proj_points[0], action='M')]
            path_dir_list += map(format_point, proj_points[1:])
            path_dir_str = " ".join(path_dir_list)
            svg_path = '<path fill="none" stroke="{stroke}" stroke-width="{linewidth}" d="{directions}"/>'.format(
                stroke=stroke, linewidth=linewidth, directions=path_dir_str)
            svg += svg_path

            # Draw arrow.
            # We are different here from 3D view
            # if Line is set to 'off', no arrow is drawn
            if hasattr(obj.ViewObject, "ArrowType") and len(obj.Points) >= 2:
                last_segment = FreeCAD.Vector(obj.Points[-1] - obj.Points[-2])
                angle = -DraftVecUtils.angle(getProj(last_segment,
                                                     plane)) + math.pi
                svg += getArrow(arrowtype=obj.ViewObject.ArrowType,
                                point=proj_points[-1],
                                arrowsize=obj.ViewObject.ArrowSize.Value /
                                pointratio,
                                color=stroke,
                                linewidth=linewidth,
                                angle=angle)

        # print text
        if gui:
            if not obj.ViewObject:
                print("export of texts to SVG is only available in GUI mode")
            else:
                fontname = obj.ViewObject.TextFont
                position = getProj(obj.Placement.Base, plane)
                rotation = obj.Placement.Rotation
                justification = obj.ViewObject.TextAlignment
                text = obj.Text
                svg += getText(stroke, fontsize, fontname, rotation, position,
                               text, linespacing, justification)

    elif getType(obj) in ["Annotation", "DraftText"]:
        "returns an svg representation of a document annotation"
        if gui:
            if not obj.ViewObject:
                print("export of texts to SVG is only available in GUI mode")
            else:
                n = obj.ViewObject.FontName
                if getType(obj) == "Annotation":
                    p = getProj(obj.Position, plane)
                    r = obj.ViewObject.Rotation.getValueAs("rad")
                    t = obj.LabelText
                else:  # DraftText
                    p = getProj(obj.Placement.Base, plane)
                    r = obj.Placement.Rotation
                    t = obj.Text
                j = obj.ViewObject.Justification
                svg += getText(stroke, fontsize, n, r, p, t, linespacing, j)

    elif getType(obj) == "Axis":
        "returns the SVG representation of an Arch Axis system"
        if gui:
            if not obj.ViewObject:
                print("export of axes to SVG is only available in GUI mode")
            else:
                vobj = obj.ViewObject
                lorig = lstyle
                fill = 'none'
                rad = vobj.BubbleSize.Value / 2
                n = 0
                for e in obj.Shape.Edges:
                    lstyle = lorig
                    svg += getPath([e])
                    lstyle = "none"
                    pos = ["Start"]
                    if hasattr(vobj, "BubblePosition"):
                        if vobj.BubblePosition == "Both":
                            pos = ["Start", "End"]
                        else:
                            pos = [vobj.BubblePosition]
                    for p in pos:
                        if p == "Start":
                            p1 = e.Vertexes[0].Point
                            p2 = e.Vertexes[1].Point
                        else:
                            p1 = e.Vertexes[1].Point
                            p2 = e.Vertexes[0].Point
                        dv = p2.sub(p1)
                        dv.normalize()
                        center = p2.add(dv.scale(rad, rad, rad))
                        svg += getCircle(Part.makeCircle(rad, center))
                        if hasattr(vobj.Proxy, "bubbletexts"):
                            if len(vobj.Proxy.bubbletexts) >= n:
                                svg += '<text fill="' + stroke + '" '
                                svg += 'font-size="' + str(rad) + '" '
                                svg += 'style="text-anchor:middle;'
                                svg += 'text-align:center;'
                                svg += 'font-family: sans;" '
                                svg += 'transform="translate(' + str(
                                    center.x +
                                    rad / 4.0) + ',' + str(center.y -
                                                           rad / 3.0) + ') '
                                svg += 'scale(1,-1)"> '
                                svg += '<tspan>' + obj.ViewObject.Proxy.bubbletexts[
                                    n].string.getValues()[0] + '</tspan>\n'
                                svg += '</text>\n'
                                n += 1
                lstyle = lorig

    elif getType(obj) == "Pipe":
        fill = stroke
        if obj.Base and obj.Diameter:
            svg += getPath(obj.Base.Shape.Edges)
        for f in obj.Shape.Faces:
            if len(f.Edges) == 1:
                if isinstance(f.Edges[0].Curve, Part.Circle):
                    svg += getCircle(f.Edges[0])

    elif getType(obj) == "Rebar":
        fill = "none"
        if obj.Proxy:
            if not hasattr(obj.Proxy, "wires"):
                obj.Proxy.execute(obj)
            if hasattr(obj.Proxy, "wires"):
                svg += getPath(wires=obj.Proxy.wires)

    elif getType(obj) == "PipeConnector":
        pass

    elif getType(obj) == "Space":
        "returns an SVG fragment for the text of a space"
        if gui:
            if not obj.ViewObject:
                print("export of spaces to SVG is only available in GUI mode")
            else:
                if fillSpaces:
                    if hasattr(obj, "Proxy"):
                        if not hasattr(obj.Proxy, "face"):
                            obj.Proxy.getArea(obj, notouch=True)
                        if hasattr(obj.Proxy, "face"):
                            # setting fill
                            if gui:
                                fill = getrgb(obj.ViewObject.ShapeColor,
                                              testbw=False)
                                fill_opacity = 1 - (
                                    obj.ViewObject.Transparency / 100.0)
                            else:
                                fill = "#888888"
                            svg += getPath(wires=[obj.Proxy.face.OuterWire])
                c = getrgb(obj.ViewObject.TextColor)
                n = obj.ViewObject.FontName
                a = 0
                if rotation != 0:
                    a = math.radians(rotation)
                t1 = obj.ViewObject.Proxy.text1.string.getValues()
                t2 = obj.ViewObject.Proxy.text2.string.getValues()
                scale = obj.ViewObject.FirstLine.Value / obj.ViewObject.FontSize.Value
                f1 = fontsize * scale
                p2 = obj.Placement.multVec(
                    FreeCAD.Vector(obj.ViewObject.Proxy.coords.translation.
                                   getValue().getValue()))
                lspc = FreeCAD.Vector(obj.ViewObject.Proxy.header.translation.
                                      getValue().getValue())
                p1 = p2.add(lspc)
                j = obj.ViewObject.TextAlign
                t3 = getText(c,
                             f1,
                             n,
                             a,
                             getProj(p1, plane),
                             t1,
                             linespacing,
                             j,
                             flip=True)
                svg += t3
                if t2:
                    ofs = FreeCAD.Vector(0, -lspc.Length, 0)
                    if a:
                        ofs = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1),
                                               -rotation).multVec(ofs)
                    t4 = getText(c,
                                 fontsize,
                                 n,
                                 a,
                                 getProj(p1, plane).add(ofs),
                                 t2,
                                 linespacing,
                                 j,
                                 flip=True)
                    svg += t4

    elif obj.isDerivedFrom('Part::Feature'):
        if obj.Shape.isNull():
            return ''
        # setting fill
        if obj.Shape.Faces:
            if gui:
                try:
                    m = obj.ViewObject.DisplayMode
                except AttributeError:
                    m = None
                if (m != "Wireframe"):
                    if fillstyle == "shape color":
                        fill = getrgb(obj.ViewObject.ShapeColor, testbw=False)
                        fill_opacity = 1 - (obj.ViewObject.Transparency /
                                            100.0)
                    else:
                        fill = 'url(#' + fillstyle + ')'
                        svg += getPattern(fillstyle)
                else:
                    fill = "none"
            else:
                fill = "#888888"
        else:
            fill = 'none'

        if len(obj.Shape.Vertexes) > 1:
            wiredEdges = []
            if obj.Shape.Faces:
                for i, f in enumerate(obj.Shape.Faces):
                    # place outer wire first
                    wires = [f.OuterWire]
                    wires.extend([
                        w for w in f.Wires
                        if w.hashCode() != f.OuterWire.hashCode()
                    ])
                    svg += getPath(wires=f.Wires,pathname='%s_f%04d' % \
                            (obj.Name,i))
                    wiredEdges.extend(f.Edges)
            else:
                for i, w in enumerate(obj.Shape.Wires):
                    svg += getPath(w.Edges,pathname='%s_w%04d' % \
                            (obj.Name,i))
                    wiredEdges.extend(w.Edges)
            if len(wiredEdges) != len(obj.Shape.Edges):
                for i, e in enumerate(obj.Shape.Edges):
                    if (DraftGeomUtils.findEdge(e, wiredEdges) is None):
                        svg += getPath([e],pathname='%s_nwe%04d' % \
                                (obj.Name,i))
        else:
            # closed circle or spline
            if obj.Shape.Edges:
                if isinstance(obj.Shape.Edges[0].Curve, Part.Circle):
                    svg = getCircle(obj.Shape.Edges[0])
                else:
                    svg = getPath(obj.Shape.Edges)
        if FreeCAD.GuiUp:
            if hasattr(obj.ViewObject, "EndArrow") and hasattr(
                    obj.ViewObject,
                    "ArrowType") and (len(obj.Shape.Vertexes) > 1):
                if obj.ViewObject.EndArrow:
                    p1 = getProj(obj.Shape.Vertexes[-1].Point, plane)
                    p2 = getProj(obj.Shape.Vertexes[-2].Point, plane)
                    angle = -DraftVecUtils.angle(p2.sub(p1))
                    arrowsize = obj.ViewObject.ArrowSize.Value / pointratio
                    svg += getArrow(obj.ViewObject.ArrowType, p1, arrowsize,
                                    stroke, linewidth, angle)

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

        PathLog.debug("holes found: {}".format(holelist))
        return features
Example #39
0
    def smoothChordCommands(self, bone, inChord, outChord, edge, wire, corner, smooth, color = None):
        if smooth == 0:
            PathLog.info(" No smoothing requested")
            return [ bone.lastCommand, outChord.g1Command() ]

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

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

        pivot = None
        pivotDistance = 0

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

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

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

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

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

            return commands

        PathLog.info(" no pivot found - straight command")
        return [ inChord.g1Command(), outChord.g1Command() ]
Example #40
0
    def action(self, arg):
        """Handle the 3D scene events.

        This is installed as an EventCallback in the Inventor view.

        Parameters
        ----------
        arg: dict
            Dictionary with strings that indicates the type of event received
            from the 3D view.
        """
        if arg["Type"] == "SoKeyboardEvent":
            if arg["Key"] == "ESCAPE":
                self.finish()
        elif arg["Type"] == "SoLocation2Event":  # mouse movement detection
            import DraftGeomUtils
            shift = gui_tool_utils.hasMod(arg, gui_tool_utils.MODCONSTRAIN)
            if self.arcmode or self.point2:
                gui_tool_utils.setMod(arg, gui_tool_utils.MODCONSTRAIN, False)
            (self.point, ctrlPoint, self.info) = gui_tool_utils.getPoint(
                self, arg, noTracker=(len(self.node) > 0))
            if (gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT)
                    or self.selectmode) and (len(self.node) < 3):
                self.dimtrack.off()
                if not self.altdown:
                    self.altdown = True
                    self.ui.switchUi(True)
                    if hasattr(Gui, "Snapper"):
                        Gui.Snapper.setSelectMode(True)
                snapped = self.view.getObjectInfo(
                    (arg["Position"][0], arg["Position"][1]))
                if snapped:
                    ob = self.doc.getObject(snapped['Object'])
                    if "Edge" in snapped['Component']:
                        num = int(snapped['Component'].lstrip('Edge')) - 1
                        ed = ob.Shape.Edges[num]
                        v1 = ed.Vertexes[0].Point
                        v2 = ed.Vertexes[-1].Point
                        self.dimtrack.update([v1, v2, self.cont])
            else:
                if self.node and (len(self.edges) < 2):
                    self.dimtrack.on()
                if len(self.edges) == 2:
                    # angular dimension
                    self.dimtrack.off()
                    r = self.point.sub(self.center)
                    self.arctrack.setRadius(r.Length)
                    a = self.arctrack.getAngle(self.point)
                    pair = DraftGeomUtils.getBoundaryAngles(a, self.pts)
                    if not (pair[0] < a < pair[1]):
                        self.angledata = [
                            4 * math.pi - pair[0], 2 * math.pi - pair[1]
                        ]
                    else:
                        self.angledata = [
                            2 * math.pi - pair[0], 2 * math.pi - pair[1]
                        ]
                    self.arctrack.setStartAngle(self.angledata[0])
                    self.arctrack.setEndAngle(self.angledata[1])
                if self.altdown:
                    self.altdown = False
                    self.ui.switchUi(False)
                    if hasattr(Gui, "Snapper"):
                        Gui.Snapper.setSelectMode(False)
                if self.dir:
                    _p = DraftVecUtils.project(self.point.sub(self.node[0]),
                                               self.dir)
                    self.point = self.node[0].add(_p)
                if len(self.node) == 2:
                    if self.arcmode and self.edges:
                        cen = self.edges[0].Curve.Center
                        rad = self.edges[0].Curve.Radius
                        baseray = self.point.sub(cen)
                        v2 = DraftVecUtils.scaleTo(baseray, rad)
                        v1 = v2.negative()
                        if shift:
                            self.node = [cen, cen.add(v2)]
                            self.arcmode = "radius"
                        else:
                            self.node = [cen.add(v1), cen.add(v2)]
                            self.arcmode = "diameter"
                        self.dimtrack.update(self.node)
                # Draw constraint tracker line.
                if shift and (not self.arcmode):
                    if len(self.node) == 2:
                        if not self.point2:
                            self.point2 = self.node[1]
                        else:
                            self.node[1] = self.point2
                        if not self.force:
                            _p = self.point.sub(self.node[0])
                            a = abs(_p.getAngle(App.DraftWorkingPlane.u))
                            if (a > math.pi / 4) and (a <= 0.75 * math.pi):
                                self.force = 1
                            else:
                                self.force = 2
                        if self.force == 1:
                            self.node[1] = App.Vector(self.node[0].x,
                                                      self.node[1].y,
                                                      self.node[0].z)
                        elif self.force == 2:
                            self.node[1] = App.Vector(self.node[1].x,
                                                      self.node[0].y,
                                                      self.node[0].z)
                else:
                    self.force = None
                    if self.point2 and (len(self.node) > 1):
                        self.node[1] = self.point2
                        self.point2 = None
                # update the dimline
                if self.node and not self.arcmode:
                    self.dimtrack.update(self.node + [self.point] +
                                         [self.cont])
            gui_tool_utils.redraw3DView()
        elif arg["Type"] == "SoMouseButtonEvent":
            if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
                import DraftGeomUtils
                if self.point:
                    self.ui.redraw()
                    if (not self.node) and (not self.support):
                        gui_tool_utils.getSupport(arg)
                    if (gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT)
                            or self.selectmode) and (len(self.node) < 3):
                        # print("snapped: ",self.info)
                        if self.info:
                            ob = self.doc.getObject(self.info['Object'])
                            if 'Edge' in self.info['Component']:
                                num = int(
                                    self.info['Component'].lstrip('Edge')) - 1
                                ed = ob.Shape.Edges[num]
                                v1 = ed.Vertexes[0].Point
                                v2 = ed.Vertexes[-1].Point
                                i1 = i2 = None
                                for i in range(len(ob.Shape.Vertexes)):
                                    if v1 == ob.Shape.Vertexes[i].Point:
                                        i1 = i
                                    if v2 == ob.Shape.Vertexes[i].Point:
                                        i2 = i
                                if (i1 is not None) and (i2 is not None):
                                    self.indices.append(num)
                                    if not self.edges:
                                        # nothing snapped yet, we treat it
                                        # as a normal edge-snapped dimension
                                        self.node = [v1, v2]
                                        self.link = [ob, i1, i2]
                                        self.edges.append(ed)
                                        if DraftGeomUtils.geomType(
                                                ed) == "Circle":
                                            # snapped edge is an arc
                                            self.arcmode = "diameter"
                                            self.link = [ob, num]
                                    else:
                                        # there is already a snapped edge,
                                        # so we start angular dimension
                                        self.edges.append(ed)
                                        # self.node now has the 4 endpoints
                                        self.node.extend([v1, v2])
                                        c = DraftGeomUtils.findIntersection(
                                            self.node[0], self.node[1],
                                            self.node[2], self.node[3], True,
                                            True)
                                        if c:
                                            # print("centers:",c)
                                            self.center = c[0]
                                            self.arctrack.setCenter(
                                                self.center)
                                            self.arctrack.on()
                                            for e in self.edges:
                                                for v in e.Vertexes:
                                                    self.pts.append(
                                                        self.arctrack.getAngle(
                                                            v.Point))
                                            self.link = [self.link[0], ob]
                                        else:
                                            _msg(
                                                translate(
                                                    "draft",
                                                    "Edges don't intersect!"))
                                            self.finish()
                                            return
                                self.dimtrack.on()
                    else:
                        self.node.append(self.point)
                    self.selectmode = False
                    # print("node", self.node)
                    self.dimtrack.update(self.node)
                    if len(self.node) == 2:
                        self.point2 = self.node[1]
                    if len(self.node) == 1:
                        self.dimtrack.on()
                        if self.planetrack:
                            self.planetrack.set(self.node[0])
                    elif len(self.node) == 2 and self.cont:
                        self.node.append(self.cont)
                        self.createObject()
                        if not self.cont:
                            self.finish()
                    elif len(self.node) == 3:
                        # for unlinked arc mode:
                        # if self.arcmode:
                        #     v = self.node[1].sub(self.node[0])
                        #     v.multiply(0.5)
                        #     cen = self.node[0].add(v)
                        #     self.node = [self.node[0], self.node[1], cen]
                        self.createObject()
                        if not self.cont:
                            self.finish()
                    elif self.angledata:
                        self.node.append(self.point)
                        self.createObject()
                        self.finish()
Example #41
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) == "Floor":
                 if p.Height.Value:
                     height = p.Height.Value
     if obj.Normal == Vector(0,0,0):
         normal = Vector(0,0,1)
     else:
         normal = Vector(obj.Normal)
     base = None
     placement = None
     basewires = None
     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 obj.Base.Shape.Wires:
                     basewires = obj.Base.Shape.Wires
                 elif len(obj.Base.Shape.Edges) == 1:
                     basewires = [Part.Wire(obj.Base.Shape.Edges)]
                 if basewires and width:
                     baseface = None
                     for wire in 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":
                             dvec.multiply(width)
                             if obj.Offset.Value:
                                 dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
                                 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.multiply(width)
                             dvec = dvec.negative()
                             if obj.Offset.Value:
                                 dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
                                 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":
                             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:
                                 baseface = baseface.fuse(f)
                             else:
                                 baseface = f
                     if baseface:
                         base,placement = self.rebase(baseface)
     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 #42
0
    def createObject(self):
        """Create the actual object in the current document."""
        import DraftGeomUtils
        Gui.addModule("Draft")

        if self.angledata:
            normal = "None"
            if len(self.edges) == 2:
                v1 = DraftGeomUtils.vec(self.edges[0])
                v2 = DraftGeomUtils.vec(self.edges[1])
                normal = DraftVecUtils.toString((v1.cross(v2)).normalize())

            _cmd = 'Draft.makeAngularDimension('
            _cmd += 'center=' + DraftVecUtils.toString(self.center) + ', '
            _cmd += 'angles='
            _cmd += '['
            _cmd += str(self.angledata[0]) + ', '
            _cmd += str(self.angledata[1])
            _cmd += '], '
            _cmd += 'p3=' + DraftVecUtils.toString(self.node[-1]) + ', '
            _cmd += 'normal=' + normal
            _cmd += ')'
            _cmd_list = [
                'dim = ' + _cmd, 'Draft.autogroup(dim)',
                'FreeCAD.ActiveDocument.recompute()'
            ]
            self.commit(translate("draft", "Create Dimension"), _cmd_list)
        elif self.link and not self.arcmode:
            ops = []
            # Linear dimension, linked
            if self.force == 1:
                _cmd = 'Draft.makeDimension'
                _cmd += '('
                _cmd += 'FreeCAD.ActiveDocument.' + self.link[0].Name + ', '
                _cmd += str(self.link[1]) + ', '
                _cmd += str(self.link[2]) + ', '
                _cmd += DraftVecUtils.toString(self.node[2])
                _cmd += ')'
                _cmd_list = [
                    'dim = ' + _cmd, 'dim.Direction = FreeCAD.Vector(0, 1, 0)',
                    'Draft.autogroup(dim)',
                    'FreeCAD.ActiveDocument.recompute()'
                ]
                self.commit(translate("draft", "Create Dimension"), _cmd_list)
            elif self.force == 2:
                _cmd = 'Draft.makeDimension'
                _cmd += '('
                _cmd += 'FreeCAD.ActiveDocument.' + self.link[0].Name + ', '
                _cmd += str(self.link[1]) + ', '
                _cmd += str(self.link[2]) + ', '
                _cmd += DraftVecUtils.toString(self.node[2])
                _cmd += ')'
                _cmd_list = [
                    'dim = ' + _cmd, 'dim.Direction = FreeCAD.Vector(1, 0, 0)',
                    'Draft.autogroup(dim)',
                    'FreeCAD.ActiveDocument.recompute()'
                ]
                self.commit(translate("draft", "Create Dimension"), _cmd_list)
            else:
                _cmd = 'Draft.makeDimension'
                _cmd += '('
                _cmd += 'FreeCAD.ActiveDocument.' + self.link[0].Name + ', '
                _cmd += str(self.link[1]) + ', '
                _cmd += str(self.link[2]) + ', '
                _cmd += DraftVecUtils.toString(self.node[2])
                _cmd += ')'
                _cmd_list = [
                    'dim = ' + _cmd, 'Draft.autogroup(dim)',
                    'FreeCAD.ActiveDocument.recompute()'
                ]
                self.commit(translate("draft", "Create Dimension"), _cmd_list)
        elif self.arcmode:
            # Radius or dimeter dimension, linked
            _cmd = 'Draft.makeDimension'
            _cmd += '('
            _cmd += 'FreeCAD.ActiveDocument.' + self.link[0].Name + ', '
            _cmd += str(self.link[1]) + ', '
            _cmd += '"' + str(self.arcmode) + '", '
            _cmd += DraftVecUtils.toString(self.node[2])
            _cmd += ')'
            _cmd_list = [
                'dim = ' + _cmd, 'Draft.autogroup(dim)',
                'FreeCAD.ActiveDocument.recompute()'
            ]
            self.commit(translate("draft", "Create Dimension"), _cmd_list)
        else:
            # Linear dimension, non-linked
            _cmd = 'Draft.makeDimension'
            _cmd += '('
            _cmd += DraftVecUtils.toString(self.node[0]) + ', '
            _cmd += DraftVecUtils.toString(self.node[1]) + ', '
            _cmd += DraftVecUtils.toString(self.node[2])
            _cmd += ')'
            _cmd_list = [
                'dim = ' + _cmd, 'Draft.autogroup(dim)',
                'FreeCAD.ActiveDocument.recompute()'
            ]
            self.commit(translate("draft", "Create Dimension"), _cmd_list)
        if self.ui.continueMode:
            self.cont = self.node[2]
            if not self.dir:
                if self.link:
                    v1 = self.link[0].Shape.Vertexes[self.link[1]].Point
                    v2 = self.link[0].Shape.Vertexes[self.link[2]].Point
                    self.dir = v2.sub(v1)
                else:
                    self.dir = self.node[1].sub(self.node[0])
            self.node = [self.node[1]]
        self.link = None
Example #43
0
    def makeStraightStairs(self, obj, edge, numberofsteps=None):

        "builds a simple, straight staircase from a straight edge"

        # Upgrade obj if it is from an older version of FreeCAD
        if not (hasattr(obj, "StringerOverlap")):
            obj.addProperty(
                "App::PropertyLength", "StringerOverlap", "Structure",
                QT_TRANSLATE_NOOP(
                    "App::Property",
                    "The overlap of the stringers above the bottom of the treads"
                ))

        # general data
        import Part, DraftGeomUtils
        if not numberofsteps:
            numberofsteps = obj.NumberOfSteps
        v = DraftGeomUtils.vec(edge)
        vLength = DraftVecUtils.scaleTo(
            v,
            float(edge.Length) / (numberofsteps - 1))
        vLength = Vector(vLength.x, vLength.y, 0)
        if round(v.z, Draft.precision()) != 0:
            h = v.z
        else:
            h = obj.Height.Value
        vHeight = Vector(0, 0, float(h) / numberofsteps)
        vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)),
                                       obj.Width.Value)
        vBase = edge.Vertexes[0].Point
        vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value))
        a = math.atan(vHeight.Length / vLength.Length)
        #print("stair data:",vLength.Length,":",vHeight.Length)

        # steps
        for i in range(numberofsteps - 1):
            p1 = vBase.add((Vector(vLength).multiply(i)).add(
                Vector(vHeight).multiply(i + 1)))
            p1 = self.align(p1, obj.Align, vWidth)
            p1 = p1.add(vNose).add(Vector(0, 0,
                                          -abs(obj.TreadThickness.Value)))
            p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength)
            p3 = p2.add(vWidth)
            p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose)
            step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1]))
            if obj.TreadThickness.Value:
                step = step.extrude(Vector(0, 0,
                                           abs(obj.TreadThickness.Value)))
                self.steps.append(step)
            else:
                self.pseudosteps.append(step)

        # structure
        lProfile = []
        struct = None
        if obj.Structure == "Massive":
            if obj.StructureThickness.Value:
                for i in range(numberofsteps - 1):
                    if not lProfile:
                        lProfile.append(vBase)
                    last = lProfile[-1]
                    if len(lProfile) == 1:
                        last = last.add(
                            Vector(0, 0, -abs(obj.TreadThickness.Value)))
                    lProfile.append(last.add(vHeight))
                    lProfile.append(lProfile[-1].add(vLength))
                resHeight1 = obj.StructureThickness.Value / math.cos(a)
                lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1)))
                resHeight2 = ((numberofsteps - 1) * vHeight.Length) - (
                    resHeight1 + obj.TreadThickness.Value)
                resLength = (vLength.Length / vHeight.Length) * resHeight2
                h = DraftVecUtils.scaleTo(vLength, -resLength)
                lProfile.append(lProfile[-1].add(Vector(h.x, h.y,
                                                        -resHeight2)))
                lProfile.append(vBase)
                #print(lProfile)
                pol = Part.makePolygon(lProfile)
                struct = Part.Face(pol)
                evec = vWidth
                if obj.StructureOffset.Value:
                    mvec = DraftVecUtils.scaleTo(vWidth,
                                                 obj.StructureOffset.Value)
                    struct.translate(mvec)
                    evec = DraftVecUtils.scaleTo(
                        evec, evec.Length - (2 * mvec.Length))
                struct = struct.extrude(evec)
        elif obj.Structure in ["One stringer", "Two stringers"]:
            if obj.StringerWidth.Value and obj.StructureThickness.Value:
                hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2)
                l1 = Vector(vLength).multiply(numberofsteps - 1)
                h1 = Vector(vHeight).multiply(numberofsteps - 1).add(
                    Vector(
                        0, 0, -abs(obj.TreadThickness.Value) +
                        obj.StringerOverlap.Value))
                p1 = vBase.add(l1).add(h1)
                p1 = self.align(p1, obj.Align, vWidth)
                if obj.StringerOverlap.Value <= float(h) / numberofsteps:
                    lProfile.append(p1)
                else:
                    p1b = vBase.add(l1).add(Vector(0, 0, float(h)))
                    p1a = p1b.add(
                        Vector(vLength).multiply(
                            (p1b.z - p1.z) / vHeight.Length))
                    lProfile.append(p1a)
                    lProfile.append(p1b)
                h2 = (obj.StructureThickness.Value / vLength.Length) * hyp
                lProfile.append(p1.add(Vector(0, 0, -abs(h2))))
                h3 = lProfile[-1].z - vBase.z
                l3 = (h3 / vHeight.Length) * vLength.Length
                v3 = DraftVecUtils.scaleTo(vLength, -l3)
                lProfile.append(lProfile[-1].add(Vector(0, 0,
                                                        -abs(h3))).add(v3))
                l4 = (obj.StructureThickness.Value / vHeight.Length) * hyp
                v4 = DraftVecUtils.scaleTo(vLength, -l4)
                lProfile.append(lProfile[-1].add(v4))
                lProfile.append(lProfile[0])
                #print(lProfile)
                pol = Part.makePolygon(lProfile)
                pol = Part.Face(pol)
                evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value)
                if obj.Structure == "One stringer":
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset.Value)
                    else:
                        mvec = DraftVecUtils.scaleTo(
                            vWidth,
                            (vWidth.Length / 2) - obj.StringerWidth.Value / 2)
                    pol.translate(mvec)
                    struct = pol.extrude(evec)
                elif obj.Structure == "Two stringers":
                    pol2 = pol.copy()
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset.Value)
                        pol.translate(mvec)
                        mvec = vWidth.add(mvec.negative())
                        pol2.translate(mvec)
                    else:
                        pol2.translate(vWidth)
                    s1 = pol.extrude(evec)
                    s2 = pol2.extrude(evec.negative())
                    struct = Part.makeCompound([s1, s2])
        if struct:
            self.structures.append(struct)
Example #44
0
    def makeStraightLanding(self, obj, edge, numberofsteps=None):

        "builds a landing from a straight edge"

        # general data
        if not numberofsteps:
            numberofsteps = obj.NumberOfSteps
        import Part, DraftGeomUtils
        v = DraftGeomUtils.vec(edge)
        vLength = Vector(v.x, v.y, 0)
        vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)),
                                                obj.Width.Value)
        vBase = edge.Vertexes[0].Point
        vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value))
        h = obj.Height.Value
        l = obj.Length.Value
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                l = obj.Base.Shape.Length
                if obj.Base.Shape.BoundBox.ZLength:
                    h = obj.Base.Shape.BoundBox.ZLength
        fLength = float(l - obj.Width.Value) / (numberofsteps - 2)
        fHeight = float(h) / numberofsteps
        a = math.atan(fHeight / fLength)
        print("landing data:", fLength, ":", fHeight)

        # step
        p1 = self.align(vBase, obj.Align, vWidth)
        p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value)))
        p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength)
        p3 = p2.add(vWidth)
        p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose)
        step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1]))
        if obj.TreadThickness.Value:
            step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value)))
            self.steps.append(step)
        else:
            self.pseudosteps.append(step)

        # structure
        lProfile = []
        struct = None
        p7 = None
        p1 = p1.add(DraftVecUtils.neg(vNose))
        p2 = p1.add(Vector(0, 0, -fHeight)).add(
            Vector(0, 0, -obj.StructureThickness.Value / math.cos(a)))
        resheight = p1.sub(p2).Length - obj.StructureThickness.Value
        reslength = resheight / math.tan(a)
        p3 = p2.add(DraftVecUtils.scaleTo(vLength, reslength)).add(
            Vector(0, 0, resheight))
        p6 = p1.add(vLength)
        if obj.TreadThickness.Value:
            p7 = p6.add(Vector(0, 0, obj.TreadThickness.Value))

        reslength = fLength + (
            obj.StructureThickness.Value / math.sin(a) -
            (fHeight - obj.TreadThickness.Value) / math.tan(a))
        if p7:
            p5 = p7.add(DraftVecUtils.scaleTo(vLength, reslength))
        else:
            p5 = p6.add(DraftVecUtils.scaleTo(vLength, reslength))
        resheight = obj.StructureThickness.Value + obj.TreadThickness.Value
        reslength = resheight / math.tan(a)
        p4 = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)).add(
            Vector(0, 0, -resheight))
        if obj.Structure == "Massive":
            if obj.StructureThickness.Value:
                if p7:
                    struct = Part.Face(
                        Part.makePolygon([p1, p2, p3, p4, p5, p7, p6, p1]))
                else:
                    struct = Part.Face(
                        Part.makePolygon([p1, p2, p3, p4, p5, p6, p1]))
                evec = vWidth
                if obj.StructureOffset.Value:
                    mvec = DraftVecUtils.scaleTo(vWidth,
                                                 obj.StructureOffset.Value)
                    struct.translate(mvec)
                    evec = DraftVecUtils.scaleTo(
                        evec, evec.Length - (2 * mvec.Length))
                struct = struct.extrude(evec)
        elif obj.Structure in ["One stringer", "Two stringers"]:
            if obj.StringerWidth.Value and obj.StructureThickness.Value:
                p1b = p1.add(Vector(0, 0, -fHeight))
                reslength = fHeight / math.tan(a)
                p1c = p1.add(DraftVecUtils.scaleTo(vLength, reslength))
                p5b = None
                p5c = None
                if obj.TreadThickness.Value:
                    reslength = obj.StructureThickness.Value / math.sin(a)
                    p5b = p5.add(DraftVecUtils.scaleTo(vLength, -reslength))
                    reslength = obj.TreadThickness.Value / math.tan(a)
                    p5c = p5b.add(DraftVecUtils.scaleTo(
                        vLength, -reslength)).add(
                            Vector(0, 0, -obj.TreadThickness.Value))
                    pol = Part.Face(
                        Part.makePolygon(
                            [p1c, p1b, p2, p3, p4, p5, p5b, p5c, p1c]))
                else:
                    pol = Part.Face(
                        Part.makePolygon([p1c, p1b, p2, p3, p4, p5, p1c]))
                evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value)
                if obj.Structure == "One stringer":
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset.Value)
                    else:
                        mvec = DraftVecUtils.scaleTo(
                            vWidth,
                            (vWidth.Length / 2) - obj.StringerWidth.Value / 2)
                    pol.translate(mvec)
                    struct = pol.extrude(evec)
                elif obj.Structure == "Two stringers":
                    pol2 = pol.copy()
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset.Value)
                        pol.translate(mvec)
                        mvec = vWidth.add(mvec.negative())
                        pol2.translate(mvec)
                    else:
                        pol2.translate(vWidth)
                    s1 = pol.extrude(evec)
                    s2 = pol2.extrude(evec.negative())
                    struct = Part.makeCompound([s1, s2])
        if struct:
            self.structures.append(struct)
Example #45
0
    def getProfiles(self, obj, noplacement=False):
        "Returns the base profile(s) of this component, if applicable"
        wires = []
        n, l, w, h = self.getDefaultValues(obj)
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Extrusion"):
                if obj.Base.Base:
                    base = obj.Base.Base.Shape.copy()
                    if noplacement:
                        base.Placement = FreeCAD.Placement()
                    return [base]
            elif obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Base.Shape:
                    base = obj.Base.Shape.copy()
                    if noplacement:
                        base.Placement = FreeCAD.Placement()
                    if not base.Solids:
                        if base.Faces:
                            import DraftGeomUtils
                            if not DraftGeomUtils.isCoplanar(base.Faces):
                                return []
                            return [base]

                        basewires = []
                        if not base.Wires:
                            if len(base.Edges) == 1:
                                import Part
                                basewires = [Part.Wire(base.Edges)]
                        else:
                            basewires = base.Wires
                        if basewires:
                            import DraftGeomUtils, DraftVecUtils, Part
                            for wire in 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(n)
                                if not DraftVecUtils.isNull(dvec):
                                    dvec.normalize()
                                sh = None
                                if hasattr(obj, "Align"):
                                    if obj.Align == "Left":
                                        dvec.multiply(w)
                                        if hasattr(obj, "Offset"):
                                            if obj.Offset.Value:
                                                dvec2 = DraftVecUtils.scaleTo(
                                                    dvec, obj.Offset.Value)
                                                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.multiply(w)
                                        dvec = dvec.negative()
                                        if hasattr(obj, "Offset"):
                                            if obj.Offset.Value:
                                                dvec2 = DraftVecUtils.scaleTo(
                                                    dvec, obj.Offset.Value)
                                                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":
                                        dvec.multiply(w / 2)
                                        w1 = DraftGeomUtils.offsetWire(
                                            wire, dvec)
                                        dvec = dvec.negative()
                                        w2 = DraftGeomUtils.offsetWire(
                                            wire, dvec)
                                        sh = DraftGeomUtils.bind(w1, w2)
                                    if sh:
                                        wires.append(sh)
                                else:
                                    wires.append(wire)
        elif Draft.getType(obj) in ["Wall", "Structure"]:
            if (Draft.getType(obj) == "Structure") and (l > h):
                if noplacement:
                    h2 = h / 2 or 0.5
                    w2 = w / 2 or 0.5
                    v1 = Vector(-h2, -w2, 0)
                    v2 = Vector(h2, -w2, 0)
                    v3 = Vector(h2, w2, 0)
                    v4 = Vector(-h2, w2, 0)
                else:
                    h2 = h / 2 or 0.5
                    w2 = w / 2 or 0.5
                    v1 = Vector(0, -w2, -h2)
                    v2 = Vector(0, -w2, h2)
                    v3 = Vector(0, w2, h2)
                    v4 = Vector(0, w2, -h2)
            else:
                l2 = l / 2 or 0.5
                w2 = w / 2 or 0.5
                v1 = Vector(-l2, -w2, 0)
                v2 = Vector(l2, -w2, 0)
                v3 = Vector(l2, w2, 0)
                v4 = Vector(-l2, w2, 0)
            import Part
            base = Part.makePolygon([v1, v2, v3, v4, v1])
            return [base]
        return wires
Example #46
0
def make_circle(radius,
                placement=None,
                face=None,
                startangle=None,
                endangle=None,
                support=None):
    """make_circle(radius, [placement, face, startangle, endangle])
    or make_circle(edge,[face]):

    Creates a circle object with given parameters. 

    Parameters
    ----------
    radius : the radius of the circle.

    placement : 
        If placement is given, it is used. 
    
    face : Bool
        If face is False, the circle is shown as a wireframe, 
        otherwise as a face. 
    
    startangle : start angle of the arc (in degrees)

    endangle : end angle of the arc (in degrees)
        if startangle and endangle are equal, a circle is created, 
        if they are different an arc is created

    edge : edge.Curve must be a 'Part.Circle'
        the circle is created from the given edge

    support : 
        TODO: Describe
    """

    if not App.ActiveDocument:
        App.Console.PrintError("No active document. Aborting\n")
        return

    if placement:
        utils.type_check([(placement, App.Placement)], "make_circle")

    if startangle != endangle:
        _name = "Arc"
    else:
        _name = "Circle"

    obj = App.ActiveDocument.addObject("Part::Part2DObjectPython", _name)

    Circle(obj)

    if face != None:
        obj.MakeFace = face

    if isinstance(radius, Part.Edge):
        edge = radius
        if DraftGeomUtils.geomType(edge) == "Circle":
            obj.Radius = edge.Curve.Radius
            placement = App.Placement(edge.Placement)
            delta = edge.Curve.Center.sub(placement.Base)
            placement.move(delta)
            # Rotation of the edge
            rotOk = App.Rotation(edge.Curve.XAxis, edge.Curve.YAxis,
                                 edge.Curve.Axis, "ZXY")
            placement.Rotation = rotOk
            if len(edge.Vertexes) > 1:
                v0 = edge.Curve.XAxis
                v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center)
                v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center)
                # Angle between edge.Curve.XAxis and the vector from center to start of arc
                a0 = math.degrees(App.Vector.getAngle(v0, v1))
                # Angle between edge.Curve.XAxis and the vector from center to end of arc
                a1 = math.degrees(App.Vector.getAngle(v0, v2))
                obj.FirstAngle = a0
                obj.LastAngle = a1
    else:
        obj.Radius = radius
        if (startangle != None) and (endangle != None):
            if startangle == -0: startangle = 0
            obj.FirstAngle = startangle
            obj.LastAngle = endangle

    obj.Support = support

    if placement:
        obj.Placement = placement

    if App.GuiUp:
        ViewProviderDraft(obj.ViewObject)
        gui_utils.format_object(obj)
        gui_utils.select(obj)

    return obj
Example #47
0
    def execute(self, obj):

        if self.clone(obj):
            return
        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return
        if not obj.Diameter.Value:
            return
        if not obj.Amount:
            return
        father = obj.Host
        fathershape = None
        if not father:
            # support for old-style rebars
            if obj.InList:
                if hasattr(obj.InList[0], "Armatures"):
                    if obj in obj.InList[0].Armatures:
                        father = obj.InList[0]
        if father:
            if father.isDerivedFrom("Part::Feature"):
                fathershape = father.Shape

        wire = obj.Base.Shape.Wires[0]
        if hasattr(obj, "Rounding"):
            #print(obj.Rounding)
            if obj.Rounding:
                radius = obj.Rounding * obj.Diameter.Value
                import DraftGeomUtils
                wire = DraftGeomUtils.filletWire(wire, radius)
        bpoint, bvec = self.getBaseAndAxis(wire)
        if not bpoint:
            return
        axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1))
        if fathershape:
            size = (ArchCommands.projectToVector(fathershape.copy(),
                                                 axis)).Length
        else:
            size = 1
        if hasattr(obj, "Direction"):
            if not DraftVecUtils.isNull(obj.Direction):
                axis = FreeCAD.Vector(obj.Direction)
                axis.normalize()
                if fathershape:
                    size = (ArchCommands.projectToVector(
                        fathershape.copy(), axis)).Length
                else:
                    size = 1
        if hasattr(obj, "Distance"):
            if obj.Distance.Value:
                size = obj.Distance.Value
        #print(axis)
        #print(size)
        spacinglist = None
        if hasattr(obj, "CustomSpacing"):
            if obj.CustomSpacing:
                spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing)
                influenceArea = sum(
                    spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2
        if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size:
            return
        # all tests ok!
        if hasattr(obj, "Length"):
            length = getLengthOfRebar(obj)
            if length:
                obj.Length = length
        pl = obj.Placement
        import Part
        circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec)
        circle = Part.Wire(circle)
        try:
            bar = wire.makePipeShell([circle], True, False, 2)
            basewire = wire.copy()
        except Part.OCCError:
            print("Arch: error sweeping rebar profile along the base sketch")
            return
        # building final shape
        shapes = []
        placementlist = []
        self.wires = []
        if father:
            rot = father.Placement.Rotation
        else:
            rot = FreeCAD.Rotation()
        if obj.Amount == 1:
            barplacement = CalculatePlacement(obj.Amount, 1, size, axis, rot,
                                              obj.OffsetStart.Value,
                                              obj.OffsetEnd.Value)
            placementlist.append(barplacement)
            if hasattr(obj, "Spacing"):
                obj.Spacing = 0
        else:
            if obj.OffsetStart.Value:
                baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value)
            else:
                baseoffset = None
            interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value)
            interval = interval / (obj.Amount - 1)
            for i in range(obj.Amount):
                barplacement = CalculatePlacement(obj.Amount, i + 1, size,
                                                  axis, rot,
                                                  obj.OffsetStart.Value,
                                                  obj.OffsetEnd.Value)
                placementlist.append(barplacement)
            if hasattr(obj, "Spacing"):
                obj.Spacing = interval
        # Calculate placement of bars from custom spacing.
        if spacinglist:
            placementlist[:] = []
            reqInfluenceArea = size - (obj.OffsetStart.Value +
                                       obj.OffsetEnd.Value)
            # Avoid unnecessary checks to pass like. For eg.: when we have values
            # like influenceArea is 100.00001 and reqInflueneArea is 100
            if round(influenceArea) > round(reqInfluenceArea):
                return FreeCAD.Console.PrintError(
                    "Influence area of rebars is greater than " +
                    str(reqInfluenceArea) + ".\n")
            elif round(influenceArea) < round(reqInfluenceArea):
                FreeCAD.Console.PrintWarning(
                    "Last span is greater that end offset.\n")
            for i in range(len(spacinglist)):
                if i == 0:
                    barplacement = CustomSpacingPlacement(
                        spacinglist, 1, axis, father.Placement.Rotation,
                        obj.OffsetStart.Value, obj.OffsetEnd.Value)
                    placementlist.append(barplacement)
                else:
                    barplacement = CustomSpacingPlacement(
                        spacinglist, i + 1, axis, father.Placement.Rotation,
                        obj.OffsetStart.Value, obj.OffsetEnd.Value)
                    placementlist.append(barplacement)
            obj.Amount = len(spacinglist)
            obj.Spacing = 0
        obj.PlacementList = placementlist
        for i in range(len(obj.PlacementList)):
            if i == 0:
                bar.Placement = obj.PlacementList[i]
                shapes.append(bar)
                basewire.Placement = obj.PlacementList[i]
                self.wires.append(basewire)
            else:
                bar = bar.copy()
                bar.Placement = obj.PlacementList[i]
                shapes.append(bar)
                w = basewire.copy()
                w.Placement = obj.PlacementList[i]
                self.wires.append(w)
        if shapes:
            obj.Shape = Part.makeCompound(shapes)
            obj.Placement = pl
        obj.TotalLength = obj.Length * len(obj.PlacementList)
Example #48
0
    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        #self.baseface = None
        self.flip = False
        if hasattr(obj, "Flip"):
            if obj.Flip:
                self.flip = True
        base = None
        baseWire = None
        if obj.Base:
            if hasattr(obj.Base, "Shape"):
                if obj.Base.Shape.Solids:
                    base = obj.Base.Shape
                    #pl = obj.Base.Placement
                else:
                    if (obj.Base.Shape.Faces and obj.Face):
                        baseWire = obj.Base.Shape.Faces[obj.Face - 1].Wires[0]
                    elif obj.Base.Shape.Wires:
                        baseWire = obj.Base.Shape.Wires[0]
        if baseWire:
            if baseWire.isClosed():
                self.profilsDico = []
                self.shps = []
                self.subVolShps = []
                heights = []
                edges = Part.__sortEdges__(baseWire.Edges)
                if self.flip:
                    edges = self.flipEdges(edges)

                ln = len(edges)

                obj.Angles = adjust_list_len(obj.Angles, ln, obj.Angles[0])
                obj.Runs = adjust_list_len(obj.Runs, ln, obj.Runs[0])
                obj.IdRel = adjust_list_len(obj.IdRel, ln, obj.IdRel[0])
                obj.Thickness = adjust_list_len(obj.Thickness, ln,
                                                obj.Thickness[0])
                obj.Overhang = adjust_list_len(obj.Overhang, ln,
                                               obj.Overhang[0])

                for i in range(ln):
                    self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i],
                                            obj.IdRel[i], obj.Overhang[i],
                                            obj.Thickness[i])
                for i in range(ln):
                    self.calcEdgeGeometry(i, edges[i])
                for i in range(ln):
                    self.calcApex(
                        i, ln)  # after calcEdgeGeometry as it uses vec data
                for i in range(ln):
                    self.calcMissingData(
                        i, ln
                    )  # after calcApex so it can use recalculated heights
                for i in range(ln):
                    self.calcDraftEdges(i)
                for i in range(ln):
                    self.calcEave(i)
                for profil in self.profilsDico:
                    heights.append(profil["height"])
                obj.Heights = heights
                for i in range(ln):
                    self.getRoofPaneProject(i)
                    profilCurr = self.profilsDico[i]
                    ptsPaneProject = profilCurr["points"]
                    if len(ptsPaneProject) == 0:
                        continue
                    face = face_from_points(ptsPaneProject)
                    if face:
                        diag = face.BoundBox.DiagonalLength
                        midpoint = DraftGeomUtils.findMidpoint(
                            profilCurr["edge"])
                        thicknessV = profilCurr["thickness"] / (math.cos(
                            math.radians(profilCurr["angle"])))
                        overhangV = profilCurr["overhang"] * math.tan(
                            math.radians(profilCurr["angle"]))
                        sol = face.extrude(
                            Vector(0.0, 0.0, profilCurr["height"] + 1000000.0))
                        sol.translate(Vector(0.0, 0.0, -2.0 * overhangV))

                        ## baseVolume shape
                        ptsPaneProfil = [
                            Vector(-profilCurr["overhang"], -overhangV, 0.0),
                            Vector(profilCurr["run"], profilCurr["height"],
                                   0.0),
                            Vector(profilCurr["run"],
                                   profilCurr["height"] + thicknessV, 0.0),
                            Vector(-profilCurr["overhang"],
                                   -overhangV + thicknessV, 0.0)
                        ]
                        self.shps.append(
                            self.createProfilShape(ptsPaneProfil, midpoint,
                                                   profilCurr["rot"],
                                                   profilCurr["vec"],
                                                   profilCurr["run"], diag,
                                                   sol))

                        ## subVolume shape
                        ptsSubVolProfil = [
                            Vector(-profilCurr["overhang"], -overhangV, 0.0),
                            Vector(profilCurr["run"], profilCurr["height"],
                                   0.0),
                            Vector(profilCurr["run"],
                                   profilCurr["height"] + 900000.0, 0.0),
                            Vector(-profilCurr["overhang"],
                                   profilCurr["height"] + 900000.0, 0.0)
                        ]
                        self.subVolShps.append(
                            self.createProfilShape(ptsSubVolProfil, midpoint,
                                                   profilCurr["rot"],
                                                   profilCurr["vec"],
                                                   profilCurr["run"], diag,
                                                   sol))

                if len(
                        self.shps
                ) == 0:  # occurs if all segments have angle=90 or run=0.
                    # create a flat roof using the eavePtLst outline:
                    ptsPaneProject = []
                    for i in range(ln):
                        ptsPaneProject.append(
                            self.profilsDico[i]["eavePtLst"][0])
                    face = face_from_points(ptsPaneProject)
                    if face:
                        thk = max(
                            1.0, self.profilsDico[0]["thickness"]
                        )  # FreeCAD will crash when extruding with a null vector here
                        self.shps = [face.extrude(Vector(0.0, 0.0, thk))]
                        self.subVolShps = [
                            face.extrude(Vector(0.0, 0.0, 1000000.0))
                        ]

                ## baseVolume
                base = self.shps.pop()
                for s in self.shps:
                    base = base.fuse(s)
                base = self.processSubShapes(obj, base, pl)
                self.applyShape(obj, base, pl, allownosolid=True)

                ## subVolume
                self.sub = self.subVolShps.pop()
                for s in self.subVolShps:
                    self.sub = self.sub.fuse(s)
                self.sub = self.sub.removeSplitter()
                if not self.sub.isNull():
                    if not DraftGeomUtils.isNull(pl):
                        self.sub.Placement = pl

        elif base:
            base = self.processSubShapes(obj, base, pl)
            self.applyShape(obj, base, pl, allownosolid=True)
        else:
            FreeCAD.Console.PrintMessage(
                translate("Arch", "Unable to create a roof"))
Example #49
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 #50
0
    def execute(self, obj):
        if len(obj.InList) != 1:
            return
        if Draft.getType(obj.InList[0]) != "Structure":
            return
        if not obj.InList[0].Shape:
            return
        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return
        if not obj.Diameter.Value:
            return
        if not obj.Amount:
            return
        father = obj.InList[0]
        wire = obj.Base.Shape.Wires[0]
        if hasattr(obj, "Rounding"):
            #print obj.Rounding
            if obj.Rounding:
                radius = obj.Rounding * obj.Diameter.Value
                import DraftGeomUtils
                wire = DraftGeomUtils.filletWire(wire, radius)
        bpoint, bvec = self.getBaseAndAxis(obj)
        if not bpoint:
            return
        axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1))
        size = (ArchCommands.projectToVector(father.Shape.copy(), axis)).Length
        if hasattr(obj, "Direction"):
            if not DraftVecUtils.isNull(obj.Direction):
                axis = FreeCAD.Vector(obj.Direction)  #.normalize()
                # don't normalize so the vector can also be used to determine the distance
                size = axis.Length
        #print axis
        #print size
        if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size:
            return

        # all tests ok!
        pl = obj.Placement
        import Part
        circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec)
        circle = Part.Wire(circle)
        try:
            bar = wire.makePipeShell([circle], True, False, 2)
        except:
            print "Arch: error sweeping rebar profile along the base sketch"
            return
        # building final shape
        shapes = []
        if obj.Amount == 1:
            offset = DraftVecUtils.scaleTo(axis, size / 2)
            bar.translate(offset)
            shapes.append(bar)
            if hasattr(obj, "Spacing"):
                obj.Spacing = 0
        else:
            if obj.OffsetStart.Value:
                baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value)
            else:
                baseoffset = None
            interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value)
            interval = interval / (obj.Amount - 1)
            vinterval = DraftVecUtils.scaleTo(axis, interval)
            for i in range(obj.Amount):
                if i == 0:
                    if baseoffset:
                        bar.translate(baseoffset)
                    shapes.append(bar)
                else:
                    bar = bar.copy()
                    bar.translate(vinterval)
                    shapes.append(bar)
            if hasattr(obj, "Spacing"):
                obj.Spacing = interval
        if shapes:
            obj.Shape = Part.makeCompound(shapes)
            obj.Placement = pl
Example #51
0
    def backPignon(self, i):

        import DraftGeomUtils
        profilCurrent = self.findProfil(i)
        profilBack1 = self.findProfil(i - 1)
        profilBack2 = self.findProfil(i - 2)
        pt1 = DraftGeomUtils.findIntersection(
            profilCurrent["edge"],
            profilBack1["eave"],
            infinite1=True,
            infinite2=True,
        )
        pt2 = DraftGeomUtils.findIntersection(
            profilBack2["edge"],
            profilBack1["eave"],
            infinite1=True,
            infinite2=True,
        )
        eaveWithoutOverhang = DraftGeomUtils.edg(pt1[0], pt2[0])
        if profilCurrent["run"] + profilBack2[
                "run"] != eaveWithoutOverhang.Length:
            points = [
                FreeCAD.Vector(0.0, 0.0, 0.0),
            ]
            points.append(
                FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"],
                               0.0))
            rampantCurrent = DraftGeomUtils.edg(points[0], points[1])
            points = [
                FreeCAD.Vector(eaveWithoutOverhang.Length, 0.0, 0.0),
            ]
            points.append(
                FreeCAD.Vector(eaveWithoutOverhang.Length - profilBack2["run"],
                               profilBack2["height"], 0.0))
            rampantBack2 = DraftGeomUtils.edg(points[0], points[1])
            point = DraftGeomUtils.findIntersection(
                rampantCurrent,
                rampantBack2,
                infinite1=True,
                infinite2=True,
            )
            ridgeCurrent = DraftGeomUtils.offset(
                profilCurrent["edge"],
                self.getPerpendicular(profilCurrent["vec"],
                                      profilCurrent["rot"], point[0].x))
            point = DraftGeomUtils.findIntersection(
                ridgeCurrent,
                profilBack1["eave"],
                infinite1=True,
                infinite2=True,
            )
        else:
            point = DraftGeomUtils.findIntersection(
                profilCurrent["ridge"],
                profilBack1["eave"],
                infinite1=True,
                infinite2=True,
            )
        self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
        point = DraftGeomUtils.findIntersection(
            profilCurrent["eave"],
            profilBack1["eave"],
            infinite1=True,
            infinite2=True,
        )
        self.ptsPaneProject.append(FreeCAD.Vector(point[0]))
Example #52
0
    def onChanged(self, obj, prop):
        if prop in ["Source", "RenderingMode", "ShowCut"]:
            import Part, DraftGeomUtils
            if hasattr(obj, "Source"):
                if obj.Source:
                    if obj.Source.Objects:
                        objs = Draft.getGroupContents(obj.Source.Objects,
                                                      walls=True,
                                                      addgroups=True)
                        objs = Draft.removeHidden(objs)
                        # separate spaces
                        self.spaces = []
                        os = []
                        for o in objs:
                            if Draft.getType(o) == "Space":
                                self.spaces.append(o)
                            else:
                                os.append(o)
                        objs = os
                        self.svg = ''
                        fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"'
                        fillpattern += ' x="0" y="0" width="10" height="10">'
                        fillpattern += '<g>'
                        fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>'

                        # generating SVG
                        if obj.RenderingMode == "Solid":
                            # render using the Arch Vector Renderer
                            import ArchVRM, WorkingPlane
                            wp = WorkingPlane.plane()
                            wp.setFromPlacement(obj.Source.Placement)
                            #wp.inverse()
                            render = ArchVRM.Renderer()
                            render.setWorkingPlane(wp)
                            render.addObjects(objs)
                            if hasattr(obj, "ShowCut"):
                                render.cut(obj.Source.Shape, obj.ShowCut)
                            else:
                                render.cut(obj.Source.Shape)
                            self.svg += '<g transform="scale(1,-1)">\n'
                            self.svg += render.getViewSVG(
                                linewidth="LWPlaceholder")
                            self.svg += fillpattern
                            self.svg += render.getSectionSVG(
                                linewidth="SWPlaceholder",
                                fillpattern="sectionfill")
                            if hasattr(obj, "ShowCut"):
                                if obj.ShowCut:
                                    self.svg += render.getHiddenSVG(
                                        linewidth="LWPlaceholder")
                            self.svg += '</g>\n'
                            # print render.info()

                        else:
                            # render using the Drawing module
                            import Drawing, Part
                            shapes = []
                            hshapes = []
                            sshapes = []
                            p = FreeCAD.Placement(obj.Source.Placement)
                            self.direction = p.Rotation.multVec(
                                FreeCAD.Vector(0, 0, 1))
                            for o in objs:
                                if o.isDerivedFrom("Part::Feature"):
                                    if o.Shape.isNull():
                                        pass
                                        #FreeCAD.Console.PrintWarning(translate("Arch","Skipping empty object: ")+o.Name)
                                    elif o.Shape.isValid():
                                        if hasattr(obj.Source, "OnlySolids"):
                                            if obj.Source.OnlySolids:
                                                shapes.extend(o.Shape.Solids)
                                            else:
                                                shapes.append(o.Shape)
                                        else:
                                            shapes.extend(o.Shape.Solids)
                                    else:
                                        FreeCAD.Console.PrintWarning(
                                            translate(
                                                "Arch",
                                                "Skipping invalid object: ") +
                                            o.Name)
                            cutface, cutvolume, invcutvolume = ArchCommands.getCutVolume(
                                obj.Source.Shape.copy(), shapes)
                            if cutvolume:
                                nsh = []
                                for sh in shapes:
                                    for sol in sh.Solids:
                                        if sol.Volume < 0:
                                            sol.reverse()
                                        c = sol.cut(cutvolume)
                                        s = sol.section(cutface)
                                        try:
                                            wires = DraftGeomUtils.findWires(
                                                s.Edges)
                                            for w in wires:
                                                f = Part.Face(w)
                                                sshapes.append(f)
                                            #s = Part.Wire(s.Edges)
                                            #s = Part.Face(s)
                                        except Part.OCCError:
                                            #print "ArchDrawingView: unable to get a face"
                                            sshapes.append(s)
                                        nsh.extend(c.Solids)
                                        #sshapes.append(s)
                                        if hasattr(obj, "ShowCut"):
                                            if obj.ShowCut:
                                                c = sol.cut(invcutvolume)
                                                hshapes.append(c)
                                shapes = nsh
                            if shapes:
                                self.shapes = shapes
                                self.baseshape = Part.makeCompound(shapes)
                                svgf = Drawing.projectToSVG(
                                    self.baseshape, self.direction)
                                if svgf:
                                    svgf = svgf.replace(
                                        'stroke-width="0.35"',
                                        'stroke-width="LWPlaceholder"')
                                    svgf = svgf.replace(
                                        'stroke-width="1"',
                                        'stroke-width="LWPlaceholder"')
                                    svgf = svgf.replace(
                                        'stroke-width:0.01',
                                        'stroke-width:LWPlaceholder')
                                    self.svg += svgf
                            if hshapes:
                                hshapes = Part.makeCompound(hshapes)
                                self.hiddenshape = hshapes
                                svgh = Drawing.projectToSVG(
                                    hshapes, self.direction)
                                if svgh:
                                    svgh = svgh.replace(
                                        'stroke-width="0.35"',
                                        'stroke-width="LWPlaceholder"')
                                    svgh = svgh.replace(
                                        'stroke-width="1"',
                                        'stroke-width="LWPlaceholder"')
                                    svgh = svgh.replace(
                                        'stroke-width:0.01',
                                        'stroke-width:LWPlaceholder')
                                    svgh = svgh.replace(
                                        'fill="none"',
                                        'fill="none"\nstroke-dasharray="DAPlaceholder"'
                                    )
                                    self.svg += svgh
                            if sshapes:
                                svgs = ""
                                if hasattr(obj, "ShowFill"):
                                    if obj.ShowFill:
                                        svgs += fillpattern
                                        svgs += '<g transform="rotate(180)">\n'
                                        for s in sshapes:
                                            if s.Edges:
                                                f = Draft.getSVG(
                                                    s,
                                                    direction=self.direction.
                                                    negative(),
                                                    linewidth=0,
                                                    fillstyle="sectionfill",
                                                    color=(0, 0, 0))
                                                svgs += f
                                        svgs += "</g>\n"
                                sshapes = Part.makeCompound(sshapes)
                                self.sectionshape = sshapes
                                svgs += Drawing.projectToSVG(
                                    sshapes, self.direction)
                                if svgs:
                                    svgs = svgs.replace(
                                        'stroke-width="0.35"',
                                        'stroke-width="SWPlaceholder"')
                                    svgs = svgs.replace(
                                        'stroke-width="1"',
                                        'stroke-width="SWPlaceholder"')
                                    svgs = svgs.replace(
                                        'stroke-width:0.01',
                                        'stroke-width:SWPlaceholder')
                                    svgs = svgs.replace(
                                        'stroke-width="0.35 px"',
                                        'stroke-width="SWPlaceholder"')
                                    svgs = svgs.replace(
                                        'stroke-width:0.35',
                                        'stroke-width:SWPlaceholder')
                                    self.svg += svgs
Example #53
0
    def makeStraightLanding(self,obj,edge,numberofsteps=None, callByMakeStraightStairsWithLanding=False):	# what is use of numberofsteps ?
        "builds a landing from a straight edge"

        # general data
        if not numberofsteps:
            numberofsteps = obj.NumberOfSteps
        import Part,DraftGeomUtils
        v = DraftGeomUtils.vec(edge)
        vLength = Vector(v.x,v.y,0)
        vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value)
        vBase = edge.Vertexes[0].Point

        # if not call by makeStraightStairsWithLanding() - not 're-base' in function there, then 're-base' here
        if not callByMakeStraightStairsWithLanding:
            vBase = self.vbaseFollowLastSement(obj, vBase)
            obj.AbsTop = vBase

        vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value))
        h = 0

        if obj.RiserHeightEnforce != 0:
            h = obj.RiserHeightEnforce * numberofsteps
        elif obj.Base: # TODO - should this happen? - though in original code
            if obj.Base.isDerivedFrom("Part::Feature"):
                #l = obj.Base.Shape.Length
                #if obj.Base.Shape.BoundBox.ZLength:
                if round(obj.Base.Shape.BoundBox.ZLength,Draft.precision()) != 0: # ? - need precision
                    h = obj.Base.Shape.BoundBox.ZLength #.Value?
                else:
                    print ("obj.Base has 0 z-value")
                    print (h)
        if h==0 and obj.Height.Value != 0:
            h = obj.Height.Value
        else:
            print (h)

        if obj.TreadDepthEnforce != 0:
                l = obj.TreadDepthEnforce.Value * (numberofsteps-2)
                if obj.LandingDepth:
                    l += obj.LandingDepth.Value
                else:
                    l += obj.Width.Value
        elif obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                l = obj.Base.Shape.Length #.Value?
        elif obj.Length.Value != 0:
            l = obj.Length.Value

        if obj.LandingDepth:
            fLength = float(l-obj.LandingDepth.Value)/(numberofsteps-2)
        else:
            fLength = float(l-obj.Width.Value)/(numberofsteps-2)

        fHeight = float(h)/numberofsteps
        a = math.atan(fHeight/fLength)
        print("landing data:",fLength,":",fHeight)

        # step
        p1 = self.align(vBase,obj.Align,vWidth)
        p1o = p1.add(Vector(0,0,-abs(obj.TreadThickness.Value)))

        p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value)))
        p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength)
        p3 = p2.add(vWidth)
        p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose)

        p4o = p3.add(DraftVecUtils.neg(vLength))
        if not callByMakeStraightStairsWithLanding:
            p2o = p2
            p3o = p3

        if callByMakeStraightStairsWithLanding:
            if obj.Flight == "HalfTurnLeft":
                p1 = p1.add(-vWidth)
                p2 = p2.add(-vWidth)
            elif obj.Flight == "HalfTurnRight":
                p3 = p3.add(vWidth)
                p4 = p4.add(vWidth)

        step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1]))
        if obj.TreadThickness.Value:
            step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value)))
            self.steps.append(step)
        else:
            self.pseudosteps.append(step)

        # structure
        lProfile = []
        struct = None
        p7 = None
        p1 = p1.add(DraftVecUtils.neg(vNose))
        p2 = p1.add(Vector(0,0,-fHeight)).add(Vector(0,0,-obj.StructureThickness.Value/math.cos(a)))
        resheight = p1.sub(p2).Length - obj.StructureThickness.Value
        reslength = resheight / math.tan(a)
        p3 = p2.add(DraftVecUtils.scaleTo(vLength,reslength)).add(Vector(0,0,resheight))
        p6 = p1.add(vLength)
        if obj.TreadThickness.Value:
            if obj.Flight == "Straight":
                p7 = p6.add(Vector(0,0,obj.TreadThickness.Value))
        reslength = fLength + (obj.StructureThickness.Value/math.sin(a)-(fHeight-obj.TreadThickness.Value)/math.tan(a))
        if p7:
            p5 = p7.add(DraftVecUtils.scaleTo(vLength,reslength))
        else:
            if obj.Flight == "Straight":
                p5 = p6.add(DraftVecUtils.scaleTo(vLength,reslength))
            else:
                p5 = None
        resheight = obj.StructureThickness.Value + obj.TreadThickness.Value
        reslength = resheight/math.tan(a)
        if obj.Flight == "Straight":
            p4 = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-resheight))
        else:
            p4 = p6.add(Vector(0,0,-obj.StructureThickness.Value))
        if obj.Structure == "Massive":
            if obj.StructureThickness.Value:
                if p7:
                    struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p7,p6,p1]))
                elif p5:
                    struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p6,p1]))
                else:
                    struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p6,p1]))
                evec = vWidth
                mvec = FreeCAD.Vector(0.0,0)
                if obj.StructureOffset.Value:
                    mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value)
                    struct.translate(mvec)
                if obj.Flight in ["HalfTurnLeft","HalfTurnRight"]:
                    evec = DraftVecUtils.scaleTo(evec,2*evec.Length-2*mvec.Length)
                else:
                    evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length))
                struct = struct.extrude(evec)
        elif obj.Structure in ["One stringer","Two stringers"]:
            if obj.StringerWidth.Value and obj.StructureThickness.Value:
                p1b = p1.add(Vector(0,0,-fHeight))
                reslength = fHeight/math.tan(a)
                p1c = p1.add(DraftVecUtils.scaleTo(vLength,reslength))
                p5b = None
                p5c = None
                if obj.TreadThickness.Value:
                    reslength = obj.StructureThickness.Value/math.sin(a)
                    p5b = p5.add(DraftVecUtils.scaleTo(vLength,-reslength))
                    reslength = obj.TreadThickness.Value/math.tan(a)
                    p5c = p5b.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-obj.TreadThickness.Value))
                    pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p5b,p5c,p1c]))
                else:
                    pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p1c]))
                evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value)
                if obj.Structure == "One stringer":
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value)
                    else:
                        mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2)
                    pol.translate(mvec)
                    struct = pol.extrude(evec)
                elif obj.Structure == "Two stringers":
                    pol2 = pol.copy()
                    if obj.StructureOffset.Value:
                        mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value)
                        pol.translate(mvec)
                        mvec = vWidth.add(mvec.negative())
                        pol2.translate(mvec)
                    else:
                        pol2.translate(vWidth)
                    s1 = pol.extrude(evec)
                    s2 = pol2.extrude(evec.negative())
                    struct = Part.makeCompound([s1,s2])

        # Overwriting result of above functions if case fit - should better avoid running the above in first place (better rewrite later)
        if not callByMakeStraightStairsWithLanding:
            if obj.StructureThickness.Value:
                struct = None
                landingFace = Part.Face(Part.makePolygon([p1o,p2o,p3o,p4o,p1o]))
                struct = landingFace.extrude(Vector(0,0,-abs(obj.StructureThickness.Value)))

        if struct:
            self.structures.append(struct)
Example #54
0
    def run(self):
        """run(): Runs a nesting operation. Returns a list of lists of
           shapes, each primary list being one filled container, or None
           if the operation failed."""

        # reset abort mechanism and variables

        self.running = True
        self.progress = 0
        starttime = datetime.now()

        # general conformity tests

        print("Executing conformity tests ... ", end="")
        if not self.container:
            print("Empty container. Aborting")
            return
        if not self.shapes:
            print("Empty shapes. Aborting")
            return
        if not isinstance(self.container, Part.Face):
            print("Container is not a face. Aborting")
            return
        normal = self.container.normalAt(0, 0)
        for s in self.shapes:
            if not self.update():
                return
            if len(s.Faces) != 1:
                print(
                    "One of the shapes does not contain exactly one face. Aborting"
                )
                return
            # check if all faces correctly oriented (same normal)
            if s.Faces[0].normalAt(0, 0).getAngle(normal) > TOLERANCE:
                # let pass faces with inverted normal
                if s.Faces[0].normalAt(
                        0, 0).getAngle(normal) - math.pi > TOLERANCE:
                    print(
                        "One of the face doesn't have the same orientation as the container. Aborting"
                    )
                    return

        # TODO
        # allow to use a non-rectangular container
        # manage margins/paddings
        # allow to prevent or force specific rotations for a piece

        # LONG-TERM TODO
        # add genetic algo to swap pieces, and check if the result is better

        # track progresses
        step = 100.0 / (len(self.shapes) * len(ROTATIONS))

        # store hashCode together with the face so we can change the order
        # and still identify the original face, so we can calculate a transform afterwards
        self.indexedfaces = [[shape.hashCode(), shape]
                             for shape in self.shapes]

        # build a clean copy so we don't touch the original
        faces = list(self.indexedfaces)

        # replace shapes by their face
        faces = [[f[0], f[1].Faces[0]] for f in faces]

        # order by area
        faces = sorted(faces, key=lambda face: face[1].Area)

        # discretize non-linear edges and remove holes
        nfaces = []
        for face in faces:
            if not self.update():
                return
            nedges = []
            allLines = True
            for edge in face[1].OuterWire.OrderedEdges:
                if isinstance(edge.Curve, (Part.LineSegment, Part.Line)):
                    nedges.append(edge)
                else:
                    allLines = False
                    last = edge.Vertexes[0].Point
                    for i in range(DISCRETIZE):
                        s = float(i + 1) / DISCRETIZE
                        par = edge.FirstParameter + (edge.LastParameter -
                                                     edge.FirstParameter) * s
                        new = edge.valueAt(par)
                        nedges.append(Part.LineSegment(last, new).toShape())
                        last = new
            f = Part.Face(Part.Wire(nedges))
            if not f.isValid():
                if allLines:
                    print("Invalid face found in set. Aborting")
                else:
                    print("Face distretizing failed. Aborting")
                return
            nfaces.append([face[0], f])
        faces = nfaces

        # container for sheets with a first, empty sheet
        sheets = [[]]

        print("Everything OK (", datetime.now() - starttime, ")")

        # main loop

        facenumber = 1
        facesnumber = len(faces)

        #print("Vertices per face:",[len(face[1].Vertexes) for face in faces])

        while faces:

            print("Placing piece",
                  facenumber,
                  "/",
                  facesnumber,
                  "Area:",
                  FreeCAD.Units.Quantity(
                      faces[-1][1].Area,
                      FreeCAD.Units.Area).getUserPreferred()[0],
                  ": ",
                  end="")

            face = faces.pop()
            boc = self.container.BoundBox

            # this stores the available solutions for each rotation of a piece
            # contains [sheetnumber,face,xlength] lists,
            # face being [hascode,transformed face] and xlength
            # the X size of all boundboxes of placed pieces
            available = []

            # this stores the possible positions on a blank
            # sheet, in case we need to create a new one
            initials = []

            # this checks if the piece don't fit in the container
            unfit = True

            for rotation in ROTATIONS:

                if not self.update():
                    return

                self.progress += step

                print(rotation, ", ", end="")
                hashcode = face[0]
                rotface = face[1].copy()
                if rotation:
                    rotface.rotate(rotface.CenterOfMass, normal, rotation)
                bof = rotface.BoundBox
                rotverts = self.order(rotface)
                #for i,v in enumerate(rotverts):
                #    Draft.makeText([str(i)],point=v)
                basepoint = rotverts[0]  # leftmost point of the rotated face
                basecorner = boc.getPoint(
                    0)  # lower left corner of the container

                # See if the piece fits in the container dimensions
                if (bof.XLength < boc.XLength) and (bof.YLength < boc.YLength):
                    unfit = False

                # Get the fit polygon of the container
                # that is, the polygon inside which basepoint can
                # circulate, and the face still be fully inside the container

                v1 = basecorner.add(basepoint.sub(bof.getPoint(0)))
                v2 = v1.add(FreeCAD.Vector(0, boc.YLength - bof.YLength, 0))
                v3 = v2.add(FreeCAD.Vector(boc.XLength - bof.XLength, 0, 0))
                v4 = v3.add(FreeCAD.Vector(0, -(boc.YLength - bof.YLength), 0))
                binpol = Part.Face(Part.makePolygon([v1, v2, v3, v4, v1]))
                initials.append([binpol, [hashcode, rotface], basepoint])

                # check for available space on each existing sheet

                for sheetnumber, sheet in enumerate(sheets):
                    # Get the no-fit polygon for each already placed face in
                    # current sheet. That is, a polygon in which basepoint
                    # cannot be, if we want our face to not overlap with the
                    # placed face.
                    # To do this, we "circulate" the face around the placed face

                    if not self.update():
                        return

                    nofitpol = []
                    for placed in sheet:
                        pts = []
                        pi = 0
                        for placedvert in self.order(placed[1], right=True):
                            fpts = []
                            for i, rotvert in enumerate(rotverts):
                                if not self.update():
                                    return

                                facecopy = rotface.copy()
                                facecopy.translate(placedvert.sub(rotvert))

                                # test if all the points of the face are outside the
                                # placed face (except the base point, which is coincident)

                                outside = True
                                faceverts = self.order(facecopy)
                                for vert in faceverts:
                                    if (vert.sub(placedvert)
                                        ).Length > TOLERANCE:
                                        if placed[1].isInside(
                                                vert, TOLERANCE, True):
                                            outside = False
                                            break

                                # also need to test for edge intersection, because even
                                # if all vertices are outside, the pieces could still
                                # overlap

                                if outside:
                                    for e1 in facecopy.OuterWire.Edges:
                                        for e2 in placed[1].OuterWire.Edges:
                                            if not self.update():
                                                return

                                            if True:
                                                # Draft code (SLOW)
                                                p = DraftGeomUtils.findIntersection(
                                                    e1, e2)
                                                if p:
                                                    p = p[0]
                                                    p1 = e1.Vertexes[0].Point
                                                    p2 = e1.Vertexes[1].Point
                                                    p3 = e2.Vertexes[0].Point
                                                    p4 = e2.Vertexes[1].Point
                                                    if (p.sub(p1).Length > TOLERANCE) and (p.sub(p2).Length > TOLERANCE) \
                                                    and (p.sub(p3).Length > TOLERANCE) and (p.sub(p4).Length > TOLERANCE):
                                                        outside = False
                                                        break
                                            else:
                                                # alt code: using distToShape (EVEN SLOWER!)
                                                p = e1.distToShape(e2)
                                                if p:
                                                    if p[0] < TOLERANCE:
                                                        # allow vertex-to-vertex intersection
                                                        if (p[2][0][0] !=
                                                                "Vertex"
                                                            ) or (p[2][0][3] !=
                                                                  "Vertex"):
                                                            outside = False
                                                            break

                                if outside:
                                    fpts.append([faceverts[0], i])
                                    #Draft.makeText([str(i)],point=faceverts[0])

                            # reorder available solutions around a same point if needed
                            # ensure they are in the correct order

                            idxs = [p[1] for p in fpts]
                            if (0 in idxs) and (len(faceverts) - 1 in idxs):
                                slicepoint = len(fpts)
                                last = len(faceverts)
                                for p in reversed(fpts):
                                    if p[1] == last - 1:
                                        slicepoint -= 1
                                        last -= 1
                                    else:
                                        break
                                fpts = fpts[slicepoint:] + fpts[:slicepoint]
                                #print(fpts)
                            pts.extend(fpts)

                        # create the polygon

                        if len(pts) < 3:
                            print(
                                "Error calculating a no-fit polygon. Aborting")
                            return
                        pts = [p[0] for p in pts]
                        pol = Part.Face(Part.makePolygon(pts + [pts[0]]))

                        if not pol.isValid():

                            # fix overlapping edges

                            overlap = True
                            while overlap:
                                overlap = False
                                for i in range(len(pol.OuterWire.Edges) - 1):
                                    if not self.update():
                                        return

                                    v1 = DraftGeomUtils.vec(
                                        pol.OuterWire.OrderedEdges[i])
                                    v2 = DraftGeomUtils.vec(
                                        pol.OuterWire.OrderedEdges[i + 1])
                                    if abs(v1.getAngle(v2) -
                                           math.pi) <= TOLERANCE:
                                        overlap = True
                                        ne = Part.LineSegment(
                                            pol.OuterWire.OrderedEdges[i].
                                            Vertexes[0].Point,
                                            pol.OuterWire.OrderedEdges[i + 1].
                                            Vertexes[-1].Point).toShape()
                                        pol = Part.Face(
                                            Part.Wire(pol.OuterWire.
                                                      OrderedEdges[:i] + [ne] +
                                                      pol.OuterWire.
                                                      OrderedEdges[i + 2:]))
                                        break

                        if not pol.isValid():

                            # trying basic OCC fix

                            pol.fix(0, 0, 0)
                            if pol.isValid():
                                if pol.ShapeType == "Face":
                                    pol = Part.Face(
                                        pol.OuterWire
                                    )  # discard possible inner holes
                                elif pol.Faces:
                                    # several faces after the fix, keep the biggest one
                                    a = 0
                                    ff = None
                                    for f in pol.Faces:
                                        if f.Area > a:
                                            a = f.Area
                                            ff = f
                                    if ff:
                                        pol = ff
                                else:
                                    print(
                                        "Unable to fix invalid no-fit polygon. Aborting"
                                    )
                                    Part.show(pol)
                                    return

                        if not pol.isValid():

                            # none of the fixes worked. Epic fail.

                            print("Invalid no-fit polygon. Aborting")
                            Part.show(pol.OuterWire)
                            for p in sheet:
                                Part.show(p[1])
                            Part.show(facecopy)
                            #for i,p in enumerate(faceverts):
                            #    Draft.makeText([str(i)],point=p)
                            return

                        if pol.isValid():
                            nofitpol.append(pol)
                            #Part.show(pol)

                    # Union all the no-fit pols into one

                    if len(nofitpol) == 1:
                        nofitpol = nofitpol[0]
                    elif len(nofitpol) > 1:
                        b = nofitpol.pop()
                        for n in nofitpol:
                            if not self.update():
                                return
                            b = b.fuse(n)
                        nofitpol = b

                        # remove internal edges (discard edges shared by 2 faces)

                        lut = {}
                        for f in fitpol.Faces:
                            for e in f.Edges:
                                h = e.hashCode()
                                if h in lut:
                                    lut[h].append(e)
                                else:
                                    lut[h] = [e]
                        edges = [e[0] for e in lut.values() if len(e) == 1]
                        try:
                            pol = Part.Face(Part.Wire(edges))
                        except:
                            # above method can fail sometimes. Try a slower method
                            w = DraftGeomUtils.findWires(edges)
                            if len(w) == 1:
                                if w[0].isClosed():
                                    try:
                                        pol = Part.Face(w[0])
                                    except:
                                        print(
                                            "Error merging polygons. Aborting")
                                        try:
                                            Part.show(Part.Wire(edges))
                                        except:
                                            for e in edges:
                                                Part.show(e)
                                        return

                    # subtract the no-fit polygon from the container's fit polygon
                    # we then have the zone where the face can be placed

                    if nofitpol:
                        fitpol = binpol.cut(nofitpol)
                    else:
                        fitpol = binpol.copy()

                    # check that we have some space on this sheet

                    if (fitpol.Area > 0) and fitpol.Vertexes:

                        # order the fitpol vertexes by smallest X
                        # and try to place the piece, making sure it doesn't
                        # intersect with already placed pieces
                        fitverts = sorted([v.Point for v in fitpol.Vertexes],
                                          key=lambda v: v.x)
                        for p in fitverts:
                            if not self.update():
                                return

                            trface = rotface.copy()
                            trface.translate(p.sub(basepoint))
                            ok = True
                            for placed in sheet:
                                if ok:
                                    for vert in trface.Vertexes:
                                        if placed[1].isInside(
                                                vert.Point, TOLERANCE, False):
                                            ok = False
                                            break
                                if ok:
                                    for e1 in trface.OuterWire.Edges:
                                        for e2 in placed[1].OuterWire.Edges:
                                            p = DraftGeomUtils.findIntersection(
                                                e1, e2)
                                            if p:
                                                p = p[0]
                                                p1 = e1.Vertexes[0].Point
                                                p2 = e1.Vertexes[1].Point
                                                p3 = e2.Vertexes[0].Point
                                                p4 = e2.Vertexes[1].Point
                                                if (p.sub(p1).Length > TOLERANCE) and (p.sub(p2).Length > TOLERANCE) \
                                                and (p.sub(p3).Length > TOLERANCE) and (p.sub(p4).Length > TOLERANCE):
                                                    ok = False
                                                    break
                                if not ok:
                                    break
                            if ok:
                                rotface = trface
                                break
                        else:
                            print(
                                "Couldn't determine location on sheet. Aborting"
                            )
                            return

                        # check the X space occupied by this solution

                        bb = rotface.BoundBox
                        for placed in sheet:
                            bb.add(placed[1].BoundBox)
                        available.append([
                            sheetnumber, [hashcode, rotface], bb.XMax, fitpol
                        ])

            if unfit:
                print("One face doesn't fit in the container. Aborting")
                return

            if available:

                # order by smallest X size and take the first one
                available = sorted(available, key=lambda sol: sol[2])
                print("Adding piece to sheet", available[0][0] + 1)
                sheets[available[0][0]].append(available[0][1])
                #Part.show(available[0][3])

            else:

                # adding to the leftmost vertex of the binpol

                sheet = []
                print("Creating new sheet, adding piece to sheet", len(sheets))
                # order initial positions by smallest X size
                initials = sorted(initials,
                                  key=lambda sol: sol[1][1].BoundBox.XLength)
                hashcode = initials[0][1][0]
                face = initials[0][1][1]
                # order binpol vertexes by X coord
                verts = sorted([v.Point for v in initials[0][0].Vertexes],
                               key=lambda v: v.x)
                face.translate(verts[0].sub(initials[0][2]))
                sheet.append([hashcode, face])
                sheets.append(sheet)

            facenumber += 1

        print("Run time:", datetime.now() - starttime)
        self.results.append(sheets)
        return sheets
Example #55
0
def make_wire(pointslist, closed=False, placement=None, face=None, support=None, bs2wire=False):
    """makeWire(pointslist,[closed],[placement])
    
    Creates a Wire object from the given list of vectors.  If face is
    true (and wire is closed), the wire will appear filled. Instead of
    a pointslist, you can also pass a Part Wire.

    Parameters
    ----------
    pointslist : [Base.Vector]
        List of points to create the polyline

    closed : bool
        If closed is True or first and last points are identical, 
        the created polyline will be closed.

    placement : Base.Placement
        If a placement is given, it is used.
    
    face : Bool
        If face is False, the rectangle is shown as a wireframe, 
        otherwise as a face.   

    support : 
        TODO: Describe
    
    bs2wire : bool
        TODO: Describe
    """
    if not App.ActiveDocument:
        App.Console.PrintError("No active document. Aborting\n")
        return None

    import Part

    if isinstance(pointslist, (list,tuple)):
        for pnt in pointslist:
            if not isinstance(pnt, App.Vector):
                App.Console.PrintError(
                    "Items must be Base.Vector objects, not {}\n".format(
                    type(pnt)))
                return None

    elif isinstance(pointslist, Part.Wire):
        for edge in pointslist.Edges:
            if not DraftGeomUtils.is_straight_line(edge):
                App.Console.PrintError("All edges must be straight lines\n")
                return None
        closed = pointslist.isClosed()
        pointslist = [v.Point for v in pointslist.OrderedVertexes]

    else:
        App.Console.PrintError("Can't make Draft Wire from {}\n".format(
            type(pointslist)))
        return None


    if len(pointslist) == 0:
        App.Console.PrintWarning("Draft Wire created with empty point list\n")
    
    if placement:
        utils.type_check([(placement, App.Placement)], "make_wire")
        ipl = placement.inverse()
        if not bs2wire:
            pointslist = [ipl.multVec(p) for p in pointslist]

    if len(pointslist) == 2: 
        fname = "Line"
    else: 
        fname = "Wire"

    obj = App.ActiveDocument.addObject("Part::Part2DObjectPython", fname)
    Wire(obj)
    obj.Points = pointslist
    obj.Closed = closed
    obj.Support = support
    
    if face != None:
        obj.MakeFace = face

    if placement: 
        obj.Placement = placement

    if App.GuiUp:
        ViewProviderWire(obj.ViewObject)
        gui_utils.format_object(obj)
        gui_utils.select(obj)

    return obj
Example #56
0
    def returnOutlines(self, obj, edges, align="left", offsetH=0, offsetV=0):	# better omit 'obj' latter - 'currently' only for vbaseFollowLastSement()?

        import DraftGeomUtils

        v, vLength, vWidth, vBase = [], [], [], []
        p1o, p2o, p1, p2, p3, p4 = [], [], [], [], [], []
        outline, outlineP1P2, outlineP3P4 = [], [], []

        enum_edges = enumerate(edges)
        for i, edge in enum_edges:
            v.append(DraftGeomUtils.vec(edge))
            vLength.append(Vector(v[i].x,v[i].y,0))
            # TODO obj.Width[i].Value for different 'edges' / 'sections' of the landing

            netWidth = obj.Width.Value - 2*offsetH
            vWidth.append(DraftVecUtils.scaleTo(vLength[i].cross(Vector(0,0,1)),netWidth))

            vBase.append(edges[i].Vertexes[0].Point)
            vBase[i] = self.vbaseFollowLastSement(obj, vBase[i])

            if offsetV != 0:  # redundant?
                vBase[i] = vBase[i].add(Vector(0,0,offsetV))
            if offsetH != 0:  # redundant?
                vOffsetH = DraftVecUtils.scaleTo(vLength[i].cross(Vector(0,0,1)),offsetH)
                vBase[i] = self.align(vBase[i], "Right", -vOffsetH)

            # step + structure							# assume all left-align first # no nosing
            p1o.append(vBase[i].add(Vector(0,0,-abs(obj.TreadThickness.Value))))
            p2o.append(p1o[i].add(vLength[i]))
            p1.append(self.align(vBase[i],obj.Align,vWidth[i]).add(Vector(0,0,-abs(obj.TreadThickness.Value))))
            p2.append(p1[i].add(vLength[i]))
            p3.append(p2[i].add(vWidth[i]))
            p4.append(p3[i].add(DraftVecUtils.neg(vLength[i])))

            #if obj.Align == 'Left':
            if False:
                outlineP1P2.append(p1[i])
                outlineP1P2.append(p2[i])					# can better skip 1 'supposedly' overlapping point every pair?
                if i > 0:
                    print ("Debug - intersection calculation")
                    print (p3[i-1])
                    print (p4[i-1])
                    print (p3[i])
                    print (p4[i])
                    intersection = DraftGeomUtils.findIntersection(p3[i-1],p4[i-1],p3[i],p4[i],True,True)
                    print (intersection)
                    outlineP3P4.insert(0, intersection[0])
                else:
                    outlineP3P4.insert(0, p4[i])

            #elif obj.Align == 'Right':
            if False:

                if i > 0:
                    intersection = DraftGeomUtils.findIntersection(p1[i-1],p2[i-1],p1[i],p2[i],True,True)
                    outlineP1P2.append(intersection[0])
                else:
                    outlineP1P2.append(p1[i])
                outlineP3P4.insert(0, p4[i])
                outlineP3P4.insert(0, p3[i])

            #elif obj.Align == 'Center':
            if True:

                if i > 0:
                    intersection = DraftGeomUtils.findIntersection(p1[i-1],p2[i-1],p1[i],p2[i],True,True)
                    outlineP1P2.append(intersection[0])
                    intersection = DraftGeomUtils.findIntersection(p3[i-1],p4[i-1],p3[i],p4[i],True,True)
                    outlineP3P4.insert(0, intersection[0])
                else:
                    outlineP1P2.append(p1[i])
                    outlineP3P4.insert(0, p4[i])

            else:
                outlineP1P2.append(p1[i])
                outlineP1P2.append(p2[i])
                outlineP3P4.insert(0, p4[i])
                outlineP3P4.insert(0, p3[i])

        # add back last/first 'missing' point(s)
        outlineP3P4.insert(0, p3[i])
        outlineP1P2.append(p2[i])

        outline = outlineP1P2 + outlineP3P4
        outline.append(p1[0])
        print (outlineP1P2)
        print (outlineP3P4)
        print (outline)

        return outline, outlineP1P2, outlineP3P4, vBase
Example #57
0
 def getBase(self,obj,wire,normal,width,height):
     "returns a full shape from a base wire"
     import DraftGeomUtils,Part
     flat = False
     if hasattr(obj.ViewObject,"DisplayMode"):
         flat = (obj.ViewObject.DisplayMode == "Flat 2D")
     dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
     if not DraftVecUtils.isNull(dvec):
         dvec.normalize()
     if obj.Align == "Left":
         dvec.multiply(width)
         if hasattr(obj,"Offset"):
             if obj.Offset.Value:
                 dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
                 wire = DraftGeomUtils.offsetWire(wire,dvec2)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Right":
         dvec.multiply(width)
         dvec = dvec.negative()
         if hasattr(obj,"Offset"):
             if obj.Offset.Value:
                 dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
                 wire = DraftGeomUtils.offsetWire(wire,dvec2)
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
         sh = DraftGeomUtils.bind(w1,w2)
     elif obj.Align == "Center":
         dvec.multiply(width/2)
         w1 = DraftGeomUtils.offsetWire(wire,dvec)
         dvec = dvec.negative()
         w2 = DraftGeomUtils.offsetWire(wire,dvec)
         sh = DraftGeomUtils.bind(w1,w2)
     # fixing self-intersections
     sh.fix(0.1,0,1)
     self.BaseProfile = sh
     if height and (not flat):
         self.ExtrusionVector = Vector(normal).multiply(height)
         sh = sh.extrude(self.ExtrusionVector)
     return sh
Example #58
0
    def execute(self, obj):
        """This method is run when the object is created or recomputed."""
        import Part

        if (obj.Length.Value == 0) or (obj.Height.Value == 0):
            obj.positionBySupport()
            return

        plm = obj.Placement

        shape = None

        if hasattr(obj, "Rows") and hasattr(obj, "Columns"):
            # TODO: verify if this is needed:
            if obj.Rows > 1:
                rows = obj.Rows
            else:
                rows = 1
            if obj.Columns > 1:
                columns = obj.Columns
            else:
                columns = 1
            # TODO: till here

            if (rows > 1) or (columns > 1):
                shapes = []
                l = obj.Length.Value / columns
                h = obj.Height.Value / rows
                for i in range(columns):
                    for j in range(rows):
                        p1 = App.Vector(i * l, j * h, 0)
                        p2 = App.Vector(p1.x + l, p1.y, p1.z)
                        p3 = App.Vector(p1.x + l, p1.y + h, p1.z)
                        p4 = App.Vector(p1.x, p1.y + h, p1.z)
                        p = Part.makePolygon([p1, p2, p3, p4, p1])
                        if "ChamferSize" in obj.PropertiesList:
                            if obj.ChamferSize.Value != 0:
                                w = DraftGeomUtils.filletWire(
                                    p, obj.ChamferSize.Value, chamfer=True)
                                if w:
                                    p = w
                        if "FilletRadius" in obj.PropertiesList:
                            if obj.FilletRadius.Value != 0:
                                w = DraftGeomUtils.filletWire(
                                    p, obj.FilletRadius.Value)
                                if w:
                                    p = w
                        if hasattr(obj, "MakeFace"):
                            if obj.MakeFace:
                                p = Part.Face(p)
                        shapes.append(p)
                if shapes:
                    shape = Part.makeCompound(shapes)

        if not shape:
            p1 = App.Vector(0, 0, 0)
            p2 = App.Vector(p1.x + obj.Length.Value, p1.y, p1.z)
            p3 = App.Vector(p1.x + obj.Length.Value, p1.y + obj.Height.Value,
                            p1.z)
            p4 = App.Vector(p1.x, p1.y + obj.Height.Value, p1.z)
            shape = Part.makePolygon([p1, p2, p3, p4, p1])
            if "ChamferSize" in obj.PropertiesList:
                if obj.ChamferSize.Value != 0:
                    w = DraftGeomUtils.filletWire(shape,
                                                  obj.ChamferSize.Value,
                                                  chamfer=True)
                    if w:
                        shape = w
            if "FilletRadius" in obj.PropertiesList:
                if obj.FilletRadius.Value != 0:
                    w = DraftGeomUtils.filletWire(shape,
                                                  obj.FilletRadius.Value)
                    if w:
                        shape = w
            if hasattr(obj, "MakeFace"):
                if obj.MakeFace:
                    shape = Part.Face(shape)
            else:
                shape = Part.Face(shape)

        obj.Shape = shape

        if hasattr(obj, "Area") and hasattr(shape, "Area"):
            obj.Area = shape.Area

        obj.Placement = plm

        obj.positionBySupport()
Example #59
0
def getIndices(shape, offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    for e in shape.Edges:
        try:
            if not isinstance(e.Curve, Part.Line):
                if not curves:
                    curves = shape.tessellate(1)
                    FreeCAD.Console.PrintWarning(
                        translate(
                            "Arch",
                            "Found a shape containing curves, triangulating\n")
                    )
                    break
        except:  # unimplemented curve type
            curves = shape.tessellate(1)
            FreeCAD.Console.PrintWarning(
                translate("Arch",
                          "Found a shape containing curves, triangulating\n"))
            break
    if curves:
        for v in curves[0]:
            vlist.append(" " + str(round(v.x, p)) + " " + str(round(v.y, p)) +
                         " " + str(round(v.z, p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" " + str(round(v.X, p)) + " " + str(round(v.Y, p)) +
                         " " + str(round(v.Z, p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(
                        findVert(e.Vertexes[0], shape.Vertexes) + offset)
                    ei += " " + str(
                        findVert(e.Vertexes[-1], shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(
                            findVert(vdata, shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                # OCC vertices are unsorted. We need to sort in the right order...
                edges = Part.__sortEdges__(f.OuterWire.Edges)
                #print edges
                for e in edges:
                    #print e.Vertexes[0].Point,e.Vertexes[1].Point
                    v = e.Vertexes[0]
                    ind = findVert(v, shape.Vertexes)
                    if ind == None:
                        return None, None, None
                    fi += " " + str(ind + offset)
                flist.append(fi)
    return vlist, elist, flist
Example #60
0
    def makeStraightStairsWithLanding(self,obj,edge):

        "builds a straight staircase with/without a landing in the middle"

        if obj.NumberOfSteps < 3:
            return
        import Part,DraftGeomUtils
        v = DraftGeomUtils.vec(edge)

        landing = 0
        if obj.TreadDepthEnforce == 0:
            if obj.Landings == "At center":
                if obj.LandingDepth:
                    reslength = edge.Length - obj.LandingDepth.Value
                else:
                    reslength = edge.Length - obj.Width.Value

                vLength = DraftVecUtils.scaleTo(v,float(reslength)/(obj.NumberOfSteps-2))
            else:
                reslength = edge.Length
                vLength = DraftVecUtils.scaleTo(v,float(reslength)/(obj.NumberOfSteps-1))

        else:

            if obj.Landings == "At center":
                reslength = obj.TreadDepthEnforce * (obj.NumberOfSteps-2) # TODO any use ?
            else:
                reslength = obj.TreadDepthEnforce * (obj.NumberOfSteps-1) # TODO any use ?
            vLength = DraftVecUtils.scaleTo(v,float(obj.TreadDepthEnforce))
        vLength = Vector(vLength.x,vLength.y,0)

        vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value)
        p1 = edge.Vertexes[0].Point

        if obj.RiserHeightEnforce == 0:
            if round(v.z,Draft.precision()) != 0:
                h = v.z
            else:
                h = obj.Height.Value
            hstep = h/obj.NumberOfSteps

        else:
            h = obj.RiserHeightEnforce.Value * (obj.NumberOfSteps) 
            hstep = obj.RiserHeightEnforce.Value

        if obj.Landings == "At center":
            landing = int(obj.NumberOfSteps/2)
        else:
            landing = obj.NumberOfSteps

        if obj.LastSegment:
            lastSegmentAbsTop = obj.LastSegment.AbsTop
            p1 = Vector(p1.x, p1.y,lastSegmentAbsTop.z)			# use Last Segment top's z-coordinate 

        obj.AbsTop = p1.add(Vector(0,0,h))
        p2 = p1.add(DraftVecUtils.scale(vLength,landing-1).add(Vector(0,0,landing*hstep)))

        if obj.Landings == "At center":
            if obj.LandingDepth:
                p3 = p2.add(DraftVecUtils.scaleTo(vLength,obj.LandingDepth.Value))
            else:
                p3 = p2.add(DraftVecUtils.scaleTo(vLength,obj.Width.Value))
   
            if obj.Flight in ["HalfTurnLeft HalfTurnLeft", "HalfTurnRight"]:
                if (obj.Align == "Left" and obj.Flight == "HalfTurnLeft") or (obj.Align == "Right" and obj.Flight == "HalfTurnRight"):
                    p3r = p2
                elif (obj.Align == "Left" and obj.Flight == "HalfTurnRight"):
                    p3r = self.align(p2,"Right",-2*vWidth) # -ve / opposite direction of "Right" - no "Left" in _Stairs.Align()
                elif (obj.Align == "Right" and obj.Flight == "HalfTurnLeft"):
                    p3r = self.align(p2,"Right",2*vWidth)
                elif (obj.Align == "Center" and obj.Flight == "HalfTurnLeft"):
                    p3r = self.align(p2,"Right",vWidth)
                elif (obj.Align == "Center" and obj.Flight == "HalfTurnRight"):
                    p3r = self.align(p2,"Right",-vWidth) # -ve / opposite direction of "Right" - no "Left" in _Stairs.Align()
                else:
                    print("Should have a bug here, if see this")
                p4r = p3r.add(DraftVecUtils.scale(-vLength,obj.NumberOfSteps-(landing+1)).add(Vector(0,0,(obj.NumberOfSteps-landing)*hstep)))
            else:
                p4 = p3.add(DraftVecUtils.scale(vLength,obj.NumberOfSteps-(landing+1)).add(Vector(0,0,(obj.NumberOfSteps-landing)*hstep)))
            self.makeStraightLanding(obj,Part.LineSegment(p2,p3).toShape(), None, True)

            if obj.Flight in ["HalfTurnLeft", "HalfTurnRight"]:
                self.makeStraightStairs(obj,Part.LineSegment(p3r,p4r).toShape(),obj.NumberOfSteps-landing)
            else:
                self.makeStraightStairs(obj,Part.LineSegment(p3,p4).toShape(),obj.NumberOfSteps-landing)

        self.makeStraightStairs(obj,Part.LineSegment(p1,p2).toShape(),landing)
        print (p1, p2)
        if obj.Landings == "At center" and obj.Flight not in ["HalfTurnLeft", "HalfTurnRight"]:
            print (p3, p4)
        elif obj.Landings == "At center" and obj.Flight in ["HalfTurnLeft", "HalfTurnRight"]:
            print (p3r, p4r)