Beispiel #1
0
def make_point_array(base, ptlst):
    """make_point_array(base,pointlist)

    Make a Draft PointArray object.

    Parameters
    ----------
    base :
        TODO: describe

    plist :
        TODO: describe
    
    """
    obj = App.ActiveDocument.addObject("Part::FeaturePython", "PointArray")
    PointArray(obj, base, ptlst)
    obj.Base = base
    obj.PointList = ptlst
    if App.GuiUp:
        ViewProviderDraftArray(obj.ViewObject)
        base.ViewObject.hide()
        gui_utils.formatObject(obj, obj.Base)
        if len(obj.Base.ViewObject.DiffuseColor) > 1:
            obj.ViewObject.Proxy.resetColors(obj.ViewObject)
        gui_utils.select(obj)
    return obj
Beispiel #2
0
def rotate(objectslist, angle, center=App.Vector(0,0,0),
           axis=App.Vector(0,0,1), copy=False):
    """rotate(objects,angle,[center,axis,copy])

    Rotates the objects contained in objects (that can be a list of objects
    or an object) of the given angle (in degrees) around the center, using
    axis as a rotation axis.

    Parameters
    ----------
    objectlist : list

    angle : list

    center : Base.Vector

    axis : Base.Vector
        If axis is omitted, the rotation will be around the vertical Z axis.

    copy : bool
        If copy is True, the actual objects are not moved, but copies
        are created instead.

    Return
    ----------
    The objects (or their copies) are returned.
    """
    import Part
    utils.type_check([(copy,bool)], "rotate")
    if not isinstance(objectslist,list):
        objectslist = [objectslist]

    objectslist.extend(groups.get_movable_children(objectslist))
    newobjlist = []
    newgroups = {}
    objectslist = utils.filter_objects_for_modifiers(objectslist, copy)

    for obj in objectslist:
        newobj = None
        # real_center and real_axis are introduced to take into account
        # the possibility that object is inside an App::Part
        if hasattr(obj, "getGlobalPlacement"):
            ci = obj.getGlobalPlacement().inverse().multVec(center)
            real_center = obj.Placement.multVec(ci)
            ai = obj.getGlobalPlacement().inverse().Rotation.multVec(axis)
            real_axis = obj.Placement.Rotation.multVec(ai)
        else:
            real_center = center
            real_axis = axis

        if copy:
            newobj = make_copy.make_copy(obj)
        else:
            newobj = obj
        if obj.isDerivedFrom("App::Annotation"):
            # TODO: this is very different from how move handle annotations
            # maybe we can uniform the two methods
            if axis.normalize() == App.Vector(1,0,0):
                newobj.ViewObject.RotationAxis = "X"
                newobj.ViewObject.Rotation = angle
            elif axis.normalize() == App.Vector(0,1,0):
                newobj.ViewObject.RotationAxis = "Y"
                newobj.ViewObject.Rotation = angle
            elif axis.normalize() == App.Vector(0,-1,0):
                newobj.ViewObject.RotationAxis = "Y"
                newobj.ViewObject.Rotation = -angle
            elif axis.normalize() == App.Vector(0,0,1):
                newobj.ViewObject.RotationAxis = "Z"
                newobj.ViewObject.Rotation = angle
            elif axis.normalize() == App.Vector(0,0,-1):
                newobj.ViewObject.RotationAxis = "Z"
                newobj.ViewObject.Rotation = -angle
        elif utils.get_type(obj) == "Point":
            v = App.Vector(obj.X,obj.Y,obj.Z)
            rv = v.sub(real_center)
            rv = DraftVecUtils.rotate(rv, math.radians(angle), real_axis)
            v = real_center.add(rv)
            newobj.X = v.x
            newobj.Y = v.y
            newobj.Z = v.z
        elif obj.isDerivedFrom("App::DocumentObjectGroup"):
            pass
        elif hasattr(obj,"Placement"):
            #FreeCAD.Console.PrintMessage("placement rotation\n")
            shape = Part.Shape()
            shape.Placement = obj.Placement
            shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle)
            newobj.Placement = shape.Placement
        elif hasattr(obj,'Shape') and (utils.get_type(obj) not in ["WorkingPlaneProxy","BuildingPart"]):
            #think it make more sense to try first to rotate placement and later to try with shape. no?
            shape = obj.Shape.copy()
            shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle)
            newobj.Shape = shape
        if copy:
            gui_utils.formatObject(newobj,obj)
        if newobj is not None:
            newobjlist.append(newobj)
        if copy:
            for p in obj.InList:
                if p.isDerivedFrom("App::DocumentObjectGroup") and (p in objectslist):
                    g = newgroups.setdefault(p.Name, App.ActiveDocument.addObject(p.TypeId, p.Name))
                    g.addObject(newobj)
                    break

    gui_utils.select(newobjlist)
    if len(newobjlist) == 1:
        return newobjlist[0]
    return newobjlist
Beispiel #3
0
def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
    """offset(object,delta,[copymode],[bind])

    Offset the given wire by applying the given delta Vector to its first
    vertex.

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

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

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

    copy : bool
        If bind is True, and provided the wire is open, the original
        and the offset wires will be bound by their endpoints, forming a face.

    sym : bool
        if sym is True, bind must be true too, and the offset is made on both
        sides, the total width being the given delta length.
    """
    import Part
    import DraftGeomUtils
    newwire = None
    delete = None

    if utils.get_type(obj).startswith("Part::") or utils.get_type(
            obj).startswith("Sketcher::"):
        copy = True
        print(
            "the offset tool is currently unable to offset a non-Draft object directly - Creating a copy"
        )

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

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

    newwire = None
    if utils.get_type(obj) == "Circle":
        pass
    elif utils.get_type(obj) == "BSpline":
        pass
    else:
        if sym:
            d1 = App.Vector(delta).multiply(0.5)
            d2 = d1.negative()
            n1 = DraftGeomUtils.offsetWire(obj.Shape, d1)
            n2 = DraftGeomUtils.offsetWire(obj.Shape, d2)
        else:
            if isinstance(delta, float) and (len(obj.Shape.Edges) == 1):
                # circle
                c = obj.Shape.Edges[0].Curve
                nc = Part.Circle(c.Center, c.Axis, delta)
                if len(obj.Shape.Vertexes) > 1:
                    nc = Part.ArcOfCircle(nc,
                                          obj.Shape.Edges[0].FirstParameter,
                                          obj.Shape.Edges[0].LastParameter)
                newwire = Part.Wire(nc.toShape())
                p = []
            else:
                newwire = DraftGeomUtils.offsetWire(obj.Shape, delta)
                if DraftGeomUtils.hasCurves(newwire) and copy:
                    p = []
                else:
                    p = DraftGeomUtils.getVerts(newwire)
    if occ:
        newobj = App.ActiveDocument.addObject("Part::Feature", "Offset")
        newobj.Shape = DraftGeomUtils.offsetWire(obj.Shape, delta, occ=True)
        gui_utils.formatObject(newobj, obj)
        if not copy:
            delete = obj.Name
    elif bind:
        if not DraftGeomUtils.isReallyClosed(obj.Shape):
            if sym:
                s1 = n1
                s2 = n2
            else:
                s1 = obj.Shape
                s2 = newwire
            if s1 and s2:
                w1 = s1.Edges
                w2 = s2.Edges
                w3 = Part.LineSegment(s1.Vertexes[0].Point,
                                      s2.Vertexes[0].Point).toShape()
                w4 = Part.LineSegment(s1.Vertexes[-1].Point,
                                      s2.Vertexes[-1].Point).toShape()
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = Part.Face(Part.Wire(w1 + [w3] + w2 + [w4]))
            else:
                print("Draft.offset: Unable to bind wires")
        else:
            newobj = App.ActiveDocument.addObject("Part::Feature", "Offset")
            newobj.Shape = Part.Face(obj.Shape.Wires[0])
        if not copy:
            delete = obj.Name
    elif copy:
        newobj = None
        if sym: return None
        if utils.get_type(obj) == "Wire":
            if p:
                newobj = make_wire(p)
                newobj.Closed = obj.Closed
            elif newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            else:
                print("Draft.offset: Unable to duplicate this object")
        elif utils.get_type(obj) == "Rectangle":
            if p:
                length, height, plac = getRect(p, obj)
                newobj = make_rectangle(length, height, plac)
            elif newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            else:
                print("Draft.offset: Unable to duplicate this object")
        elif utils.get_type(obj) == "Circle":
            pl = obj.Placement
            newobj = make_circle(delta)
            newobj.FirstAngle = obj.FirstAngle
            newobj.LastAngle = obj.LastAngle
            newobj.Placement = pl
        elif utils.get_type(obj) == "Polygon":
            pl = obj.Placement
            newobj = make_polygon(obj.FacesNumber)
            newobj.Radius = getRadius(obj, delta)
            newobj.DrawMode = obj.DrawMode
            newobj.Placement = pl
        elif utils.get_type(obj) == "BSpline":
            newobj = make_bspline(delta)
            newobj.Closed = obj.Closed
        else:
            # try to offset anyway
            try:
                if p:
                    newobj = make_wire(p)
                    newobj.Closed = obj.Shape.isClosed()
            except Part.OCCError:
                pass
            if (not newobj) and newwire:
                newobj = App.ActiveDocument.addObject("Part::Feature",
                                                      "Offset")
                newobj.Shape = newwire
            if not newobj:
                print("Draft.offset: Unable to create an offset")
        if newobj:
            gui_utils.formatObject(newobj, obj)
    else:
        newobj = None
        if sym: return None
        if utils.get_type(obj) == "Wire":
            if obj.Base or obj.Tool:
                App.Console.PrintWarning("Warning: object history removed\n")
                obj.Base = None
                obj.Tool = None
            obj.Placement = App.Placement(
            )  # p points are in the global coordinate system
            obj.Points = p
        elif utils.get_type(obj) == "BSpline":
            #print(delta)
            obj.Points = delta
            #print("done")
        elif utils.get_type(obj) == "Rectangle":
            length, height, plac = getRect(p, obj)
            obj.Placement = plac
            obj.Length = length
            obj.Height = height
        elif utils.get_type(obj) == "Circle":
            obj.Radius = delta
        elif utils.get_type(obj) == "Polygon":
            obj.Radius = getRadius(obj, delta)
        elif utils.get_type(obj) == 'Part':
            print("unsupported object")  # TODO
        newobj = obj
    if copy and utils.get_param("selectBaseObjects", False):
        gui_utils.select(newobj)
    else:
        gui_utils.select(obj)
    if delete:
        App.ActiveDocument.removeObject(delete)
    return newobj
Beispiel #4
0
def make_path_array(base_object,
                    path_object,
                    count=4,
                    extra=App.Vector(0, 0, 0),
                    subelements=None,
                    align=False,
                    align_mode="Original",
                    tan_vector=App.Vector(1, 0, 0),
                    force_vertical=False,
                    vertical_vector=App.Vector(0, 0, 1),
                    use_link=True):
    """Make a Draft PathArray object.

    Distribute copies of a `base_object` along `path_object`
    or `subelements` from `path_object`.

    Parameters
    ----------
    base_object: Part::Feature or str
        Any of object that has a `Part::TopoShape` that can be duplicated.
        This means most 2D and 3D objects produced with any workbench.
        If it is a string, it must be the `Label` of that object.
        Since a label is not guaranteed to be unique in a document,
        it will use the first object found with this label.

    path_object: Part::Feature or str
        Path object like a polyline, B-Spline, or bezier curve that should
        contain edges.
        Just like `base_object` it can also be `Label`.

    count: int, float, optional
        It defaults to 4.
        Number of copies to create along the `path_object`.
        It must be at least 2.
        If a `float` is provided, it will be truncated by `int(count)`.

    extra: Base.Vector3, optional
        It defaults to `App.Vector(0, 0, 0)`.
        It translates each copy by the value of `extra`.
        This is useful to adjust for the difference between shape centre
        and shape reference point.

    subelements: list or tuple of str, optional
        It defaults to `None`.
        It should be a list of names of edges that must exist in `path_object`.
        Then the path array will be created along these edges only,
        and not the entire `path_object`.
        ::
            subelements = ['Edge1', 'Edge2']

        The edges must be contiguous, meaning that it is not allowed to
        input `'Edge1'` and `'Edge3'` if they do not touch each other.

        A single string value is also allowed.
        ::
            subelements = 'Edge1'

    align: bool, optional
        It defaults to `False`.
        If it is `True` it will align `base_object` to tangent, normal,
        or binormal to the `path_object`, depending on the value
        of `tan_vector`.

    align_mode: str, optional
        It defaults to `'Original'` which is the traditional alignment.
        It can also be `'Frenet'` or `'Tangent'`.

        - Original. It does not calculate curve normal.
          `X` is curve tangent, `Y` is normal parameter, Z is the cross
          product `X` x `Y`.
        - Frenet. It defines a local coordinate system along the path.
          `X` is tangent to curve, `Y` is curve normal, `Z` is curve binormal.
          If normal cannot be computed, for example, in a straight path,
          a default is used.
        - Tangent. It is similar to `'Original'` but includes a pre-rotation
          to align the base object's `X` to the value of `tan_vector`,
          then `X` follows curve tangent.

    tan_vector: Base::Vector3, optional
        It defaults to `App.Vector(1, 0, 0)` or the +X axis.
        It aligns the tangent of the path to this local unit vector
        of the object.

    force_vertical: Base::Vector3, optional
        It defaults to `False`.
        If it is `True`, the value of `vertical_vector`
        will be used when `align_mode` is `'Original'` or `'Tangent'`.

    vertical_vector: Base::Vector3, optional
        It defaults to `App.Vector(0, 0, 1)` or the +Z axis.
        It will force this vector to be the vertical direction
        when `force_vertical` is `True`.

    use_link: bool, optional
        It defaults to `True`, in which case the copies are `App::Link`
        elements. Otherwise, the copies are shape copies which makes
        the resulting array heavier.

    Returns
    -------
    Part::FeaturePython
        The scripted object of type `'PathArray'`.
        Its `Shape` is a compound of the copies of the original object.

    None
        If there is a problem it will return `None`.
    """
    _name = "make_path_array"
    utils.print_header(_name, "Path array")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(_tr("No active document. Aborting."))
        return None

    if isinstance(base_object, str):
        base_object_str = base_object

    found, base_object = utils.find_object(base_object, doc)
    if not found:
        _msg("base_object: {}".format(base_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("base_object: {}".format(base_object.Label))

    if isinstance(path_object, str):
        path_object_str = path_object

    found, path_object = utils.find_object(path_object, doc)
    if not found:
        _msg("path_object: {}".format(path_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("path_object: {}".format(path_object.Label))

    _msg("count: {}".format(count))
    try:
        utils.type_check([(count, (int, float))], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a number."))
        return None
    count = int(count)

    _msg("extra: {}".format(extra))
    try:
        utils.type_check([(extra, App.Vector)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a vector."))
        return None

    _msg("subelements: {}".format(subelements))
    if subelements:
        try:
            # Make a list
            if isinstance(subelements, str):
                subelements = [subelements]

            utils.type_check([(subelements, (list, tuple, str))], name=_name)
        except TypeError:
            _err(
                _tr("Wrong input: must be a list or tuple of strings. "
                    "Or a single string."))
            return None

        # The subelements list is used to build a special list
        # called a LinkSubList, which includes the path_object.
        # Old style: [(path_object, "Edge1"), (path_object, "Edge2")]
        # New style: [(path_object, ("Edge1", "Edge2"))]
        #
        # If a simple list is given ["a", "b"], this will create an old-style
        # SubList.
        # If a nested list is given [["a", "b"]], this will create a new-style
        # SubList.
        # In any case, the property of the object accepts both styles.
        #
        # If the old style is deprecated then this code should be updated
        # to create new style lists exclusively.
        sub_list = list()
        for sub in subelements:
            sub_list.append((path_object, sub))
    else:
        sub_list = None

    align = bool(align)
    _msg("align: {}".format(align))

    _msg("align_mode: {}".format(align_mode))
    try:
        utils.type_check([(align_mode, str)], name=_name)

        if align_mode not in ("Original", "Frenet", "Tangent"):
            raise TypeError
    except TypeError:
        _err(_tr("Wrong input: must be "
                 "'Original', 'Frenet', or 'Tangent'."))
        return None

    _msg("tan_vector: {}".format(tan_vector))
    try:
        utils.type_check([(tan_vector, App.Vector)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a vector."))
        return None

    force_vertical = bool(force_vertical)
    _msg("force_vertical: {}".format(force_vertical))

    _msg("vertical_vector: {}".format(vertical_vector))
    try:
        utils.type_check([(vertical_vector, App.Vector)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a vector."))
        return None

    use_link = bool(use_link)
    _msg("use_link: {}".format(use_link))

    if use_link:
        # The PathArray class must be called in this special way
        # to make it a PathLinkArray
        new_obj = doc.addObject("Part::FeaturePython", "PathArray",
                                PathArray(None), None, True)
    else:
        new_obj = doc.addObject("Part::FeaturePython", "PathArray")
        PathArray(new_obj)

    new_obj.Base = base_object
    new_obj.PathObject = path_object
    new_obj.Count = count
    new_obj.ExtraTranslation = extra
    new_obj.PathSubelements = sub_list
    new_obj.Align = align
    new_obj.AlignMode = align_mode
    new_obj.TangentVector = tan_vector
    new_obj.ForceVertical = force_vertical
    new_obj.VerticalVector = vertical_vector

    if App.GuiUp:
        if use_link:
            ViewProviderDraftLink(new_obj.ViewObject)
        else:
            ViewProviderDraftArray(new_obj.ViewObject)
            gui_utils.formatObject(new_obj, new_obj.Base)

            if hasattr(new_obj.Base.ViewObject, "DiffuseColor"):
                if len(new_obj.Base.ViewObject.DiffuseColor) > 1:
                    new_obj.ViewObject.Proxy.resetColors(new_obj.ViewObject)

        new_obj.Base.ViewObject.hide()
        gui_utils.select(new_obj)

    return new_obj
Beispiel #5
0
def make_path_twisted_array(base_object,
                            path_object,
                            count=15,
                            rot_factor=0.25,
                            use_link=True):
    """Create a Path twisted array."""
    _name = "make_path_twisted_array"
    utils.print_header(_name, "Path twisted array")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(_tr("No active document. Aborting."))
        return None

    if isinstance(base_object, str):
        base_object_str = base_object

    found, base_object = utils.find_object(base_object, doc)
    if not found:
        _msg("base_object: {}".format(base_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("base_object: {}".format(base_object.Label))

    if isinstance(path_object, str):
        path_object_str = path_object

    found, path_object = utils.find_object(path_object, doc)
    if not found:
        _msg("path_object: {}".format(path_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("path_object: {}".format(path_object.Label))

    _msg("count: {}".format(count))
    try:
        utils.type_check([(count, (int, float))], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a number."))
        return None
    count = int(count)

    use_link = bool(use_link)
    _msg("use_link: {}".format(use_link))

    if use_link:
        # The PathTwistedArray class must be called in this special way
        # to make it a PathTwistLinkArray
        new_obj = doc.addObject("Part::FeaturePython", "PathTwistedArray",
                                PathTwistedArray(None), None, True)
    else:
        new_obj = doc.addObject("Part::FeaturePython", "PathTwistedArray")
        PathTwistedArray(new_obj)

    new_obj.Base = base_object
    new_obj.PathObject = path_object
    new_obj.Count = count
    new_obj.RotationFactor = rot_factor

    if App.GuiUp:
        if use_link:
            ViewProviderDraftLink(new_obj.ViewObject)
        else:
            ViewProviderDraftArray(new_obj.ViewObject)
            gui_utils.formatObject(new_obj, new_obj.Base)

        if hasattr(new_obj.Base.ViewObject, "DiffuseColor"):
            if len(new_obj.Base.ViewObject.DiffuseColor) > 1:
                new_obj.ViewObject.Proxy.resetColors(new_obj.ViewObject)

        new_obj.Base.ViewObject.hide()
        gui_utils.select(new_obj)

    return new_obj
Beispiel #6
0
def make_point_array(base_object, point_object, extra=None):
    """Make a Draft PointArray object.

    Distribute copies of a `base_object` in the points
    defined by `point_object`.

    Parameters
    ----------
    base_object: Part::Feature or str
        Any of object that has a `Part::TopoShape` that can be duplicated.
        This means most 2D and 3D objects produced with any workbench.
        If it is a string, it must be the `Label` of that object.
        Since a label is not guaranteed to be unique in a document,
        it will use the first object found with this label.

    point_object: Part::Feature or str
        An object that is a type of container for holding points.
        This object must have one of the following properties `Geometry`,
        `Links`, or `Components`, which themselves must contain objects
        with `X`, `Y`, and `Z` properties.

        This object could be:

        - A `Sketcher::SketchObject`, as it has a `Geometry` property.
          The sketch can contain different elements but it must contain
          at least one `Part::GeomPoint`.

        - A `Part::Compound`, as it has a `Links` property. The compound
          can contain different elements but it must contain at least
          one object that has `X`, `Y`, and `Z` properties,
          like a `Draft Point` or a `Part::Vertex`.

        - A `Draft Block`, as it has a `Components` property. This `Block`
          behaves essentially the same as a `Part::Compound`. It must
          contain at least a point or vertex object.

    extra: Base::Placement, Base::Vector3, or Base::Rotation, optional
        It defaults to `None`.
        If it is provided, it is an additional placement that is applied
        to each copy of the array.
        The input could be a full placement, just a vector indicating
        the additional translation, or just a rotation.

    Returns
    -------
    Part::FeaturePython
        A scripted object of type `'PointArray'`.
        Its `Shape` is a compound of the copies of the original object.

    None
        If there is a problem it will return `None`.
    """
    _name = "make_point_array"
    utils.print_header(_name, "Point array")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(_tr("No active document. Aborting."))
        return None

    if isinstance(base_object, str):
        base_object_str = base_object

    found, base_object = utils.find_object(base_object, doc)
    if not found:
        _msg("base_object: {}".format(base_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("base_object: {}".format(base_object.Label))

    if isinstance(point_object, str):
        point_object_str = point_object

    found, point_object = utils.find_object(point_object, doc)
    if not found:
        _msg("point_object: {}".format(point_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("point_object: {}".format(point_object.Label))
    if (not hasattr(point_object, "Geometry")
            and not hasattr(point_object, "Links")
            and not hasattr(point_object, "Components")):
        _err(
            _tr("Wrong input: point object doesn't have "
                "'Geometry', 'Links', or 'Components'."))
        return None

    _msg("extra: {}".format(extra))
    if not extra:
        extra = App.Placement()
    try:
        utils.type_check([(extra, (App.Placement, App.Vector, App.Rotation))],
                         name=_name)
    except TypeError:
        _err(
            _tr("Wrong input: must be a placement, a vector, "
                "or a rotation."))
        return None

    # Convert the vector or rotation to a full placement
    if isinstance(extra, App.Vector):
        extra = App.Placement(extra, App.Rotation())
    elif isinstance(extra, App.Rotation):
        extra = App.Placement(App.Vector(), extra)

    new_obj = doc.addObject("Part::FeaturePython", "PointArray")
    PointArray(new_obj)
    new_obj.Base = base_object
    new_obj.PointObject = point_object
    new_obj.ExtraPlacement = extra

    if App.GuiUp:
        ViewProviderDraftArray(new_obj.ViewObject)
        gui_utils.formatObject(new_obj, new_obj.Base)

        if hasattr(new_obj.Base.ViewObject, "DiffuseColor"):
            if len(new_obj.Base.ViewObject.DiffuseColor) > 1:
                new_obj.ViewObject.Proxy.resetColors(new_obj.ViewObject)

        new_obj.Base.ViewObject.hide()
        gui_utils.select(new_obj)

    return new_obj
Beispiel #7
0
def move(objectslist, vector, copy=False):
    """move(objects,vector,[copy])
    
    Move the objects contained in objects (that can be an object or a
    list of objects) in the direction and distance indicated by the given
    vector. 

    Parameters
    ----------
    objectslist : list

    vector : Base.Vector
        Delta Vector to move the clone from the original position. 

    copy : bool
        If copy is True, the actual objects are not moved, but copies
        are created instead. 

    Return
    ----------
    The objects (or their copies) are returned.
    """
    utils.type_check([(vector, App.Vector), (copy,bool)], "move")
    if not isinstance(objectslist, list): objectslist = [objectslist]
    objectslist.extend(utils.get_movable_children(objectslist))
    newobjlist = []
    newgroups = {}
    objectslist = utils.filter_objects_for_modifiers(objectslist, copy)
    for obj in objectslist:
        newobj = None
        # real_vector have been introduced to take into account
        # the possibility that object is inside an App::Part
        if hasattr(obj, "getGlobalPlacement"):
            v_minus_global = obj.getGlobalPlacement().inverse().Rotation.multVec(vector)
            real_vector = obj.Placement.Rotation.multVec(v_minus_global)
        else:
            real_vector = vector
        if utils.get_type(obj) == "Point":
            v = App.Vector(obj.X,obj.Y,obj.Z)
            v = v.add(real_vector)
            if copy:
                newobj = make_copy(obj)
            else:
                newobj = obj
            newobj.X = v.x
            newobj.Y = v.y
            newobj.Z = v.z
        elif obj.isDerivedFrom("App::DocumentObjectGroup"):
            pass
        elif hasattr(obj,'Shape'):
            if copy:
                newobj = make_copy(obj)
            else:
                newobj = obj
            pla = newobj.Placement
            pla.move(real_vector)
        elif utils.get_type(obj) == "Annotation":
            if copy:
                newobj = App.ActiveDocument.addObject("App::Annotation",
                                                      utils.getRealName(obj.Name))
                newobj.LabelText = obj.LabelText
                if App.GuiUp:
                    gui_utils.formatObject(newobj,obj)
            else:
                newobj = obj
            newobj.Position = obj.Position.add(real_vector)
        elif utils.get_type(obj) == "Text":
            if copy:
                # TODO: Why make_copy do not handle Text object??
                newobj = App.ActiveDocument.addObject("App::FeaturePython",
                                                      utils.getRealName(obj.Name))
                Text(newobj)
                if App.GuiUp:
                    ViewProviderText(newobj.ViewObject)
                    gui_utils.formatObject(newobj,obj)
                newobj.Text = obj.Text
                newobj.Placement = obj.Placement
                if App.GuiUp:
                    gui_utils.formatObject(newobj,obj)
            else:
                newobj = obj
            newobj.Placement.Base = obj.Placement.Base.add(real_vector)
        elif utils.get_type(obj) in ["Dimension","LinearDimension"]:
            if copy:
                # TODO: Why make_copy do not handle Dimension object??
                # TODO: Support also Label and Angular dimension
                newobj = App.ActiveDocument.addObject("App::FeaturePython",
                                                      utils.getRealName(obj.Name))
                LinearDimension(newobj)
                if App.GuiUp:
                    ViewProviderLinearDimension(newobj.ViewObject)
                    gui_utils.formatObject(newobj,obj)
            else:
                newobj = obj
            newobj.Start = obj.Start.add(real_vector)
            newobj.End = obj.End.add(real_vector)
            newobj.Dimline = obj.Dimline.add(real_vector)
        else:
            if copy and obj.isDerivedFrom("Mesh::Feature"):
                print("Mesh copy not supported at the moment") # TODO
            newobj = obj
            if "Placement" in obj.PropertiesList:
                pla = obj.Placement
                pla.move(real_vector)
        if newobj is not None:
            newobjlist.append(newobj)
        if copy:
            for p in obj.InList:
                if p.isDerivedFrom("App::DocumentObjectGroup") and (p in objectslist):
                    g = newgroups.setdefault(p.Name,App.ActiveDocument.addObject(p.TypeId,p.Name))
                    g.addObject(newobj)
                    break
                if utils.get_type(p) == "Layer":
                    p.Proxy.addObject(p,newobj)
    if copy and utils.get_param("selectBaseObjects",False):
        gui_utils.select(objectslist)
    else:
        gui_utils.select(newobjlist)
    if len(newobjlist) == 1: return newobjlist[0]
    return newobjlist
Beispiel #8
0
def make_path_array(baseobject,pathobject,count,xlate=None,align=False,pathobjsubs=[],use_link=False):
    """make_path_array(docobj, path, count, xlate, align, pathobjsubs, use_link)
    
    Make a Draft PathArray object.
    
    Distribute count copies of a document baseobject along a pathobject 
    or subobjects of a pathobject. 

    
    Parameters
    ----------
    docobj : 
        Object to array

    path : 
        Path object

    pathobjsubs : 
        TODO: Complete documentation

    align : 
        Optionally aligns baseobject to tangent/normal/binormal of path. TODO: verify

    count : 
        TODO: Complete documentation

    xlate : Base.Vector
        Optionally translates each copy by FreeCAD.Vector xlate direction
        and distance to adjust for difference in shape centre vs shape reference point.
        
    use_link :
        TODO: Complete documentation
    """

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

    if use_link:
        obj = App.ActiveDocument.addObject("Part::FeaturePython","PathArray", PathArray(None), None, True)
    else:
        obj = App.ActiveDocument.addObject("Part::FeaturePython","PathArray")
        PathArray(obj)

    obj.Base = baseobject
    obj.PathObj = pathobject

    if pathobjsubs:
        sl = []
        for sub in pathobjsubs:
            sl.append((obj.PathObj,sub))
        obj.PathSubs = list(sl)

    if count > 1:
        obj.Count = count

    if xlate:
        obj.Xlate = xlate

    obj.Align = align

    if App.GuiUp:
        if use_link:
            ViewProviderDraftLink(obj.ViewObject)
        else:
            ViewProviderDraftArray(obj.ViewObject)
            gui_utils.formatObject(obj,obj.Base)
            if hasattr(obj.Base.ViewObject, "DiffuseColor"):
                if len(obj.Base.ViewObject.DiffuseColor) > 1:
                    obj.ViewObject.Proxy.resetColors(obj.ViewObject)
        baseobject.ViewObject.hide()
        gui_utils.select(obj)
    return obj