Example #1
0
 def GetFace(self):
   self.edges.append(Part.makeLine(self.lastPoint, self.firstPoint))
   w = Part.Wire(self.edges)
   return Part.Face(w)
Example #2
0
def make_face(v1, v2, v3):
    wire = Part.makePolygon([v1, v2, v3, v1])
    face = Part.Face(wire)
    return face
    def __init__(
            self,
            depth,
            aluprof_dict,
            xtr_d=0,
            xtr_nd=0,
            axis_d=VX,
            axis_w=VY,
            axis_h=V0,
            pos_d=0,
            pos_w=0,
            pos_h=0,
            pos=V0,
            model_type=1,  # dimensional model
            name=None):

        width = aluprof_dict['w']
        depth = depth
        thick = aluprof_dict['t']
        slot = aluprof_dict['slot']
        insquare = aluprof_dict['insq']
        indiam = aluprof_dict['indiam']

        # either axis_w or axis_h can be V0, but not both
        if (axis_w is None) or (axis_w == V0):
            if (axis_h is None) or (axis_h == V0):
                logger.error('Either axis_w or axis_h must be defined')
                logger.warning('getting a random perpendicular verctor')
                axis_w = fcfun.get_fc_perpend1(axis_d)
            else:
                axis_w = axis_h.cross(axis_d)

        if (axis_h is None) or (axis_h == V0):
            axis_h = axis_d.cross(axis_w)

        if name == None:
            name = ('aluprof_w' + str(int(aluprof_dict['w'])) + 'l_' +
                    str(int(xtr_nd + depth + xtr_d)))

        Obj3D.__init__(self, axis_d, axis_w, axis_h, name=name)

        # save the arguments as attributes:
        frame = inspect.currentframe()
        args, _, _, values = inspect.getargvalues(frame)
        for i in args:
            if not hasattr(self, i):
                setattr(self, i, values[i])

        self.pos = FreeCAD.Vector(0, 0, 0)
        self.position = pos

        self.d0_cen = 0
        self.w0_cen = 1  # symmetric
        self.h0_cen = 1  # symmetric

        # total length (depth)
        self.tot_d = xtr_nd + depth + xtr_d

        # vectors from the origin to the points along axis_d:
        self.d_o[0] = V0  # origin
        self.d_o[1] = self.vec_d(xtr_nd)  #if xtr_nd= 0: same as d_o[0]
        # middle point, not considering xtr_nd and xtr_d
        self.d_o[2] = self.vec_d(xtr_nd + depth / 2.)
        # middle point considering xtr_nd and xtr_d
        self.d_o[3] = self.vec_d(self.tot_d / 2.)
        self.d_o[4] = self.vec_d(xtr_nd + depth)
        self.d_o[5] = self.vec_d(self.tot_d)

        # vectors from the origin to the points along axis_w:
        # symmetric: negative
        self.w_o[0] = V0  # center: origin
        self.w_o[1] = self.vec_w(-insquare / 2.)
        self.w_o[2] = self.vec_w(-(width / 2. - thick))
        self.w_o[3] = self.vec_w(-width / 2.)

        # vectors from the origin to the points along axis_h:
        # symmetric: negative
        self.h_o[0] = V0  # center: origin
        self.h_o[1] = self.vec_h(-insquare / 2.)
        self.h_o[2] = self.vec_h(-(width / 2. - thick))
        self.h_o[3] = self.vec_h(-width / 2.)

        # calculates the position of the origin, and keeps it in attribute pos_o
        self.set_pos_o()

        shp_alu_wire = fcfun.shp_aluwire_dir(
            width,
            thick,
            slot,
            insquare,
            fc_axis_x=self.axis_w,
            fc_axis_y=self.axis_h,
            ref_x=1,  # pos_o is centered
            ref_y=1,  # pos_o is centered
            pos=self.pos_o)

        # make a face of the wire
        shp_alu_face = Part.Face(shp_alu_wire)
        # inner hole
        if indiam > 0:
            hole = Part.makeCircle(
                indiam / 2.,  # Radius
                self.pos_o,  # Position
                self.axis_d)  # direction
            wire_hole = Part.Wire(hole)
            face_hole = Part.Face(wire_hole)
            shp_alu_face = shp_alu_face.cut(face_hole)

        # extrude it
        dir_extrud = DraftVecUtils.scaleTo(self.axis_d, self.tot_d)
        shp_aluprof = shp_alu_face.extrude(dir_extrud)

        self.shp = shp_aluprof

        super().create_fco()
        # Need to set first in (0,0,0) and after that set the real placement.
        # This enable to do rotations without any issue
        self.fco.Placement.Base = FreeCAD.Vector(0, 0, 0)
        self.fco.Placement.Base = self.position
Example #4
0
def areas(ship,
          n,
          draft=None,
          roll=Units.parseQuantity("0 deg"),
          trim=Units.parseQuantity("0 deg")):
    """Compute the ship transversal areas

    Position arguments:
    ship -- Ship object (see createShip)
    n -- Number of points to compute

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    List of sections, each section contains 2 values, the x longitudinal
    coordinate, and the transversal area. If n < 2, an empty list will be
    returned.
    """
    if n < 2:
        return []

    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    # Sections distance computation
    bbox = shape.BoundBox
    xmin = bbox.XMin
    xmax = bbox.XMax
    dx = (xmax - xmin) / (n - 1.0)

    # Since we are computing the sections in the total length (not in the
    # length between perpendiculars), we can grant that the starting and
    # ending sections have null area
    areas = [(Units.Quantity(xmin,
                             Units.Length), Units.Quantity(0.0, Units.Area))]
    # And since we just need to compute areas we will create boxes with its
    # front face at the desired transversal area position, computing the
    # common solid part, dividing it by faces, and getting only the desired
    # ones.
    App.Console.PrintMessage("Computing transversal areas...\n")
    App.Console.PrintMessage("Some Inventor representation errors can be"
                             " shown, please ignore them.\n")
    for i in range(1, n - 1):
        App.Console.PrintMessage("{0} / {1}\n".format(i, n - 2))
        x = xmin + i * dx
        try:
            f = Part.Face(shape.slice(Vector(1, 0, 0), x))
        except Part.OCCError:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Part.OCCError: Transversal area computation failed", None)
            App.Console.PrintError(msg + '\n')
            areas.append((Units.Quantity(x, Units.Length),
                          Units.Quantity(0.0, Units.Area)))
            continue
        # It is a valid face, so we can add this area
        areas.append(
            (Units.Quantity(x,
                            Units.Length), Units.Quantity(f.Area, Units.Area)))
    # Last area is equal to zero (due to the total length usage)
    areas.append(
        (Units.Quantity(xmax, Units.Length), Units.Quantity(0.0, Units.Area)))
    App.Console.PrintMessage("Done!\n")
    return areas
Example #5
0
def createMeshView(obj,
                   direction=FreeCAD.Vector(0, 0, -1),
                   outeronly=False,
                   largestonly=False):
    """createMeshView(obj,[direction,outeronly,largestonly]): creates a flat shape that is the
    projection of the given mesh object in the given direction (default = on the XY plane). If
    outeronly is True, only the outer contour is taken into consideration, discarding the inner
    holes. If largestonly is True, only the largest segment of the given mesh will be used."""

    import Mesh, math, Part, DraftGeomUtils
    if not obj.isDerivedFrom("Mesh::Feature"):
        return
    mesh = obj.Mesh

    # 1. Flattening the mesh
    proj = []
    for f in mesh.Facets:
        nf = []
        for v in f.Points:
            v = FreeCAD.Vector(v)
            a = v.negative().getAngle(direction)
            l = math.cos(a) * v.Length
            p = v.add(FreeCAD.Vector(direction).multiply(l))
            p = DraftVecUtils.rounded(p)
            nf.append(p)
        proj.append(nf)
    flatmesh = Mesh.Mesh(proj)

    # 2. Removing wrong faces
    facets = []
    for f in flatmesh.Facets:
        if f.Normal.getAngle(direction) < math.pi:
            facets.append(f)
    cleanmesh = Mesh.Mesh(facets)

    #Mesh.show(cleanmesh)

    # 3. Getting the bigger mesh from the planar segments
    if largestonly:
        c = cleanmesh.getSeparateComponents()
        #print(c)
        cleanmesh = c[0]
        segs = cleanmesh.getPlanarSegments(1)
        meshes = []
        for s in segs:
            f = [cleanmesh.Facets[i] for i in s]
            meshes.append(Mesh.Mesh(f))
        a = 0
        for m in meshes:
            if m.Area > a:
                boundarymesh = m
                a = m.Area
        #Mesh.show(boundarymesh)
        cleanmesh = boundarymesh

    # 4. Creating a Part and getting the contour

    shape = None
    for f in cleanmesh.Facets:
        p = Part.makePolygon(f.Points + [f.Points[0]])
        #print(p,len(p.Vertexes),p.isClosed())
        try:
            p = Part.Face(p)
            if shape:
                shape = shape.fuse(p)
            else:
                shape = p
        except Part.OCCError:
            pass
    shape = shape.removeSplitter()

    # 5. Extracting the largest wire

    if outeronly:
        count = 0
        largest = None
        for w in shape.Wires:
            if len(w.Vertexes) > count:
                count = len(w.Vertexes)
                largest = w
        if largest:
            try:
                f = Part.Face(w)
            except Part.OCCError:
                print("Unable to produce a face from the outer wire.")
            else:
                shape = f

    return shape
    def areaOpShapes(self, obj):
        '''areaOpShapes(obj) ... return shapes representing the solids to be removed.'''
        PathLog.track()
        PathLog.debug("----- areaOpShapes() in PathPocketShape.py")

        baseSubsTuples = []
        subCount = 0
        allTuples = []

        def planarFaceFromExtrusionEdges(face, trans):
            useFace = 'useFaceName'
            minArea = 0.0
            fCnt = 0
            clsd = []
            planar = False
            # Identify closed edges
            for edg in face.Edges:
                if edg.isClosed():
                    PathLog.debug('  -e.isClosed()')
                    clsd.append(edg)
                    planar = True
            # Attempt to create planar faces and select that with smallest area for use as pocket base
            if planar is True:
                planar = False
                for edg in clsd:
                    fCnt += 1
                    fName = sub + '_face_' + str(fCnt)
                    # Create planar face from edge
                    mFF = Part.Face(Part.Wire(Part.__sortEdges__([edg])))
                    if mFF.isNull():
                        PathLog.debug('Face(Part.Wire()) failed')
                    else:
                        if trans is True:
                            mFF.translate(
                                FreeCAD.Vector(
                                    0, 0,
                                    face.BoundBox.ZMin - mFF.BoundBox.ZMin))
                        if FreeCAD.ActiveDocument.getObject(fName):
                            FreeCAD.ActiveDocument.removeObject(fName)
                        tmpFace = FreeCAD.ActiveDocument.addObject(
                            'Part::Feature', fName).Shape = mFF
                        tmpFace = FreeCAD.ActiveDocument.getObject(fName)
                        tmpFace.purgeTouched()
                        if minArea == 0.0:
                            minArea = tmpFace.Shape.Face1.Area
                            useFace = fName
                            planar = True
                        elif tmpFace.Shape.Face1.Area < minArea:
                            minArea = tmpFace.Shape.Face1.Area
                            FreeCAD.ActiveDocument.removeObject(useFace)
                            useFace = fName
                        else:
                            FreeCAD.ActiveDocument.removeObject(fName)
            if useFace != 'useFaceName':
                self.useTempJobClones(useFace)
            return (planar, useFace)

        def clasifySub(self, bs, sub):
            face = bs.Shape.getElement(sub)

            if type(face.Surface) == Part.Plane:
                PathLog.debug('type() == Part.Plane')
                if PathGeom.isVertical(face.Surface.Axis):
                    PathLog.debug('  -isVertical()')
                    # it's a flat horizontal face
                    self.horiz.append(face)
                    return True
                elif PathGeom.isHorizontal(face.Surface.Axis):
                    PathLog.debug('  -isHorizontal()')
                    self.vert.append(face)
                    return True
                else:
                    return False
            elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(
                    face.Surface.Axis):
                PathLog.debug('type() == Part.Cylinder')
                # vertical cylinder wall
                if any(e.isClosed() for e in face.Edges):
                    PathLog.debug('  -e.isClosed()')
                    # complete cylinder
                    circle = Part.makeCircle(face.Surface.Radius,
                                             face.Surface.Center)
                    disk = Part.Face(Part.Wire(circle))
                    disk.translate(
                        FreeCAD.Vector(0, 0, face.BoundBox.ZMin -
                                       disk.BoundBox.ZMin))
                    self.horiz.append(disk)
                    return True
                else:
                    PathLog.debug('  -none isClosed()')
                    # partial cylinder wall
                    self.vert.append(face)
                    return True
            elif type(face.Surface) == Part.SurfaceOfExtrusion:
                # extrusion wall
                PathLog.debug('type() == Part.SurfaceOfExtrusion')
                # Attempt to extract planar face from surface of extrusion
                (planar, useFace) = planarFaceFromExtrusionEdges(face,
                                                                 trans=True)
                # Save face object to self.horiz for processing or display error
                if planar is True:
                    uFace = FreeCAD.ActiveDocument.getObject(useFace)
                    self.horiz.append(uFace.Shape.Faces[0])
                    msg = translate(
                        'Path',
                        "<b>Verify depth of pocket for '{}'.</b>".format(sub))
                    msg += translate(
                        'Path', "\n<br>Pocket is based on extruded surface.")
                    msg += translate(
                        'Path',
                        "\n<br>Bottom of pocket might be non-planar and/or not normal to spindle axis."
                    )
                    msg += translate(
                        'Path',
                        "\n<br>\n<br><i>3D pocket bottom is NOT available in this operation</i>."
                    )
                    PathLog.warning(msg)
                    # title = translate('Path', 'Depth Warning')
                    # self.guiMessage(title, msg, False)
                else:
                    PathLog.error(
                        translate(
                            "Path",
                            "Failed to create a planar face from edges in {}.".
                            format(sub)))
            else:
                PathLog.debug('  -type(face.Surface): {}'.format(
                    type(face.Surface)))
                return False

        if obj.Base:
            PathLog.debug('Processing... obj.Base')
            self.removalshapes = []  # pylint: disable=attribute-defined-outside-init
            # ----------------------------------------------------------------------
            if obj.EnableRotation == 'Off':
                stock = PathUtils.findParentJob(obj).Stock
                for (base, subList) in obj.Base:
                    baseSubsTuples.append((base, subList, 0.0, 'X', stock))
            else:
                for p in range(0, len(obj.Base)):
                    (base, subsList) = obj.Base[p]
                    isLoop = False

                    # First, check all subs collectively for loop of faces
                    if len(subsList) > 2:
                        (isLoop, norm,
                         surf) = self.checkForFacesLoop(base, subsList)
                    if isLoop is True:
                        PathLog.info(
                            "Common Surface.Axis or normalAt() value found for loop faces."
                        )
                        rtn = False
                        subCount += 1
                        (rtn, angle, axis,
                         praInfo) = self.faceRotationAnalysis(obj, norm, surf)  # pylint: disable=unused-variable
                        PathLog.info("angle: {};  axis: {}".format(
                            angle, axis))

                        if rtn is True:
                            faceNums = ""
                            for f in subsList:
                                faceNums += '_' + f.replace('Face', '')
                            (clnBase, angle, clnStock,
                             tag) = self.applyRotationalAnalysis(
                                 obj, base, angle, axis, faceNums)  # pylint: disable=unused-variable

                            # Verify faces are correctly oriented - InverseAngle might be necessary
                            PathLog.debug(
                                "Checking if faces are oriented correctly after rotation..."
                            )
                            for sub in subsList:
                                face = clnBase.Shape.getElement(sub)
                                if type(face.Surface) == Part.Plane:
                                    if not PathGeom.isHorizontal(
                                            face.Surface.Axis):
                                        rtn = False
                                        break
                            if rtn is False:
                                if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
                                    (clnBase, clnStock,
                                     angle) = self.applyInverseAngle(
                                         obj, clnBase, clnStock, axis, angle)
                                else:
                                    PathLog.info(
                                        translate(
                                            "Path",
                                            "Consider toggling the InverseAngle property and recomputing the operation."
                                        ))

                            tup = clnBase, subsList, angle, axis, clnStock
                        else:
                            if self.warnDisabledAxis(obj, axis) is False:
                                PathLog.debug("No rotation used")
                            axis = 'X'
                            angle = 0.0
                            stock = PathUtils.findParentJob(obj).Stock
                            tup = base, subsList, angle, axis, stock
                        # Eif
                        allTuples.append(tup)
                        baseSubsTuples.append(tup)
                    # Eif

                    if isLoop is False:
                        PathLog.debug(
                            translate('Path',
                                      "Processing subs individually ..."))
                        for sub in subsList:
                            subCount += 1
                            if 'Face' in sub:
                                rtn = False
                                face = base.Shape.getElement(sub)
                                if type(face.Surface
                                        ) == Part.SurfaceOfExtrusion:
                                    # extrusion wall
                                    PathLog.debug(
                                        'analyzing type() == Part.SurfaceOfExtrusion'
                                    )
                                    # Attempt to extract planar face from surface of extrusion
                                    (planar,
                                     useFace) = planarFaceFromExtrusionEdges(
                                         face, trans=False)
                                    # Save face object to self.horiz for processing or display error
                                    if planar is True:
                                        base = FreeCAD.ActiveDocument.getObject(
                                            useFace)
                                        sub = 'Face1'
                                        PathLog.debug(
                                            '  -successful face created: {}'.
                                            format(useFace))
                                    else:
                                        PathLog.error(
                                            translate(
                                                "Path",
                                                "Failed to create a planar face from edges in {}."
                                                .format(sub)))

                                (norm, surf) = self.getFaceNormAndSurf(face)
                                (rtn, angle, axis,
                                 praInfo) = self.faceRotationAnalysis(
                                     obj, norm, surf)  # pylint: disable=unused-variable

                                if rtn is True:
                                    faceNum = sub.replace('Face', '')
                                    (clnBase, angle, clnStock,
                                     tag) = self.applyRotationalAnalysis(
                                         obj, base, angle, axis, faceNum)
                                    # Verify faces are correctly oriented - InverseAngle might be necessary
                                    faceIA = clnBase.Shape.getElement(sub)
                                    (norm,
                                     surf) = self.getFaceNormAndSurf(faceIA)
                                    (rtn, praAngle, praAxis,
                                     praInfo) = self.faceRotationAnalysis(
                                         obj, norm, surf)  # pylint: disable=unused-variable
                                    if rtn is True:
                                        PathLog.debug(
                                            "Face not aligned after initial rotation."
                                        )
                                        if obj.AttemptInverseAngle is True and obj.InverseAngle is False:
                                            (clnBase, clnStock,
                                             angle) = self.applyInverseAngle(
                                                 obj, clnBase, clnStock, axis,
                                                 angle)
                                        else:
                                            PathLog.info(
                                                translate(
                                                    "Path",
                                                    "Consider toggling the InverseAngle property and recomputing the operation."
                                                ))
                                    else:
                                        PathLog.debug(
                                            "Face appears to be oriented correctly."
                                        )

                                    tup = clnBase, [sub], angle, axis, clnStock
                                else:
                                    if self.warnDisabledAxis(obj,
                                                             axis) is False:
                                        PathLog.debug(
                                            str(sub) + ": No rotation used")
                                    axis = 'X'
                                    angle = 0.0
                                    stock = PathUtils.findParentJob(obj).Stock
                                    tup = base, [sub], angle, axis, stock
                                # Eif
                                allTuples.append(tup)
                                baseSubsTuples.append(tup)
                            else:
                                ignoreSub = base.Name + '.' + sub
                                PathLog.error(
                                    translate(
                                        'Path',
                                        "Selected feature is not a Face. Ignoring: {}"
                                        .format(ignoreSub)))

            for o in baseSubsTuples:
                self.horiz = []  # pylint: disable=attribute-defined-outside-init
                self.vert = []  # pylint: disable=attribute-defined-outside-init
                subBase = o[0]
                subsList = o[1]
                angle = o[2]
                axis = o[3]
                stock = o[4]

                for sub in subsList:
                    if 'Face' in sub:
                        if clasifySub(self, subBase, sub) is False:
                            PathLog.error(
                                translate(
                                    'PathPocket',
                                    'Pocket does not support shape %s.%s') %
                                (subBase.Label, sub))
                            if obj.EnableRotation != 'Off':
                                PathLog.info(
                                    translate(
                                        'PathPocket',
                                        'Face might not be within rotation accessibility limits.'
                                    ))

                # Determine final depth as highest value of bottom boundbox of vertical face,
                #   in case of uneven faces on bottom
                if len(self.vert) > 0:
                    vFinDep = self.vert[0].BoundBox.ZMin
                    for vFace in self.vert:
                        if vFace.BoundBox.ZMin > vFinDep:
                            vFinDep = vFace.BoundBox.ZMin
                    # Determine if vertical faces for a loop: Extract planar loop wire as new horizontal face.
                    self.vertical = PathGeom.combineConnectedShapes(self.vert)  # pylint: disable=attribute-defined-outside-init
                    self.vWires = [
                        TechDraw.findShapeOutline(shape, 1,
                                                  FreeCAD.Vector(0, 0, 1))
                        for shape in self.vertical
                    ]  # pylint: disable=attribute-defined-outside-init
                    for wire in self.vWires:
                        w = PathGeom.removeDuplicateEdges(wire)
                        face = Part.Face(w)
                        # face.tessellate(0.1)
                        if PathGeom.isRoughly(face.Area, 0):
                            msg = translate(
                                'PathPocket',
                                'Vertical faces do not form a loop - ignoring')
                            PathLog.error(msg)
                            # title = translate("Path", "Face Selection Warning")
                            # self.guiMessage(title, msg, True)
                        else:
                            face.translate(
                                FreeCAD.Vector(0, 0,
                                               vFinDep - face.BoundBox.ZMin))
                            self.horiz.append(face)
                            msg = translate(
                                'Path',
                                'Verify final depth of pocket shaped by vertical faces.'
                            )
                            PathLog.warning(msg)
                            # title = translate('Path', 'Depth Warning')
                            # self.guiMessage(title, msg, False)

                # add faces for extensions
                self.exts = []  # pylint: disable=attribute-defined-outside-init
                for ext in self.getExtensions(obj):
                    wire = ext.getWire()
                    if wire:
                        face = Part.Face(wire)
                        self.horiz.append(face)
                        self.exts.append(face)

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

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

                # extrude all faces up to StartDepth and those are the removal shapes
                sD = obj.StartDepth.Value
                fD = obj.FinalDepth.Value
                extent = FreeCAD.Vector(0, 0, sD - fD)
                for face in self.horizontal:
                    self.removalshapes.append(
                        (face.removeSplitter().extrude(extent), False,
                         'pathPocketShape', angle, axis, sD, fD))
                    PathLog.debug(
                        "Extent depths are str: {}, and fin: {}".format(
                            sD, fD))
                # Efor face
            # Efor

        else:
            # process the job base object as a whole
            PathLog.debug(translate("Path", 'Processing model as a whole ...'))
            finDep = obj.FinalDepth.Value
            strDep = obj.StartDepth.Value
            self.outlines = [
                Part.Face(
                    TechDraw.findShapeOutline(base.Shape, 1,
                                              FreeCAD.Vector(0, 0, 1)))
                for base in self.model
            ]  # pylint: disable=attribute-defined-outside-init
            stockBB = self.stock.Shape.BoundBox

            self.removalshapes = []  # pylint: disable=attribute-defined-outside-init
            self.bodies = []  # pylint: disable=attribute-defined-outside-init
            for outline in self.outlines:
                outline.translate(FreeCAD.Vector(0, 0, stockBB.ZMin - 1))
                body = outline.extrude(
                    FreeCAD.Vector(0, 0, stockBB.ZLength + 2))
                self.bodies.append(body)
                self.removalshapes.append(
                    (self.stock.Shape.cut(body), False, 'pathPocketShape', 0.0,
                     'X', strDep, finDep))

        for (shape, hole, sub, angle, axis, strDep,
             finDep) in self.removalshapes:  # pylint: disable=unused-variable
            shape.tessellate(0.05)  # originally 0.1

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

        return self.removalshapes
Example #7
0
 def __init__(self, name, origin, side='L'):
     self.name = name
     if not isinstance(origin, Base.Vector):
         raise RuntimeError("origin is not a Vector!")
     self.origin = origin
     ox = origin.x
     oy = origin.y
     oz = origin.z
     bracketPoly = list()
     bracketPoly.append(Base.Vector(ox, oy, oz))
     self.bracketmh = dict()
     if side == 'L':
         x = ox
         y = oy + self.AngleLength()
         bracketPoly.append(Base.Vector(x, y, oz))
         x -= self.AngleWidth()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= self.AngleNotchDY2()
         bracketPoly.append(Base.Vector(x, y, oz))
         x += self.AngleNotchDX()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= (self.AngleNotchDY1() - self.AngleNotchDY2())
         bracketPoly.append(Base.Vector(x, y, oz))
         x -= self.AngleNotchDX()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= (self.AngleLength() - self.AngleNotchDY1())
         bracketPoly.append(Base.Vector(x, y, oz))
         bracketPoly.append(Base.Vector(ox, oy, oz))
         angle_a = Part.Face(Part.Wire(Part.makePolygon(bracketPoly)))
         self.bracketmh[1] = origin.add(
             Base.Vector(-self.BRACKET_z(), self.M1_y(), 0))
         self.bracketmh[2] = origin.add(
             Base.Vector(-self.BRACKET_z(), self.M2_y(), 0))
         self.bracketmh[3] = origin.add(
             Base.Vector(-self.BRACKET_z(), self.M3_y(), 0))
         self.bracketmh[4] = origin.add(
             Base.Vector(-self.BRACKET_z(), self.M4_y(), 0))
         extrude_b = Base.Vector(-self.AngleThickness(), 0, 0)
     elif side == 'R':
         x = ox
         y = oy + self.AngleLength()
         bracketPoly.append(Base.Vector(x, y, oz))
         x += self.AngleWidth()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= self.AngleNotchDY2()
         bracketPoly.append(Base.Vector(x, y, oz))
         x -= self.AngleNotchDX()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= (self.AngleNotchDY1() - self.AngleNotchDY2())
         bracketPoly.append(Base.Vector(x, y, oz))
         x += self.AngleNotchDX()
         bracketPoly.append(Base.Vector(x, y, oz))
         y -= (self.AngleLength() - self.AngleNotchDY1())
         bracketPoly.append(Base.Vector(x, y, oz))
         bracketPoly.append(Base.Vector(ox, oy, oz))
         angle_a = Part.Face(Part.Wire(Part.makePolygon(bracketPoly)))
         self.bracketmh[1] = origin.add(
             Base.Vector(self.BRACKET_z(), self.M1_y(), 0))
         self.bracketmh[2] = origin.add(
             Base.Vector(self.BRACKET_z(), self.M2_y(), 0))
         self.bracketmh[3] = origin.add(
             Base.Vector(self.BRACKET_z(), self.M3_y(), 0))
         self.bracketmh[4] = origin.add(
             Base.Vector(self.BRACKET_z(), self.M4_y(), 0))
         extrude_b = Base.Vector(self.AngleThickness(), 0, 0)
     else:
         raise RuntimeError("side must be L or R!")
     self.bracketPoly = bracketPoly
     borig = origin.add(
         Base.Vector(0, self.AngleLength(), -self.AngleHeight()))
     angle_b = Part.makePlane(self.AngleHeight(), self.AngleLength(), borig,
                              Base.Vector(1, 0, 0))
     self.lcdmh = dict()
     self.lcdmh[1] = origin.add(Base.Vector(0, self.M1_y(), -self.M_x()))
     self.lcdmh[2] = origin.add(Base.Vector(0, self.M2_y(), -self.M_x()))
     self.lcdmh[3] = origin.add(Base.Vector(0, self.M3_y(), -self.M_x()))
     self.lcdmh[4] = origin.add(Base.Vector(0, self.M4_y(), -self.M_x()))
     #self.mhFaces = dict()
     for i in [1, 2, 3, 4]:
         bmhFace = Part.Face(
             Part.Wire(Part.makeCircle(self.BRACKET_r(),
                                       self.bracketmh[i])))
         angle_a = angle_a.cut(bmhFace)
         mhFace = Part.Face(
             Part.Wire(
                 Part.makeCircle(self.M_r(), self.lcdmh[i],
                                 Base.Vector(1, 0, 0))))
         angle_b = angle_b.cut(mhFace)
         #self.mhFaces[i] = mhFace.extrude(extrude_b)
     extrude_a = Base.Vector(0, 0, -self.AngleThickness())
     self.bracket = angle_a.extrude(extrude_a)
     self.bracket = self.bracket.fuse(angle_b.extrude(extrude_b))
     self._mapPolyVerts()
     self._mapBMHoleEdges()
     self._mapLCDMHoleEdges()
Example #8
0
def setup_rcwall2d(doc=None, solver="ccxtools"):
    # setup reinfoced wall in 2D

    if doc is None:
        doc = init_doc()

    # part
    from FreeCAD import Vector as vec
    import Part
    from Part import makeLine as ln

    v1 = vec(0, -2000, 0)
    v2 = vec(500, -2000, 0)
    v3 = vec(500, 0, 0)
    v4 = vec(3500, 0, 0)
    v5 = vec(3500, -2000, 0)
    v6 = vec(4000, -2000, 0)
    v7 = vec(4000, 2000, 0)
    v8 = vec(0, 2000, 0)
    l1 = ln(v1, v2)
    l2 = ln(v2, v3)
    l3 = ln(v3, v4)
    l4 = ln(v4, v5)
    l5 = ln(v5, v6)
    l6 = ln(v6, v7)
    l7 = ln(v7, v8)
    l8 = ln(v8, v1)
    rcwall = doc.addObject("Part::Feature", "FIB_Wall")
    rcwall.Shape = Part.Face(Part.Wire([l1, l2, l3, l4, l5, l6, l7, l8]))

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

    # solver
    # TODO How to pass multiple solver for one analysis in one doc
    if solver == "calculix":
        solver = analysis.addObject(
            ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0]
        solver.AnalysisType = "static"
        solver.GeometricalNonlinearity = "linear"
        solver.ThermoMechSteadyState = False
        solver.MatrixSolverType = "default"
        solver.IterationsControlParameterTimeUse = False
    elif solver == "ccxtools":
        solver = analysis.addObject(
            ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0]
        solver.AnalysisType = "static"
        solver.GeometricalNonlinearity = "linear"
        solver.ThermoMechSteadyState = False
        solver.MatrixSolverType = "default"
        solver.IterationsControlParameterTimeUse = False
        solver.WorkingDir = u""

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

    # material
    matrixprop = {}
    matrixprop["Name"] = "Concrete-EN-C35/45"
    matrixprop["YoungsModulus"] = "32000 MPa"
    matrixprop["PoissonRatio"] = "0.17"
    matrixprop["CompressiveStrength"] = "15.75 MPa"
    # make some hint on the possible angle units in material system
    matrixprop["AngleOfFriction"] = "30 deg"
    matrixprop["Density"] = "2500 kg/m^3"
    reinfoprop = {}
    reinfoprop["Name"] = "Reinforcement-FIB-B500"
    reinfoprop["YieldStrength"] = "315 MPa"
    # not an official FreeCAD material property
    reinfoprop["ReinforcementRatio"] = "0.0"
    material_reinforced = analysis.addObject(
        ObjectsFem.makeMaterialReinforced(doc, "MaterialReinforced"))[0]
    material_reinforced.Material = matrixprop
    material_reinforced.Reinforcement = reinfoprop

    # fixed_constraint
    fixed_constraint = analysis.addObject(
        ObjectsFem.makeConstraintFixed(doc, name="ConstraintFixed"))[0]
    fixed_constraint.References = [(rcwall, "Edge1"), (rcwall, "Edge5")]

    # force constraint
    force_constraint = doc.Analysis.addObject(
        ObjectsFem.makeConstraintForce(doc, name="ConstraintForce"))[0]
    force_constraint.References = [(rcwall, "Edge7")]
    force_constraint.Force = 1000000.0
    force_constraint.Direction = (rcwall, ["Edge8"])
    force_constraint.Reversed = False

    # displacement_constraint
    displacement_constraint = doc.Analysis.addObject(
        ObjectsFem.makeConstraintDisplacement(
            doc, name="ConstraintDisplacmentPrescribed"))[0]
    displacement_constraint.References = [(rcwall, "Face1")]
    displacement_constraint.zFix = True

    # mesh
    from femexamples.meshes.mesh_rc_wall_2d_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(
        doc.addObject("Fem::FemMeshObject", mesh_name))[0]
    femmesh_obj.FemMesh = fem_mesh

    doc.recompute()
    return doc
Example #9
0
def smCornerR(reliefsketch="Circle",
              size=3.0,
              ratio=1.0,
              xoffset=0.0,
              yoffset=0.0,
              kfactor=0.5,
              sketch='',
              flipped=False,
              selEdgeNames='',
              MainObject=None):

    resultSolid = MainObject.Shape.copy()
    REdgelist = []
    for selEdgeName in selEdgeNames:
        REdge = resultSolid.getElement(selEdgeName)
        REdgelist.append(REdge)

    DetailList = getBendDetail(resultSolid, REdgelist[0], REdgelist[1],
                               kfactor)
    cornerPoint, centerPoint, LargeFace, thk, unfoldLength, neutralRadius = DetailList
    normal = LargeFace.normalAt(0, 0)

    SplitLineVector = centerPoint - cornerPoint
    if "Scaled" in reliefsketch:
        size = ratio * abs(SplitLineVector.Length)
    SplitLineVector.normalize()
    #print([centerPoint, cornerPoint, SplitLineVector] )
    SplitLine = Part.makeLine(centerPoint + SplitLineVector * size * 3,
                              cornerPoint + SplitLineVector * -size * 3)
    #Part.show(SplitLine,"SplitLine")

    if reliefsketch != "Sketch":
        sketch = makeSketch(reliefsketch, size, ratio, centerPoint, normal,
                            SplitLineVector)
        reliefFace = Part.Face(sketch)
    else:
        reliefFace = Part.Face(sketch.Shape.Wires[0])
    #Part.show(reliefFace,'reliefFace')

    #To check face direction
    coeff = normal.dot(reliefFace.Faces[0].normalAt(0, 0))
    if coeff < 0:
        reliefFace.reverse()

    # to get top face cut
    First_face = LargeFace.common(reliefFace)
    #Part.show(First_face,'First_face')
    Balance_Face = reliefFace.cut(First_face)
    #Part.show(Balance_Face,'Balance_Face')

    #To get bend solid face
    SplitFaces = BOPTools.SplitAPI.slice(Balance_Face.Faces[0],
                                         SplitLine.Edges, "Standard", 0.0)
    #Part.show(SplitFaces,"SplitFaces")

    #To get top face normal, flatsolid
    solidlist = []
    if First_face.Faces:
        Flatsolid = First_face.extrude(normal * -thk)
        #Part.show(Flatsolid,"Flatsolid")
        solidlist.append(Flatsolid)

    if SplitFaces.Faces:
        for BalanceFace in SplitFaces.Faces:
            #Part.show(BalanceFace,"BalanceFace")
            TopFace = LargeFace
            #Part.show(TopFace,"TopFace")
            while BalanceFace.Faces:
                BendEdgelist = smGetEdgelist(BalanceFace, TopFace)
                for BendEdge in BendEdgelist:
                    #Part.show(BendEdge,"BendEdge")
                    edge_facelist = resultSolid.ancestorsOfType(
                        BendEdge, Part.Face)
                    for cyl_face in edge_facelist:
                        #print(type(cyl_face.Surface))
                        if issubclass(type(cyl_face.Surface), Part.Cylinder):
                            break
                    if issubclass(type(cyl_face.Surface), Part.Cylinder):
                        break
                #Part.show(BendEdge,"BendEdge")
                facelist = resultSolid.ancestorsOfType(BendEdge, Part.Face)

                #To get bend radius, bend angle
                for cylface in facelist:
                    if issubclass(type(cylface.Surface), Part.Cylinder):
                        break
                if not (issubclass(type(cylface.Surface), Part.Cylinder)):
                    break
                #Part.show(cylface,"cylface")
                for planeface in facelist:
                    if issubclass(type(planeface.Surface), Part.Plane):
                        break
                #Part.show(planeface,"planeface")
                normal = planeface.normalAt(0, 0)
                revAxisV = cylface.Surface.Axis
                revAxisP = cylface.Surface.Center
                bendA = bendAngle(cylface, revAxisP)
                #print([bendA, revAxisV, revAxisP, cylface.Orientation])

                #To check bend direction
                offsetface = cylface.makeOffsetShape(-thk, 0.0, fill=False)
                #Part.show(offsetface,"offsetface")
                if offsetface.Area < cylface.Area:
                    bendR = cylface.Surface.Radius - thk
                    flipped = True
                else:
                    bendR = cylface.Surface.Radius
                    flipped = False

                #To arrive unfold Length, neutralRadius
                unfoldLength = (bendR +
                                kfactor * thk) * abs(bendA) * math.pi / 180.0
                neutralRadius = (bendR + kfactor * thk)
                #print([unfoldLength,neutralRadius])

                #To get faceNormal, bend face
                faceNormal = normal.cross(revAxisV).normalize()
                #print(faceNormal)
                if bendR < cylface.Surface.Radius:
                    offsetSolid = cylface.makeOffsetShape(bendR / 2.0,
                                                          0.0,
                                                          fill=True)
                else:
                    offsetSolid = cylface.makeOffsetShape(-bendR / 2.0,
                                                          0.0,
                                                          fill=True)
                #Part.show(offsetSolid,"offsetSolid")
                tool = BendEdge.copy()
                FaceArea = tool.extrude(faceNormal * -unfoldLength)
                #Part.show(FaceArea,"FaceArea")
                #Part.show(BalanceFace,"BalanceFace")
                SolidFace = offsetSolid.common(FaceArea)
                if not (SolidFace.Faces):
                    faceNormal = faceNormal * -1
                    FaceArea = tool.extrude(faceNormal * -unfoldLength)
                BendSolidFace = BalanceFace.common(FaceArea)
                #Part.show(FaceArea,"FaceArea")
                #Part.show(BendSolidFace,"BendSolidFace")
                #print([bendR, bendA, revAxisV, revAxisP, normal, flipped, BendSolidFace.Faces[0].normalAt(0,0)])

                bendsolid = SheetMetalBendSolid.BendSolid(
                    BendSolidFace.Faces[0], BendEdge, bendR, thk,
                    neutralRadius, revAxisV, flipped)
                #Part.show(bendsolid,"bendsolid")
                solidlist.append(bendsolid)

                if flipped == True:
                    bendA = -bendA
                if not (SolidFace.Faces):
                    revAxisV = revAxisV * -1
                sketch_face = BalanceFace.cut(BendSolidFace)
                sketch_face.translate(faceNormal * unfoldLength)
                #Part.show(sketch_face,"sketch_face")
                sketch_face.rotate(revAxisP, -revAxisV, bendA)
                #Part.show(sketch_face,"Rsketch_face")
                CylEdge = smGetEdge(sketch_face, cylface)
                #Part.show(CylEdge,"CylEdge")
                edgefacelist = resultSolid.ancestorsOfType(CylEdge, Part.Face)
                for TopFace in edgefacelist:
                    if not (issubclass(type(TopFace.Surface), Part.Cylinder)):
                        break
                #Part.show(TopFace,"TopFace")

                #To get top face normal, flatsolid
                normal = TopFace.normalAt(0, 0)
                Flatface = sketch_face.common(TopFace)
                BalanceFace = sketch_face.cut(Flatface)
                #Part.show(BalanceFace,"BalanceFace")
                if Flatface.Faces:
                    BalanceFace = sketch_face.cut(Flatface)
                    #Part.show(BalanceFace,"BalanceFace")
                    Flatsolid = Flatface.extrude(normal * -thk)
                    #Part.show(Flatsolid,"Flatsolid")
                    solidlist.append(Flatsolid)
                else:
                    BalanceFace = sketch_face

    #To get relief Solid fused
    if len(solidlist) > 1:
        SMSolid = solidlist[0].multiFuse(solidlist[1:])
        #Part.show(SMSolid,"SMSolid")
        SMSolid = SMSolid.removeSplitter()
    else:
        SMSolid = solidlist[0]
    #Part.show(SMSolid,"SMSolid")
    resultSolid = resultSolid.cut(SMSolid)
    return resultSolid
Example #10
0
    def execute(self, obj):
        if hasattr(obj, "VisibleOnly"):
            if obj.VisibleOnly:
                if obj.ViewObject:
                    if obj.ViewObject.Visibility == False:
                        return False
        import Part, DraftGeomUtils
        obj.positionBySupport()
        pl = obj.Placement
        if obj.Base:
            if utils.get_type(obj.Base) in ["BuildingPart", "SectionPlane"]:
                objs = []
                if utils.get_type(obj.Base) == "SectionPlane":
                    objs = obj.Base.Objects
                    cutplane = obj.Base.Shape
                else:
                    objs = obj.Base.Group
                    cutplane = Part.makePlane(1000, 1000,
                                              App.Vector(-500, -500, 0))
                    m = 1
                    if obj.Base.ViewObject and hasattr(obj.Base.ViewObject,
                                                       "CutMargin"):
                        m = obj.Base.ViewObject.CutMargin.Value
                    cutplane.translate(App.Vector(0, 0, m))
                    cutplane.Placement = cutplane.Placement.multiply(
                        obj.Base.Placement)
                if objs:
                    onlysolids = True
                    if hasattr(obj.Base, "OnlySolids"):
                        onlysolids = obj.Base.OnlySolids
                    import Arch, Part, Drawing
                    objs = utils.get_group_contents(objs, walls=True)
                    objs = gui_utils.remove_hidden(objs)
                    shapes = []
                    if hasattr(obj, "FuseArch") and obj.FuseArch:
                        shtypes = {}
                        for o in objs:
                            if utils.get_type(o) in ["Wall", "Structure"]:
                                if onlysolids:
                                    shtypes.setdefault(
                                        o.Material.Name if
                                        (hasattr(o, "Material") and o.Material)
                                        else "None", []).extend(o.Shape.Solids)
                                else:
                                    shtypes.setdefault(
                                        o.Material.Name if
                                        (hasattr(o, "Material") and o.Material)
                                        else "None", []).append(o.Shape.copy())
                            elif hasattr(o, 'Shape'):
                                if onlysolids:
                                    shapes.extend(o.Shape.Solids)
                                else:
                                    shapes.append(o.Shape.copy())
                        for k, v in shtypes.items():
                            v1 = v.pop()
                            if v:
                                v1 = v1.multiFuse(v)
                                v1 = v1.removeSplitter()
                            if v1.Solids:
                                shapes.extend(v1.Solids)
                            else:
                                print(
                                    "Shape2DView: Fusing Arch objects produced non-solid results"
                                )
                                shapes.append(v1)
                    else:
                        for o in objs:
                            if hasattr(o, 'Shape'):
                                if onlysolids:
                                    shapes.extend(o.Shape.Solids)
                                else:
                                    shapes.append(o.Shape.copy())
                    clip = False
                    if hasattr(obj.Base, "Clip"):
                        clip = obj.Base.Clip
                    cutp, cutv, iv = Arch.getCutVolume(cutplane, shapes, clip)
                    cuts = []
                    opl = App.Placement(obj.Base.Placement)
                    proj = opl.Rotation.multVec(App.Vector(0, 0, 1))
                    if obj.ProjectionMode == "Solid":
                        for sh in shapes:
                            if cutv:
                                if sh.Volume < 0:
                                    sh.reverse()
                                #if cutv.BoundBox.intersect(sh.BoundBox):
                                #    c = sh.cut(cutv)
                                #else:
                                #    c = sh.copy()
                                c = sh.cut(cutv)
                                if onlysolids:
                                    cuts.extend(c.Solids)
                                else:
                                    cuts.append(c)
                            else:
                                if onlysolids:
                                    cuts.extend(sh.Solids)
                                else:
                                    cuts.append(sh.copy())
                        comp = Part.makeCompound(cuts)
                        obj.Shape = self.getProjected(obj, comp, proj)
                    elif obj.ProjectionMode in ["Cutlines", "Cutfaces"]:
                        for sh in shapes:
                            if sh.Volume < 0:
                                sh.reverse()
                            c = sh.section(cutp)
                            faces = []
                            if (obj.ProjectionMode
                                    == "Cutfaces") and (sh.ShapeType
                                                        == "Solid"):
                                if hasattr(obj, "InPlace"):
                                    if not obj.InPlace:
                                        c = self.getProjected(obj, c, proj)
                                wires = DraftGeomUtils.findWires(c.Edges)
                                for w in wires:
                                    if w.isClosed():
                                        faces.append(Part.Face(w))
                            if faces:
                                cuts.extend(faces)
                            else:
                                cuts.append(c)
                        comp = Part.makeCompound(cuts)
                        opl = App.Placement(obj.Base.Placement)
                        comp.Placement = opl.inverse()
                        if comp:
                            obj.Shape = comp

            elif obj.Base.isDerivedFrom("App::DocumentObjectGroup"):
                shapes = []
                objs = utils.get_group_contents(obj.Base)
                for o in objs:
                    if hasattr(o, 'Shape'):
                        if o.Shape:
                            if not o.Shape.isNull():
                                shapes.append(o.Shape)
                if shapes:
                    import Part
                    comp = Part.makeCompound(shapes)
                    obj.Shape = self.getProjected(obj, comp, obj.Projection)

            elif hasattr(obj.Base, 'Shape'):
                if not DraftVecUtils.isNull(obj.Projection):
                    if obj.ProjectionMode == "Solid":
                        obj.Shape = self.getProjected(obj, obj.Base.Shape,
                                                      obj.Projection)
                    elif obj.ProjectionMode == "Individual Faces":
                        import Part
                        if obj.FaceNumbers:
                            faces = []
                            for i in obj.FaceNumbers:
                                if len(obj.Base.Shape.Faces) > i:
                                    faces.append(obj.Base.Shape.Faces[i])
                            views = []
                            for f in faces:
                                views.append(
                                    self.getProjected(obj, f, obj.Projection))
                            if views:
                                obj.Shape = Part.makeCompound(views)
                    else:
                        App.Console.PrintWarning(obj.ProjectionMode +
                                                 " mode not implemented\n")
        if not DraftGeomUtils.isNull(pl):
            obj.Placement = pl
Example #11
0
    def onChanged(self, obj, prop):
        if prop in ["Source", "RenderingMode", "ShowCut"]:
            import Part, DraftGeomUtils
            if hasattr(obj, "Source"):
                if obj.Source:
                    if obj.Source.Objects:
                        objs = Draft.getGroupContents(obj.Source.Objects,
                                                      walls=True,
                                                      addgroups=True)
                        objs = Draft.removeHidden(objs)
                        # separate spaces
                        self.spaces = []
                        os = []
                        for o in objs:
                            if Draft.getType(o) == "Space":
                                self.spaces.append(o)
                            else:
                                os.append(o)
                        objs = os
                        self.svg = ''
                        fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"'
                        fillpattern += ' x="0" y="0" width="10" height="10">'
                        fillpattern += '<g>'
                        fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>'

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

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

    import Part,DraftGeomUtils
    shapes = []
    hshapes = []
    sshapes = []
    objectShapes = []
    objectSshapes = []
    for o in objs:
        if o.isDerivedFrom("Part::Feature"):
            if o.Shape.isNull():
                pass
            elif section.OnlySolids:
                if o.Shape.isValid():
                    solids = []
                    solids.extend(o.Shape.Solids)

                    shapes.extend(solids)

                    objectShapes.append((o, solids))
                else:
                    print(section.Label,": Skipping invalid object:",o.Label)
            else:
                shapes.append(o.Shape)
                objectShapes.append((o, [o.Shape]))
    cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes)
    if cutvolume:
        for o, shapeList in objectShapes:
            tmpSshapes = []
            for sh in shapeList:
                for sol in sh.Solids:
                    if sol.Volume < 0:
                        sol.reverse()
                    c = sol.cut(cutvolume)
                    s = sol.section(cutface)
                    try:
                        wires = DraftGeomUtils.findWires(s.Edges)
                        for w in wires:
                            f = Part.Face(w)
                            tmpSshapes.append(f)
                        #s = Part.Wire(s.Edges)
                        #s = Part.Face(s)
                    except Part.OCCError:
                        #print "ArchDrawingView: unable to get a face"
                        tmpSshapes.append(s)
                    shapes.extend(c.Solids)
                    #sshapes.append(s)
                    if showHidden:
                        c = sol.cut(invcutvolume)
                        hshapes.append(c)

            if len(tmpSshapes) > 0:
                sshapes.extend(tmpSshapes)
                
                if groupSshapesByObject:
                    objectSshapes.append((o, tmpSshapes))
    
    if groupSshapesByObject:
        return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes
    else:
        return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume
Example #13
0
    def createGeometry(self, obj):
        import Part, DraftGeomUtils

        # getting default values
        height = width = length = 1
        if hasattr(obj, "Length"):
            if obj.Length:
                length = obj.Length
        if hasattr(obj, "Width"):
            if obj.Width:
                width = obj.Width
        if hasattr(obj, "Height"):
            if obj.Height:
                height = obj.Height

        # creating base shape
        pl = obj.Placement
        base = None
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Normal == Vector(0, 0, 0):
                    p = FreeCAD.Placement(obj.Base.Placement)
                    normal = p.Rotation.multVec(Vector(0, 0, 1))
                else:
                    normal = Vector(obj.Normal)
                normal = normal.multiply(height)
                base = obj.Base.Shape.copy()
                if base.Solids:
                    pass
                elif base.Faces:
                    base = base.extrude(normal)
                elif (len(base.Wires) == 1):
                    if base.Wires[0].isClosed():
                        base = Part.Face(base.Wires[0])
                        base = base.extrude(normal)
            elif obj.Base.isDerivedFrom("Mesh::Feature"):
                if obj.Base.Mesh.isSolid():
                    if obj.Base.Mesh.countComponents() == 1:
                        sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh)
                        if sh.isClosed() and sh.isValid() and sh.Solids:
                            base = sh
        else:
            if obj.Normal == Vector(0, 0, 0):
                normal = Vector(0, 0, 1)
            else:
                normal = Vector(obj.Normal)
            normal = normal.multiply(height)
            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.makePolygon([v1, v2, v3, v4, v1])
            base = Part.Face(base)
            base = base.extrude(normal)

        base = self.processSubShapes(obj, base)

        if base:
            # applying axes
            pts = self.getAxisPoints(obj)
            apl = self.getAxisPlacement(obj)
            if pts:
                fsh = []
                for i in range(len(pts)):
                    if hasattr(obj, "Exclude"):
                        if i in obj.Exclude:
                            continue
                    sh = base.copy()
                    if apl:
                        sh.Placement.Rotation = apl.Rotation
                    sh.translate(pts[i])
                    fsh.append(sh)
                    obj.Shape = Part.makeCompound(fsh)

            # finalizing

            else:
                if base:
                    if not base.isNull():
                        if base.isValid() and base.Solids:
                            if base.Volume < 0:
                                base.reverse()
                            if base.Volume < 0:
                                FreeCAD.Console.PrintError(
                                    str(
                                        translate(
                                            "Arch",
                                            "Couldn't compute the wall shape"))
                                )
                                return
                            base = base.removeSplitter()
                            obj.Shape = base
                if not DraftGeomUtils.isNull(pl):
                    obj.Placement = pl
Example #14
0
 def computeAreas(self, obj):
     "computes the area properties"
     if not obj.Shape:
         return
     if obj.Shape.isNull():
         return
     if not obj.Shape.isValid():
         return
     if not obj.Shape.Faces:
         return
     import Drawing, Part
     a = 0
     fset = []
     for i, f in enumerate(obj.Shape.Faces):
         try:
             ang = f.normalAt(0, 0).getAngle(FreeCAD.Vector(0, 0, 1))
         except Part.OCCError:
             print("Debug: Error computing areas for ", obj.Label,
                   ": normalAt() Face ", i)
             return
         else:
             if (ang > 1.57) and (ang < 1.571):
                 a += f.Area
             if ang < 1.5707:
                 fset.append(f)
     if a and hasattr(obj, "VerticalArea"):
         if obj.VerticalArea.Value != a:
             obj.VerticalArea = a
     if fset and hasattr(obj, "HorizontalArea"):
         pset = []
         for f in fset:
             if f.normalAt(0, 0).getAngle(FreeCAD.Vector(0, 0,
                                                         1)) < 0.00001:
                 # already horizontal
                 pset.append(f)
             else:
                 try:
                     pf = Part.Face(
                         Part.Wire(
                             Drawing.project(f,
                                             FreeCAD.Vector(0, 0,
                                                            1))[0].Edges))
                 except Part.OCCError:
                     # error in computing the areas. Better set them to zero than show a wrong value
                     if obj.HorizontalArea.Value != 0:
                         print("Debug: Error computing areas for ",
                               obj.Label, ": unable to project face: ",
                               str([v.Point for v in f.Vertexes]),
                               " (face normal:", f.normalAt(0, 0), ")")
                         obj.HorizontalArea = 0
                     if hasattr(obj, "PerimeterLength"):
                         if obj.PerimeterLength.Value != 0:
                             obj.PerimeterLength = 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.HorizontalArea.Value != self.flatarea.Area:
                 obj.HorizontalArea = self.flatarea.Area
             if hasattr(obj, "PerimeterLength") and (len(
                     self.flatarea.Faces) == 1):
                 if obj.PerimeterLength.Value != self.flatarea.Faces[
                         0].OuterWire.Length:
                     obj.PerimeterLength = self.flatarea.Faces[
                         0].OuterWire.Length
    def _getRegularWire(self):
        """_getRegularWire()... Private method to retrieve the extension area, pertaining to the feature
        and sub element provided at class instantiation, as a closed wire.  If no closed wire
        is possible, a `None` value is returned."""
        PathLog.track()

        length = self.length.Value
        if PathGeom.isRoughly(0, length) or not self.sub:
            PathLog.debug("no extension, length=%.2f, sub=%s" %
                          (length, self.sub))
            return None

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

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

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

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

                    extWire = Part.Wire([e3])
                    self.extFaces = [self._makeCircularExtFace(edge, extWire)]
                    return extWire

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

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

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

            #    return self._extendEdge(feature, edge, direction)
            return self._extendEdge(feature, edges[0], direction)
        elif sub.isClosed():
            PathLog.debug("Extending multi-edge closed wire")
            subFace = Part.Face(sub)
            featFace = Part.Face(feature.Wires[0])
            isOutside = True
            if not PathGeom.isRoughly(featFace.Area, subFace.Area):
                length = -1.0 * length
                isOutside = False

            try:
                off2D = sub.makeOffset2D(length)
            except FreeCAD.Base.FreeCADError as ee:
                PathLog.debug(ee)
                return None

            if isOutside:
                self.extFaces = [Part.Face(off2D).cut(featFace)]
            else:
                self.extFaces = [subFace.cut(Part.Face(off2D))]
            return off2D

        PathLog.debug("Extending multi-edge open wire")
        return extendWire(feature, sub, length)
Example #16
0
    def addtofreecad(self, doc=None, fcpar=None):
        def center(obj, x, y, z):
            obj.Placement = FreeCAD.Placement(\
               FreeCAD.Vector(-x/2.0,-y/2.0,-z/2.0),\
               FreeCAD.Rotation(0,0,0,1))

        import FreeCAD, Part
        if not doc:
            doc = FreeCAD.newDocument()
        namel = self.name.lower()
        multifeature = {
            'union': "Part::MultiFuse",
            'imp_union': "Part::MultiFuse",
            'intersection': "Part::MultiCommon"
        }
        if namel in multifeature:
            if len(self.children) > 1:
                obj = doc.addObject(multifeature[namel], namel)
                subobjs = [
                    child.addtofreecad(doc, obj) for child in self.children
                ]
                obj.Shapes = subobjs
                for subobj in subobjs:
                    subobj.ViewObject.hide()
            elif len(self.children) == 1:
                obj = self.children[0].addtofreecad(doc, fcpar or True)
            else:
                obj = fcpar
        elif namel == 'difference':
            if len(self.children) == 1:
                obj = self.children[0].addtofreecad(doc, fcpar or True)
            else:
                obj = doc.addObject("Part::Cut", namel)
                base = self.children[0].addtofreecad(doc, obj)

                if len(self.children) == 2:
                    tool = self.children[1].addtofreecad(doc, obj)
                else:
                    tool = Node(name='imp_union',\
                        children=self.children[1:]).addtofreecad(doc,obj)
                obj.Base = base
                obj.Tool = tool
                base.ViewObject.hide()
                tool.ViewObject.hide()
        elif namel == 'cube':
            obj = doc.addObject('Part::Box', namel)
            x, y, z = self.arguments['size']
            obj.Length = x
            obj.Width = y
            obj.Height = z
            if self.arguments['center']:
                center(obj, x, y, z)
        elif namel == 'sphere':
            obj = doc.addObject("Part::Sphere", namel)
            obj.Radius = self.arguments['r']
        elif namel == 'cylinder':
            h = self.arguments['h']
            r1, r2 = self.arguments['r1'], self.arguments['r2']
            if '$fn' in self.arguments and self.arguments['$fn'] > 2 \
            and self.arguments['$fn']<=Node.fnmin: # polygonal
                if r1 == r2:  # prismatic
                    obj = doc.addObject("Part::Prism", "prism")
                    obj.Polygon = int(self.arguments['$fn'])
                    obj.Circumradius = r1
                    obj.Height = h
                    if self.arguments['center']:
                        center(obj, 0, 0, h)
                    #base.ViewObject.hide()
                elif False:  #use Frustum Feature with makeRuledSurface
                    obj = doc.addObject("Part::FeaturePython", 'frustum')
                    Frustum(obj, r1, r2, int(self.arguments['$fn']), h)
                    ViewProviderTree(obj.ViewObject)
                    if self.arguments['center']:
                        center(obj, 0, 0, h)
                else:  #Use Part::Loft and GetWire Feature
                    obj = doc.addObject('Part::Loft', 'frustum')
                    import Draft
                    p1 = Draft.makePolygon(int(self.arguments['$fn']), r1)
                    p2 = Draft.makePolygon(int(self.arguments['$fn']), r2)
                    if self.arguments['center']:
                        p1.Placement = FreeCAD.Placement(\
                        FreeCAD.Vector(0.0,0.0,-h/2.0),FreeCAD.Rotation())
                        p2.Placement = FreeCAD.Placement(\
                        FreeCAD.Vector(0.0,0.0,h/2.0),FreeCAD.Rotation())
                    else:
                        p2.Placement = FreeCAD.Placement(\
                        FreeCAD.Vector(0.0,0.0,h),FreeCAD.Rotation())
                    w1 = doc.addObject("Part::FeaturePython", 'polygonwire1')
                    w2 = doc.addObject("Part::FeaturePython", 'polygonwire2')
                    GetWire(w1, p1)
                    GetWire(w2, p2)
                    ViewProviderTree(w1.ViewObject)
                    ViewProviderTree(w2.ViewObject)
                    obj.Sections = [w1, w2]
                    obj.Solid = True
                    obj.Ruled = True
                    p1.ViewObject.hide()
                    p2.ViewObject.hide()
                    w1.ViewObject.hide()
                    w2.ViewObject.hide()
            else:
                if r1 == r2:
                    obj = doc.addObject("Part::Cylinder", namel)
                    obj.Height = h
                    obj.Radius = r1
                else:
                    obj = doc.addObject("Part::Cone", 'cone')
                    obj.Height = h
                    obj.Radius1, obj.Radius2 = r1, r2
                if self.arguments['center']:
                    center(obj, 0, 0, h)
        elif namel == 'polyhedron':
            obj = doc.addObject("Part::Feature", namel)
            points = self.arguments['points']
            faces = self.arguments['triangles']
            shell=Part.Shell([Part.Face(Part.makePolygon(\
                    [tuple(points[pointindex]) for pointindex in \
                    (face+face[0:1])])) for face in faces])
            #            obj.Shape=Part.Solid(shell).removeSplitter()
            solid = Part.Solid(shell).removeSplitter()
            if solid.Volume < 0:
                #                solid.complement()
                solid.reverse()
            obj.Shape = solid  #.removeSplitter()

        elif namel == 'polygon':
            obj = doc.addObject("Part::Feature", namel)
            points = self.arguments['points']
            paths = self.arguments.get('paths')
            if not paths:
                faces = [
                    Part.Face(
                        Part.makePolygon([(x, y, 0)
                                          for x, y in points + points[0:1]]))
                ]
            else:
                faces= [Part.Face(Part.makePolygon([(points[pointindex][0],points[pointindex][1],0) for \
                    pointindex in (path+path[0:1])])) for path in paths]
            obj.Shape = subtractfaces(faces)
        elif namel == 'square':
            obj = doc.addObject("Part::Plane", namel)
            x, y = self.arguments['size']
            obj.Length = x
            obj.Width = y
            if self.arguments['center']:
                center(obj, x, y, 0)
        elif namel == 'circle':
            r = self.arguments['r']
            import Draft
            if '$fn' in self.arguments and self.arguments['$fn'] != 0 \
            and self.arguments['$fn']<=Node.fnmin:
                obj = Draft.makePolygon(int(self.arguments['$fn']), r)
            else:
                obj = Draft.makeCircle(r)  # create a Face
                #obj = doc.addObject("Part::Circle",namel);obj.Radius = r
        elif namel == 'color':
            if len(self.children) == 1:
                obj = self.children[0].addtofreecad(doc, fcpar or True)
            else:
                obj = Node(name='imp_union',\
                        children=self.children).addtofreecad(doc,fcpar or True)
            obj.ViewObject.ShapeColor = tuple(
                [float(p) for p in self.arguments[:3]])  #RGB
            transp = 100 - int(math.floor(100 * self.arguments[3]))  #Alpha
            obj.ViewObject.Transparency = transp
        elif namel == 'multmatrix':
            assert (len(self.children) > 0)
            m1l = [round(f, 12) for f in sum(self.arguments, [])
                   ]  #Thats the original matrix
            m1 = FreeCAD.Matrix(*tuple(m1l))  #Thats the original matrix
            if isspecialorthogonalpython(fcsubmatrix(
                    m1)):  #a Placement can represent the transformation
                if len(self.children) == 1:
                    obj = self.children[0].addtofreecad(doc, fcpar or True)
                else:
                    obj = Node(name='imp_union',\
                            children=self.children).addtofreecad(doc,fcpar or True)
                    #FreeCAD.Console.PrintMessage('obj %s\nmat %s/n' % (obj.Placement,m1))
                obj.Placement = FreeCAD.Placement(m1).multiply(obj.Placement)
            else:  #we need to apply the matrix transformation to the Shape using a custom PythonFeature
                obj = doc.addObject("Part::FeaturePython", namel)
                if len(self.children) == 1:
                    child = self.children[0].addtofreecad(doc, obj)
                else:
                    child = Node(name='imp_union',\
                            children=self.children).addtofreecad(doc,obj)
                MatrixTransform(
                    obj, m1, child)  #This object is not mutable from the GUI
                ViewProviderTree(obj.ViewObject)
        #elif namel == 'import': pass #Custom Feature
        elif namel == 'linear_extrude':
            height = self.arguments['height']
            twist = self.arguments.get('twist')
            if not twist:
                obj = doc.addObject("Part::Extrusion", namel)
            else:  #twist
                obj = doc.addObject("Part::FeaturePython", 'twist_extrude')
            if len(self.children) == 0:
                base = Node('import', self.arguments).addtofreecad(doc, obj)
            elif len(self.children) == 1:
                base = self.children[0].addtofreecad(doc, obj)
            else:
                base = Node(name='imp_union',\
                            children=self.children).addtofreecad(doc,obj)
            if False and base.isDerivedFrom('Part::MultiFuse'):
                #does not solve all the problems
                newobj = doc.addObject("Part::FeaturePython", 'refine')
                RefineShape(newobj, base)
                ViewProviderTree(newobj.ViewObject)
                base.ViewObject.hide()
                base = newobj
            if not twist:
                obj.Base = base
                obj.Dir = (0, 0, height)
            else:  #twist
                Twist(obj, base, height, -twist)
                ViewProviderTree(obj.ViewObject)
            if self.arguments['center']:
                center(obj, 0, 0, height)
            base.ViewObject.hide()

        elif namel == 'rotate_extrude':
            obj = doc.addObject("Part::Revolution", namel)
            if len(self.children) == 0:
                base = Node('import', self.arguments).addtofreecad(doc, obj)
            elif len(self.children) == 1:
                base = self.children[0].addtofreecad(doc, obj)
            else:
                base = Node(name='imp_union',\
                            children=self.children).addtofreecad(doc,obj)
            if False and base.isDerivedFrom('Part::MultiFuse'):
                #creates 'Axe and meridian are confused' Errors
                newobj = doc.addObject("Part::FeaturePython", 'refine')
                RefineShape(newobj, base)
                ViewProviderTree(newobj.ViewObject)
                base.ViewObject.hide()
                base = newobj
            obj.Source = base
            obj.Axis = (0.00, 1.00, 0.00)
            obj.Base = (0.00, 0.00, 0.00)
            obj.Angle = 360.00
            base.ViewObject.hide()
            obj.Placement = FreeCAD.Placement(FreeCAD.Vector(),
                                              FreeCAD.Rotation(0, 0, 90))
        elif namel == 'projection':
            if self.arguments['cut']:
                planename = 'xy_plane_used_for_project_cut'
                obj = doc.addObject('Part::MultiCommon', 'projection_cut')
                plane = doc.getObject(planename)
                if not plane:
                    plane = doc.addObject("Part::Plane", planename)
                    plane.Length = Node.planedim * 2
                    plane.Width = Node.planedim * 2
                    plane.Placement = FreeCAD.Placement(FreeCAD.Vector(\
                    -Node.planedim,-Node.planedim,0),FreeCAD.Rotation(0,0,0,1))
                #plane.ViewObject.hide()
                subobjs = [
                    child.addtofreecad(doc, obj) for child in self.children
                ]
                subobjs.append(plane)
                obj.Shapes = subobjs
                for subobj in subobjs:
                    subobj.ViewObject.hide()
            else:
                #Do a proper projection
                raise (NotImplementedError)
        elif namel == 'import':
            filename = self.arguments.get('file')
            scale = self.arguments.get('scale')
            origin = self.arguments.get('origin')
            if filename:
                import os
                docname = os.path.split(filename)[1]
                objname, extension = docname.split('.', 1)
                if not os.path.isabs(filename):
                    try:
                        global lastimportpath
                        filename = os.path.join(lastimportpath, filename)
                    except:
                        raise  #no path given
                # Check for a mesh fileformat support by the Mesh mddule
                if extension.lower() in reverseimporttypes()['Mesh']:
                    import Mesh
                    mesh1 = doc.getObject(objname)  #reuse imported object
                    if not mesh1:
                        Mesh.insert(filename)
                        mesh1 = doc.getObject(objname)
                    mesh1.ViewObject.hide()
                    sh = Part.Shape()
                    sh.makeShapeFromMesh(mesh1.Mesh.Topology, 0.1)
                    solid = Part.Solid(sh)
                    obj = doc.addObject("Part::FeaturePython",
                                        'import_%s_%s' % (extension, objname))
                    #obj=doc.addObject('Part::Feature',)
                    ImportObject(
                        obj, mesh1)  #This object is not mutable from the GUI
                    ViewProviderTree(obj.ViewObject)
                    solid = solid.removeSplitter()
                    if solid.Volume < 0:
                        #sh.reverse()
                        #sh = sh.copy()
                        solid.complement()
                    obj.Shape = solid  #.removeSplitter()
                elif extension in ['dxf']:
                    layera = self.arguments.get('layer')
                    featname = 'import_dxf_%s_%s' % (objname, layera)
                    # reusing an allready imported object does not work if the
                    #shape in not yet calculated
                    import importDXF
                    global dxfcache
                    layers = dxfcache.get(id(doc), [])
                    if layers:
                        groupobj = [
                            go for go in layers
                            if (not layera) or go.Label == layera
                        ]
                    else:
                        groupobj = None
                    if not groupobj:
                        groupname = objname
                        layers = importDXF.processdxf(
                            doc, filename) or importDXF.layers
                        dxfcache[id(doc)] = layers[:]
                        for l in layers:
                            for o in l.Group:
                                o.ViewObject.hide()
                            l.ViewObject.hide()
                        groupobj = [
                            go for go in layers
                            if (not layera) or go.Label == layera
                        ]
                    edges = []
                    for shapeobj in groupobj[0].Group:
                        edges.extend(shapeobj.Shape.Edges)
                    try:
                        f = edgestofaces(edges)
                    except Part.OCCError:
                        FreeCAD.Console.PrintError(\
 'processing of dxf import faild\nPlease rework \'%s\' manualy\n' % layera)
                        f = Part.Shape()  #empty Shape
                    obj = doc.addObject("Part::FeaturePython",
                                        'import_dxf_%s_%s' % (objname, layera))
                    #obj=doc.addObject('Part::Feature',)
                    ImportObject(
                        obj,
                        groupobj[0])  #This object is not mutable from the GUI
                    ViewProviderTree(obj.ViewObject)
                    obj.Shape = f

                else:
                    FreeCAD.Console.ErrorMessage(\
                            'Filetype of %s not supported\n' % (filename))
                    raise (NotImplementedError)
                if obj:  #handle origin and scale
                    if scale is not None and scale != 1:
                        if origin is not None and any([c != 0
                                                       for c in origin]):
                            raise (NotImplementedError
                                   )  # order of transformations unkown
                        child = obj
                        m1 = FreeCAD.Matrix()
                        m1.scale(scale, scale, scale)
                        obj = doc.addObject("Part::FeaturePython",
                                            'scale_import')
                        MatrixTransform(
                            obj, m1,
                            child)  #This object is not mutable from the GUI
                        ViewProviderTree(obj.ViewObject)
                    elif origin is not None and any([c != 0 for c in origin]):
                        placement = FreeCAD.Placement(
                            FreeCAD.Vector(*[-c for c in origin]),
                            FreeCAD.Rotation())
                        obj.Placement = placement.multiply(obj.Placement)
                else:
                    FreeCAD.Console.ErrorMessage('Import of %s failed\n' %
                                                 (filename))

        elif namel == 'minkowski':
            childrennames = [child.name.lower() for child in self.children]
            if len(self.children) == 2 and \
                childrennames.count('cube')==1 and \
                (childrennames.count('sphere') + \
                childrennames.count('cylinder')) == 1:
                if self.children[0].name.lower() == 'cube':
                    cube = self.children[0]
                    roundobj = self.children[1]
                elif self.children[1].name.lower() == 'cube':
                    cube = self.children[1]
                    roundobj = self.children[0]
                roundobjname = roundobj.name.lower()
                issphere = roundobjname == 'sphere'
                cubeobj = doc.addObject('Part::Box', 'roundedcube')
                x, y, z = cube.arguments['size']
                r=roundobj.arguments.get('r') or \
                        roundobj.arguments.get('r1')
                cubeobj.Length = x + 2 * r
                cubeobj.Width = y + 2 * r
                cubeobj.Height = z + 2 * r * issphere
                obj = doc.addObject("Part::Fillet",
                                    "%s_%s" % (namel, roundobjname))
                obj.Base = cubeobj
                cubeobj.ViewObject.hide()
                if issphere:
                    obj.Edges = [(i, r, r) for i in range(1, 13)]
                else:  #cylinder
                    obj.Edges = [(i, r, r) for i in [1, 3, 5, 7]]
                if cube.arguments['center']:
                    center(cubeobj, x + 2 * r, y + 2 * r, z + 2 * r * issphere)
                else:  #htandle a rotated cylinder
                    #OffsetShape
                    raise (NotImplementedError)
            elif childrennames.count('sphere') == 1:
                sphereindex = childrennames.index('sphere')
                sphere = self.children[sphereindex]
                offset = sphere.arguments['r']
                nonsphere=self.children[0:sphereindex]+\
                        self.sphere[sphereindex+1:]
                obj = doc.addObject("Part::FeaturePython", 'Offset')
                if len(nonsphere) == 1:
                    child = nonsphere[0].addtofreecad(doc, obj)
                else:
                    child = Node(name='imp_union',\
                        children=nonsphere).addtofreecad(doc,obj)
                OffsetShape(obj, child, offset)
                ViewProviderTree(obj.ViewObject)
            elif False:
                raise (NotImplementedError)
                pass  # handle rotated cylinders and select edges that
                #radius = radius0 * m1.multiply(FreeCAD.Vector(0,0,1)).dot(edge.Curve.tangent(0)[0])
            else:
                raise (NotImplementedError)
        elif namel == 'surface':
            obj = doc.addObject("Part::Feature", namel)  #include filename?
            obj.Shape, xoff, yoff = makeSurfaceVolume(self.arguments['file'])
            if self.arguments['center']:
                center(obj, xoff, yoff, 0.0)
            return obj
            #import os
            #scadstr = 'surface(file = "%s", center = %s );' % \
            #    (self.arguments['file'], 'true' if self.arguments['center'] else 'false')
            #docname=os.path.split(self.arguments['file'])[1]
            #objname,extension = docname.split('.',1)
            #obj = openscadmesh(doc,scadstr,objname)

        elif namel in ['glide', 'hull']:
            raise (NotImplementedError)
        elif namel in ['render', 'subdiv'] or True:
            lenchld = len(self.children)
            if lenchld == 1:
                FreeCAD.Console.PrintMessage('Not recognized %s\n' % (self))
                obj = self.children[0].addtofreecad(doc, fcpar)
            elif lenchld > 1:
                obj = Node(name='imp_union',\
                        children=self.children).addtofreecad(doc,fcpar or True)
            else:
                obj = doc.addObject("Part::Feature", 'Not_Impl_%s' % namel)
        if fcpar == True:  #We are the last real object, our parent is not rendered.
            return obj

        if fcpar:
            try:
                obj.ViewObject.hide()
            except:
                raise
            if True:  #never refine the Shape, as it itroduces crashes
                return obj
            else:  #refine Shape
                import Draft
                if obj.Type =='Part::Extrusion' and obj.Base.Type == 'Part::Part2DObjectPython' and \
                    isinstance(obj.Base.Proxy,Draft._Polygon) or \
                    (not obj.isDerivedFrom('Part::Extrusion') and \
                    not obj.isDerivedFrom('Part::Boolean') and \
                    not obj.isDerivedFrom('Part::Cut') and \
                    not obj.isDerivedFrom('Part::MultiCommon') and \
                    not obj.isDerivedFrom('Part::MultiFuse') and \
                    not obj.isDerivedFrom('Part::Revolution') ) \
                    or (obj.isDerivedFrom('Part::FeaturePython') and isinstance(obj.Proxy,RefineShape)):
                    return obj
                else:
                    newobj = doc.addObject("Part::FeaturePython", 'refine')
                    RefineShape(newobj, obj)
                    ViewProviderTree(newobj.ViewObject)
                    obj.ViewObject.hide()
                    return newobj

        else:
            doc.recompute()
Example #17
0
    def execute(self, obj):
        import Part, math, DraftGeomUtils
        pl = obj.Placement
        self.baseface = None

        base = None
        if obj.Base and obj.Angles:
            w = None
            if obj.Base.isDerivedFrom("Part::Feature"):
                if (obj.Base.Shape.Faces and obj.Face):
                    w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0]
                elif obj.Base.Shape.Wires:
                    w = obj.Base.Shape.Wires[0]
            if w:
                if w.isClosed():
                    self.profilsDico = []
                    self.shps = []
                    self.subVolshps = []
                    heights = []
                    edges = DraftGeomUtils.sortEdges(w.Edges)
                    l = len(edges)
                    print("le contour contient " + str(l) + " aretes")
                    for i in range(l):
                        self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i],
                                                obj.IdRel[i], obj.Overhang[i],
                                                obj.Thickness[i])
                    for i in range(l):
                        self.calcMissingData(i)
                    for i in range(l):
                        self.calcEdgeGeometry(edges, i)
                    for i in range(l):
                        self.calcDraftEdges(i)
                    for i in range(l):
                        self.calcEave(i)
                    for p in self.profilsDico:
                        heights.append(p["height"])
                    obj.Heights = heights
                    for i in range(l):
                        self.getRoofPaneProject(i)
                        profilCurrent = self.findProfil(i)
                        midpoint = DraftGeomUtils.findMidpoint(
                            profilCurrent["edge"])
                        ptsPaneProject = profilCurrent["points"]
                        lp = len(ptsPaneProject)
                        if lp != 0:
                            #print FreeCAD.Vector(ptsPaneProject[0])
                            ptsPaneProject.append(ptsPaneProject[0])
                            edgesWire = []
                            for p in range(lp):
                                edge = Part.makeLine(ptsPaneProject[p],
                                                     ptsPaneProject[p + 1])
                                edgesWire.append(edge)
                            wire = Part.Wire(edgesWire)
                            d = wire.BoundBox.DiagonalLength
                            thicknessV = profilCurrent["thickness"] / (
                                math.cos(math.radians(profilCurrent["angle"])))
                            overhangV = profilCurrent["overhang"] * math.tan(
                                math.radians(profilCurrent["angle"]))
                            if wire.isClosed():
                                f = Part.Face(wire)
                                #Part.show(f)
                                f = f.extrude(
                                    FreeCAD.Vector(
                                        0, 0, profilCurrent["height"] +
                                        2 * thicknessV + 2 * overhangV))
                                f.translate(
                                    FreeCAD.Vector(0.0, 0.0, -2 * overhangV))
                            ptsPaneProfil = [
                                FreeCAD.Vector(-profilCurrent["overhang"],
                                               -overhangV, 0.0),
                                FreeCAD.Vector(profilCurrent["run"],
                                               profilCurrent["height"], 0.0),
                                FreeCAD.Vector(
                                    profilCurrent["run"],
                                    profilCurrent["height"] + thicknessV, 0.0),
                                FreeCAD.Vector(-profilCurrent["overhang"],
                                               -overhangV + thicknessV, 0.0)
                            ]
                            self.createProfilShape(ptsPaneProfil, midpoint,
                                                   profilCurrent["rot"],
                                                   profilCurrent["vec"],
                                                   profilCurrent["run"], d,
                                                   self.shps, f)
                            ## subVolume shape
                            ptsSubVolumeProfil = [
                                FreeCAD.Vector(-profilCurrent["overhang"],
                                               -overhangV, 0.0),
                                FreeCAD.Vector(profilCurrent["run"],
                                               profilCurrent["height"], 0.0),
                                FreeCAD.Vector(profilCurrent["run"],
                                               profilCurrent["height"] + 10000,
                                               0.0),
                                FreeCAD.Vector(0.0,
                                               profilCurrent["height"] + 10000,
                                               0.0)
                            ]
                            self.createProfilShape(ptsSubVolumeProfil,
                                                   midpoint,
                                                   profilCurrent["rot"],
                                                   profilCurrent["vec"],
                                                   profilCurrent["run"], d,
                                                   self.subVolshps, f)

                    ## SubVolume
                    self.sub = self.subVolshps.pop()
                    for s in self.subVolshps:
                        self.sub = self.sub.fuse(s)
                    self.sub = self.sub.removeSplitter()
                    if not self.sub.isNull():
                        if not DraftGeomUtils.isNull(pl):
                            self.sub.Placement = pl
                    ## BaseVolume
                    base = Part.makeCompound(self.shps)
                    if not base.isNull():
                        if not DraftGeomUtils.isNull(pl):
                            base.Placement = pl
        base = self.processSubShapes(obj, base)
        if base:
            if not base.isNull():
                obj.Shape = base
Example #18
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
        def clasifySub(self, bs, sub):
            face = bs.Shape.getElement(sub)

            if type(face.Surface) == Part.Plane:
                PathLog.debug('type() == Part.Plane')
                if PathGeom.isVertical(face.Surface.Axis):
                    PathLog.debug('  -isVertical()')
                    # it's a flat horizontal face
                    self.horiz.append(face)
                    return True
                elif PathGeom.isHorizontal(face.Surface.Axis):
                    PathLog.debug('  -isHorizontal()')
                    self.vert.append(face)
                    return True
                else:
                    return False
            elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(
                    face.Surface.Axis):
                PathLog.debug('type() == Part.Cylinder')
                # vertical cylinder wall
                if any(e.isClosed() for e in face.Edges):
                    PathLog.debug('  -e.isClosed()')
                    # complete cylinder
                    circle = Part.makeCircle(face.Surface.Radius,
                                             face.Surface.Center)
                    disk = Part.Face(Part.Wire(circle))
                    disk.translate(
                        FreeCAD.Vector(0, 0, face.BoundBox.ZMin -
                                       disk.BoundBox.ZMin))
                    self.horiz.append(disk)
                    return True
                else:
                    PathLog.debug('  -none isClosed()')
                    # partial cylinder wall
                    self.vert.append(face)
                    return True
            elif type(face.Surface) == Part.SurfaceOfExtrusion:
                # extrusion wall
                PathLog.debug('type() == Part.SurfaceOfExtrusion')
                # Attempt to extract planar face from surface of extrusion
                (planar, useFace) = planarFaceFromExtrusionEdges(face,
                                                                 trans=True)
                # Save face object to self.horiz for processing or display error
                if planar is True:
                    uFace = FreeCAD.ActiveDocument.getObject(useFace)
                    self.horiz.append(uFace.Shape.Faces[0])
                    msg = translate(
                        'Path',
                        "<b>Verify depth of pocket for '{}'.</b>".format(sub))
                    msg += translate(
                        'Path', "\n<br>Pocket is based on extruded surface.")
                    msg += translate(
                        'Path',
                        "\n<br>Bottom of pocket might be non-planar and/or not normal to spindle axis."
                    )
                    msg += translate(
                        'Path',
                        "\n<br>\n<br><i>3D pocket bottom is NOT available in this operation</i>."
                    )
                    PathLog.warning(msg)
                    # title = translate('Path', 'Depth Warning')
                    # self.guiMessage(title, msg, False)
                else:
                    PathLog.error(
                        translate(
                            "Path",
                            "Failed to create a planar face from edges in {}.".
                            format(sub)))
            else:
                PathLog.debug('  -type(face.Surface): {}'.format(
                    type(face.Surface)))
                return False
Example #20
0
    def makeStraightLanding(self, obj, edge, numberofsteps=None):

        "builds a landing from a straight edge"

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

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

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

        reslength = fLength + (obj.StructureThickness / math.sin(a) -
                               (fHeight - obj.TreadThickness) / math.tan(a))
        if p7:
            p5 = p7.add(DraftVecUtils.scaleTo(vLength, reslength))
        else:
            p5 = p6.add(DraftVecUtils.scaleTo(vLength, reslength))
        resheight = obj.StructureThickness + obj.TreadThickness
        reslength = resheight / math.tan(a)
        p4 = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)).add(
            Vector(0, 0, -resheight))
        if obj.Structure == "Massive":
            if obj.StructureThickness:
                if p7:
                    struct = Part.Face(
                        Part.makePolygon([p1, p2, p3, p4, p5, p7, p6, p1]))
                else:
                    struct = Part.Face(
                        Part.makePolygon([p1, p2, p3, p4, p5, p6, p1]))
                evec = vWidth
                if obj.StructureOffset:
                    mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset)
                    struct.translate(mvec)
                    evec = DraftVecUtils.scaleTo(
                        evec, evec.Length - (2 * mvec.Length))
                struct = struct.extrude(evec)
        elif obj.Structure in ["One stringer", "Two stringers"]:
            if obj.StringerWidth and obj.StructureThickness:
                p1b = p1.add(Vector(0, 0, -fHeight))
                reslength = fHeight / math.tan(a)
                p1c = p1.add(DraftVecUtils.scaleTo(vLength, reslength))
                p5b = None
                p5c = None
                if obj.TreadThickness:
                    reslength = obj.StructureThickness / math.sin(a)
                    p5b = p5.add(DraftVecUtils.scaleTo(vLength, -reslength))
                    reslength = obj.TreadThickness / math.tan(a)
                    p5c = p5b.add(DraftVecUtils.scaleTo(
                        vLength,
                        -reslength)).add(Vector(0, 0, -obj.TreadThickness))
                    pol = Part.Face(
                        Part.makePolygon(
                            [p1c, p1b, p2, p3, p4, p5, p5b, p5c, p1c]))
                else:
                    pol = Part.Face(
                        Part.makePolygon([p1c, p1b, p2, p3, p4, p5, p1c]))
                evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth)
                if obj.Structure == "One stringer":
                    if obj.StructureOffset:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset)
                    else:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     (vWidth.Length / 2) -
                                                     obj.StringerWidth / 2)
                    pol.translate(mvec)
                    struct = pol.extrude(evec)
                elif obj.Structure == "Two stringers":
                    pol2 = pol.copy()
                    if obj.StructureOffset:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset)
                        pol.translate(mvec)
                        mvec = vWidth.add(mvec.negative())
                        pol2.translate(mvec)
                    else:
                        pol2.translate(vWidth)
                    s1 = pol.extrude(evec)
                    s2 = pol2.extrude(evec.negative())
                    struct = Part.makeCompound([s1, s2])
        if struct:
            self.structures.append(struct)
Example #21
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 #22
0
    def makeStraightStairs(self, obj, edge, numberofsteps=None):

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

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

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

        # structure
        lProfile = []
        struct = None
        if obj.Structure == "Massive":
            if obj.StructureThickness:
                for i in range(numberofsteps - 1):
                    if not lProfile:
                        lProfile.append(vBase)
                    last = lProfile[-1]
                    if len(lProfile) == 1:
                        last = last.add(Vector(0, 0, -abs(obj.TreadThickness)))
                    lProfile.append(last.add(vHeight))
                    lProfile.append(lProfile[-1].add(vLength))
                resHeight1 = obj.StructureThickness / math.cos(a)
                lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1)))
                resHeight2 = ((numberofsteps - 1) * vHeight.Length) - (
                    resHeight1 + obj.TreadThickness)
                resLength = (vLength.Length / vHeight.Length) * resHeight2
                h = DraftVecUtils.scaleTo(vLength, -resLength)
                lProfile.append(lProfile[-1].add(Vector(h.x, h.y,
                                                        -resHeight2)))
                lProfile.append(vBase)
                #print lProfile
                pol = Part.makePolygon(lProfile)
                struct = Part.Face(pol)
                evec = vWidth
                if obj.StructureOffset:
                    mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset)
                    struct.translate(mvec)
                    evec = DraftVecUtils.scaleTo(
                        evec, evec.Length - (2 * mvec.Length))
                struct = struct.extrude(evec)
        elif obj.Structure in ["One stringer", "Two stringers"]:
            if obj.StringerWidth and obj.StructureThickness:
                hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2)
                l1 = Vector(vLength).multiply(numberofsteps - 1)
                h1 = Vector(vHeight).multiply(numberofsteps - 1).add(
                    Vector(0, 0, -abs(obj.TreadThickness)))
                p1 = vBase.add(l1).add(h1)
                p1 = self.align(p1, obj.Align, vWidth)
                lProfile.append(p1)
                h2 = (obj.StructureThickness / vLength.Length) * hyp
                lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h2))))
                h3 = lProfile[-1].z - vBase.z
                l3 = (h3 / vHeight.Length) * vLength.Length
                v3 = DraftVecUtils.scaleTo(vLength, -l3)
                lProfile.append(lProfile[-1].add(Vector(0, 0,
                                                        -abs(h3))).add(v3))
                l4 = (obj.StructureThickness / vHeight.Length) * hyp
                v4 = DraftVecUtils.scaleTo(vLength, -l4)
                lProfile.append(lProfile[-1].add(v4))
                lProfile.append(lProfile[0])
                #print lProfile
                pol = Part.makePolygon(lProfile)
                pol = Part.Face(pol)
                evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth)
                if obj.Structure == "One stringer":
                    if obj.StructureOffset:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset)
                    else:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     (vWidth.Length / 2) -
                                                     obj.StringerWidth / 2)
                    pol.translate(mvec)
                    struct = pol.extrude(evec)
                elif obj.Structure == "Two stringers":
                    pol2 = pol.copy()
                    if obj.StructureOffset:
                        mvec = DraftVecUtils.scaleTo(vWidth,
                                                     obj.StructureOffset)
                        pol.translate(mvec)
                        mvec = vWidth.add(mvec.negative())
                        pol2.translate(mvec)
                    else:
                        pol2.translate(vWidth)
                    s1 = pol.extrude(evec)
                    s2 = pol2.extrude(evec.negative())
                    struct = Part.makeCompound([s1, s2])
        if struct:
            self.structures.append(struct)
Example #23
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.Line(V1,V2)
	# and the second one
	L2 = Part.Line(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()
def faceArray(tool, tool_face, base_faces, skip_edges, offset, align):
    tool_list = []
    for base_face in base_faces:
        skiplist = []
        # generate hashcode for skiped edges
        for skip_edge in skip_edges:
            skiplist.append(skip_edge.hashCode())
        # print(skiplist)

        wire_list = []
        # remove wires with skip edge specified based on hashcode
        for i, wire in enumerate(base_face.Wires):
            if i != 0:
                for edge in wire.Edges:
                    if edge.hashCode() in skiplist:
                        break
                if edge.hashCode() not in skiplist:
                    wire_list.append(wire)

        for wire in wire_list:
            tool_copy = tool.copy()
            make_face = Part.Face(wire)
            dir, point = face_direction(make_face)
            offsetPoint = point - base_face.CenterOfMass + dir * offset

            # Aligned, if align option specified
        if align:
            # Alignment Based on Largest edge of both faces
            size = 0.0
            for medge in make_face.Edges:
                if medge.Length > size and issubclass(type(medge.Curve),
                                                      (Part.Line)):
                    base_face_edge = medge
                    size = medge.Length
            # print(size)
            #Part.show(base_face_edge, "base_face_edge")
            base_vec = base_face_edge.valueAt(
                base_face_edge.LastParameter) - base_face_edge.valueAt(
                    base_face_edge.FirstParameter)

            size = 0.0
            for nedge in tool_face.Edges:
                if nedge.Length > size and issubclass(type(nedge.Curve),
                                                      (Part.Line)):
                    tool_face_edge = nedge
                    size = nedge.Length
            # print(size)
            #Part.show(tool_face_edge, "tool_face_edge")
            tool_vec = tool_face_edge.valueAt(
                tool_face_edge.LastParameter) - tool_face_edge.valueAt(
                    tool_face_edge.FirstParameter)

            #        # Alignment Based on boundbox (useful, if oriented boundbox available)
            #        base_vec = FreeCAD.Vector (make_face.BoundBox.XMax, make_face.BoundBox.YMax, make_face.BoundBox.ZMax)
            #              - FreeCAD.Vector (make_face.BoundBox.XMin, make_face.BoundBox.YMin, make_face.BoundBox.ZMin)
            #        tool_vec = FreeCAD.Vector (tool_face.BoundBox.XMax, tool_face.BoundBox.YMax, tool_face.BoundBox.ZMax)
            #                - FreeCAD.Vector (tool_face.BoundBox.XMin, tool_face.BoundBox.YMin, tool_face.BoundBox.ZMin)
            angle = angleBetween(base_vec, tool_vec)
            # print(angle)
            tool_tran = transform_tool(tool_copy, base_face, tool_face,
                                       offsetPoint, angle)
        else:
            tool_tran = transform_tool(tool_copy, base_face, tool_face,
                                       offsetPoint)
            #Part.show(tool_tran, "tool_tran")
            tool_list.append(tool_tran)
    return tool_list
Example #25
0
    def execute(self, obj):

        if self.clone(obj):
            return

        import Part, DraftGeomUtils

        pl = obj.Placement

        # test properties
        if not obj.Base:
            FreeCAD.Console.PrintLog(obj.Label + ": no base\n")
            return
        if not hasattr(obj.Base, "Shape"):
            FreeCAD.Console.PrintLog(obj.Label + ": invalid base\n")
            return
        if obj.VerticalMullionProfile:
            if not hasattr(obj.VerticalMullionProfile, "Shape"):
                FreeCAD.Console.PrintLog(
                    obj.Label + ": invalid vertical mullion profile\n")
                return
        if obj.HorizontalMullionProfile:
            if not hasattr(obj.HorizontalMullionProfile, "Shape"):
                FreeCAD.Console.PrintLog(
                    obj.Label + ": invalid horizontal mullion profile\n")
                return
        if obj.DiagonalMullionProfile:
            if not hasattr(obj.DiagonalMullionProfile, "Shape"):
                FreeCAD.Console.PrintLog(
                    obj.Label + ": invalid diagonal mullion profile\n")
                return

        facets = []

        faces = []
        if obj.Base.Shape.Faces:
            faces = obj.Base.Shape.Faces
        elif obj.Height.Value and obj.VerticalDirection.Length:
            ext = FreeCAD.Vector(obj.VerticalDirection)
            ext.normalize()
            ext = ext.multiply(obj.Height.Value)
            faces = [edge.extrude(ext) for edge in obj.Base.Shape.Edges]
        if not faces:
            FreeCAD.Console.PrintLog(obj.Label +
                                     ": unable to build base faces\n")
            return

        # subdivide the faces into quads
        for face in faces:

            fp = face.ParameterRange

            # guessing horizontal/vertical directions
            vdir = obj.VerticalDirection
            if not vdir.Length:
                vdir = FreeCAD.Vector(0, 0, 1)
            vdir.normalize()
            basevector = face.valueAt(fp[1],
                                      fp[3]).sub(face.valueAt(fp[0], fp[2]))
            a = basevector.getAngle(vdir)
            if (a <= math.pi / 2 + ANGLETOLERANCE) and (
                    a >= math.pi / 2 - ANGLETOLERANCE):
                facedir = True
                vertsec = obj.VerticalSections
                horizsec = obj.HorizontalSections
            else:
                facedir = False
                vertsec = obj.HorizontalSections
                horizsec = obj.VerticalSections

            hstep = (fp[1] - fp[0])
            if vertsec:
                hstep = hstep / vertsec
            vstep = (fp[3] - fp[2])
            if horizsec:
                vstep = vstep / horizsec

            # construct facets
            for i in range(vertsec or 1):
                for j in range(horizsec or 1):
                    p0 = face.valueAt(fp[0] + i * hstep, fp[2] + j * vstep)
                    p1 = face.valueAt(fp[0] + (i + 1) * hstep,
                                      fp[2] + j * vstep)
                    p2 = face.valueAt(fp[0] + (i + 1) * hstep,
                                      fp[2] + (j + 1) * vstep)
                    p3 = face.valueAt(fp[0] + i * hstep,
                                      fp[2] + (j + 1) * vstep)
                    facet = Part.Face(Part.makePolygon([p0, p1, p2, p3, p0]))
                    facets.append(facet)

        if not facets:
            FreeCAD.Console.PrintLog(obj.Label +
                                     ": failed to subdivide shape\n")
            return

        baseshape = Part.makeShell(facets)

        # make edge/normal relation table
        edgetable = {}
        for face in baseshape.Faces:
            for edge in face.Edges:
                ec = edge.hashCode()
                if ec in edgetable:
                    edgetable[ec].append(face)
                else:
                    edgetable[ec] = [face]
        self.edgenormals = {}
        for ec, faces in edgetable.items():
            if len(faces) == 1:
                self.edgenormals[ec] = faces[0].normalAt(0, 0)
            else:
                n = faces[0].normalAt(0, 0).add(faces[1].normalAt(0, 0))
                if n.Length > 0.001:
                    n.normalize()
                else:
                    # adjacent faces have same normals
                    n = faces[0].normalAt(0, 0)
                self.edgenormals[ec] = n

        # sort edges between vertical/horizontal
        hedges = []
        vedges = []
        for edge in baseshape.Edges:
            v = edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point)
            a = v.getAngle(vdir)
            if (a <= math.pi / 2 + ANGLETOLERANCE) and (
                    a >= math.pi / 2 - ANGLETOLERANCE):
                hedges.append(edge)
            else:
                vedges.append(edge)

        # construct vertical mullions
        vmullions = []
        vprofile = self.getMullionProfile(obj, "Vertical")
        if vprofile and vertsec:
            for vedge in vedges:
                vn = self.edgenormals[vedge.hashCode()]
                if (vn.x != 0) or (vn.y != 0):
                    avn = FreeCAD.Vector(vn.x, vn.y, 0)
                    rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0), avn)
                else:
                    rot = FreeCAD.Rotation()
                if obj.VerticalMullionAlignment:
                    ev = vedge.Vertexes[-1].Point.sub(vedge.Vertexes[0].Point)
                    rot = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0),
                                           ev).multiply(rot)
                vmullions.append(
                    self.makeMullion(vedge, vprofile, rot, obj.CenterProfiles))

        # construct horizontal mullions
        hmullions = []
        hprofile = self.getMullionProfile(obj, "Horizontal")
        if hprofile and horizsec:
            for hedge in hedges:
                rot = FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -90)
                vn = self.edgenormals[hedge.hashCode()]
                if (vn.x != 0) or (vn.y != 0):
                    avn = FreeCAD.Vector(vn.x, vn.y, 0)
                    rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0),
                                           avn).multiply(rot)
                    if obj.HorizontalMullionAlignment:
                        rot = FreeCAD.Rotation(avn, vn).multiply(rot)
                hmullions.append(
                    self.makeMullion(hedge, hprofile, rot, obj.CenterProfiles))

        # construct panels
        panels = []
        dedges = []
        if obj.PanelThickness.Value:
            for face in baseshape.Faces:
                verts = [v.Point for v in face.OuterWire.OrderedVertexes]
                if len(verts) == 4:
                    if DraftGeomUtils.isPlanar(verts):
                        panel = self.makePanel(verts, obj.PanelThickness.Value)
                        panels.append(panel)
                    else:
                        verts1 = [verts[0], verts[1], verts[2]]
                        panel = self.makePanel(verts1,
                                               obj.PanelThickness.Value)
                        panels.append(panel)
                        verts2 = [verts[0], verts[2], verts[3]]
                        panel = self.makePanel(verts2,
                                               obj.PanelThickness.Value)
                        panels.append(panel)
                        dedges.append(Part.makeLine(verts[0], verts[2]))

        # construct diagonal mullions
        dmullions = []
        if dedges:
            n = (dedges[0].Vertexes[-1].Point.sub(dedges[0].Point))
            dprofile = self.getMullionProfile(obj, "Diagonal")
            if dprofile:
                for dedge in dedges:
                    rot = FreeCAD.Rotation(
                        FreeCAD.Vector(0, 0, 1),
                        dedge.Vertexes[-1].Point.sub(dedge.Vertexes[0].Point))
                    dmullions.append(
                        self.makeMullion(dedge, dprofile, rot,
                                         obj.CenterProfiles))

        # perform subtractions
        if obj.Refine:
            subvmullion = None
            subhmullion = None
            subdmullion = None
            if vmullions:
                subvmullion = vmullions[0].copy()
                for m in vmullions[1:]:
                    subvmullion = subvmullion.fuse(m)
            if hmullions:
                subhmullion = hmullions[0].copy()
                for m in hmullions[1:]:
                    subhmullion = subhmullion.fuse(m)
            if dmullions:
                subdmullion = dmullions[0].copy()
                for m in dmullions[1:]:
                    subdmullion = subdmullion.fuse(m)
            if subvmullion:
                hmullions = [m.cut(subvmullion) for m in hmullions]
                if subhmullion:
                    dmullions = [m.cut(subvmullion) for m in dmullions]
                    dmullions = [m.cut(subhmullion) for m in dmullions]
                    panels = [m.cut(subvmullion) for m in panels]
                    panels = [m.cut(subhmullion) for m in panels]
                    if subdmullion:
                        panels = [m.cut(subdmullion) for m in panels]

        # mount shape
        obj.VerticalMullionNumber = len(vmullions)
        obj.HorizontalMullionNumber = len(hmullions)
        obj.DiagonalMullionNumber = len(dmullions)
        obj.PanelNumber = len(panels)
        shape = Part.makeCompound(vmullions + hmullions + dmullions + panels)
        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)
    def execute(self, obj):
        if not obj.Base:
            return
        if not obj.Base.Shape:
            return
        if not obj.Base.Shape.Wires:
            return

        pl = obj.Placement
        if obj.Base.Shape.Solids:
            obj.Shape = obj.Base.Shape.copy()
            if not pl.isNull():
                obj.Placement = obj.Shape.Placement.multiply(pl)
        else:
            if not obj.Profile:
                return
            if not obj.Profile.isDerivedFrom("Part::Part2DObject"):
                return
            if not obj.Profile.Shape:
                return
            if not obj.Profile.Shape.Wires:
                return
            if not obj.Profile.Shape.Faces:
                for w in obj.Profile.Shape.Wires:
                    if not w.isClosed():
                        return
            import DraftGeomUtils, Part, math
            baseprofile = obj.Profile.Shape.copy()
            if not baseprofile.Faces:
                f = []
                for w in baseprofile.Wires:
                    f.append(Part.Face(w))
                if len(f) == 1:
                    baseprofile = f[0]
                else:
                    baseprofile = Part.makeCompound(f)
            shapes = []
            normal = DraftGeomUtils.getNormal(obj.Base.Shape)
            #for wire in obj.Base.Shape.Wires:
            for e in obj.Base.Shape.Edges:
                #e = wire.Edges[0]
                bvec = DraftGeomUtils.vec(e)
                bpoint = e.Vertexes[0].Point
                profile = baseprofile.copy()
                #basepoint = profile.Placement.Base
                basepoint = profile.CenterOfMass
                profile.translate(bpoint.sub(basepoint))
                if obj.Align:
                    axis = profile.Placement.Rotation.multVec(
                        FreeCAD.Vector(0, 0, 1))
                    angle = bvec.getAngle(axis)
                    if round(angle, Draft.precision()) != 0:
                        if round(angle, Draft.precision()) != round(
                                math.pi, Draft.precision()):
                            rotaxis = axis.cross(bvec)
                            profile.rotate(DraftVecUtils.tup(bpoint),
                                           DraftVecUtils.tup(rotaxis),
                                           math.degrees(angle))
                if obj.Rotation:
                    profile.rotate(
                        DraftVecUtils.tup(bpoint),
                        DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()),
                        obj.Rotation)
                #profile = wire.makePipeShell([profile],True,False,2) TODO buggy
                profile = profile.extrude(bvec)
                if obj.Offset:
                    if not DraftVecUtils.isNull(obj.Offset):
                        profile.translate(obj.Offset)
                shapes.append(profile)
            if shapes:
                obj.Shape = Part.makeCompound(shapes)
                obj.Placement = pl
Example #27
0
    def execute(self, obj):
        "creates the panel shape"

        import Part, DraftGeomUtils

        # base tests
        if obj.Base:
            if obj.Base.isDerivedFrom("Part::Feature"):
                if obj.Base.Shape.isNull():
                    return
            elif obj.Base.isDerivedFrom("Mesh::Feature"):
                if not obj.Base.Mesh.isSolid():
                    return
        else:
            if obj.Length.Value:
                length = obj.Length.Value
            else:
                return
            if obj.Width.Value:
                width = obj.Width.Value
            else:
                return
        if obj.Thickness.Value:
            thickness = obj.Thickness.Value
        else:
            if not obj.Base:
                return
            elif obj.Base.isDerivedFrom("Part::Feature"):
                if not obj.Base.Solids:
                    return

        # creating base shape
        pl = obj.Placement
        base = None
        normal = None
        if obj.Base:
            p = FreeCAD.Placement(obj.Base.Placement)
            normal = p.Rotation.multVec(Vector(0, 0, 1))
            normal = normal.multiply(thickness)
            base = obj.Base.Shape.copy()
            if base.Solids:
                pass
            elif base.Faces:
                self.BaseProfile = base
                self.ExtrusionVector = normal
                base = base.extrude(normal)
            elif base.Wires:
                closed = True
                for w in base.Wires:
                    if not w.isClosed():
                        closed = False
                if closed:
                    base = ArchCommands.makeFace(base.Wires)
                    self.BaseProfile = base
                    self.ExtrusionVector = normal
                    base = base.extrude(normal)
            elif obj.Base.isDerivedFrom("Mesh::Feature"):
                if obj.Base.Mesh.isSolid():
                    if obj.Base.Mesh.countComponents() == 1:
                        sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh)
                        if sh.isClosed() and sh.isValid() and sh.Solids:
                            base = sh
        else:
            normal = Vector(0, 0, 1).multiply(thickness)
            self.ExtrusionVector = normal
            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.makePolygon([v1, v2, v3, v4, v1])
            base = Part.Face(base)
            self.BaseProfile = base
            base = base.extrude(self.ExtrusionVector)

        if base and (obj.Sheets > 1) and normal and thickness:
            bases = [base]
            for i in range(1, obj.Sheets):
                n = FreeCAD.Vector(normal).normalize().multiply(i * thickness)
                b = base.copy()
                b.translate(n)
                bases.append(b)
            base = Part.makeCompound(bases)

        if base and normal and hasattr(obj, "Offset"):
            if obj.Offset.Value:
                v = DraftVecUtils.scaleTo(normal, obj.Offset.Value)
                base.translate(v)

        # process subshapes
        base = self.processSubShapes(obj, base, pl)

        # applying
        if base:
            if not base.isNull():
                if base.isValid() and base.Solids:
                    if base.Volume < 0:
                        base.reverse()
                    if base.Volume < 0:
                        FreeCAD.Console.PrintError(
                            translate("Arch", "Couldn't compute a shape"))
                        return
                    base = base.removeSplitter()
                    obj.Shape = base
                    if not pl.isNull():
                        obj.Placement = pl
Example #28
0
    def Create(doc, constraint, solver, rigid1, rigid2):
        c = constraint

        if c.Type == "pointIdentity":
            dep1 = DependencyPointIdentity(c, "point")
            dep2 = DependencyPointIdentity(c, "point")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)

            vert1 = getObjectVertexFromName(ob1, c.SubElement1)
            vert2 = getObjectVertexFromName(ob2, c.SubElement2)
            dep1.refPoint = vert1.Point
            dep2.refPoint = vert2.Point

        elif c.Type == "sphereCenterIdent":
            dep1 = DependencyPointIdentity(c, "point")
            dep2 = DependencyPointIdentity(c, "point")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)

            vert1 = getPos(ob1, c.SubElement1)
            vert2 = getPos(ob2, c.SubElement2)
            dep1.refPoint = vert1
            dep2.refPoint = vert2

        elif c.Type == "pointOnLine":
            dep1 = DependencyPointOnLine(c, "point")
            dep2 = DependencyPointOnLine(c, "pointAxis")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)

            #vert1 = getObjectVertexFromName(ob1, c.SubElement1)
            #dep1.refPoint = vert1.Point
            dep1.refPoint = getPos(ob1, c.SubElement1)
            dep2.refPoint = getPos(ob2, c.SubElement2)

            axis2 = getAxis(ob2, c.SubElement2)
            dep2.refAxisEnd = dep2.refPoint.add(axis2)

        elif c.Type == "pointOnPlane":
            dep1 = DependencyPointOnPlane(c, "point")
            dep2 = DependencyPointOnPlane(c, "plane")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)

            #vert1 = getObjectVertexFromName(ob1, c.SubElement1)
            dep1.refPoint = getPos(ob1, c.SubElement1)

            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            normal2 = a2plib.getPlaneNormal(plane2.Surface)
            #shift refPoint of plane by offset
            try:
                offs = c.offset
            except:
                offs = 0.0
            offsetVector = Base.Vector(normal2)
            offsetVector.multiply(offs)
            dep2.refPoint = dep2.refPoint.add(offsetVector)

            dep2.refAxisEnd = dep2.refPoint.add(normal2)

        elif c.Type == "circularEdge":
            dep1 = DependencyCircularEdge(c, "pointAxis")
            dep2 = DependencyCircularEdge(c, "pointAxis")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            circleEdge1 = getObjectEdgeFromName(ob1, c.SubElement1)
            circleEdge2 = getObjectEdgeFromName(ob2, c.SubElement2)
            dep1.refPoint = circleEdge1.Curve.Center
            dep2.refPoint = circleEdge2.Curve.Center

            axis1 = circleEdge1.Curve.Axis
            axis2 = circleEdge2.Curve.Axis
            if dep2.direction == "opposed":
                axis2.multiply(-1.0)
            dep1.refAxisEnd = dep1.refPoint.add(axis1)
            dep2.refAxisEnd = dep2.refPoint.add(axis2)
            #
            if abs(dep2.offset) > solver.mySOLVER_SPIN_ACCURACY * 1e-1:
                offsetAdjustVec = Base.Vector(axis2.x, axis2.y, axis2.z)
                offsetAdjustVec.multiply(dep2.offset)
                dep2.refPoint = dep2.refPoint.add(offsetAdjustVec)
                dep2.refAxisEnd = dep2.refAxisEnd.add(offsetAdjustVec)

        elif c.Type == "planesParallel":
            dep1 = DependencyParallelPlanes(c, "pointNormal")
            dep2 = DependencyParallelPlanes(c, "pointNormal")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            plane1 = getObjectFaceFromName(ob1, c.SubElement1)
            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep1.refPoint = plane1.Faces[0].BoundBox.Center
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            normal1 = a2plib.getPlaneNormal(plane1.Surface)
            normal2 = a2plib.getPlaneNormal(plane2.Surface)

            if dep2.direction == "opposed":
                normal2.multiply(-1.0)
            dep1.refAxisEnd = dep1.refPoint.add(normal1)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)

        elif c.Type == "angledPlanes":
            dep1 = DependencyAngledPlanes(c, "pointNormal")
            dep2 = DependencyAngledPlanes(c, "pointNormal")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            plane1 = getObjectFaceFromName(ob1, c.SubElement1)
            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep1.refPoint = plane1.Faces[0].BoundBox.Center
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            normal1 = a2plib.getPlaneNormal(plane1.Surface)
            normal2 = a2plib.getPlaneNormal(plane2.Surface)
            dep1.refAxisEnd = dep1.refPoint.add(normal1)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)

        elif c.Type == "plane":
            dep1 = DependencyPlane(c, "pointNormal")
            dep2 = DependencyPlane(c, "pointNormal")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            plane1 = getObjectFaceFromName(ob1, c.SubElement1)
            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep1.refPoint = plane1.Faces[0].BoundBox.Center
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            normal1 = a2plib.getPlaneNormal(plane1.Surface)
            normal2 = a2plib.getPlaneNormal(plane2.Surface)
            if dep2.direction == "opposed":
                normal2.multiply(-1.0)
            dep1.refAxisEnd = dep1.refPoint.add(normal1)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)
            #
            if abs(dep2.offset) > solver.mySOLVER_SPIN_ACCURACY * 1e-1:
                offsetAdjustVec = Base.Vector(normal2.x, normal2.y, normal2.z)
                offsetAdjustVec.multiply(dep2.offset)
                dep2.refPoint = dep2.refPoint.add(offsetAdjustVec)
                dep2.refAxisEnd = dep2.refAxisEnd.add(offsetAdjustVec)

        elif c.Type == "axial":
            dep1 = DependencyAxial(c, "pointAxis")
            dep2 = DependencyAxial(c, "pointAxis")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            dep1.refPoint = getPos(ob1, c.SubElement1)
            dep2.refPoint = getPos(ob2, c.SubElement2)
            axis1 = getAxis(ob1, c.SubElement1)
            axis2 = getAxis(ob2, c.SubElement2)
            if dep2.direction == "opposed":
                axis2.multiply(-1.0)

            dep1.refPoint = dep1.adjustRefPoints(ob1, c.SubElement1,
                                                 dep1.refPoint, axis1)
            dep2.refPoint = dep2.adjustRefPoints(ob2, c.SubElement2,
                                                 dep2.refPoint, axis2)

            dep1.refAxisEnd = dep1.refPoint.add(axis1)
            dep2.refAxisEnd = dep2.refPoint.add(axis2)

        elif c.Type == "axisParallel":
            dep1 = DependencyAxisParallel(c, "pointAxis")
            dep2 = DependencyAxisParallel(c, "pointAxis")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            dep1.refPoint = getPos(ob1, c.SubElement1)
            dep2.refPoint = getPos(ob2, c.SubElement2)
            axis1 = getAxis(ob1, c.SubElement1)
            axis2 = getAxis(ob2, c.SubElement2)
            if dep2.direction == "opposed":
                axis2.multiply(-1.0)

            dep1.refAxisEnd = dep1.refPoint.add(axis1)
            dep2.refAxisEnd = dep2.refPoint.add(axis2)

        elif c.Type == "axisPlaneParallel":
            dep1 = DependencyAxisPlaneParallel(c, "pointAxis")
            dep2 = DependencyAxisPlaneParallel(c, "pointNormal")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            axis1 = getAxis(ob1, c.SubElement1)
            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep1.refPoint = getPos(ob1, c.SubElement1)
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            axis1Normalized = Base.Vector(axis1)
            axis1Normalized.normalize()
            dep1.refAxisEnd = dep1.refPoint.add(axis1Normalized)

            normal2 = a2plib.getPlaneNormal(plane2.Surface)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)

        elif c.Type == "axisPlaneVertical" or c.Type == "axisPlaneNormal":  # axisPlaneVertical for compat.
            dep1 = DependencyAxisPlaneNormal(c, "pointAxis")
            dep2 = DependencyAxisPlaneNormal(c, "pointNormal")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)
            axis1 = getAxis(ob1, c.SubElement1)
            plane2 = getObjectFaceFromName(ob2, c.SubElement2)
            dep1.refPoint = getPos(ob1, c.SubElement1)
            dep2.refPoint = plane2.Faces[0].BoundBox.Center

            axis1Normalized = Base.Vector(axis1)
            axis1Normalized.normalize()
            dep1.refAxisEnd = dep1.refPoint.add(axis1Normalized)

            normal2 = a2plib.getPlaneNormal(plane2.Surface)
            if dep2.direction == "opposed":
                normal2.multiply(-1.0)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)

        elif c.Type == "CenterOfMass":
            dep1 = DependencyCenterOfMass(c, "point")
            dep2 = DependencyCenterOfMass(c, "point")

            ob1 = doc.getObject(c.Object1)
            ob2 = doc.getObject(c.Object2)

            if c.SubElement1.startswith('Face'):
                plane1 = getObjectFaceFromName(ob1, c.SubElement1)
                dep1.refPoint = plane1.Faces[0].CenterOfMass
            elif c.SubElement1.startswith('Edge'):
                plane1 = Part.Face(
                    Part.Wire(getObjectEdgeFromName(ob1, c.SubElement1)))
                dep1.refPoint = plane1.CenterOfMass
            if c.SubElement2.startswith('Face'):
                plane2 = getObjectFaceFromName(ob2, c.SubElement2)
                dep2.refPoint = plane2.Faces[0].CenterOfMass
            elif c.SubElement2.startswith('Edge'):
                plane2 = Part.Face(
                    Part.Wire(getObjectEdgeFromName(ob2, c.SubElement2)))
                dep2.refPoint = plane2.CenterOfMass

            normal1 = a2plib.getPlaneNormal(plane1.Surface)
            normal2 = a2plib.getPlaneNormal(plane2.Surface)

            if dep2.direction == "opposed":
                normal2.multiply(-1.0)
            dep1.refAxisEnd = dep1.refPoint.add(normal1)
            dep2.refAxisEnd = dep2.refPoint.add(normal2)
            #  to be improved: toggle direction even if offset == 0.0
            if abs(dep2.offset) > solver.mySOLVER_SPIN_ACCURACY * 1e-1:
                offsetAdjustVec = Base.Vector(normal2.x, normal2.y, normal2.z)
                offsetAdjustVec.multiply(dep2.offset)
                dep2.refPoint = dep2.refPoint.add(offsetAdjustVec)
                dep2.refAxisEnd = dep2.refAxisEnd.add(offsetAdjustVec)

        else:
            raise NotImplementedError(
                "Constraint type {} was not implemented!".format(c.Type))

        # Assignments
        dep1.currentRigid = rigid1
        dep1.dependedRigid = rigid2
        dep1.foreignDependency = dep2

        dep2.currentRigid = rigid2
        dep2.dependedRigid = rigid1
        dep2.foreignDependency = dep1

        rigid1.dependencies.append(dep1)
        rigid2.dependencies.append(dep2)
Example #29
0
    def __init__(
            self,
            block_dict,
            rail_dict,
            axis_d=VX,
            axis_w=V0,
            axis_h=VZ,
            pos_d=0,
            pos_w=0,
            pos_h=0,
            pos=V0,
            model_type=1,  # dimensional model
            name=None):

        self.pos = FreeCAD.Vector(0, 0, 0)
        self.position = pos

        if name == None:
            self.name = block_dict['name'] + '_block'

        if rail_dict is None:
            self.rail_h = 0
            self.rail_w = 0
        else:
            self.rail_h = rail_dict['rh']
            self.rail_w = rail_dict['rw']

        if (axis_w is None) or (axis_w == V0):
            axis_w = axis_h.cross(axis_d)

        Obj3D.__init__(self, axis_d, axis_w, axis_h, self.name)

        self.block_d = block_dict['bl']
        self.block_ds = block_dict['bls']
        self.block_w = block_dict['bw']
        self.block_ws = block_dict['bws']
        self.block_h = block_dict['bh']

        self.linguide_h = block_dict['lh']

        self.bolt_dsep = block_dict['boltlsep']
        self.bolt_wsep = block_dict['boltwsep']
        self.bolt_d = block_dict['boltd']
        self.bolt_l = block_dict['boltl']

        linguide_h = block_dict['lh']

        # save the arguments as attributes:
        frame = inspect.currentframe()
        args, _, _, values = inspect.getargvalues(frame)
        for i in args:
            if not hasattr(self, i):
                setattr(self, i, values[i])

        self.d0_cen = 1  # symmetric
        self.w0_cen = 1  # symmetric
        self.h0_cen = 0

        if self.bolt_l == 0:  # thruhole
            self.bolt_l = self.block_h
            self.thruhole = 1
        else:
            self.thruhole = 0

        if self.rail_h == 0 or linguide_h == 0:
            self.rail_h = 0
            self.linguide_h = 0
            self.rail_ins_h = 0
            self.rail_bot_h = 0
        else:
            self.rail_ins_h = self.block_h - (self.linguide_h - self.rail_h)
            self.rail_bot_h = self.rail_h - self.rail_ins_h

        # vectors from the origin to the points along axis_d:
        self.d_o[0] = V0  # Origin (center symmetric)
        self.d_o[1] = self.vec_d(-self.bolt_dsep / 2.)
        self.d_o[2] = self.vec_d(-self.block_ds / 2.)
        self.d_o[3] = self.vec_d(-self.block_d / 2.)

        # vectors from the origin to the points along axis_w:
        self.w_o[0] = V0  # Origin (center symmetric)
        self.w_o[1] = self.vec_w(-self.rail_w / 2.)
        self.w_o[2] = self.vec_w(-self.bolt_wsep / 2.)
        self.w_o[3] = self.vec_w(-self.block_ws / 2.)
        self.w_o[4] = self.vec_w(-self.block_w / 2.)

        # vectors from the origin to the points along axis_h:
        # could make more sense to have the origin at the top
        self.h_o[0] = V0  # Origin at the bottom
        self.h_o[1] = self.vec_h(self.rail_ins_h)
        self.h_o[2] = self.vec_h(self.block_h - self.bolt_l)
        self.h_o[3] = self.vec_h(self.block_h)
        self.h_o[4] = self.vec_h(-self.rail_bot_h)

        # calculates the position of the origin, and keeps it in attribute pos_o
        self.set_pos_o()

        # the main block
        shp_mblock = fcfun.shp_box_dir(box_w=self.block_w,
                                       box_d=self.block_ds,
                                       box_h=self.block_h,
                                       fc_axis_w=self.axis_w,
                                       fc_axis_d=self.axis_d,
                                       fc_axis_h=self.axis_h,
                                       cw=1,
                                       cd=1,
                                       ch=0,
                                       pos=self.pos_o)

        # the extra block
        shp_exblock = fcfun.shp_box_dir(box_w=self.block_ws,
                                        box_d=self.block_d,
                                        box_h=self.block_h,
                                        fc_axis_w=self.axis_w,
                                        fc_axis_d=self.axis_d,
                                        fc_axis_h=self.axis_h,
                                        cw=1,
                                        cd=1,
                                        ch=0,
                                        pos=self.pos_o)

        # fusion of these blocks
        shp_block = shp_mblock.fuse(shp_exblock)

        holes_list = []

        # rail hole:
        if self.rail_h > 0 and self.rail_w > 0:
            wire_rail = fcfun.wire_lgrail(rail_w=self.rail_w,
                                          rail_h=self.rail_h,
                                          axis_w=self.axis_w,
                                          axis_h=self.axis_h,
                                          pos_w=0,
                                          pos_h=0,
                                          pos=self.get_pos_h(4))

            face_rail = Part.Face(wire_rail)
            shp_rail = fcfun.shp_extrud_face(face=face_rail,
                                             length=self.block_d + 2,
                                             vec_extr_axis=self.axis_d,
                                             centered=1)

            #Part.show(shp_rail)
            holes_list.append(shp_rail)

        # bolt holes:
        for d_i in (-1, 1):  # positions of the holes along axis_d
            for w_i in (-2, 2):  # positions of the holes along axis_w
                shp_bolt = fcfun.shp_cylcenxtr(r=self.bolt_d / 2.,
                                               h=self.bolt_l,
                                               normal=axis_h,
                                               ch=0,
                                               xtr_top=1,
                                               xtr_bot=self.thruhole,
                                               pos=self.get_pos_dwh(
                                                   d_i, w_i, 2))
                holes_list.append(shp_bolt)

        shp_holes = fcfun.fuseshplist(holes_list)
        shp_block = shp_block.cut(shp_holes)
        shp_block = shp_block.removeSplitter()

        self.shp = shp_block
        super().create_fco(self.name)
        # Need to set first in (0,0,0) and after that set the real placement.
        # This enable to do rotations without any issue
        self.fco.Placement.Base = FreeCAD.Vector(0, 0, 0)
        self.fco.Placement.Base = self.position
Example #30
0
    def calculateAdaptivePocket(self, obj, base, subObjTups):
        '''calculateAdaptivePocket(obj, base, subObjTups)
        Orient multiple faces around common facial center of mass.
        Identify edges that are connections for adjacent faces.
        Attempt to separate unconnected edges into top and bottom loops of the pocket.
        Trim the top and bottom of the pocket if available and requested.
        return: tuple with pocket shape information'''
        low = []
        high = []
        removeList = []
        Faces = []
        allEdges = []
        makeHighFace = 0
        tryNonPlanar = False
        isHighFacePlanar = True
        isLowFacePlanar = True
        faceType = 0

        for (sub, face) in subObjTups:
            Faces.append(face)

        # identify max and min face heights for top loop
        (zmin, zmax) = self.getMinMaxOfFaces(Faces)

        # Order faces around common center of mass
        subObjTups = self.orderFacesAroundCenterOfMass(subObjTups)
        # find connected edges and map to edge names of base
        (connectedEdges, touching) = self.findSharedEdges(subObjTups)
        (low, high) = self.identifyUnconnectedEdges(subObjTups, touching)

        if len(high) > 0 and obj.AdaptivePocketStart is True:
            # attempt planar face with top edges of pocket
            allEdges = []
            makeHighFace = 0
            tryNonPlanar = False
            for (sub, face, ei) in high:
                allEdges.append(face.Edges[ei])

            (hzmin, hzmax) = self.getMinMaxOfFaces(allEdges)

            try:
                highFaceShape = Part.Face(
                    Part.Wire(Part.__sortEdges__(allEdges)))
            except Exception as ee:
                PathLog.warning(ee)
                PathLog.error(
                    translate(
                        "Path",
                        "A planar adaptive start is unavailable. The non-planar will be attempted."
                    ))
                tryNonPlanar = True
            else:
                makeHighFace = 1

            if tryNonPlanar is True:
                try:
                    highFaceShape = Part.makeFilledFace(
                        Part.__sortEdges__(allEdges))  # NON-planar face method
                except Exception as eee:
                    PathLog.warning(eee)
                    PathLog.error(
                        translate(
                            "Path",
                            "The non-planar adaptive start is also unavailable."
                        ) + "(1)")
                    isHighFacePlanar = False
                else:
                    makeHighFace = 2

            if makeHighFace > 0:
                FreeCAD.ActiveDocument.addObject('Part::Feature',
                                                 'topEdgeFace')
                highFace = FreeCAD.ActiveDocument.ActiveObject
                highFace.Shape = highFaceShape
                removeList.append(highFace.Name)

            # verify non-planar face is within high edge loop Z-boundaries
            if makeHighFace == 2:
                mx = hzmax + obj.StepDown.Value
                mn = hzmin - obj.StepDown.Value
                if highFace.Shape.BoundBox.ZMax > mx or highFace.Shape.BoundBox.ZMin < mn:
                    PathLog.warning("ZMaxDiff: {};  ZMinDiff: {}".format(
                        highFace.Shape.BoundBox.ZMax - mx,
                        highFace.Shape.BoundBox.ZMin - mn))
                    PathLog.error(
                        translate(
                            "Path",
                            "The non-planar adaptive start is also unavailable."
                        ) + "(2)")
                    isHighFacePlanar = False
                    makeHighFace = 0
        else:
            isHighFacePlanar = False

        if len(low) > 0 and obj.AdaptivePocketFinish is True:
            # attempt planar face with bottom edges of pocket
            allEdges = []
            for (sub, face, ei) in low:
                allEdges.append(face.Edges[ei])

            # (lzmin, lzmax) = self.getMinMaxOfFaces(allEdges)

            try:
                lowFaceShape = Part.Face(
                    Part.Wire(Part.__sortEdges__(allEdges)))
                # lowFaceShape = Part.makeFilledFace(Part.__sortEdges__(allEdges))  # NON-planar face method
            except Exception as ee:
                PathLog.error(ee)
                PathLog.error("An adaptive finish is unavailable.")
                isLowFacePlanar = False
            else:
                FreeCAD.ActiveDocument.addObject('Part::Feature',
                                                 'bottomEdgeFace')
                lowFace = FreeCAD.ActiveDocument.ActiveObject
                lowFace.Shape = lowFaceShape
                removeList.append(lowFace.Name)
        else:
            isLowFacePlanar = False

        # Start with a regular pocket envelope
        strDep = obj.StartDepth.Value
        finDep = obj.FinalDepth.Value
        cuts = []
        starts = []
        finals = []
        starts.append(obj.StartDepth.Value)
        finals.append(zmin)
        if obj.AdaptivePocketStart is True or len(subObjTups) == 1:
            strDep = zmax + obj.StepDown.Value
            starts.append(zmax + obj.StepDown.Value)

        finish_step = obj.FinishDepth.Value if hasattr(obj,
                                                       "FinishDepth") else 0.0
        depthparams = PathUtils.depth_params(
            clearance_height=obj.ClearanceHeight.Value,
            safe_height=obj.SafeHeight.Value,
            start_depth=strDep,
            step_down=obj.StepDown.Value,
            z_finish_step=finish_step,
            final_depth=finDep,
            user_depths=None)
        shape = Part.makeCompound(Faces)
        env = PathUtils.getEnvelope(base[0].Shape,
                                    subshape=shape,
                                    depthparams=depthparams)
        cuts.append(env.cut(base[0].Shape))

        # Might need to change to .cut(job.Stock.Shape) if pocket has no bottom
        # job = PathUtils.findParentJob(obj)
        # envBody = env.cut(job.Stock.Shape)

        if isHighFacePlanar is True and len(subObjTups) > 1:
            starts.append(hzmax + obj.StepDown.Value)
            # make shape to trim top of reg pocket
            strDep1 = obj.StartDepth.Value + (hzmax - hzmin)
            if makeHighFace == 1:
                # Planar face
                finDep1 = highFace.Shape.BoundBox.ZMin + obj.StepDown.Value
            else:
                # Non-Planar face
                finDep1 = hzmin + obj.StepDown.Value
            depthparams1 = PathUtils.depth_params(
                clearance_height=obj.ClearanceHeight.Value,
                safe_height=obj.SafeHeight.Value,
                start_depth=strDep1,
                step_down=obj.StepDown.Value,
                z_finish_step=finish_step,
                final_depth=finDep1,
                user_depths=None)
            envTop = PathUtils.getEnvelope(base[0].Shape,
                                           subshape=highFace.Shape,
                                           depthparams=depthparams1)
            cbi = len(cuts) - 1
            cuts.append(cuts[cbi].cut(envTop))

        if isLowFacePlanar is True and len(subObjTups) > 1:
            # make shape to trim top of pocket
            if makeHighFace == 1:
                # Planar face
                strDep2 = lowFace.Shape.BoundBox.ZMax
            else:
                # Non-Planar face
                strDep2 = hzmax
            finDep2 = obj.FinalDepth.Value
            depthparams2 = PathUtils.depth_params(
                clearance_height=obj.ClearanceHeight.Value,
                safe_height=obj.SafeHeight.Value,
                start_depth=strDep2,
                step_down=obj.StepDown.Value,
                z_finish_step=finish_step,
                final_depth=finDep2,
                user_depths=None)
            envBottom = PathUtils.getEnvelope(base[0].Shape,
                                              subshape=lowFace.Shape,
                                              depthparams=depthparams2)
            cbi = len(cuts) - 1
            cuts.append(cuts[cbi].cut(envBottom))

        # package pocket details into tuple
        sdi = len(starts) - 1
        fdi = len(finals) - 1
        cbi = len(cuts) - 1
        pocket = (cuts[cbi], False, '3DPocket', 0.0, 'X', starts[sdi],
                  finals[fdi])
        if FreeCAD.GuiUp:
            import FreeCADGui
            for rn in removeList:
                FreeCADGui.ActiveDocument.getObject(rn).Visibility = False

        for rn in removeList:
            FreeCAD.ActiveDocument.getObject(rn).purgeTouched()
            self.tempObjectNames.append(rn)
        return pocket