Example #1
0
def setup(doc=None, solvertype="ccxtools"):
    # setup model

    if doc is None:
        doc = init_doc()

    # geometry objects
    # TODO turn circle of upper tube to have the line on the other side
    # make a boolean fragment of them to be sure there is a mesh point on remesh
    # but as long as we do not remesh it works without the boolean fragment too

    # tubes
    tube_radius = 25
    tube_length = 500
    sh_lower_circle = Part.Wire(Part.makeCircle(tube_radius))
    sh_lower_tube = sh_lower_circle.extrude(FreeCAD.Vector(0, 0, tube_length))
    sh_lower_tube.reverse()
    lower_tube = doc.addObject("Part::Feature", "Lower_tube")
    lower_tube.Shape = sh_lower_tube

    sh_upper_circle = Part.Wire(Part.makeCircle(tube_radius))
    sh_upper_tube = sh_upper_circle.extrude(FreeCAD.Vector(0, 0, tube_length))
    sh_upper_tube.reverse()
    upper_tube = doc.addObject("Part::Feature", "Upper_tube")
    upper_tube.Shape = sh_upper_tube
    upper_tube.Placement = FreeCAD.Placement(
        FreeCAD.Vector(-25, 51, 475),
        FreeCAD.Rotation(90, 0, 90),
        FreeCAD.Vector(0, 0, 0),
    )

    # point for load
    v_force_pt = FreeCAD.Vector(0, 76, 475)
    sh_force_point = Part.Vertex(v_force_pt)
    force_point = doc.addObject("Part::Feature", "Load_place_point")
    force_point.Shape = sh_force_point
    if FreeCAD.GuiUp:
        force_point.ViewObject.PointSize = 10.0
        force_point.ViewObject.PointColor = (1.0, 0.0, 0.0)

    # boolean fragment of upper tubo and force point
    boolfrag = SplitFeatures.makeBooleanFragments(name='BooleanFragments')
    boolfrag.Objects = [upper_tube, force_point]
    if FreeCAD.GuiUp:
        upper_tube.ViewObject.hide()

    # compound out of bool frag and lower tube
    geom_obj = doc.addObject("Part::Compound", "AllGeomCompound")
    geom_obj.Links = [boolfrag, lower_tube]

    # line for load direction
    sh_load_line = Part.makeLine(v_force_pt, FreeCAD.Vector(0, 150, 475))
    load_line = doc.addObject("Part::Feature", "Load_direction_line")
    load_line.Shape = sh_load_line
    if FreeCAD.GuiUp:
        load_line.ViewObject.LineWidth = 5.0
        load_line.ViewObject.LineColor = (1.0, 0.0, 0.0)

    doc.recompute()

    if FreeCAD.GuiUp:
        geom_obj.ViewObject.Document.activeView().viewAxonometric()
        geom_obj.ViewObject.Document.activeView().fitAll()

    # analysis
    analysis = ObjectsFem.makeAnalysis(doc, "Analysis")

    # solver
    if solvertype == "calculix":
        solver_object = analysis.addObject(
            ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0]
    elif solvertype == "ccxtools":
        solver_object = analysis.addObject(
            ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0]
        solver_object.WorkingDir = u""
    if solvertype == "calculix" or solvertype == "ccxtools":
        solver_object.AnalysisType = "static"
        solver_object.BeamShellResultOutput3D = True
        solver_object.GeometricalNonlinearity = "linear"  # really?
        # TODO iterations parameter !!!
        solver_object.ThermoMechSteadyState = False
        solver_object.MatrixSolverType = "default"
        solver_object.IterationsControlParameterTimeUse = False
        solver_object.SplitInputWriter = False

    # shell thickness
    analysis.addObject(
        ObjectsFem.makeElementGeometry2D(doc, 0.5, 'ShellThickness'))

    # material
    material_obj = analysis.addObject(
        ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial"))[0]
    mat = material_obj.Material
    mat["Name"] = "AlCuMgPb"
    mat["YoungsModulus"] = "72000 MPa"
    mat["PoissonRatio"] = "0.30"
    material_obj.Material = mat
    analysis.addObject(material_obj)

    # fixed_constraint
    fixed_constraint = analysis.addObject(
        ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed"))[0]
    fixed_constraint.References = [
        (lower_tube, "Edge2"),
        (upper_tube, "Edge3"),
    ]

    # force_constraint
    force_constraint = doc.Analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce"))[0]
    # TODO use point of tube boolean fragment
    force_constraint.References = [(force_point, "Vertex1")]
    force_constraint.Force = 5000.0
    force_constraint.Direction = (load_line, ["Edge1"])
    force_constraint.Reversed = True

    # contact constraint
    contact_constraint = doc.Analysis.addObject(
        ObjectsFem.makeConstraintContact(doc, name="ConstraintContact"))[0]
    contact_constraint.References = [
        (lower_tube, "Face1"),
        (upper_tube, "Face1"),
    ]
    contact_constraint.Friction = 0.0
    # contact_constrsh_aint.Slope = "1000000.0 kg/(mm*s^2)"  # contact stiffness
    contact_constraint.Slope = 1000000.0  # should be 1000000.0 kg/(mm*s^2)

    # mesh
    from .meshes.mesh_contact_tube_tube_tria3 import create_nodes, create_elements
    fem_mesh = Fem.FemMesh()
    control = create_nodes(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating nodes.\n")
    control = create_elements(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating elements.\n")
    femmesh_obj = analysis.addObject(
        doc.addObject("Fem::FemMeshObject", mesh_name))[0]
    femmesh_obj.FemMesh = fem_mesh

    doc.recompute()
    return doc
Example #2
0
def superWireReverse(debuglist, closed=False):
    '''superWireReverse(debuglist,[closed]): forces a wire between edges
    that don't necessarily have coincident endpoints. If closed=True, wire
    will always be closed. debuglist has a tuple for every edge.The first
    entry is the edge, the second is the flag 'does not need to be inverted'
    '''

    #taken from draftlibs
    def median(v1, v2):
        vd = v2.sub(v1)
        vd.scale(.5, .5, .5)
        return v1.add(vd)

    try:
        from DraftGeomUtils import findMidpoint
    except ImportError:  #workaround for Version 0.12
        from draftlibs.fcgeo import findMidpoint  #workaround for Version 0.12
    import Part
    #edges = sortEdges(edgeslist)
    print(debuglist)
    newedges = []
    for i in range(len(debuglist)):
        curr = debuglist[i]
        if i == 0:
            if closed:
                prev = debuglist[-1]
            else:
                prev = None
        else:
            prev = debuglist[i - 1]
        if i == (len(debuglist) - 1):
            if closed:
                nexte = debuglist[0]
            else:
                nexte = None
        else:
            nexte = debuglist[i + 1]
        print(i, prev, curr, nexte)
        if prev:
            if curr[0].Vertexes[-1*(not curr[1])].Point == \
                    prev[0].Vertexes[-1*prev[1]].Point:
                p1 = curr[0].Vertexes[-1 * (not curr[1])].Point
            else:
                p1 = median(curr[0].Vertexes[-1*(not curr[1])].Point,\
                        prev[0].Vertexes[-1*prev[1]].Point)
        else:
            p1 = curr[0].Vertexes[-1 * (not curr[1])].Point
        if nexte:
            if curr[0].Vertexes[-1*curr[1]].Point == \
                nexte[0].Vertexes[-1*(not nexte[1])].Point:
                p2 = nexte[0].Vertexes[-1 * (not nexte[1])].Point
            else:
                p2 = median(curr[0].Vertexes[-1*(curr[1])].Point,\
                        nexte[0].Vertexes[-1*(not nexte[1])].Point)
        else:
            p2 = curr[0].Vertexes[-1 * (curr[1])].Point
        if isinstance(curr[0].Curve, (Part.LineSegment, Part.Line)):
            print("line", p1, p2)
            newedges.append(Part.LineSegment(p1, p2).toShape())
        elif isinstance(curr[0].Curve, Part.Circle):
            p3 = findMidpoint(curr[0])
            print("arc", p1, p3, p2)
            newedges.append(Part.Arc(p1, p3, p2).toShape())
        else:
            print("Cannot superWire edges that are not lines or arcs")
            return None
    print(newedges)
    return Part.Wire(newedges)
Example #3
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 #4
0
    def build(self, delta=0.25, delta_phi=math.radians(2)):
        exit_radius = math.sqrt(throat_radius * throat_radius *
                                self.nozzle_expansion_ratio)

        inflection_angle = math.radians(self.inflection_angle_deg)
        exit_angle = math.radians(self.exit_angle_deg)
        diverging_radius = diverging_radius_koef * throat_radius

        inflection_point = circle_point(inflection_angle, diverging_radius, 0,
                                        (1 + diverging_radius_koef) *
                                        throat_radius)

        edges = []

        # converging arc

        converging_radius = throat_radius * converging_radius_koef
        converging_circle_center = 0, throat_radius + converging_radius

        x = 0
        y = converging_circle_center[1]

        px = -converging_radius
        py = 0

        phi = math.radians(180)

        while phi <= math.radians(270):
            x = math.cos(phi) * converging_radius + converging_circle_center[0]
            y = math.sin(phi) * converging_radius + converging_circle_center[1]

            edges.append(Part.makeLine((px, py, 0), (x, y, 0)))
            px = x
            py = y

            phi = phi + delta_phi

        # diverging arc
        diverging_circle_center = 0, throat_radius + diverging_radius

        while y < inflection_point[1]:
            x = math.cos(phi) * diverging_radius + diverging_circle_center[0]
            y = math.sin(phi) * diverging_radius + diverging_circle_center[1]

            edges.append(Part.makeLine((px, py, 0), (x, y, 0)))
            px = x
            py = y

            phi = phi + delta_phi

        # diverging parabola
        abc = parabola_koef(inflection_angle, exit_angle, exit_radius,
                            inflection_point)

        while y <= exit_radius:
            y = py + delta
            ny = min(y, exit_radius)
            x = abc[0] * sqr(ny) + abc[1] * ny + abc[2]

            edges.append(Part.makeLine((px, py, 0), (x, ny, 0)))
            px = x
            py = ny

        # back to the axis
        edges.append(Part.makeLine((px, py, 0), (px, 0, 0)))
        edges.append(Part.makeLine((px, 0, 0), (-converging_radius, 0, 0)))

        nozzle_contour = Part.Wire(edges)
        nozzle_face = Part.Face(nozzle_contour)

        self.solid = nozzle_face.revolve(App.Vector(1, 0, 0),
                                         App.Vector(360, 0, 0))
        self.converging_length = converging_radius
        self.diverging_length = px
        self.exit_radius = exit_radius
Example #5
0
    def computeAreas(self,obj):

        if not obj.Shape:
            return
        if obj.Shape.isNull():
            return
        if not obj.Shape.isValid():
            return
        if not obj.Shape.Faces:
            return
        if not hasattr(obj,"Perimeter"): # check we have a latest version site
            return
        if not obj.Terrain:
            return
        # compute area
        fset = []
        for f in obj.Shape.Faces:
            if f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1)) < 1.5707:
                fset.append(f)
        if fset:
            import Drawing,Part
            pset = []
            for f in fset:
                try:
                    pf = Part.Face(Part.Wire(Drawing.project(f,FreeCAD.Vector(0,0,1))[0].Edges))
                except Part.OCCError:
                    # error in computing the area. Better set it to zero than show a wrong value
                    if obj.ProjectedArea.Value != 0:
                        print("Error computing areas for ",obj.Label)
                        obj.ProjectedArea = 0
                else:
                    pset.append(pf)
            if pset:
                self.flatarea = pset.pop()
                for f in pset:
                    self.flatarea = self.flatarea.fuse(f)
                self.flatarea = self.flatarea.removeSplitter()
                if obj.ProjectedArea.Value != self.flatarea.Area:
                    obj.ProjectedArea = self.flatarea.Area
        # compute perimeter
        lut = {}
        for e in obj.Shape.Edges:
            lut.setdefault(e.hashCode(),[]).append(e)
        l = 0
        for e in lut.values():
            if len(e) == 1: # keep only border edges
                l += e[0].Length
        if l:
                if obj.Perimeter.Value != l:
                    obj.Perimeter = l
        # compute volumes
        if obj.Terrain.Shape.Solids:
            shapesolid = obj.Terrain.Shape.copy()
        else:
            shapesolid = obj.Terrain.Shape.extrude(obj.ExtrusionVector)
        addvol = 0
        subvol = 0
        for sub in obj.Subtractions:
            subvol += sub.Shape.common(shapesolid).Volume
        for sub in obj.Additions:
            addvol += sub.Shape.cut(shapesolid).Volume
        if obj.SubtractionVolume.Value != subvol:
            obj.SubtractionVolume = subvol
        if obj.AdditionVolume.Value != addvol:
            obj.AdditionVolume = addvol
Example #6
0
    def execute(self, obj):
        output = ""

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

        if obj.Base:
            for b in obj.Base:
                for sub in b[1]:
                    import Part
                    import PathScripts.PathKurveUtils
                    if "Face" in sub:
                        shape = getattr(b[0].Shape, sub)
                        wire = shape.OuterWire
                        edges = wire.Edges
                    else:
                        edges = [getattr(b[0].Shape, sub) for sub in b[1]]
                        wire = Part.Wire(edges)
                        shape = None

                    # output = ""
                    if obj.Algorithm == "OCC Native":
                        if shape is None:
                            shape = wire
                        output += self.buildpathocc(obj, shape)
                    else:
                        try:
                            import area
                        except:
                            FreeCAD.Console.PrintError(
                                translate(
                                    "PathKurve",
                                    "libarea needs to be installed for this command to work.\n"
                                ))
                            return

                        a = area.Area()
                        if shape is None:
                            c = PathScripts.PathKurveUtils.makeAreaCurve(
                                wire.Edges, 'CW')
                            a.append(c)
                        else:
                            for w in shape.Wires:
                                c = PathScripts.PathKurveUtils.makeAreaCurve(
                                    w.Edges, 'CW')
                                a.append(c)

                        a.Reorder()
                        output += self.buildpathlibarea(obj, a)

            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True
            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
Example #7
0
def zbeam(params, document):
    # key = params['type']
    h = params["h"]
    c1 = params["c1"]
    tw = params["tw"]
    tf = params["tf"]
    le = params["l"]
    name = params["name"]

    rf = tf / 2.0
    rw = tw

    # points, starting at the left upper corner, going counter-clockwise
    V1 = Vector(-0.5 * tw, 0, 0)
    V2 = Vector(-0.5 * tw + c1, 0, 0)
    V3 = Vector(-0.5 * tw + c1, tf - rf, 0)
    V4 = Vector(-0.5 * tw + c1 - rf, tf, 0)
    V5 = Vector(0.5 * tw + rw, tf, 0)
    V6 = Vector(0.5 * tw, tf + rw, 0)
    V7 = Vector(0.5 * tw, h, 0)
    V8 = Vector(0.5 * tw - c1, h, 0)
    V9 = Vector(0.5 * tw - c1, h - tf + rf, 0)
    V10 = Vector(0.5 * tw - c1 + rf, h - tf, 0)
    V11 = Vector(-0.5 * tw - rw, h - tf, 0)
    V12 = Vector(-0.5 * tw, h - tf - rw, 0)

    # circle center of the fillets, starting right bottom, going counter-clockwise
    Vc1 = Vector(-0.5 * tw + c1 - rf, tf - rf, 0)
    Vc2 = Vector(0.5 * tw + rw, tf + rw, 0)
    Vc3 = Vector(0.5 * tw - c1 + rf, h - tf + rf, 0)
    Vc4 = Vector(-0.5 * tw - rw, h - tf - rw, 0)
    normal = Vector(0, 0, 1)

    # edges
    E1 = makeLine(V1, V2)
    E2 = makeLine(V2, V3)
    E3 = makeCircle(rf, Vc1, normal, 0, 90)
    E4 = makeLine(V4, V5)
    E5 = makeCircle(rw, Vc2, normal, 180, 270)
    E6 = makeLine(V6, V7)
    E7 = makeLine(V7, V8)
    E8 = makeLine(V8, V9)
    E9 = makeCircle(rf, Vc3, normal, 180, 270)
    E10 = makeLine(V10, V11)
    E11 = makeCircle(rw, Vc4, normal, 0, 90)
    E12 = makeLine(V12, V1)

    # putting the segments together make a wire, a face and extrude it
    W = Part.Wire([E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12])
    F = Part.Face(W)

    if params["arch"]:
        from ArchStructure import makeStructure

        part = makeStructure(name=name)

        prof = document.addObject("Part::Feature", "Profile")
        prof.Shape = F
        part.Base = prof

        part.Height = le
    else:
        part = document.addObject("Part::Feature", "BOLTS_part")
        part.Label = name

        beam = F.extrude(Vector(0, 0, le))
        part.Shape = beam
Example #8
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::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(DraftGeomUtils.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(DraftGeomUtils.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 #9
0
def figure_to_freecad_25d_part(ai_figure, ai_extrude_height):
    """ the first outline of the figure ai_figure is the outer line of the part
      the other outlines are holes in the part
      If one outline is not closed, only wire (not face) are extruded
      the height of the extrusion is ai_extrude_height
      It returns a FreeCAD Part object
      If you want to make more complex fuse and cut combinations, you need to work at the outline level (not figure level)
  """
    # extra length to remove skin during 3D cut operation
    remove_skin_extra = 10.0
    # check the number of outlines
    outline_nb = len(ai_figure)
    if (outline_nb < 1):
        print("ERR876: Error, the figure doesn't contain any outlines!")
        sys.exit(2)
    # check if one outline is not closed
    face_nwire = True
    for oli in range(len(ai_figure)):
        ol = ai_figure[oli]
        if (isinstance(
                ol[0],
            (list, tuple))):  # it's a general outline (not a circle)
            #print("dbg663: outline with {:d} segments".format(len(ol)-1))
            if ((ol[0][0] != ol[-1][-2]) or (ol[0][1] != ol[-1][-1])):
                face_nwire = False
                print(
                    "WARN504: Warning, the outline {:d} is not closed! Only wire can be extruded."
                    .format(oli + 1))
    # create the FreeCAD part
    if (face_nwire):  # generate a real solid part
        outer_face = Part.Face(
            Part.Wire(outline_arc_line(ai_figure[0], 'freecad').Edges))
        outer_solid = outer_face.extrude(Base.Vector(
            0, 0, ai_extrude_height))  # straight linear extrusion
        if (outline_nb > 1):  # holes need to be cut from outer_solid
            inner_solid = []
            for i in range(outline_nb - 1):
                inner_face = Part.Face(
                    Part.Wire(
                        outline_arc_line(ai_figure[i + 1], 'freecad').Edges))
                inner_solid.append(
                    inner_face.extrude(
                        Base.Vector(
                            0, 0, ai_extrude_height + 2 *
                            remove_skin_extra)))  # straight linear extrusion
            #inner_hole = Part.makeCompound(inner_solid) # not satisfying result with overlap holes
            inner_hole = inner_solid[0]
            for i in range(outline_nb - 2):
                inner_hole = inner_hole.fuse(inner_solid[i + 1])
            inner_hole.translate(Base.Vector(0, 0, -remove_skin_extra))
            r_part = outer_solid.cut(inner_hole)
        else:
            r_part = outer_solid
    else:  # generate a simple extrusion of wires
        wire_part = []
        for i in range(outline_nb):
            wire = Part.Wire(outline_arc_line(ai_figure[i], 'freecad').Edges)
            wire_part.append(wire.extrude(Base.Vector(0, 0,
                                                      ai_extrude_height)))
        r_part = Part.makeCompound(wire_part)
    # return
    return (r_part)
Example #10
0
    def trimObject(self):
        """Trim the actual object."""
        import Part

        if self.extrudeMode:
            delta = self.extrude(self.shift, real=True)
            # print("delta", delta)
            self.doc.openTransaction("Extrude")
            Gui.addModule("Draft")
            obj = Draft.extrude(self.obj, delta, solid=True)
            self.doc.commitTransaction()
            self.obj = obj
        else:
            edges = self.redraw(self.point,
                                self.snapped,
                                self.shift,
                                self.alt,
                                real=True)
            newshape = Part.Wire(edges)
            self.doc.openTransaction("Trim/extend")
            if utils.getType(self.obj) in ["Wire", "BSpline"]:
                p = []
                if self.placement:
                    invpl = self.placement.inverse()
                for v in newshape.Vertexes:
                    np = v.Point
                    if self.placement:
                        np = invpl.multVec(np)
                    p.append(np)
                self.obj.Points = p
            elif utils.getType(self.obj) == "Part::Line":
                p = []
                if self.placement:
                    invpl = self.placement.inverse()
                for v in newshape.Vertexes:
                    np = v.Point
                    if self.placement:
                        np = invpl.multVec(np)
                    p.append(np)
                if ((p[0].x == self.obj.X1) and (p[0].y == self.obj.Y1)
                        and (p[0].z == self.obj.Z1)):
                    self.obj.X2 = p[-1].x
                    self.obj.Y2 = p[-1].y
                    self.obj.Z2 = p[-1].z
                elif ((p[-1].x == self.obj.X1) and (p[-1].y == self.obj.Y1)
                      and (p[-1].z == self.obj.Z1)):
                    self.obj.X2 = p[0].x
                    self.obj.Y2 = p[0].y
                    self.obj.Z2 = p[0].z
                elif ((p[0].x == self.obj.X2) and (p[0].y == self.obj.Y2)
                      and (p[0].z == self.obj.Z2)):
                    self.obj.X1 = p[-1].x
                    self.obj.Y1 = p[-1].y
                    self.obj.Z1 = p[-1].z
                else:
                    self.obj.X1 = p[0].x
                    self.obj.Y1 = p[0].y
                    self.obj.Z1 = p[0].z
            elif utils.getType(self.obj) == "Circle":
                angles = self.ghost[0].getAngles()
                # print("original", self.obj.FirstAngle," ",self.obj.LastAngle)
                # print("new", angles)
                if angles[0] > angles[1]:
                    angles = (angles[1], angles[0])
                self.obj.FirstAngle = angles[0]
                self.obj.LastAngle = angles[1]
            else:
                self.obj.Shape = newshape
            self.doc.commitTransaction()
        self.doc.recompute()
        for g in self.ghost:
            g.off()
Example #11
0
    def trimObjects(self, objectslist):
        """Attempt to trim two objects together."""
        import Part
        import DraftGeomUtils

        wires = []
        for obj in objectslist:
            if not utils.getType(obj) in ["Wire", "Circle"]:
                _err(
                    translate(
                        "draft", "Unable to trim these objects, "
                        "only Draft wires and arcs are supported."))
                return
            if len(obj.Shape.Wires) > 1:
                _err(
                    translate(
                        "draft", "Unable to trim these objects, "
                        "too many wires"))
                return
            if len(obj.Shape.Wires) == 1:
                wires.append(obj.Shape.Wires[0])
            else:
                wires.append(Part.Wire(obj.Shape.Edges))
        ints = []
        edge1 = None
        edge2 = None
        for i1, e1 in enumerate(wires[0].Edges):
            for i2, e2 in enumerate(wires[1].Edges):
                i = DraftGeomUtils.findIntersection(e1, e2, dts=False)
                if len(i) == 1:
                    ints.append(i[0])
                    edge1 = i1
                    edge2 = i2
        if not ints:
            _err(translate("draft", "These objects don't intersect."))
            return
        if len(ints) != 1:
            _err(translate("draft", "Too many intersection points."))
            return

        v11 = wires[0].Vertexes[0].Point
        v12 = wires[0].Vertexes[-1].Point
        v21 = wires[1].Vertexes[0].Point
        v22 = wires[1].Vertexes[-1].Point
        if DraftVecUtils.closest(ints[0], [v11, v12]) == 1:
            last1 = True
        else:
            last1 = False
        if DraftVecUtils.closest(ints[0], [v21, v22]) == 1:
            last2 = True
        else:
            last2 = False
        for i, obj in enumerate(objectslist):
            if i == 0:
                ed = edge1
                la = last1
            else:
                ed = edge2
                la = last2
            if utils.getType(obj) == "Wire":
                if la:
                    pts = obj.Points[:ed + 1] + ints
                else:
                    pts = ints + obj.Points[ed + 1:]
                obj.Points = pts
            else:
                vec = ints[0].sub(obj.Placement.Base)
                vec = obj.Placement.inverse().Rotation.multVec(vec)
                _x = App.Vector(1, 0, 0)
                _ang = -DraftVecUtils.angle(vec,
                                            obj.Placement.Rotation.multVec(_x),
                                            obj.Shape.Edges[0].Curve.Axis)
                ang = math.degrees(_ang)
                if la:
                    obj.LastAngle = ang
                else:
                    obj.FirstAngle = ang
        self.doc.recompute()
Example #12
0
 def execute(self, fp):
     if fp.Base:
         import Part
         #fp.Shape=fp.Base.Shape.Wires[0]
         fp.Shape = Part.Wire(
             fp.Base.Shape.Wires[0])  # works with 0.13 stable
Example #13
0
    def Activated(self):

        # check that the selection contains exactly what we want
        selection = FreeCADGui.Selection.getSelectionEx()
        if len(selection) != 1:
            FreeCAD.Console.PrintError(
                translate(
                    "Path_Pocket",
                    "Please select an edges loop from one object, or a single face\n"
                ))
            return
        if len(selection[0].SubObjects) == 0:
            FreeCAD.Console.PrintError(
                translate(
                    "Path_Pocket",
                    "Please select an edges loop from one object, or a single face\n"
                ))
            return
        for s in selection[0].SubObjects:
            if s.ShapeType != "Edge":
                if (s.ShapeType != "Face") or (len(selection[0].SubObjects) !=
                                               1):
                    FreeCAD.Console.PrintError(
                        translate(
                            "Path_Pocket",
                            "Please select only edges or a single face\n"))
                    return
        if selection[0].SubObjects[0].ShapeType == "Edge":
            try:
                import Part
                w = Part.Wire(selection[0].SubObjects)
            except:
                FreeCAD.Console.PrintError(
                    translate("Path_Pocket",
                              "The selected edges don't form a loop\n"))
                return

        # if everything is ok, execute and register the transaction in the undo/redo stack
        FreeCAD.ActiveDocument.openTransaction(
            translate("Path_Pocket", "Create Pocket"))
        FreeCADGui.addModule("PathScripts.PathPocket")
        FreeCADGui.doCommand('prjexists = False')
        FreeCADGui.doCommand(
            'obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Pocket")'
        )
        FreeCADGui.doCommand('PathScripts.PathPocket.ObjectPocket(obj)')
        FreeCADGui.doCommand(
            'PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)')
        subs = "["
        for s in selection[0].SubElementNames:
            subs += '"' + s + '",'
        subs += "]"
        FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' +
                             selection[0].ObjectName + ',' + subs + ')')
        FreeCADGui.doCommand('obj.Active = True')
        snippet = '''
from PathScripts import PathUtils
PathUtils.addToProject(obj)

ZMax = obj.Base[0].Shape.BoundBox.ZMax
ZMin = obj.Base[0].Shape.BoundBox.ZMin
obj.StepDown = 1.0
obj.StartDepth = ZMax
obj.FinalDepth = ZMin
obj.ClearanceHeight =  ZMax + 5.0
    
'''
        FreeCADGui.doCommand(snippet)
        FreeCAD.ActiveDocument.commitTransaction()
        FreeCAD.ActiveDocument.recompute()
Example #14
0
    def execute(self, obj):
        if obj.Base:
            tool = PathUtils.getLastTool(obj)

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

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

            # absolute coords, millimeters, cancel offsets
            output = "G90\nG21\nG40\n"
            # save tool
            if obj.ToolNumber > 0 and tool.ToolNumber != obj.ToolNumber:
                output += "M06 T" + str(tool.ToolNumber) + "\n"

            # build offsets
            offsets = []
            nextradius = radius
            result = DraftGeomUtils.pocket2d(shape, nextradius)
            while result:
                #print "Adding " + str(len(result)) + " wires"
                offsets.extend(result)
                nextradius += radius
                result = DraftGeomUtils.pocket2d(shape, nextradius)

            # first move will be rapid, subsequent will be at feed rate
            first = True
            startPoint = None
            fastZPos = max(obj.StartDepth + 2, obj.RetractHeight)

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

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

            def prnt(vlu):
                return str("%.4f" % round(vlu, 4))

            #Fraction of tool radius our plunge helix is to be
            #FIXME: This should be configurable
            plungeR = 0.75

            #(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging
            #FIXME: This should be configurable
            #FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best
            rampD = 0.75

            #Total offset from the desired pocket edge is tool radius plus the plunge helix radius
            #Any point on these curves could be the center of a plunge
            helixBounds = DraftGeomUtils.pocket2d(
                shape, tool.Diameter / 2. * (1 + plungeR))

            #Try to find a location to nicely plunge, starting with a helix, then ramp
            #Can't do it without knowledge of a tool
            plungePos = None
            rampEdge = None
            if not tool:
                raise Error("Ramp plunge location-finding requires a tool")
                return
            else:
                #Since we're going to start machining either the inner-most
                #edge or the outer (depending on StartAt setting), try to
                #plunge near that location

                if helixBounds:
                    #Edge is easy- pick a point on helixBounds and go with it
                    if obj.StartAt == 'Edge':
                        plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                    #Center is harder- use a point from the first offset, check if it works
                    else:
                        plungePos = offsets[0].Edges[0].Vertexes[0].Point

                        #If it turns out this is invalid for some reason, nuke plungePos
                        [perp, idx] = DraftGeomUtils.findPerpendicular(
                            plungePos, shape.Edges)
                        if not perp or perp.Length < tool.Diameter / 2. * (
                                1 + plungeR):
                            plungePos = None
                        #FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
                        #Or some math to prove that it has to be (doubt that's true)
                        #Maybe reverse helixBounds and pick off that?

                #If we didn't find a place to helix, how about a ramp?
                if not plungePos:
                    #Check first edge of our offsets
                    if (offsets[0].Edges[0].Length >=
                            tool.Diameter * rampD) and not (isinstance(
                                offsets[0].Edges[0].Curve, Part.Circle)):
                        rampEdge = offsets[0].Edges[0]
                    #The last edge also connects with the starting location- try that
                    elif (offsets[0].Edges[-1].Length >=
                          tool.Diameter * rampD) and not (isinstance(
                              offsets[0].Edges[-1].Curve, Part.Circle)):
                        rampEdge = offsets[0].Edges[-1]
                    else:
                        print "Neither edge works: " + str(
                            offsets[0].Edges[0]) + ", " + str(
                                offsets[0].Edges[-1])
                    #FIXME: There's got to be a smarter way to find a place to ramp

            #Returns gcode to perform a rapid move
            def rapid(x=None, y=None, z=None):
                retstr = "G00"
                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"

            #Returns gcode to perform a linear feed
            def feed(x=None, y=None, z=None):
                global feedxy
                retstr = "G01 F"
                if (x == None) and (y == None):
                    retstr += str("%.4f" % obj.HorizFeed)
                else:
                    retstr += str("%.4f" % obj.VertFeed)

                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"

            #Returns gcode to perform an arc
            #Assumes XY plane or helix around Z
            #Don't worry about starting Z- assume that's dealt with elsewhere
            def arc(cx, cy, sx, sy, ex, ey, ez=None, ccw=False):
                #If start/end radii aren't within eps, abort
                eps = 0.01
                if (math.sqrt((cx - sx)**2 +
                              (cy - sy)**2) - math.sqrt((cx - ex)**2 +
                                                        (cy - ey)**2)) >= eps:
                    print "ERROR: Illegal arc: Stand and end radii not equal"
                    return ""

                #Set [C]CW and feed
                retstr = ""
                if ccw:
                    retstr += "G03 F"
                else:
                    retstr += "G02 F"
                retstr += str(obj.HorizFeed)

                #End location
                retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)

                #Helix if requested
                if ez != None:
                    retstr += " Z" + str("%.4f" % ez)

                #Append center offsets
                retstr += " I" + str("%.4f" %
                                     (cx - sx)) + " J" + str("%.4f" %
                                                             (cy - sy))

                return retstr + "\n"

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

                helixX = plungePos.x + tool.Diameter / 2. * plungeR
                helixY = plungePos.y

                helixCirc = math.pi * tool.Diameter * plungeR
                dzPerRev = math.sin(rampangle / 180. * math.pi) * helixCirc

                #Go to the start of the helix position
                helixCmds += rapid(helixX, helixY)
                helixCmds += rapid(z=startZ)

                #Helix as required to get to the requested depth
                lastZ = startZ
                curZ = max(startZ - dzPerRev, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)
                    #NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid
                    #helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True)

                    #Use two half-helixes; FreeCAD renders that correctly,
                    #and it fits with the other code breaking up 360-degree arcs
                    helixCmds += arc(plungePos.x,
                                     plungePos.y,
                                     helixX,
                                     helixY,
                                     helixX - tool.Diameter * plungeR,
                                     helixY,
                                     ez=(curZ + lastZ) / 2.,
                                     ccw=True)
                    helixCmds += arc(plungePos.x,
                                     plungePos.y,
                                     helixX - tool.Diameter * plungeR,
                                     helixY,
                                     helixX,
                                     helixY,
                                     ez=curZ,
                                     ccw=True)
                    lastZ = curZ
                    curZ = max(curZ - dzPerRev, destZ)

                return helixCmds

            #Returns commands to linearly ramp into a cut
            #FIXME: This ramps along the first edge, assuming it's long
            #enough, NOT just wiggling back and forth by ~0.75 * toolD.
            #Not sure if that's any worse, but it's simpler
            #FIXME: This code is untested
            def rampPlunge(edge, rampangle, destZ, startZ):
                rampCmds = "(START RAMP PLUNGE)\n"
                if (edge == None):
                    raise Error("Ramp plunging requires an edge!")
                    return None
                if (not tool):
                    raise Error("Ramp plunging requires a tool!")

                sPoint = edge.Vertexes[0].Point
                ePoint = edge.Vertexes[1].Point
                #Evidently edges can get flipped- pick the right one in this case
                #FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below
                if ePoint == sPoint:
                    #print "FLIP"
                    ePoint = edge.Vertexes[-1].Point
                #print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ)

                rampDist = edge.Length
                rampDZ = math.sin(rampangle / 180. * math.pi) * rampDist

                rampCmds += rapid(sPoint.x, sPoint.y)
                rampCmds += rapid(z=startZ)

                #Ramp down to the requested depth
                #FIXME: This might be an arc, so handle that as well
                lastZ = startZ
                curZ = max(startZ - rampDZ, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)

                    #If it's an arc, handle it!
                    if isinstance(edge.Curve, Part.Circle):
                        raise Error(
                            "rampPlunge: Screw it, not handling an arc.")
                    #Straight feed! Easy!
                    else:
                        rampCmds += feed(ePoint.x, ePoint.y, curZ)
                        rampCmds += feed(sPoint.x, sPoint.y)

                    lastZ = curZ
                    curZ = max(curZ - rampDZ, destZ)

                return rampCmds

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

            for vpos in frange(obj.StartDepth, obj.FinalDepth, obj.StepDown,
                               obj.FinishDepth):
                #                print "vpos: " + str(vpos)
                #Every for every depth we should helix down
                first = True
                # loop over successive wires
                for currentWire in offsets:
                    #                    print "new line (offset)"
                    last = None
                    for edge in currentWire.Edges:
                        #                        print "new edge"
                        if not last:
                            # we set the base GO to our fast move to our starting pos
                            if first:
                                #If we can helix, do so
                                if plungePos:
                                    output += helicalPlunge(
                                        plungePos, 3, vpos, lastZ)
                                    #print output
                                    lastZ = vpos
                                #Otherwise, see if we can ramp
                                #FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
                                elif rampEdge:
                                    output += rampPlunge(
                                        rampEdge, 3, vpos, lastZ)
                                    lastZ = vpos
                                #Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
                                #FIXME: At least not with the lazy ramp programming above...
                                else:
                                    print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
                                    startPoint = edge.Vertexes[0].Point
                                    output += "G0 X" + prnt(startPoint.x) + " Y" + prnt(startPoint.y) +\
                                              " Z" + prnt(fastZPos) + "\n"
                                first = False
                            #then move slow down to our starting point for our profile
                            last = edge.Vertexes[0].Point
                            output += "G1 X" + prnt(last.x) + " Y" + prnt(
                                last.y) + " Z" + prnt(vpos) + "\n"
                        #if isinstance(edge.Curve,Part.Circle):
                        if DraftGeomUtils.geomType(edge) == "Circle":
                            point = edge.Vertexes[-1].Point
                            if point == last:  # edges can come flipped
                                point = edge.Vertexes[0].Point


#                                print "flipped"
                            center = edge.Curve.Center
                            relcenter = center.sub(last)
                            v1 = last.sub(center)
                            v2 = point.sub(center)
                            if v1.cross(v2).z < 0:
                                output += "G2"
                            else:
                                output += "G3"
                            output += " X" + prnt(point.x) + " Y" + prnt(
                                point.y) + " Z" + prnt(vpos)
                            output += " I" + prnt(relcenter.x) + " J" + prnt(
                                relcenter.y) + " K" + prnt(relcenter.z)
                            output += "\n"
                            last = point
                        else:
                            point = edge.Vertexes[-1].Point
                            if point == last:  # edges can come flipped
                                point = edge.Vertexes[0].Point
                            output += "G1 X" + prnt(point.x) + " Y" + prnt(
                                point.y) + " Z" + prnt(vpos) + "\n"
                            last = point

            #move back up
            output += "G0 Z" + prnt(fastZPos) + "\n"
            #            print output
            #            path = Path.Path(output)
            #            obj.Path = path
            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True
            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
def setup(doc=None, solvertype="ccxtools"):

    # init FreeCAD document
    if doc is None:
        doc = init_doc()

    # explanation object
    # just keep the following line and change text string in get_explanation method
    manager.add_explanation_obj(
        doc, get_explanation(manager.get_header(get_information())))

    # geometric object
    v1 = vec(-200, -100, 0)
    v2 = vec(200, -100, 0)
    v3 = vec(200, 100, 0)
    v4 = vec(-200, 100, 0)
    l1 = ln(v1, v2)
    l2 = ln(v2, v3)
    l3 = ln(v3, v4)
    l4 = ln(v4, v1)
    v5 = vec(0, 0, 0)
    c1 = ci(50, v5)
    face = Part.makeFace([Part.Wire([l1, l2, l3, l4]), c1],
                         "Part::FaceMakerBullseye")
    geom_obj = doc.addObject("Part::Feature", "Hole_Plate")
    geom_obj.Shape = face.extrude(vec(0, 0, 10))
    doc.recompute()

    if FreeCAD.GuiUp:
        geom_obj.ViewObject.Document.activeView().viewAxonometric()
        geom_obj.ViewObject.Document.activeView().fitAll()

    # analysis
    analysis = ObjectsFem.makeAnalysis(doc, "Analysis")

    # solver
    if solvertype == "calculix":
        solver_obj = ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX")
    elif solvertype == "ccxtools":
        solver_obj = ObjectsFem.makeSolverCalculixCcxTools(
            doc, "CalculiXccxTools")
        solver_obj.WorkingDir = u""
    else:
        FreeCAD.Console.PrintWarning(
            "Not known or not supported solver type: {}. "
            "No solver object was created.\n".format(solvertype))
    if solvertype == "calculix" or solvertype == "ccxtools":
        solver_obj.SplitInputWriter = False
        solver_obj.AnalysisType = "static"
        solver_obj.GeometricalNonlinearity = "linear"
        solver_obj.ThermoMechSteadyState = False
        solver_obj.MatrixSolverType = "default"
        solver_obj.IterationsControlParameterTimeUse = False
        solver_obj.GeometricalNonlinearity = 'nonlinear'
        solver_obj.MaterialNonlinearity = 'nonlinear'
    analysis.addObject(solver_obj)

    # linear material
    material_obj = ObjectsFem.makeMaterialSolid(doc, "Material_lin")
    matprop = material_obj.Material
    matprop["Name"] = "CalculiX-Steel"
    matprop["YoungsModulus"] = "210000 MPa"
    matprop["PoissonRatio"] = "0.30"
    material_obj.Material = matprop
    analysis.addObject(material_obj)

    # nonlinear material
    name_nlm = "Material_nonlin"
    nonlinear_mat = ObjectsFem.makeMaterialMechanicalNonlinear(
        doc, material_obj, name_nlm)
    nonlinear_mat.YieldPoints = ['240.0, 0.0', '270.0, 0.025']
    analysis.addObject(nonlinear_mat)
    # check solver attributes, Nonlinearity needs to be set to nonlinear

    # constraint fixed
    con_fixed = ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed")
    con_fixed.References = [(geom_obj, "Face4")]
    analysis.addObject(con_fixed)

    # pressure constraint
    con_pressure = ObjectsFem.makeConstraintPressure(doc, "ConstraintPressure")
    con_pressure.References = [(geom_obj, "Face2")]
    con_pressure.Pressure = 130.0
    con_pressure.Reversed = True
    analysis.addObject(con_pressure)

    # mesh
    from .meshes.mesh_platewithhole_tetra10 import create_nodes, create_elements
    fem_mesh = Fem.FemMesh()
    control = create_nodes(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating nodes.\n")
    control = create_elements(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating elements.\n")
    femmesh_obj = analysis.addObject(
        ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
    femmesh_obj.FemMesh = fem_mesh
    femmesh_obj.Part = geom_obj
    femmesh_obj.SecondOrderLinear = False

    doc.recompute()
    return doc
Example #16
0
def outline_arc_line_test1():
    """ test the functions outline_arc_line and outline_circle.
  """
    l_ol1 = [[0, 0], [20, 0], [20, 20], [0, 20], [0, 0]]

    l_ol2 = [[110, 0], [120, 0], [130, 0, 130, 10], [130, 20],
             [130, 30, 120, 30], [110, 30], [100, 30, 100, 20], [100, 10],
             [100, 0, 110, 0]]

    l_ol3 = [[210, 0], [220, 0], [230, 0, 230, 10], [230, 20],
             [230, 30, 220, 30], [210, 30], [200, 30, 200, 20], [200, 10]]
    #[200,0, 210,0]]

    # check CC (clock wise)
    l_ol4 = [[300, 10], [300, 20], [300, 30, 310, 30], [320, 30],
             [330, 30, 330, 20], [330, 10], [330, 0, 320, 0], [310, 0]]

    l_ol5 = [[0, 100], [100, 150], [110, 155, 120, 150], [150, 110],
             [160, 100, 170, 105], [200, 200], [0, 200], [0, 100]]

    l_ols = [l_ol1, l_ol2, l_ol3, l_ol4, l_ol5]
    #l_ols = [l_ol2]
    # circle
    l_circle_center = [200, 200]
    l_circle_radius = 150
    # backend freecad
    print("dbg701: test1 backend freecad")
    for i_ol in l_ols:
        r_ol = outline_arc_line(i_ol, 'freecad')
        #Part.show(r_ol)
        l_test_face = Part.Face(Part.Wire(r_ol.Edges))
        r_test_solid = l_test_face.extrude(Base.Vector(
            0, 0, 1))  # straight linear extrusion
        Part.show(r_test_solid)
    r_ol = outline_circle(l_circle_center, l_circle_radius, 'freecad')
    l_test_face = Part.Face(Part.Wire(r_ol.Edges))
    r_test_solid = l_test_face.extrude(Base.Vector(
        0, 0, 1))  # straight linear extrusion
    Part.show(r_test_solid)
    # create the output directory
    l_output_dir = "test_output"
    print("Create the output directory: {:s}".format(l_output_dir))
    design_help.mkdir_p(l_output_dir)
    # backend svgwrite
    print("dbg702: test1 backend svgwrite")
    output_svg_file_name = "{:s}/outline_arc_line_test1_00.svg".format(
        l_output_dir)
    object_svg = svgwrite.Drawing(filename=output_svg_file_name)
    #output_file_idx = 0
    for i_ol in l_ols:
        #output_file_idx += 1
        #output_svg_file_name =  "outline_arc_line_test1_{:02d}.svg".format(output_file_idx)
        #object_svg = svgwrite.Drawing(filename = output_svg_file_name)
        svg_outline = outline_arc_line(i_ol, 'svgwrite')
        for one_line_or_arc in svg_outline:
            object_svg.add(one_line_or_arc)
        #object_svg.save()
    one_circle = outline_circle(l_circle_center, l_circle_radius, 'svgwrite')
    object_svg.add(one_circle[0])
    object_svg.save()
    # backend dxfwrite
    print("dbg703: test1 backend dxfwrite")
    output_dxf_file_name = "{:s}/outline_arc_line_test1_00.dxf".format(
        l_output_dir)
    object_dxf = DXFEngine.drawing(output_dxf_file_name)
    #object_dxf.add_layer(default_dxf_layer_name)
    for i_ol in l_ols:
        dxf_outline = outline_arc_line(i_ol, 'dxfwrite')
        for one_line_or_arc in dxf_outline:
            object_dxf.add(one_line_or_arc)
    one_circle = outline_circle(l_circle_center, l_circle_radius, 'dxfwrite')
    object_dxf.add(one_circle[0])
    object_dxf.save()
    # backend tkinter
    print("dbg704: test1 backend tkinter")
    tk_root = Tkinter.Tk()
    #my_canvas = display_backend.Two_Canvas(tk_root)
    my_canvas = Two_Canvas(tk_root)

    # callback function for display_backend
    def sub_canvas_graphics(ai_rotation_direction, ai_angle_position):
        # angle position
        l_angle_position = float(ai_angle_position) / 100
        #
        r_canvas_graphics = []
        for i_ol in l_ols:
            r_canvas_graphics.append(
                ('graphic_lines', outline_arc_line(i_ol, 'tkinter'), 'red', 2))
        r_canvas_graphics.append(
            ('graphic_lines',
             outline_circle(l_circle_center, l_circle_radius,
                            'tkinter'), 'blue', 2))
        return (r_canvas_graphics)

    # end of callback function
    my_canvas.add_canvas_graphic_function(sub_canvas_graphics)
    tk_root.mainloop()
    del (my_canvas, tk_root
         )  # because Tkinter will be used again later in this script
    #time.sleep(0.3)
    ### test the figure-level functions
    wfl_outer_rectangle_B = [[-60, -40], [60, -40], [60, 40], [-60, 40],
                             [-60, -40]]

    wfl_inner_square_B = [[-10, -10], [10, -10], [10, 10], [-10, 10],
                          [-10, -10]]

    wfl_inner_circle1 = [30, 0, 15]
    wfl_inner_circle2 = [40, 0, 10]

    wfl_figure = [
        wfl_outer_rectangle_B, wfl_inner_square_B, wfl_inner_circle1,
        wfl_inner_circle2
    ]

    # display the figure
    figure_simple_display(wfl_figure)

    wfl_extrude_height = 20.0
    # create a FreeCAD part
    wfl_part = figure_to_freecad_25d_part(wfl_figure, wfl_extrude_height)

    # output file with mozman
    print("Generate {:s}/obt1_with_mozman.svg".format(l_output_dir))
    write_figure_in_svg(wfl_figure,
                        "{:s}/obt1_with_mozman.svg".format(l_output_dir))
    print("Generate {:s}/obt1_with_mozman.dxf".format(l_output_dir))
    write_figure_in_dxf(wfl_figure,
                        "{:s}/obt1_with_mozman.dxf".format(l_output_dir))

    # wfl_part in 3D BRep
    print("Generate {:s}/obt1_part.brep".format(l_output_dir))
    wfl_part.exportBrep("{:s}/obt1_part.brep".format(l_output_dir))
    # wfl_part in 2D DXF
    print("Generate {:s}/obt1_part.dxf".format(l_output_dir))
    export_2d.export_to_dxf(
        wfl_part, Base.Vector(0, 0, 1), wfl_extrude_height / 2,
        "{:s}/obt1_part.dxf".format(l_output_dir)
    )  # slice wfl_part in the XY plan at a height of wfl_extrude_height/2
    #
    r_test = 1
    return (r_test)
Example #17
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
     # build wall layers
     layers = []
     if hasattr(obj, "Material"):
         if obj.Material:
             if hasattr(obj.Material, "Materials"):
                 varwidth = 0
                 restwidth = width - sum(obj.Material.Thicknesses)
                 if restwidth > 0:
                     varwidth = [
                         t for t in obj.Material.Thicknesses if t == 0
                     ]
                     if varwidth:
                         varwidth = restwidth / len(varwidth)
                 for t in obj.Material.Thicknesses:
                     if t:
                         layers.append(t)
                     elif varwidth:
                         layers.append(varwidth)
     if obj.Base:
         if obj.Base.isDerivedFrom("Part::Feature"):
             if obj.Base.Shape:
                 if obj.Base.Shape.Solids:
                     return None
                 elif obj.Face > 0:
                     if len(obj.Base.Shape.Faces) >= obj.Face:
                         face = obj.Base.Shape.Faces[obj.Face - 1]
                         # this wall is based on a specific face of its base object
                         normal = face.normalAt(0, 0)
                         if normal.getAngle(Vector(0, 0, 1)) > math.pi / 4:
                             normal.multiply(width)
                             base = face.extrude(normal)
                             if obj.Align == "Center":
                                 base.translate(
                                     normal.negative().multiply(0.5))
                             elif obj.Align == "Right":
                                 base.translate(normal.negative())
                         else:
                             normal.multiply(height)
                             base = face.extrude(normal)
                         base, placement = self.rebase(base)
                         return (base, normal, placement)
                 elif obj.Base.Shape.Faces:
                     if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
                         return None
                     else:
                         base, placement = self.rebase(obj.Base.Shape)
                 elif 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:
                     if (len(basewires) == 1) and layers:
                         basewires = [basewires[0] for l in layers]
                     layeroffset = 0
                     baseface = None
                     for i, wire in enumerate(basewires):
                         e = wire.Edges[0]
                         if isinstance(e.Curve, Part.Circle):
                             dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
                         else:
                             dvec = DraftGeomUtils.vec(
                                 wire.Edges[0]).cross(normal)
                         if not DraftVecUtils.isNull(dvec):
                             dvec.normalize()
                         sh = None
                         if obj.Align == "Left":
                             off = obj.Offset.Value
                             if layers:
                                 off = off + layeroffset
                                 dvec.multiply(layers[i])
                                 layeroffset += layers[i]
                             else:
                                 dvec.multiply(width)
                             if off:
                                 dvec2 = DraftVecUtils.scaleTo(dvec, off)
                                 wire = DraftGeomUtils.offsetWire(
                                     wire, dvec2)
                             w2 = DraftGeomUtils.offsetWire(wire, dvec)
                             w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                             sh = DraftGeomUtils.bind(w1, w2)
                         elif obj.Align == "Right":
                             dvec = dvec.negative()
                             off = obj.Offset.Value
                             if layers:
                                 off = off + layeroffset
                                 dvec.multiply(layers[i])
                                 layeroffset += layers[i]
                             else:
                                 dvec.multiply(width)
                             if off:
                                 dvec2 = DraftVecUtils.scaleTo(dvec, off)
                                 wire = DraftGeomUtils.offsetWire(
                                     wire, dvec2)
                             w2 = DraftGeomUtils.offsetWire(wire, dvec)
                             w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
                             sh = DraftGeomUtils.bind(w1, w2)
                         elif obj.Align == "Center":
                             if layers:
                                 off = width / 2 - layeroffset
                                 d1 = Vector(dvec).multiply(off)
                                 w1 = DraftGeomUtils.offsetWire(wire, d1)
                                 layeroffset += layers[i]
                                 off = width / 2 - layeroffset
                                 d1 = Vector(dvec).multiply(off)
                                 w2 = DraftGeomUtils.offsetWire(wire, d1)
                             else:
                                 dvec.multiply(width / 2)
                                 w1 = DraftGeomUtils.offsetWire(wire, dvec)
                                 dvec = dvec.negative()
                                 w2 = DraftGeomUtils.offsetWire(wire, dvec)
                             sh = DraftGeomUtils.bind(w1, w2)
                         if sh:
                             sh.fix(0.1, 0,
                                    1)  # fixes self-intersecting wires
                             f = Part.Face(sh)
                             if baseface:
                                 if layers:
                                     baseface.append(f)
                                 else:
                                     baseface = baseface.fuse(f)
                             else:
                                 if layers:
                                     baseface = [f]
                                 else:
                                     baseface = f
                     if baseface:
                         base, placement = self.rebase(baseface)
     else:
         if layers:
             totalwidth = sum(layers)
             offset = 0
             base = []
             for l in layers:
                 l2 = length / 2 or 0.5
                 w1 = -totalwidth / 2 + offset
                 w2 = w1 + l
                 v1 = Vector(-l2, w1, 0)
                 v2 = Vector(l2, w1, 0)
                 v3 = Vector(l2, w2, 0)
                 v4 = Vector(-l2, w2, 0)
                 base.append(
                     Part.Face(Part.makePolygon([v1, v2, v3, v4, v1])))
                 offset += l
         else:
             l2 = length / 2 or 0.5
             w2 = width / 2 or 0.5
             v1 = Vector(-l2, -w2, 0)
             v2 = Vector(l2, -w2, 0)
             v3 = Vector(l2, w2, 0)
             v4 = Vector(-l2, w2, 0)
             base = Part.Face(Part.makePolygon([v1, v2, v3, v4, v1]))
         placement = FreeCAD.Placement()
     if base and placement:
         extrusion = normal.multiply(height)
         return (base, extrusion, placement)
     return None
Example #18
0
rot = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),alfa)   

centre = FreeCAD.Vector(0,0,0)                  

pos = obj.Placement.Base                        

newplace = FreeCAD.Placement(pos,rot,centre)    

obj.Placement = newplace          

App.getDocument('TOBERA').recompute()

#####################  CARAS ENTRADA y SALIDA ############

Part.Face(Part.Wire(Part.__sortEdges__([App.ActiveDocument.TUBO.Shape.Edge13, ])))

App.ActiveDocument.addObject('Part::Feature','ENTRADA').Shape=_

Part.Face(Part.Wire(Part.__sortEdges__([App.ActiveDocument.TOBERA.Shape.Edge3, ])))

App.ActiveDocument.addObject('Part::Feature','SALIDA').Shape=_

######################    MALLADO  #####################  


__doc__=FreeCAD.getDocument("TOBERA")

__mesh__=__doc__.addObject("Mesh::Feature","tubo_mesh")

__mesh__.Mesh=MeshPart.meshFromShape(Shape=__doc__.getObject("TUBO").Shape,MaxLength=m_tubo)
Example #19
0
    def execute(self, obj):
        import Part
        plm = obj.Placement
        if obj.Base and (not obj.Tool):
            if obj.Base.isDerivedFrom("Sketcher::SketchObject"):
                shape = obj.Base.Shape.copy()
                if obj.Base.Shape.isClosed():
                    if getattr(obj,"MakeFace",True):
                        shape = Part.Face(shape)
                obj.Shape = shape
        elif obj.Base and obj.Tool:
            if hasattr(obj.Base,'Shape') and hasattr(obj.Tool,'Shape'):
                if (not obj.Base.Shape.isNull()) and (not obj.Tool.Shape.isNull()):
                    sh1 = obj.Base.Shape.copy()
                    sh2 = obj.Tool.Shape.copy()
                    shape = sh1.fuse(sh2)
                    if DraftGeomUtils.isCoplanar(shape.Faces):
                        shape = DraftGeomUtils.concatenate(shape)
                        obj.Shape = shape
                        p = []
                        for v in shape.Vertexes: p.append(v.Point)
                        if obj.Points != p: obj.Points = p
        elif obj.Points:
            if obj.Points[0] == obj.Points[-1]:
                if not obj.Closed: obj.Closed = True
                obj.Points.pop()
            if obj.Closed and (len(obj.Points) > 2):
                pts = obj.Points
                if getattr(obj,"Subdivisions",0) > 0:
                    npts = []
                    for i in range(len(pts)):
                        p1 = pts[i]
                        npts.append(pts[i])
                        if i == len(pts)-1:
                            p2 = pts[0]
                        else:
                            p2 = pts[i+1]
                        v = p2.sub(p1)
                        v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
                        for j in range(obj.Subdivisions):
                            npts.append(p1.add(App.Vector(v).multiply(j+1)))
                    pts = npts
                shape = Part.makePolygon(pts+[pts[0]])
                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
                try:
                    if getattr(obj,"MakeFace",True):
                        shape = Part.Face(shape)
                except Part.OCCError:
                    pass
            else:
                edges = []
                pts = obj.Points[1:]
                lp = obj.Points[0]
                for p in pts:
                    if not DraftVecUtils.equals(lp,p):
                        if getattr(obj,"Subdivisions",0) > 0:
                            npts = []
                            v = p.sub(lp)
                            v = DraftVecUtils.scaleTo(v,v.Length/(obj.Subdivisions+1))
                            edges.append(Part.LineSegment(lp,lp.add(v)).toShape())
                            lv = lp.add(v)
                            for j in range(obj.Subdivisions):
                                edges.append(Part.LineSegment(lv,lv.add(v)).toShape())
                                lv = lv.add(v)
                        else:
                            edges.append(Part.LineSegment(lp,p).toShape())
                        lp = p
                try:
                    shape = Part.Wire(edges)
                except Part.OCCError:
                    print("Error wiring edges")
                    shape = None
                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 shape:
                obj.Shape = shape
                if hasattr(obj,"Area") and hasattr(shape,"Area"):
                    obj.Area = shape.Area
                if hasattr(obj,"Length"):
                    obj.Length = shape.Length

        obj.Placement = plm
        obj.positionBySupport()
        self.onChanged(obj,"Placement")
Example #20
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
     normal = None
     if not height:
         for p in obj.InList:
             if Draft.getType(p) == "Floor":
                 if p.Height.Value:
                     height = p.Height.Value
     base = None
     placement = None
     if obj.Base:
         if obj.Base.isDerivedFrom("Part::Feature"):
             if obj.Base.Shape:
                 if obj.Base.Shape.Solids:
                     return None
                 elif obj.Base.Shape.Faces:
                     if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
                         return None
                     else:
                         base,placement = self.rebase(obj.Base.Shape)
                         normal = obj.Base.Shape.Faces[0].normalAt(0,0)
                         normal = placement.inverse().Rotation.multVec(normal)
                 elif obj.Base.Shape.Wires:
                     baseface = None
                     if hasattr(obj,"FaceMaker"):
                         if obj.FaceMaker != "None":
                             try:
                                 baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker))
                             except:
                                 FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n")
                                 return None
                             if len(baseface.Faces) > 1:
                                 baseface = baseface.Faces[0]
                             normal = baseface.normalAt(0,0)
                             normal = placement.inverse().Rotation.multVec(normal)
                     if not baseface:
                         for w in obj.Base.Shape.Wires:
                             w.fix(0.1,0,1) # fixes self-intersecting wires
                             f = Part.Face(w)
                             if baseface:
                                 baseface = baseface.fuse(f)
                             else:
                                 baseface = f
                                 normal = f.normalAt(0,0)
                     base,placement = self.rebase(baseface)
                 elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1):
                     # closed edge
                     w = Part.Wire(obj.Base.Shape.Edges[0])
                     baseface = Part.Face(w)
                     base,placement = self.rebase(baseface)
     elif length and width and height:
         if (length > height) and (obj.Role != "Slab"):
             h2 = height/2 or 0.5
             w2 = width/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 = 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)
         import Part
         baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
         base,placement = self.rebase(baseface)
     if base and placement:
         if obj.Normal == Vector(0,0,0):
             if not normal:
                 normal = Vector(0,0,1)
         else:
             normal = Vector(obj.Normal)
         if (length > height) and (obj.Role != "Slab"):
             extrusion = normal.multiply(length)
         else:
             extrusion = normal.multiply(height)
         return (base,extrusion,placement)
     return None
Example #21
0
 def to_wire(self):
     return Part.Wire(self.edges)
Example #22
0
def process(doc, filename):
    # The common airfoil dat format has many flavors
    # This code should work with almost every dialect

    # Regex to identify data rows and throw away unused metadata
    regex = re.compile(
        r'^\s*(?P<xval>(\-|\d*)\.\d+(E\-?\d+)?)\,?\s*(?P<yval>\-?\s*\d*\.\d+(E\-?\d+)?)\s*$'
    )
    afile = pythonopen(filename, 'r')
    # read the airfoil name which is always at the first line
    airfoilname = afile.readline().strip()

    coords = []
    upside = True
    last_x = None

    # Collect the data for the upper and the lower side separately if possible
    for lin in afile:
        curdat = regex.match(lin)
        if curdat != None:

            x = float(curdat.group("xval"))
            y = float(curdat.group("yval"))

            # the normal processing
            coords.append(Vector(x, y, 0))

        # End of if curdat != None
    # End of for lin in file
    afile.close()

    if len(coords) < 3:
        print('Did not find enough coordinates\n')
        return

    # sometimes coords are divided in upper an lower side
    # so that x-coordinate begin new from leading or trailing edge
    # check for start coordinates in the middle of list

    if coords[0:-1].count(coords[0]) > 1:
        flippoint = coords.index(coords[0], 1)
        upper = coords[0:flippoint]
        lower = coords[flippoint + 1:]
        lower.reverse()
        for i in lower:
            upper.append(i)
        coords = upper

    # do we use the parametric Draft Wire?
    if useDraftWire:
        obj = makeWire(coords, True)
        #obj.label = airfoilname
    else:
        # alternate solution, uses common Part Faces
        lines = []
        first_v = None
        last_v = None
        for v in coords:
            if first_v == None:
                first_v = v
            # End of if first_v == None

            # Line between v and last_v if they're not equal
            if (last_v != None) and (last_v != v):
                lines.append(Part.makeLine(last_v, v))
            # End of if (last_v != None) and (last_v != v)
            # The new last_v
            last_v = v
        # End of for v in upper
        # close the wire if needed
        if last_v != first_v:
            lines.append(Part.makeLine(last_v, first_v))
        # End of if last_v != first_v

        wire = Part.Wire(lines)
        face = Part.Face(wire)
        obj = FreeCAD.ActiveDocument.addObject('Part::Feature', airfoilname)
        obj.Shape = face

    doc.recompute()
Example #23
0
def getObjectData(obj, wireframeMode=wireframeStyle):
    """returns the geometry data of an object as three.js snippet. wireframeMode
    can be multimaterial, faceloop or None"""

    result = ""
    wires = []

    if obj.isDerivedFrom("Part::Feature"):
        fcmesh = obj.Shape.tessellate(0.1)
        result = "var geom = new THREE.Geometry();\n"
        # adding vertices data
        for i in range(len(fcmesh[0])):
            v = fcmesh[0][i]
            result += tab + "var v" + str(i) + " = new THREE.Vector3(" + str(
                v.x) + "," + str(v.y) + "," + str(v.z) + ");\n"
        result += tab + "console.log(geom.vertices)\n"
        for i in range(len(fcmesh[0])):
            result += tab + "geom.vertices.push(v" + str(i) + ");\n"
        # adding facets data
        for f in fcmesh[1]:
            result += tab + "geom.faces.push( new THREE.Face3" + str(
                f) + " );\n"
        for f in obj.Shape.Faces:
            for w in f.Wires:
                wo = Part.Wire(Part.__sortEdges__(w.Edges))
                wires.append(wo.discretize(QuasiDeflection=0.1))

    elif obj.isDerivedFrom("Mesh::Feature"):
        mesh = obj.Mesh
        result = "var geom = new THREE.Geometry();\n"
        # adding vertices data
        for p in mesh.Points:
            v = p.Vector
            i = p.Index
            result += tab + "var v" + str(i) + " = new THREE.Vector3(" + str(
                v.x) + "," + str(v.y) + "," + str(v.z) + ");\n"
        result += tab + "console.log(geom.vertices)\n"
        for p in mesh.Points:
            result += tab + "geom.vertices.push(v" + str(p.Index) + ");\n"
        # adding facets data
        for f in mesh.Facets:
            pointIndices = tuple([int(i) for i in f.PointIndices])
            result += tab + "geom.faces.push( new THREE.Face3" + str(
                pointIndices) + " );\n"

    if result:
        # adding a base material
        if FreeCADGui:
            col = obj.ViewObject.ShapeColor
            rgb = Draft.getrgb(col, testbw=False)
        else:
            rgb = "#888888"  # test color
        result += tab + "var basematerial = new THREE.MeshBasicMaterial( { color: 0x" + str(
            rgb)[1:] + " } );\n"
        #result += tab+"var basematerial = new THREE.MeshLambertMaterial( { color: 0x"+str(rgb)[1:]+" } );\n"

        if wireframeMode == "faceloop":
            # adding the mesh to the scene with a wireframe copy
            result += tab + "var mesh = new THREE.Mesh( geom, basematerial );\n"
            result += tab + "scene.add( mesh );\n"
            result += tab + "var linematerial = new THREE.LineBasicMaterial({linewidth: %d, color: 0x000000,});\n" % linewidth
            for w in wires:
                result += tab + "var wire = new THREE.Geometry();\n"
                for p in w:
                    result += tab + "wire.vertices.push(new THREE.Vector3("
                    result += str(p.x) + ", " + str(p.y) + ", " + str(
                        p.z) + "));\n"
                result += tab + "var line = new THREE.Line(wire, linematerial);\n"
                result += tab + "scene.add(line);\n"

        elif wireframeMode == "multimaterial":
            # adding a wireframe material
            result += tab + "var wireframe = new THREE.MeshBasicMaterial( { color: "
            result += "0x000000, wireframe: true, transparent: true } );\n"
            result += tab + "var material = [ basematerial, wireframe ];\n"
            result += tab + "var mesh = new THREE.SceneUtils.createMultiMaterialObject( geom, material );\n"
            result += tab + "scene.add( mesh );\n" + tab

        else:
            # adding the mesh to the scene with simple material
            result += tab + "var mesh = new THREE.Mesh( geom, basematerial );\n"
            result += tab + "scene.add( mesh );\n" + tab

    return result
Example #24
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 Exception:
                            # 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 Exception:
                                        print(
                                            "Error merging polygons. Aborting")
                                        try:
                                            Part.show(Part.Wire(edges))
                                        except Exception:
                                            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 #25
0
def setup(doc=None, solvertype="ccxtools"):

    if doc is None:
        doc = init_doc()

    # geometry object
    # name is important because the other method in this module use obj name
    l1 = Part.makeLine((-142.5, -142.5, 0), (142.5, -142.5, 0))
    l2 = Part.makeLine((142.5, -142.5, 0), (142.5, 142.5, 0))
    l3 = Part.makeLine((142.5, 142.5, 0), (-142.5, 142.5, 0))
    l4 = Part.makeLine((-142.5, 142.5, 0), (-142.5, -142.5, 0))
    wire = Part.Wire([l1, l2, l3, l4])
    shape = wire.extrude(Vector(0, 0, 1000))
    geom_obj = doc.addObject('Part::Feature', 'SquareTube')
    geom_obj.Shape = shape

    points_forces = []
    points_forces.append(Part.Vertex(-142.5, 142.5, 0.0))
    points_forces.append(Part.Vertex(-142.5, -142.5, 0.0))
    points_forces.append(Part.Vertex(-142.5, 95.0, 0.0))
    points_forces.append(Part.Vertex(-142.5, 47.5, 0.0))
    points_forces.append(Part.Vertex(-142.5, 0.0, 0.0))
    points_forces.append(Part.Vertex(-142.5, -47.5, 0.0))
    points_forces.append(Part.Vertex(-142.5, -95.0, 0.0))
    points_forces.append(Part.Vertex(142.5, -142.5, 0.0))
    points_forces.append(Part.Vertex(-95.0, -142.5, 0.0))
    points_forces.append(Part.Vertex(-47.5, -142.5, 0.0))
    points_forces.append(Part.Vertex(0.0, -142.5, 0.0))
    points_forces.append(Part.Vertex(47.5, -142.5, 0.0))
    points_forces.append(Part.Vertex(95.0, -142.5, 0.0))
    points_forces.append(Part.Vertex(142.5, 142.5, 0.0))
    points_forces.append(Part.Vertex(142.5, -95.0, 0.0))
    points_forces.append(Part.Vertex(142.5, -47.5, 0.0))
    points_forces.append(Part.Vertex(142.5, 0.0, 0.0))
    points_forces.append(Part.Vertex(142.5, 47.5, 0.0))
    points_forces.append(Part.Vertex(142.5, 95.0, 0.0))
    points_forces.append(Part.Vertex(95.0, 142.5, 0.0))
    points_forces.append(Part.Vertex(47.5, 142.5, 0.0))
    points_forces.append(Part.Vertex(0.0, 142.5, 0.0))
    points_forces.append(Part.Vertex(-47.5, 142.5, 0.0))
    points_forces.append(Part.Vertex(-95.0, 142.5, 0.0))
    points_forces.append(Part.Vertex(-142.5, 118.75, 0.0))
    points_forces.append(Part.Vertex(-142.5, -118.75, 0.0))
    points_forces.append(Part.Vertex(-142.5, 71.25, 0.0))
    points_forces.append(Part.Vertex(-142.5, 23.75, 0.0))
    points_forces.append(Part.Vertex(-142.5, -23.75, 0.0))
    points_forces.append(Part.Vertex(-142.5, -71.25, 0.0))
    points_forces.append(Part.Vertex(118.75, -142.5, 0.0))
    points_forces.append(Part.Vertex(-71.25, -142.5, 0.0))
    points_forces.append(Part.Vertex(-118.75, -142.5, 0.0))
    points_forces.append(Part.Vertex(-23.75, -142.5, 0.0))
    points_forces.append(Part.Vertex(23.75, -142.5, 0.0))
    points_forces.append(Part.Vertex(71.25, -142.5, 0.0))
    points_forces.append(Part.Vertex(142.5, 118.75, 0.0))
    points_forces.append(Part.Vertex(142.5, -71.25, 0.0))
    points_forces.append(Part.Vertex(142.5, -118.75, 0.0))
    points_forces.append(Part.Vertex(142.5, -23.75, 0.0))
    points_forces.append(Part.Vertex(142.5, 23.75, 0.0))
    points_forces.append(Part.Vertex(142.5, 71.25, 0.0))
    points_forces.append(Part.Vertex(71.25, 142.5, 0.0))
    points_forces.append(Part.Vertex(118.75, 142.5, 0.0))
    points_forces.append(Part.Vertex(23.75, 142.5, 0.0))
    points_forces.append(Part.Vertex(-23.75, 142.5, 0.0))
    points_forces.append(Part.Vertex(-71.25, 142.5, 0.0))
    points_forces.append(Part.Vertex(-118.75, 142.5, 0.0))

    points_fixes = []
    points_fixes.append(Part.Vertex(-142.5, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 95.0, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 47.5, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 0.0, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -47.5, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -95.0, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-95.0, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-47.5, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(0.0, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(47.5, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(95.0, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -95.0, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -47.5, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 0.0, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 47.5, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 95.0, 1000.0))
    points_fixes.append(Part.Vertex(95.0, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(47.5, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(0.0, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-47.5, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-95.0, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 118.75, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -118.75, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 71.25, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, 23.75, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -23.75, 1000.0))
    points_fixes.append(Part.Vertex(-142.5, -71.25, 1000.0))
    points_fixes.append(Part.Vertex(118.75, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-71.25, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-118.75, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(-23.75, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(23.75, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(71.25, -142.5, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 118.75, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -71.25, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -118.75, 1000.0))
    points_fixes.append(Part.Vertex(142.5, -23.75, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 23.75, 1000.0))
    points_fixes.append(Part.Vertex(142.5, 71.25, 1000.0))
    points_fixes.append(Part.Vertex(71.25, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(118.75, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(23.75, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-23.75, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-71.25, 142.5, 1000.0))
    points_fixes.append(Part.Vertex(-118.75, 142.5, 1000.0))

    forces_obj = doc.addObject('Part::Feature', 'Forces')
    forces_obj.Shape = Part.makeCompound(points_forces)
    fixes_obj = doc.addObject('Part::Feature', 'Fixes')
    fixes_obj.Shape = Part.makeCompound(points_fixes)

    doc.recompute()

    if FreeCAD.GuiUp:
        forces_obj.ViewObject.PointColor = (1.0, 0.0, 0.0, 0.0)
        forces_obj.ViewObject.PointSize = 10.0
        fixes_obj.ViewObject.PointColor = (1.0, 0.0, 0.0, 0.0)
        fixes_obj.ViewObject.PointSize = 10.0
        geom_obj.ViewObject.Document.activeView().viewAxonometric()
        geom_obj.ViewObject.Document.activeView().fitAll()

    # analysis
    analysis = ObjectsFem.makeAnalysis(doc, "Analysis")

    # solver
    if solvertype == "calculix":
        solver_object = analysis.addObject(
            ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX")
        )[0]
    elif solvertype == "ccxtools":
        solver_object = analysis.addObject(
            ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools")
        )[0]
        solver_object.WorkingDir = u""
    else:
        FreeCAD.Console.PrintWarning(
            "Not known or not supported solver type: {}. "
            "No solver object was created.\n".format(solvertype)
        )
    if solvertype == "calculix" or solvertype == "ccxtools":
        solver_object.SplitInputWriter = False
        solver_object.AnalysisType = "static"
        solver_object.GeometricalNonlinearity = "linear"
        solver_object.ThermoMechSteadyState = False
        solver_object.MatrixSolverType = "default"
        solver_object.IterationsControlParameterTimeUse = False

    # shell thickness
    thickness = analysis.addObject(
        ObjectsFem.makeElementGeometry2D(doc, 0, "ShellThickness")
    )[0]
    thickness.Thickness = 15.0

    # material
    material_object = analysis.addObject(
        ObjectsFem.makeMaterialSolid(doc, "FemMaterial")
    )[0]
    mat = material_object.Material
    mat["Name"] = "Steel-Generic"
    mat["YoungsModulus"] = "200000 MPa"
    mat["PoissonRatio"] = "0.30"
    mat["Density"] = "7900 kg/m^3"
    material_object.Material = mat

    # fixed_constraint
    fixed_constraint = analysis.addObject(
        ObjectsFem.makeConstraintFixed(doc, name="ConstraintFixed"))[0]
    fixed_constraint.References = [
        (doc.Fixes, 'Vertex6'),
        (doc.Fixes, 'Vertex15'),
        (doc.Fixes, 'Vertex5'),
        (doc.Fixes, 'Vertex29'),
        (doc.Fixes, 'Vertex42'),
        (doc.Fixes, 'Vertex30'),
        (doc.Fixes, 'Vertex9'),
        (doc.Fixes, 'Vertex31'),
        (doc.Fixes, 'Vertex33'),
        (doc.Fixes, 'Vertex32'),
        (doc.Fixes, 'Vertex3'),
        (doc.Fixes, 'Vertex34'),
        (doc.Fixes, 'Vertex46'),
        (doc.Fixes, 'Vertex1'),
        (doc.Fixes, 'Vertex36'),
        (doc.Fixes, 'Vertex11'),
        (doc.Fixes, 'Vertex38'),
        (doc.Fixes, 'Vertex12'),
        (doc.Fixes, 'Vertex39'),
        (doc.Fixes, 'Vertex13'),
        (doc.Fixes, 'Vertex40'),
        (doc.Fixes, 'Vertex16'),
        (doc.Fixes, 'Vertex35'),
        (doc.Fixes, 'Vertex14'),
        (doc.Fixes, 'Vertex47'),
        (doc.Fixes, 'Vertex20'),
        (doc.Fixes, 'Vertex37'),
        (doc.Fixes, 'Vertex18'),
        (doc.Fixes, 'Vertex41'),
        (doc.Fixes, 'Vertex17'),
        (doc.Fixes, 'Vertex10'),
        (doc.Fixes, 'Vertex26'),
        (doc.Fixes, 'Vertex43'),
        (doc.Fixes, 'Vertex21'),
        (doc.Fixes, 'Vertex44'),
        (doc.Fixes, 'Vertex19'),
        (doc.Fixes, 'Vertex4'),
        (doc.Fixes, 'Vertex28'),
        (doc.Fixes, 'Vertex48'),
        (doc.Fixes, 'Vertex22'),
        (doc.Fixes, 'Vertex8'),
        (doc.Fixes, 'Vertex23'),
        (doc.Fixes, 'Vertex7'),
        (doc.Fixes, 'Vertex24'),
        (doc.Fixes, 'Vertex45'),
        (doc.Fixes, 'Vertex27'),
        (doc.Fixes, 'Vertex2'),
        (doc.Fixes, 'Vertex25')]

    # force_constraint1
    force_constraint1 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce1"))[0]
    force_constraint1.References = [(forces_obj, 'Vertex1'), (forces_obj, 'Vertex14')]
    force_constraint1.Force = 5555.56
    force_constraint1.Direction = (doc.SquareTube, ["Edge9"])
    force_constraint1.Reversed = False

    # force_constraint2
    force_constraint2 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce2"))[0]
    force_constraint2.References = [(forces_obj, 'Vertex2'), (forces_obj, 'Vertex8')]
    force_constraint2.Force = 5555.56
    force_constraint2.Direction = (doc.SquareTube, ["Edge3"])
    force_constraint2.Reversed = False

    # force_constraint3
    force_constraint3 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce3"))[0]
    force_constraint3.References = [
        (forces_obj, 'Vertex20'),
        (forces_obj, 'Vertex21'),
        (forces_obj, 'Vertex22'),
        (forces_obj, 'Vertex23'),
        (forces_obj, 'Vertex24'), ]
    force_constraint3.Force = 27777.78
    force_constraint3.Direction = (doc.SquareTube, ["Edge9"])
    force_constraint3.Reversed = False

    # force_constraint4
    force_constraint4 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce4"))[0]
    force_constraint4.References = [
        (forces_obj, 'Vertex9'),
        (forces_obj, 'Vertex10'),
        (forces_obj, 'Vertex11'),
        (forces_obj, 'Vertex12'),
        (forces_obj, 'Vertex13'), ]
    force_constraint4.Force = 27777.78
    force_constraint4.Direction = (doc.SquareTube, ["Edge3"])
    force_constraint4.Reversed = False

    # force_constraint5
    force_constraint5 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce5"))[0]
    force_constraint5.References = [
        (forces_obj, 'Vertex43'),
        (forces_obj, 'Vertex44'),
        (forces_obj, 'Vertex45'),
        (forces_obj, 'Vertex46'),
        (forces_obj, 'Vertex47'),
        (forces_obj, 'Vertex48'), ]
    force_constraint5.Force = 66666.67
    force_constraint5.Direction = (doc.SquareTube, ["Edge9"])
    force_constraint5.Reversed = False

    # force_constraint6
    force_constraint6 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce6"))[0]
    force_constraint6.References = [
        (forces_obj, 'Vertex31'),
        (forces_obj, 'Vertex32'),
        (forces_obj, 'Vertex33'),
        (forces_obj, 'Vertex34'),
        (forces_obj, 'Vertex35'),
        (forces_obj, 'Vertex36'), ]
    force_constraint6.Force = 66666.67
    force_constraint6.Direction = (doc.SquareTube, ["Edge3"])
    force_constraint6.Reversed = False

    # force_constraint7
    force_constraint7 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce7"))[0]
    force_constraint7.References = [(forces_obj, 'Vertex1'), (forces_obj, 'Vertex2')]
    force_constraint7.Force = 5555.56
    force_constraint7.Direction = (doc.SquareTube, ["Edge11"])
    force_constraint7.Reversed = False

    # force_constraint8
    force_constraint8 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce8"))[0]
    force_constraint8.References = [(forces_obj, 'Vertex8'), (forces_obj, 'Vertex14')]
    force_constraint8.Force = 5555.56
    force_constraint8.Direction = (doc.SquareTube, ["Edge6"])
    force_constraint8.Reversed = False

    # force_constraint9
    force_constraint9 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce9"))[0]
    force_constraint9.References = [
        (forces_obj, 'Vertex3'),
        (forces_obj, 'Vertex4'),
        (forces_obj, 'Vertex5'),
        (forces_obj, 'Vertex6'),
        (forces_obj, 'Vertex7'), ]
    force_constraint9.Force = 27777.78
    force_constraint9.Direction = (doc.SquareTube, ["Edge11"])
    force_constraint9.Reversed = False

    # force_constraint10
    force_constraint10 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce10"))[0]
    force_constraint10.References = [
        (forces_obj, 'Vertex15'),
        (forces_obj, 'Vertex16'),
        (forces_obj, 'Vertex17'),
        (forces_obj, 'Vertex18'),
        (forces_obj, 'Vertex19'), ]
    force_constraint10.Force = 27777.78
    force_constraint10.Direction = (doc.SquareTube, ["Edge6"])
    force_constraint10.Reversed = False

    # force_constraint11
    force_constraint11 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce11"))[0]
    force_constraint11.References = [
        (forces_obj, 'Vertex25'),
        (forces_obj, 'Vertex26'),
        (forces_obj, 'Vertex27'),
        (forces_obj, 'Vertex28'),
        (forces_obj, 'Vertex29'),
        (forces_obj, 'Vertex30'), ]
    force_constraint11.Force = 66666.67
    force_constraint11.Direction = (doc.SquareTube, ["Edge11"])
    force_constraint11.Reversed = False

    # force_constraint12
    force_constraint12 = analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce12"))[0]
    force_constraint12.References = [
        (forces_obj, 'Vertex37'),
        (forces_obj, 'Vertex38'),
        (forces_obj, 'Vertex39'),
        (forces_obj, 'Vertex40'),
        (forces_obj, 'Vertex41'),
        (forces_obj, 'Vertex42'), ]
    force_constraint12.Force = 66666.67
    force_constraint12.Direction = (doc.SquareTube, ["Edge6"])
    force_constraint12.Reversed = False

    # mesh
    from .meshes.mesh_square_pipe_end_twisted_tria6 import create_nodes, create_elements
    fem_mesh = Fem.FemMesh()
    control = create_nodes(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating nodes.\n")
    control = create_elements(fem_mesh)
    if not control:
        FreeCAD.Console.PrintError("Error on creating elements.\n")
    femmesh_obj = analysis.addObject(
        ObjectsFem.makeMeshGmsh(doc, mesh_name)
    )[0]
    femmesh_obj.FemMesh = fem_mesh
    femmesh_obj.Part = geom_obj
    femmesh_obj.SecondOrderLinear = False

    doc.recompute()
    return doc
Example #26
0
def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
    """offset(object,delta,[copymode],[bind])
    
    Offset the given wire by applying the given delta Vector to its first 
    vertex.

    Parameters
    ----------
    obj :

    delta : Base.Vector or list of Base.Vector
        If offsetting a BSpline, the delta must not be a Vector but a list
        of Vectors, one for each node of the spline.

    copy : bool
        If copymode is True, another object is created, otherwise the same
        object gets offsetted.

    copy : bool
        If bind is True, and provided the wire is open, the original
        and the offset wires will be bound by their endpoints, forming a face.
    
    sym : bool
        if sym is True, bind must be true too, and the offset is made on both
        sides, the total width being the given delta length.
    """
    import Part
    import DraftGeomUtils
    newwire = None
    delete = None

    if utils.get_type(obj) in ["Sketch", "Part"]:
        copy = True
        print(
            "the offset tool is currently unable to offset a non-Draft object directly - Creating a copy"
        )

    def getRect(p, obj):
        """returns length,height,placement"""
        pl = obj.Placement.copy()
        pl.Base = p[0]
        diag = p[2].sub(p[0])
        bb = p[1].sub(p[0])
        bh = p[3].sub(p[0])
        nb = DraftVecUtils.project(diag, bb)
        nh = DraftVecUtils.project(diag, bh)
        if obj.Length.Value < 0: l = -nb.Length
        else: l = nb.Length
        if obj.Height.Value < 0: h = -nh.Length
        else: h = nh.Length
        return l, h, pl

    def getRadius(obj, delta):
        """returns a new radius for a regular polygon"""
        an = math.pi / obj.FacesNumber
        nr = DraftVecUtils.rotate(delta, -an)
        nr.multiply(1 / math.cos(an))
        nr = obj.Shape.Vertexes[0].Point.add(nr)
        nr = nr.sub(obj.Placement.Base)
        nr = nr.Length
        if obj.DrawMode == "inscribed":
            return nr
        else:
            return nr * math.cos(math.pi / obj.FacesNumber)

    newwire = None
    if utils.get_type(obj) == "Circle":
        pass
    elif utils.get_type(obj) == "BSpline":
        pass
    else:
        if sym:
            d1 = App.Vector(delta).multiply(0.5)
            d2 = d1.negative()
            n1 = DraftGeomUtils.offsetWire(obj.Shape, d1)
            n2 = DraftGeomUtils.offsetWire(obj.Shape, d2)
        else:
            if isinstance(delta, float) and (len(obj.Shape.Edges) == 1):
                # circle
                c = obj.Shape.Edges[0].Curve
                nc = Part.Circle(c.Center, c.Axis, delta)
                if len(obj.Shape.Vertexes) > 1:
                    nc = Part.ArcOfCircle(nc,
                                          obj.Shape.Edges[0].FirstParameter,
                                          obj.Shape.Edges[0].LastParameter)
                newwire = Part.Wire(nc.toShape())
                p = []
            else:
                newwire = DraftGeomUtils.offsetWire(obj.Shape, delta)
                if DraftGeomUtils.hasCurves(newwire) and copy:
                    p = []
                else:
                    p = DraftGeomUtils.getVerts(newwire)
    if occ:
        newobj = App.ActiveDocument.addObject("Part::Feature", "Offset")
        newobj.Shape = DraftGeomUtils.offsetWire(obj.Shape, delta, occ=True)
        gui_utils.formatObject(newobj, obj)
        if not copy:
            delete = obj.Name
    elif bind:
        if not DraftGeomUtils.isReallyClosed(obj.Shape):
            if sym:
                s1 = n1
                s2 = n2
            else:
                s1 = obj.Shape
                s2 = newwire
            if s1 and s2:
                w1 = s1.Edges
                w2 = s2.Edges
                w3 = Part.LineSegment(s1.Vertexes[0].Point,
                                      s2.Vertexes[0].Point).toShape()
                w4 = Part.LineSegment(s1.Vertexes[-1].Point,
                                      s2.Vertexes[-1].Point).toShape()
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = Part.Face(Part.Wire(w1 + [w3] + w2 + [w4]))
            else:
                print("Draft.offset: Unable to bind wires")
        else:
            newobj = App.ActiveDocument.addObject("Part::Feature", "Offset")
            newobj.Shape = Part.Face(obj.Shape.Wires[0])
        if not copy:
            delete = obj.Name
    elif copy:
        newobj = None
        if sym: return None
        if utils.get_type(obj) == "Wire":
            if p:
                newobj = makeWire(p)
                newobj.Closed = obj.Closed
            elif newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            else:
                print("Draft.offset: Unable to duplicate this object")
        elif utils.get_type(obj) == "Rectangle":
            if p:
                length, height, plac = getRect(p, obj)
                newobj = makeRectangle(length, height, plac)
            elif newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            else:
                print("Draft.offset: Unable to duplicate this object")
        elif utils.get_type(obj) == "Circle":
            pl = obj.Placement
            newobj = makeCircle(delta)
            newobj.FirstAngle = obj.FirstAngle
            newobj.LastAngle = obj.LastAngle
            newobj.Placement = pl
        elif utils.get_type(obj) == "Polygon":
            pl = obj.Placement
            newobj = makePolygon(obj.FacesNumber)
            newobj.Radius = getRadius(obj, delta)
            newobj.DrawMode = obj.DrawMode
            newobj.Placement = pl
        elif utils.get_type(obj) == "BSpline":
            newobj = makeBSpline(delta)
            newobj.Closed = obj.Closed
        else:
            # try to offset anyway
            try:
                if p:
                    newobj = makeWire(p)
                    newobj.Closed = obj.Shape.isClosed()
            except Part.OCCError:
                pass
            if not (newobj) and newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            else:
                print("Draft.offset: Unable to create an offset")
        if newobj:
            gui_utils.formatObject(newobj, obj)
    else:
        newobj = None
        if sym: return None
        if utils.get_type(obj) == "Wire":
            if obj.Base or obj.Tool:
                App.Console.PrintWarning("Warning: object history removed\n")
                obj.Base = None
                obj.Tool = None
            obj.Points = p
        elif utils.get_type(obj) == "BSpline":
            #print(delta)
            obj.Points = delta
            #print("done")
        elif utils.get_type(obj) == "Rectangle":
            length, height, plac = getRect(p, obj)
            obj.Placement = plac
            obj.Length = length
            obj.Height = height
        elif utils.get_type(obj) == "Circle":
            obj.Radius = delta
        elif utils.get_type(obj) == "Polygon":
            obj.Radius = getRadius(obj, delta)
        elif utils.get_type(obj) == 'Part':
            print("unsupported object")  # TODO
        newobj = obj
    if copy and utils.get_param("selectBaseObjects", False):
        gui_utils.select(newobj)
    else:
        gui_utils.select(obj)
    if delete:
        App.ActiveDocument.removeObject(delete)
    return newobj
Example #27
0
    def execute(self, obj):

        if self.clone(obj):
            return

        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(wire)
        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 Part.OCCError:
            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 #28
0
def compute():
    QtGui.qApp.setOverrideCursor(QtCore.Qt.WaitCursor)

    if FreeCAD.ActiveDocument == None:
        FreeCAD.newDocument("Gear")

    oldDocumentObjects = App.ActiveDocument.Objects

    try:
        N = int(l1.text())
        p = float(l2.text())
        alfa = int(l3.text())
        y = float(
            l4.text())  #standard value y<1 for gear drives y>1 for Gear pumps
        m = p / math.pi  #standard value 0.06, 0.12, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 60 (polish norm)
        c = float(l5.text()) * m  #standard value 0,1*m - 0,3*m
        j = float(l6.text()) * m  #standard value 0,015 - 0,04*m
        width = float(l7.text())  #gear width
    except ValueError:
        FreeCAD.Console.PrintError("Wrong input! Only numbers allowed...\n")

    #tooth height
    h = 2 * y * m + c

    #pitch diameter
    d = N * m

    #root diameter
    df = d - 2 * y * m - 2 * c  #df=d-2hf where and hf=y*m+c

    #addendum diameter
    da = d + 2 * y * m  #da=d+2ha where ha=y*m

    #base diameter for involute
    db = d * math.cos(math.radians(alfa))

    #Base circle
    baseCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                  "BaseCircle")
    Draft._Circle(baseCircle)
    Draft._ViewProviderDraft(baseCircle.ViewObject)
    baseCircle.Radius = db / 2
    baseCircle.FirstAngle = 0.0
    baseCircle.LastAngle = 0.0

    #Root circle
    rootCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                  "RootCircle")
    Draft._Circle(rootCircle)
    Draft._ViewProviderDraft(rootCircle.ViewObject)
    rootCircle.Radius = df / 2
    rootCircle.FirstAngle = 0.0
    rootCircle.LastAngle = 0.0

    #Addendum circle
    addendumCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                      "AddendumCircle")
    Draft._Circle(addendumCircle)
    Draft._ViewProviderDraft(addendumCircle.ViewObject)
    addendumCircle.Radius = da / 2
    addendumCircle.FirstAngle = 0.0
    addendumCircle.LastAngle = 0.0

    #Pitch circle
    pitchCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                   "PitchCircle")
    Draft._Circle(pitchCircle)
    Draft._ViewProviderDraft(pitchCircle.ViewObject)
    pitchCircle.Radius = d / 2
    pitchCircle.FirstAngle = 0.0
    pitchCircle.LastAngle = 0.0

    #************ Calculating right sides of teeth
    #Involute of base circle
    involute = []
    involutee = []
    involutesav = []

    for t in range(0, 60, 1):
        x = db / 2 * (math.cos(math.radians(t)) +
                      math.radians(t) * math.sin(math.radians(t)))
        y = db / 2 * (math.sin(math.radians(t)) -
                      math.radians(t) * math.cos(math.radians(t)))
        involute.append(Part.Vertex(x, y, 0).Point)


#************ Drawing rigth sides of teeth
    involutesav.extend(involute)
    involutee.extend(involute)

    for angle in range(1, N + 1, 1):
        involuteobj = FreeCAD.ActiveDocument.addObject(
            "Part::Feature", "InvoluteL" + str(angle))
        involutee.insert(0, (0, 0, 0))
        involuteshape = Part.makePolygon(involutee)
        involuteobj.Shape = involuteshape
        involutee = []
        for num in range(0, 60, 1):
            point = involute.pop()
            pointt = Part.Vertex(
                point.x * math.cos(math.radians(angle * 360 / N)) -
                point.y * math.sin(math.radians(angle * 360 / N)),
                point.x * math.sin(math.radians(angle * 360 / N)) +
                point.y * math.cos(math.radians(angle * 360 / N)), 0).Point
            involutee.insert(0, pointt)
        involute.extend(involutesav)
    involutee = []

    #************ Calculating difference between tooth spacing on BaseCircle and PitchCircle

    pc = App.ActiveDocument.getObject("PitchCircle")
    inv = App.ActiveDocument.getObject("InvoluteL1")
    cut = inv.Shape.cut(pc.Shape)
    #    FreeCAD.ActiveDocument.addObject("Part::Feature","CutInv").Shape=cut
    invPoint = cut.Vertexes[0].Point

    diff = invPoint.y * 2  # instead of making axial symmetry and calculating point distance.
    anglediff = 2 * math.asin(diff / d)

    #************ Calculating left sides of teeth

    #************ Inversing Involute
    for num in range(0, 60, 1):
        point = involute.pop()
        pointt = Part.Vertex(point.x, point.y * -1, 0).Point
        involutee.insert(0, pointt)
    involute.extend(involutee)
    involutee = []

    #Normal tooth size calculated as: 0,5*  p    -      j                         j=m * 0,1 below are calculations
    #                                 0,5*  p    -      m      * 0,1
    #                                 0,5*  p    -     p   /pi * 0,1
    #                                 0,5*360/N  - ((360/N)/pi)* 0,1
    #                                 0,5*360/N  - (360/N)*((1/pi)*0,1)           j=(p/pi)*0,1
    #                                 0,5*360/N  - (360/N)*((p/pi)*0,1)/p
    #                                 0,5*360/N  - (360/N)*(    j     )/p
    for num in range(0, 60, 1):
        point = involute.pop()
        pointt = Part.Vertex(
            point.x *
            math.cos(math.radians(180 / N - (360 / N) *
                                  (j / p)) + anglediff) - point.y *
            math.sin(math.radians(180 / N - (360 / N) * (j / p)) + anglediff),
            point.x *
            math.sin(math.radians(180 / N - (360 / N) *
                                  (j / p)) + anglediff) + point.y *
            math.cos(math.radians(180 / N - (360 / N) * (j / p)) + anglediff),
            0).Point
        involutee.insert(0, pointt)
    involute.extend(involutee)
    involutesav = []
    involutesav.extend(involute)

    #************ Drawing left sides of teeth
    for angle in range(1, N + 1, 1):
        involuteobj = FreeCAD.ActiveDocument.addObject(
            "Part::Feature", "InvoluteR" + str(angle))
        involutee.insert(0, (0, 0, 0))
        involuteshape = Part.makePolygon(involutee)
        involuteobj.Shape = involuteshape
        involutee = []
        for num in range(0, 60, 1):
            point = involute.pop()
            pointt = Part.Vertex(
                point.x * math.cos(math.radians(angle * 360 / N)) -
                point.y * math.sin(math.radians(angle * 360 / N)),
                point.x * math.sin(math.radians(angle * 360 / N)) +
                point.y * math.cos(math.radians(angle * 360 / N)), 0).Point
            involutee.insert(0, pointt)
        involute.extend(involutesav)

    Gui.SendMsgToActiveView("ViewFit")

    #************ Forming teeth

    cutCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                                 "CutCircle")
    Draft._Circle(cutCircle)
    Draft._ViewProviderDraft(cutCircle.ViewObject)
    cutCircle.Radius = da  # da because must be bigger than addendumCircle and bigger than whole construction da is right for this but it not has to be.
    cutCircle.FirstAngle = 0.0
    cutCircle.LastAngle = 0.0

    cutTool = cutCircle.Shape.cut(addendumCircle.Shape)
    #cutshape=Part.show(cutTool)

    gearShape = rootCircle.Shape

    for invNum in range(1, N + 1, 1):
        invL = App.ActiveDocument.getObject("InvoluteL" + str(invNum))
        invR = App.ActiveDocument.getObject("InvoluteR" + str(invNum))
        cutL = invL.Shape.cut(cutTool)
        cutR = invR.Shape.cut(cutTool)
        pointL = cutL.Vertexes.pop().Point
        pointR = cutR.Vertexes.pop().Point
        faceEdge = Part.makeLine(pointL, pointR)

        toothWhole = cutL.fuse(cutR)
        toothWhole = toothWhole.fuse(faceEdge)
        toothWire = Part.Wire(toothWhole.Edges)
        toothShape = Part.Face(toothWire)
        #        tooth=App.ActiveDocument.addObject("Part::Feature","Tooth"+str(invNum))
        #        tooth.Shape=toothShape
        gearShape = gearShape.fuse(toothShape)

    for o in App.ActiveDocument.Objects:
        if oldDocumentObjects.count(o) == 0:
            App.ActiveDocument.removeObject(o.Name)

    gearFlat = App.ActiveDocument.addObject("Part::Feature", "GearFlat")
    gearFlat.Shape = gearShape
    Gui.ActiveDocument.getObject(gearFlat.Name).Visibility = False

    gear = App.ActiveDocument.addObject("Part::Extrusion", "Gear3D")
    gear.Base = gearFlat
    gear.Dir = (0, 0, width)
    App.ActiveDocument.recompute()

    if c1.isChecked() == True:
        gearMesh = App.ActiveDocument.addObject("Mesh::Feature", "Gear3D-mesh")

        faces = []
        triangles = gear.Shape.tessellate(
            1)  # the number represents the precision of the tessellation)
        for tri in triangles[1]:
            face = []
            for i in range(3):
                vindex = tri[i]
                face.append(triangles[0][vindex])
            faces.append(face)
        mesh = Mesh.Mesh(faces)

        gearMesh.Mesh = mesh
        App.ActiveDocument.removeObject(gear.Name)
        App.ActiveDocument.removeObject(gearFlat.Name)

    App.ActiveDocument.recompute()
    Gui.SendMsgToActiveView("ViewFit")

    QtGui.qApp.restoreOverrideCursor()

    hide()
Example #29
0
def makeBoreHole():
    # create a document if needed
    if App.ActiveDocument == None:
        App.newDocument("Solid")

    Group = App.ActiveDocument.addObject("App::DocumentObjectGroup", "Group")
    Group.Label = "Bore hole"

    V1 = Base.Vector(0, 10, 0)
    V2 = Base.Vector(30, 10, 0)
    V3 = Base.Vector(30, -10, 0)
    V4 = Base.Vector(0, -10, 0)
    VC1 = Base.Vector(-10, 0, 0)
    C1 = Part.Arc(V1, VC1, V4)
    # and the second one
    VC2 = Base.Vector(40, 0, 0)
    C2 = Part.Arc(V2, VC2, V3)
    L1 = Part.LineSegment(V1, V2)
    # and the second one
    L2 = Part.LineSegment(V4, V3)
    S1 = Part.Shape([C1, C2, L1, L2])

    W = Part.Wire(S1.Edges)
    F = Part.Face(W)
    P = F.extrude(Base.Vector(0, 0, 5))

    # add objects with the shape
    Wire = Group.newObject("Part::Feature", "Wire")
    Wire.Shape = W
    Face = Group.newObject("Part::Feature", "Face")
    Face.Shape = F
    Prism = Group.newObject("Part::Feature", "Extrude")
    Prism.Shape = P

    c = Part.Circle(Base.Vector(0, 0, -1), Base.Vector(0, 0, 1), 2.0)
    w = Part.Wire(c.toShape())
    f = Part.Face(w)
    p = f.extrude(Base.Vector(0, 0, 7))
    P = P.cut(p)

    # add first borer
    Bore1 = Group.newObject("Part::Feature", "Borer_1")
    Bore1.Shape = p
    Hole1 = Group.newObject("Part::Feature", "Borer_Hole1")
    Hole1.Shape = P

    c = Part.Circle(Base.Vector(0, -11, 2.5), Base.Vector(0, 1, 0), 1.0)
    w = Part.Wire(c.toShape())
    f = Part.Face(w)
    p = f.extrude(Base.Vector(0, 22, 0))
    P = P.cut(p)

    # add second borer
    Bore2 = Group.newObject("Part::Feature", "Borer_2")
    Bore2.Shape = p
    Hole2 = Group.newObject("Part::Feature", "Borer_Hole2")
    Hole2.Shape = P

    App.ActiveDocument.recompute()

    # hide all objets except of the final one
    Gui.ActiveDocument.getObject(Wire.Name).hide()
    Gui.ActiveDocument.getObject(Face.Name).hide()
    Gui.ActiveDocument.getObject(Prism.Name).hide()
    Gui.ActiveDocument.getObject(Bore1.Name).hide()
    Gui.ActiveDocument.getObject(Hole1.Name).hide()
    Gui.ActiveDocument.getObject(Bore2.Name).hide()
    Gui.ActiveDocument.ActiveView.fitAll()
Example #30
0
    def execute(self, obj):

        if self.clone(obj):
            return
        if not obj.Base:
            FreeCAD.Console.PrintError(
                "No Base, return without a rebar shape for {}.\n".format(
                    obj.Name))
            return
        if not obj.Base.Shape:
            FreeCAD.Console.PrintError(
                "No Shape in Base, return without a rebar shape for {}.\n".
                format(obj.Name))
            return
        if obj.Base.Shape.Faces:
            FreeCAD.Console.PrintError(
                "Faces in Shape of Base, return without a rebar shape for {}.\n"
                .format(obj.Name))
            return
        if not obj.Base.Shape.Edges:
            FreeCAD.Console.PrintError(
                "No Edges in Shape of Base, return without a rebar shape for {}.\n"
                .format(obj.Name))
            return
        if not obj.Diameter.Value:
            FreeCAD.Console.PrintError(
                "No Diameter Value, return without a rebar shape for {}.\n".
                format(obj.Name))
            return
        if not obj.Amount:
            FreeCAD.Console.PrintError(
                "No Amount, return without a rebar shape for {}.\n".format(
                    obj.Name))
            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 hasattr(father, 'Shape'):
                fathershape = father.Shape

        import Part
        # corner cases:
        #    compound from more Wires
        #    compound without Wires but with multiple Edges
        # Does they make sense? If yes handle them.
        # Does it makes sense to handle Shapes with Faces or even Solids?
        if not obj.Base.Shape.Wires and len(obj.Base.Shape.Edges) == 1:
            wire = Part.Wire(obj.Base.Shape.Edges[0])
        else:
            wire = obj.Base.Shape.Wires[0]
        if hasattr(obj, "Rounding"):
            #print(obj.Rounding)
            if obj.Rounding:
                radius = obj.Rounding * obj.Diameter.Value
                from DraftGeomUtils import filletWire
                wire = 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
        spacinglist = None
        if hasattr(obj, "CustomSpacing"):
            if obj.CustomSpacing:
                spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing)
                influenceArea = sum(
                    spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2
        # Drop this check to solve issue as discussed here: https://github.com/FreeCAD/FreeCAD/pull/2550
        # 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
        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 = []
        rot = FreeCAD.Rotation()
        if obj.Amount == 1:
            if hasattr(obj, "RebarShape"):
                barplacement = CalculatePlacement(
                    obj.Amount, 1, obj.Diameter.Value, size, axis, rot,
                    obj.OffsetStart.Value, obj.OffsetEnd.Value, obj.RebarShape)
            else:
                barplacement = CalculatePlacement(obj.Amount, 1,
                                                  obj.Diameter.Value, 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
            if hasattr(obj, "RebarShape") and obj.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)
            for i in range(obj.Amount):
                if hasattr(obj, "RebarShape"):
                    barplacement = CalculatePlacement(obj.Amount, i + 1,
                                                      obj.Diameter.Value, size,
                                                      axis, rot,
                                                      obj.OffsetStart.Value,
                                                      obj.OffsetEnd.Value,
                                                      obj.RebarShape)
                else:
                    barplacement = CalculatePlacement(obj.Amount, i + 1,
                                                      obj.Diameter.Value, 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[:] = []
            if hasattr(obj, "RebarShape") and obj.RebarShape == "Stirrup":
                reqInfluenceArea = size - (obj.OffsetStart.Value +
                                           obj.OffsetEnd.Value +
                                           obj.Diameter.Value)
            else:
                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):
                FreeCAD.Console.PrintWarning(
                    "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)