Пример #1
0
def make_sketch(objectslist,
                autoconstraints=False,
                addTo=None,
                delete=False,
                name="Sketch",
                radiusPrecision=-1):
    """makeSketch(objectslist,[autoconstraints],[addTo],[delete],[name],[radiusPrecision])

    Makes a Sketch objectslist with the given Draft objects.

    Parameters
    ----------
    objectlist: can be single or list of objects of Draft type objects,
        Part::Feature, Part.Shape, or mix of them.

    autoconstraints(False): if True, constraints will be automatically added to
        wire nodes, rectangles and circles.

    addTo(None) : if set to an existing sketch, geometry will be added to it
        instead of creating a new one.

    delete(False): if True, the original object will be deleted.
        If set to a string 'all' the object and all its linked object will be
        deleted

    name('Sketch'): the name for the new sketch object

    radiusPrecision(-1): If <0, disable radius constraint. If =0, add indiviaul
        radius constraint. If >0, the radius will be rounded according to this
        precision, and 'Equal' constraint will be added to curve with equal
        radius within precision.
    """

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

    import Part
    from Sketcher import Constraint
    import Sketcher

    StartPoint = 1
    EndPoint = 2
    MiddlePoint = 3
    deletable = None

    if not isinstance(objectslist, (list, tuple)):
        objectslist = [objectslist]
    for obj in objectslist:
        if isinstance(obj, Part.Shape):
            shape = obj
        elif not hasattr(obj, 'Shape'):
            App.Console.PrintError(translate("draft", "not shape found"))
            return None
        else:
            shape = obj.Shape
        if not DraftGeomUtils.isPlanar(shape):
            App.Console.PrintError(
                translate("draft", "All Shapes must be co-planar"))
            return None
    if addTo:
        nobj = addTo
    else:
        nobj = App.ActiveDocument.addObject("Sketcher::SketchObject", name)
        deletable = nobj
        if App.GuiUp:
            nobj.ViewObject.Autoconstraints = False

    # Collect constraints and add in one go to improve performance
    constraints = []
    radiuses = {}

    def addRadiusConstraint(edge):
        try:
            if radiusPrecision < 0:
                return
            if radiusPrecision == 0:
                constraints.append(
                    Constraint('Radius', nobj.GeometryCount - 1,
                               edge.Curve.Radius))
                return
            r = round(edge.Curve.Radius, radiusPrecision)
            constraints.append(
                Constraint('Equal', radiuses[r], nobj.GeometryCount - 1))
        except KeyError:
            radiuses[r] = nobj.GeometryCount - 1
            constraints.append(Constraint('Radius', nobj.GeometryCount - 1, r))
        except AttributeError:
            pass

    def convertBezier(edge):
        if DraftGeomUtils.geomType(edge) == "BezierCurve":
            return (edge.Curve.toBSpline(edge.FirstParameter,
                                         edge.LastParameter).toShape())
        else:
            return (edge)

    rotation = None
    for obj in objectslist:
        ok = False
        tp = utils.get_type(obj)
        if tp in ["Circle", "Ellipse"]:
            if obj.Shape.Edges:
                if rotation is None:
                    rotation = obj.Placement.Rotation
                edge = obj.Shape.Edges[0]
                if len(edge.Vertexes) == 1:
                    newEdge = DraftGeomUtils.orientEdge(edge)
                    nobj.addGeometry(newEdge)
                else:
                    # make new ArcOfCircle
                    circle = DraftGeomUtils.orientEdge(edge)
                    angle = edge.Placement.Rotation.Angle
                    axis = edge.Placement.Rotation.Axis
                    circle.Center = DraftVecUtils.rotate(
                        edge.Curve.Center, -angle, axis)
                    first = math.radians(obj.FirstAngle)
                    last = math.radians(obj.LastAngle)
                    arc = Part.ArcOfCircle(circle, first, last)
                    nobj.addGeometry(arc)
                addRadiusConstraint(edge)
                ok = True
        elif tp == "Rectangle":
            if rotation is None:
                rotation = obj.Placement.Rotation
            if obj.FilletRadius.Value == 0:
                for edge in obj.Shape.Edges:
                    nobj.addGeometry(DraftGeomUtils.orientEdge(edge))
                if autoconstraints:
                    last = nobj.GeometryCount - 1
                    segs = [last - 3, last - 2, last - 1, last]
                    if obj.Placement.Rotation.Q == (0, 0, 0, 1):
                        constraints.append(
                            Constraint("Coincident", last - 3, EndPoint,
                                       last - 2, StartPoint))
                        constraints.append(
                            Constraint("Coincident", last - 2, EndPoint,
                                       last - 1, StartPoint))
                        constraints.append(
                            Constraint("Coincident", last - 1, EndPoint, last,
                                       StartPoint))
                        constraints.append(
                            Constraint("Coincident", last, EndPoint, last - 3,
                                       StartPoint))
                    constraints.append(Constraint("Horizontal", last - 3))
                    constraints.append(Constraint("Vertical", last - 2))
                    constraints.append(Constraint("Horizontal", last - 1))
                    constraints.append(Constraint("Vertical", last))
                ok = True
        elif tp in ["Wire", "Polygon"]:
            if obj.FilletRadius.Value == 0:
                closed = False
                if tp == "Polygon":
                    closed = True
                elif hasattr(obj, "Closed"):
                    closed = obj.Closed

                if obj.Shape.Edges:
                    if (len(obj.Shape.Vertexes) < 3):
                        e = obj.Shape.Edges[0]
                        nobj.addGeometry(
                            Part.LineSegment(e.Curve, e.FirstParameter,
                                             e.LastParameter))
                    else:
                        # Use the first three points to make a working plane. We've already
                        # checked to make sure everything is coplanar
                        plane = Part.Plane(
                            *[i.Point for i in obj.Shape.Vertexes[:3]])
                        normal = plane.Axis
                        if rotation is None:
                            axis = App.Vector(0, 0, 1).cross(normal)
                            angle = DraftVecUtils.angle(
                                normal, App.Vector(0, 0, 1)) * App.Units.Radian
                            rotation = App.Rotation(axis, angle)
                        for edge in obj.Shape.Edges:
                            # edge.rotate(App.Vector(0,0,0), rotAxis, rotAngle)
                            edge = DraftGeomUtils.orientEdge(edge, normal)
                            nobj.addGeometry(edge)
                        if autoconstraints:
                            last = nobj.GeometryCount
                            segs = list(
                                range(last - len(obj.Shape.Edges), last - 1))
                            for seg in segs:
                                constraints.append(
                                    Constraint("Coincident", seg, EndPoint,
                                               seg + 1, StartPoint))
                                if DraftGeomUtils.isAligned(
                                        nobj.Geometry[seg], "x"):
                                    constraints.append(
                                        Constraint("Vertical", seg))
                                elif DraftGeomUtils.isAligned(
                                        nobj.Geometry[seg], "y"):
                                    constraints.append(
                                        Constraint("Horizontal", seg))
                            if closed:
                                constraints.append(
                                    Constraint("Coincident", last - 1,
                                               EndPoint, segs[0], StartPoint))
                    ok = True
        elif tp == "BSpline":
            if obj.Shape.Edges:
                nobj.addGeometry(obj.Shape.Edges[0].Curve)
                nobj.exposeInternalGeometry(nobj.GeometryCount - 1)
                ok = True
        elif tp == "BezCurve":
            if obj.Shape.Edges:
                bez = obj.Shape.Edges[0].Curve
                bsp = bez.toBSpline(bez.FirstParameter, bez.LastParameter)
                nobj.addGeometry(bsp)
                nobj.exposeInternalGeometry(nobj.GeometryCount - 1)
                ok = True
        elif tp == 'Shape' or hasattr(obj, 'Shape'):
            shape = obj if tp == 'Shape' else obj.Shape

            if not DraftGeomUtils.isPlanar(shape):
                App.Console.PrintError(
                    translate(
                        "draft",
                        "The given object is not planar and cannot be converted into a sketch."
                    ))
                return None
            if rotation is None:
                #rotation = obj.Placement.Rotation
                norm = DraftGeomUtils.getNormal(shape)
                if norm:
                    rotation = App.Rotation(App.Vector(0, 0, 1), norm)
                else:
                    App.Console.PrintWarning(
                        translate(
                            "draft",
                            "Unable to guess the normal direction of this object"
                        ))
                    rotation = App.Rotation()
                    norm = obj.Placement.Rotation.Axis
            if not shape.Wires:
                for e in shape.Edges:
                    # unconnected edges
                    newedge = convertBezier(e)
                    nobj.addGeometry(
                        DraftGeomUtils.orientEdge(newedge, norm,
                                                  make_arc=True))
                    addRadiusConstraint(newedge)

            # if not addTo:
            # nobj.Placement.Rotation = DraftGeomUtils.calculatePlacement(shape).Rotation

            if autoconstraints:
                for wire in shape.Wires:
                    last_count = nobj.GeometryCount
                    edges = wire.OrderedEdges
                    for edge in edges:
                        newedge = convertBezier(edge)
                        nobj.addGeometry(
                            DraftGeomUtils.orientEdge(newedge,
                                                      norm,
                                                      make_arc=True))
                        addRadiusConstraint(newedge)
                    for i, g in enumerate(nobj.Geometry[last_count:]):
                        if edges[i].Closed:
                            continue
                        seg = last_count + i

                        if DraftGeomUtils.isAligned(g, "x"):
                            constraints.append(Constraint("Vertical", seg))
                        elif DraftGeomUtils.isAligned(g, "y"):
                            constraints.append(Constraint("Horizontal", seg))

                        if seg == nobj.GeometryCount - 1:
                            if not wire.isClosed():
                                break
                            g2 = nobj.Geometry[last_count]
                            seg2 = last_count
                        else:
                            seg2 = seg + 1
                            g2 = nobj.Geometry[seg2]

                        end1 = g.value(g.LastParameter)
                        start2 = g2.value(g2.FirstParameter)
                        if DraftVecUtils.equals(end1, start2):
                            constraints.append(
                                Constraint("Coincident", seg, EndPoint, seg2,
                                           StartPoint))
                            continue
                        end2 = g2.value(g2.LastParameter)
                        start1 = g.value(g.FirstParameter)
                        if DraftVecUtils.equals(end2, start1):
                            constraints.append(
                                Constraint("Coincident", seg, StartPoint, seg2,
                                           EndPoint))
                        elif DraftVecUtils.equals(start1, start2):
                            constraints.append(
                                Constraint("Coincident", seg, StartPoint, seg2,
                                           StartPoint))
                        elif DraftVecUtils.equals(end1, end2):
                            constraints.append(
                                Constraint("Coincident", seg, EndPoint, seg2,
                                           EndPoint))
            else:
                for wire in shape.Wires:
                    for edge in wire.OrderedEdges:
                        newedge = convertBezier(edge)
                        nobj.addGeometry(
                            DraftGeomUtils.orientEdge(newedge,
                                                      norm,
                                                      make_arc=True))
            ok = True
        gui_utils.format_object(nobj, obj)
        if ok and delete and hasattr(obj, 'Shape'):
            doc = obj.Document

            def delObj(obj):
                if obj.InList:
                    App.Console.PrintWarning(
                        translate(
                            "draft", "Cannot delete object {} with dependency".
                            format(obj.Label)) + "\n")
                else:
                    doc.removeObject(obj.Name)

            try:
                if delete == 'all':
                    objs = [obj]
                    while objs:
                        obj = objs[0]
                        objs = objs[1:] + obj.OutList
                        delObj(obj)
                else:
                    delObj(obj)
            except Exception as ex:
                App.Console.PrintWarning(
                    translate(
                        "draft", "Failed to delete object {}: {}".format(
                            obj.Label, ex)) + "\n")
    if rotation:
        nobj.Placement.Rotation = rotation
    else:
        print("-----error!!! rotation is still None...")
    nobj.addConstraint(constraints)

    return nobj
Пример #2
0
def make_sketch(objects_list,
                autoconstraints=False,
                addTo=None,
                delete=False,
                name="Sketch",
                radiusPrecision=-1,
                tol=1e-3):
    """makeSketch(objects_list,[autoconstraints],[addTo],[delete],
                  [name],[radiusPrecision],[tol])

    Makes a Sketch objects_list with the given Draft objects.

    Parameters
    ----------
    objects_list: can be single or list of objects of Draft type objects,
        Part::Feature, Part.Shape, or mix of them.

    autoconstraints(False): if True, constraints will be automatically added to
        wire nodes, rectangles and circles.

    addTo(None) : if set to an existing sketch, geometry will be added to it
        instead of creating a new one.

    delete(False): if True, the original object will be deleted.
        If set to a string 'all' the object and all its linked object will be
        deleted.

    name('Sketch'): the name for the new sketch object.

    radiusPrecision(-1): If <0, disable radius constraint. If =0, add individual
        radius constraint. If >0, the radius will be rounded according to this
        precision, and 'Equal' constraint will be added to curve with equal
        radius within precision.

    tol(1e-3): Tolerance used to check if the shapes are planar and coplanar.
        Consider change to tol=-1 for a more accurate analysis.
    """

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

    import Part
    from Sketcher import Constraint
    import Sketcher

    start_point = 1
    end_point = 2
    middle_point = 3
    deletable = None

    if App.GuiUp:
        v_dir = gui_utils.get_3d_view().getViewDirection()
    else:
        v_dir = App.Base.Vector(0, 0, -1)

    # lists to accumulate shapes with defined normal and undefined normal
    shape_norm_yes = list()
    shape_norm_no = list()

    if not isinstance(objects_list, (list, tuple)):
        objects_list = [objects_list]

    for obj in objects_list:
        if isinstance(obj, Part.Shape):
            shape = obj
        elif not hasattr(obj, 'Shape'):
            App.Console.PrintError(translate("draft", "No shape found") + "\n")
            return None
        else:
            shape = obj.Shape

        if not DraftGeomUtils.is_planar(shape, tol):
            App.Console.PrintError(
                translate("draft", "All Shapes must be planar") + "\n")
            return None

        if DraftGeomUtils.get_normal(shape, tol):
            shape_norm_yes.append(shape)
        else:
            shape_norm_no.append(shape)

    shapes_list = shape_norm_yes + shape_norm_no

    # test if all shapes are coplanar
    if len(shape_norm_yes) >= 1:
        for shape in shapes_list[1:]:
            if not DraftGeomUtils.are_coplanar(shapes_list[0], shape, tol):
                App.Console.PrintError(
                    translate("draft", "All Shapes must be coplanar") + "\n")
                return None
        # define sketch normal
        normal = DraftGeomUtils.get_normal(shapes_list[0], tol)

    else:
        # suppose all geometries are straight lines or points
        points = [
            vertex.Point for shape in shapes_list for vertex in shape.Vertexes
        ]
        if len(points) >= 2:
            poly = Part.makePolygon(points)
            if not DraftGeomUtils.is_planar(poly, tol):
                App.Console.PrintError(
                    translate("draft", "All Shapes must be coplanar") + "\n")
                return None
            normal = DraftGeomUtils.get_normal(poly, tol)
            if not normal:
                # all points aligned
                poly_dir = poly.Edges[0].Curve.Direction
                normal = (v_dir - v_dir.dot(poly_dir) * poly_dir).normalize()
                normal = normal.negative()
        else:
            # only one point
            normal = v_dir.negative()

    if addTo:
        nobj = addTo
    else:
        nobj = App.ActiveDocument.addObject("Sketcher::SketchObject", name)
        deletable = nobj
        if App.GuiUp:
            nobj.ViewObject.Autoconstraints = False

    # Collect constraints and add in one go to improve performance
    constraints = []
    radiuses = {}

    def addRadiusConstraint(edge):
        try:
            if radiusPrecision < 0:
                return
            if radiusPrecision == 0:
                constraints.append(
                    Constraint('Radius', nobj.GeometryCount - 1,
                               edge.Curve.Radius))
                return
            r = round(edge.Curve.Radius, radiusPrecision)
            constraints.append(
                Constraint('Equal', radiuses[r], nobj.GeometryCount - 1))
        except KeyError:
            radiuses[r] = nobj.GeometryCount - 1
            constraints.append(Constraint('Radius', nobj.GeometryCount - 1, r))
        except AttributeError:
            pass

    def convertBezier(edge):
        if DraftGeomUtils.geomType(edge) == "BezierCurve":
            return (edge.Curve.toBSpline(edge.FirstParameter,
                                         edge.LastParameter).toShape())
        else:
            return (edge)

    axis = App.Vector(0, 0, 1).cross(normal)
    angle = DraftVecUtils.angle(normal, App.Vector(0, 0, 1)) * App.Units.Radian
    rotation = App.Rotation(axis, angle)

    for obj in objects_list:
        ok = False
        tp = utils.get_type(obj)
        if tp in ["Circle", "Ellipse"]:
            if obj.Shape.Edges:
                edge = obj.Shape.Edges[0]
                if len(edge.Vertexes) == 1:
                    newedge = DraftGeomUtils.orientEdge(edge, normal)
                    nobj.addGeometry(newedge)
                else:
                    # make new ArcOfCircle
                    circle = DraftGeomUtils.orientEdge(edge, normal)
                    first = math.radians(obj.FirstAngle)
                    last = math.radians(obj.LastAngle)
                    arc = Part.ArcOfCircle(circle, first, last)
                    nobj.addGeometry(arc)
                addRadiusConstraint(edge)
                ok = True
        elif tp == "Rectangle":
            if obj.FilletRadius.Value == 0:
                for edge in obj.Shape.Edges:
                    nobj.addGeometry(DraftGeomUtils.orientEdge(edge, normal))
                # TODO: the previous implementation for autoconstraints fails in front
                # and side view. So the autoconstraints for wires is used. This need
                # more checking
                if autoconstraints:
                    last = nobj.GeometryCount
                    segs = list(range(last - len(obj.Shape.Edges), last - 1))
                    for seg in segs:
                        constraints.append(
                            Constraint("Coincident", seg, end_point, seg + 1,
                                       start_point))
                        if DraftGeomUtils.isAligned(nobj.Geometry[seg], "x"):
                            constraints.append(Constraint("Vertical", seg))
                        elif DraftGeomUtils.isAligned(nobj.Geometry[seg], "y"):
                            constraints.append(Constraint("Horizontal", seg))
                    constraints.append(
                        Constraint("Coincident", last - 1, end_point, segs[0],
                                   start_point))
                ok = True
                # if autoconstraints:
                #     last = nobj.GeometryCount - 1
                #     segs = [last-3,last-2,last-1,last]
                #     if obj.Placement.Rotation.Q == (0,0,0,1):
                #         constraints.append(Constraint("Coincident",last-3,end_point,last-2,start_point))
                #         constraints.append(Constraint("Coincident",last-2,end_point,last-1,start_point))
                #         constraints.append(Constraint("Coincident",last-1,end_point,last,start_point))
                #         constraints.append(Constraint("Coincident",last,end_point,last-3,start_point))
                #     constraints.append(Constraint("Horizontal",last-3))
                #     constraints.append(Constraint("Vertical",last-2))
                #     constraints.append(Constraint("Horizontal",last-1))
                #     constraints.append(Constraint("Vertical",last))
                # ok = True
        elif tp in ["Wire", "Polygon"]:
            if obj.FilletRadius.Value == 0:
                closed = False
                if tp == "Polygon":
                    closed = True
                elif hasattr(obj, "Closed"):
                    closed = obj.Closed

                if obj.Shape.Edges:
                    for edge in obj.Shape.Edges:
                        edge = DraftGeomUtils.orientEdge(edge, normal)
                        nobj.addGeometry(edge)
                    if autoconstraints:
                        last = nobj.GeometryCount
                        segs = list(
                            range(last - len(obj.Shape.Edges), last - 1))
                        for seg in segs:
                            constraints.append(
                                Constraint("Coincident", seg, end_point,
                                           seg + 1, start_point))
                            if DraftGeomUtils.isAligned(
                                    nobj.Geometry[seg], "x"):
                                constraints.append(Constraint("Vertical", seg))
                            elif DraftGeomUtils.isAligned(
                                    nobj.Geometry[seg], "y"):
                                constraints.append(
                                    Constraint("Horizontal", seg))
                        if closed:
                            constraints.append(
                                Constraint("Coincident", last - 1, end_point,
                                           segs[0], start_point))
                    ok = True

        elif tp == "BSpline":
            if obj.Shape.Edges:
                edge = DraftGeomUtils.orientEdge(obj.Shape.Edges[0], normal)
                nobj.addGeometry(edge)
                nobj.exposeInternalGeometry(nobj.GeometryCount - 1)
                ok = True

        elif tp == "BezCurve":
            if obj.Shape.Edges:
                for piece in obj.Shape.Edges:
                    bez = piece.Curve
                    bsp = bez.toBSpline(bez.FirstParameter,
                                        bez.LastParameter).toShape()
                    edge = DraftGeomUtils.orientEdge(bsp.Edges[0], normal)
                    nobj.addGeometry(edge)
                    nobj.exposeInternalGeometry(nobj.GeometryCount - 1)
                ok = True
                # TODO: set coincident constraint for vertexes in multi-edge bezier curve

        elif tp == "Point":
            shape = obj.Shape.copy()
            if angle:
                shape.rotate(App.Base.Vector(0, 0, 0), axis, -1 * angle)
            point = Part.Point(shape.Point)
            nobj.addGeometry(point)
            ok = True

        elif tp == 'Shape' or hasattr(obj, 'Shape'):
            shape = obj if tp == 'Shape' else obj.Shape
            if not shape.Wires:
                for e in shape.Edges:
                    # unconnected edges
                    newedge = convertBezier(e)
                    nobj.addGeometry(
                        DraftGeomUtils.orientEdge(newedge,
                                                  normal,
                                                  make_arc=True))
                    addRadiusConstraint(newedge)

            if autoconstraints:
                for wire in shape.Wires:
                    last_count = nobj.GeometryCount
                    edges = wire.OrderedEdges
                    for edge in edges:
                        newedge = convertBezier(edge)
                        nobj.addGeometry(
                            DraftGeomUtils.orientEdge(newedge,
                                                      normal,
                                                      make_arc=True))
                        addRadiusConstraint(newedge)
                    for i, g in enumerate(nobj.Geometry[last_count:]):
                        if edges[i].Closed:
                            continue
                        seg = last_count + i

                        if DraftGeomUtils.isAligned(g, "x"):
                            constraints.append(Constraint("Vertical", seg))
                        elif DraftGeomUtils.isAligned(g, "y"):
                            constraints.append(Constraint("Horizontal", seg))

                        if seg == nobj.GeometryCount - 1:
                            if not wire.isClosed():
                                break
                            g2 = nobj.Geometry[last_count]
                            seg2 = last_count
                        else:
                            seg2 = seg + 1
                            g2 = nobj.Geometry[seg2]

                        end1 = g.value(g.LastParameter)
                        start2 = g2.value(g2.FirstParameter)
                        if DraftVecUtils.equals(end1, start2):
                            constraints.append(
                                Constraint("Coincident", seg, end_point, seg2,
                                           start_point))
                            continue
                        end2 = g2.value(g2.LastParameter)
                        start1 = g.value(g.FirstParameter)
                        if DraftVecUtils.equals(end2, start1):
                            constraints.append(
                                Constraint("Coincident", seg, start_point,
                                           seg2, end_point))
                        elif DraftVecUtils.equals(start1, start2):
                            constraints.append(
                                Constraint("Coincident", seg, start_point,
                                           seg2, start_point))
                        elif DraftVecUtils.equals(end1, end2):
                            constraints.append(
                                Constraint("Coincident", seg, end_point, seg2,
                                           end_point))
            else:
                for wire in shape.Wires:
                    for edge in wire.OrderedEdges:
                        newedge = convertBezier(edge)
                        nobj.addGeometry(
                            DraftGeomUtils.orientEdge(newedge,
                                                      normal,
                                                      make_arc=True))
            ok = True
        gui_utils.format_object(nobj, obj)
        if ok and delete and hasattr(obj, 'Shape'):
            doc = obj.Document

            def delObj(obj):
                if obj.InList:
                    App.Console.PrintWarning(
                        translate(
                            "draft", "Cannot delete object {} with dependency".
                            format(obj.Label)) + "\n")
                else:
                    doc.removeObject(obj.Name)

            try:
                if delete == 'all':
                    objs = [obj]
                    while objs:
                        obj = objs[0]
                        objs = objs[1:] + obj.OutList
                        delObj(obj)
                else:
                    delObj(obj)
            except Exception as ex:
                App.Console.PrintWarning(
                    translate(
                        "draft", "Failed to delete object {}: {}".format(
                            obj.Label, ex)) + "\n")

    nobj.Placement.Rotation = rotation
    nobj.addConstraint(constraints)

    return nobj