Пример #1
0
def find_object(obj, doc=None):
    """Find object in the document, inclusive by Label.

    Parameters
    ----------
    obj: App::DocumentObject or str
        The object to search in `doc`.
        Or if the `obj` is a string, it will search the object by `Label`.
        Since Labels are not guaranteed to be unique, it will get the first
        object with that label in the document.

    doc: App::Document or str, optional
        The document in which the object will be searched.
        It defaults to `None`, in which case it tries to search in the
        active document.
        If `doc` is a string, it will search the document by `Name`.

    Returns
    -------
    bool, App::DocumentObject
        A tuple containing the information on whether the search
        was successful. In this case, the boolean is `True`,
        and the second value is the object found.

    False, None
        If the object doesn't exist in the document.
    """
    FOUND = True

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

    if isinstance(obj, str):
        try:
            obj = doc.getObjectsByLabel(obj)[0]
        except IndexError:
            return not FOUND, None

    if obj not in doc.Objects:
        return not FOUND, None

    return FOUND, obj
Пример #2
0
    def create_object(self):
        """Create the new object.

        At this stage we already tested that the input is correct
        so the necessary attributes are already set.
        Then we proceed with the internal function to create the new object.
        """
        if len(self.selection) == 1:
            sel_obj = self.selection[0]
        else:
            # TODO: this should handle multiple objects.
            # For example, it could take the shapes of all objects,
            # make a compound and then use it as input for the array function.
            sel_obj = self.selection[0]

        # This creates the object immediately
        # obj = Draft.makeArray(sel_obj,
        #                       self.center, self.angle, self.number,
        #                       self.use_link)
        # if obj:
        #     obj.Fuse = self.fuse

        # Instead, we build the commands to execute through the parent
        # of this class, the GuiCommand.
        # This is needed to schedule geometry manipulation
        # that would crash Coin3D if done in the event callback.
        _cmd = "draftobjects.polararray.make_polar_array"
        _cmd += "("
        _cmd += "App.ActiveDocument." + sel_obj.Name + ", "
        _cmd += "number=" + str(self.number) + ", "
        _cmd += "angle=" + str(self.angle) + ", "
        _cmd += "center=" + DraftVecUtils.toString(self.center) + ", "
        _cmd += "use_link=" + str(self.use_link)
        _cmd += ")"

        _cmd_list = ["Gui.addModule('Draft')",
                     "Gui.addModule('draftobjects.polararray')",
                     "obj = " + _cmd,
                     "obj.Fuse = " + str(self.fuse),
                     "Draft.autogroup(obj)",
                     "App.ActiveDocument.recompute()"]

        # We commit the command list through the parent command
        self.source_command.commit(_tr(self.name), _cmd_list)
Пример #3
0
 def Activated(self):
     """Execute when the command is called."""
     self.running = False
     super(Offset, self).Activated(name=_tr("Offset"))
     self.ghost = None
     self.linetrack = None
     self.arctrack = None
     if self.ui:
         if not Gui.Selection.getSelection():
             self.ui.selectUi()
             _msg(translate("draft", "Select an object to offset"))
             self.call = self.view.addEventCallback(
                 "SoEvent", gui_tool_utils.selectObject)
         elif len(Gui.Selection.getSelection()) > 1:
             _wrn(
                 translate("draft", "Offset only works "
                           "on one object at a time."))
         else:
             self.proceed()
Пример #4
0
def makeLabel(targetpoint=None, target=None, direction=None,
              distance=None, labeltype=None, placement=None):
    """Create a Label. DEPRECATED. Use 'make_label'."""
    utils.use_instead("make_label")

    _name = "makeLabel"
    subelements = None

    if target:
        try:
            utils.type_check([(target, (tuple, list))],
                             name=_name)
        except TypeError:
            _err(_tr("Wrong input: must be a list of two elements. "
                     "For example, [object, 'Edge1']."))
            return None

    # In the old function `target` is the original parameter,
    # a list of two elements, the target object itself, and the subelement.
    # If the list is a single element, it is expanded to two elements
    # with the second being empty
    # target = [object]
    # target = [object, ]
    # target = [object, []]
    # target = (object, )
    # target = (object, ())

    # Parentheses can be used as well except a single pair
    # target = (object)
    target = list(target)
    if len(target) == 1:
        target.append([])

    target_object = target[0]
    subelements = target[1]

    return make_label(target_point=targetpoint,
                      placement=placement,
                      target_object=target_object,
                      subelements=subelements,
                      label_type=labeltype,
                      direction=direction,
                      distance=distance)
Пример #5
0
    def onDocumentRestored(self, obj):
        """Run when the document that is using this class is restored.

        Check if new properties are present after the object is restored
        in order to migrate older objects.
        """
        if hasattr(obj, "ViewObject") and obj.ViewObject:
            if not hasattr(obj.ViewObject, 'ScaleMultiplier'):
                # annotation properties
                vobj = obj.ViewObject
                _tip = "Dimension size overall multiplier"
                vobj.addProperty("App::PropertyFloat",
                                 "ScaleMultiplier",
                                 "Annotation",
                                 QT_TRANSLATE_NOOP("App::Property", _tip))
                vobj.ScaleMultiplier = 1.00

                _info = "added view property 'ScaleMultiplier'"
                _wrn("v0.19, " + obj.Label + ", " + _tr(_info))
Пример #6
0
    def Activated(self):
        """Execute when the command is called."""
        if self.running:
            self.finish()

        # TODO: iterate over all selected items to transform
        # many objects. As it is right now, it only works on the first object
        # in the selection.
        # Also, it is recommended to use the `self.commit` function
        # in order to properly open a transaction and commit it.
        selection = Gui.Selection.getSelection()
        if selection:
            if utils.getType(selection[0]) in ['Wire', 'BSpline']:
                super(WireToBSpline,
                      self).Activated(name=_tr("Convert polyline/B-spline"))
                if self.doc:
                    self.obj = Gui.Selection.getSelection()
                    if self.obj:
                        self.obj = self.obj[0]
                        self.pl = None
                        if "Placement" in self.obj.PropertiesList:
                            self.pl = self.obj.Placement
                        self.Points = self.obj.Points
                        self.closed = self.obj.Closed
                        n = None
                        if utils.getType(self.obj) == 'Wire':
                            n = Draft.makeBSpline(self.Points,
                                                  closed=self.closed,
                                                  placement=self.pl)
                        elif utils.getType(self.obj) == 'BSpline':
                            self.bs2wire = True
                            n = Draft.makeWire(self.Points,
                                               closed=self.closed,
                                               placement=self.pl,
                                               face=None,
                                               support=None,
                                               bs2wire=self.bs2wire)
                        if n:
                            Draft.formatObject(n, self.obj)
                            self.doc.recompute()
                    else:
                        self.finish()
Пример #7
0
 def Activated(self):
     """Execute when the command is called."""
     super(Arc, self).Activated(name=_tr(self.featureName))
     if self.ui:
         self.step = 0
         self.center = None
         self.rad = None
         self.angle = 0  # angle inscribed by arc
         self.tangents = []
         self.tanpoints = []
         if self.featureName == "Arc":
             self.ui.arcUi()
         else:
             self.ui.circleUi()
         self.altdown = False
         self.ui.sourceCmd = self
         self.linetrack = trackers.lineTracker(dotted=True)
         self.arctrack = trackers.arcTracker()
         self.call = self.view.addEventCallback("SoEvent", self.action)
         _msg(translate("draft", "Pick center point"))
Пример #8
0
def _are_numbers(d_x, d_y, d_z=None, name="Unknown"):
    """Check that the numbers are numbers."""
    _msg("d_x: {}".format(d_x))
    _msg("d_y: {}".format(d_y))
    if d_z:
        _msg("d_z: {}".format(d_z))

    try:
        if d_z:
            utils.type_check([(d_x, (int, float)), (d_y, (int, float)),
                              (d_z, (int, float))],
                             name=name)
        else:
            utils.type_check([(d_x, (int, float)), (d_y, (int, float))],
                             name=name)
    except TypeError:
        _err(_tr("Wrong input: must be a number."))
        return False, d_x, d_y, d_z

    return True, d_x, d_y, d_z
Пример #9
0
    def Activated(self, name="Point array"):
        """Execute when the command is called."""
        self.name = name
        super(PointArray, self).Activated(name=_tr(self.name))
        # This was deactivated because it doesn't work correctly;
        # the selection needs to be made on two objects, but currently
        # it only selects one.

        # if not Gui.Selection.getSelectionEx():
        #     if self.ui:
        #         self.ui.selectUi()
        #         _msg(translate("draft",
        #                        "Please select exactly two objects, "
        #                        "the base object and the point object, "
        #                        "before calling this command."))
        #         self.call = \
        #             self.view.addEventCallback("SoEvent",
        #                                        gui_tool_utils.selectObject)
        # else:
        #     self.proceed()
        self.proceed()
Пример #10
0
    def Activated(self, mode="None"):
        """Execute when the command is called.

        Parameters
        ----------
        action: str
            Indicates the type of mode to switch to.
            It can be `'construction'` or `'continue'`.
        """
        super().Activated()

        if hasattr(Gui, "draftToolBar"):
            _ui = Gui.draftToolBar
        else:
            _msg(_tr("No active Draft Toolbar."))
            return

        if _ui is not None:
            if mode == "construction" and hasattr(_ui, "constrButton"):
                _ui.constrButton.toggle()
            elif mode == "continue":
                _ui.toggleContinue()
Пример #11
0
def find_doc(doc=None):
    """Return the active document or find a document by name.

    Parameters
    ----------
    doc: App::Document or str, optional
        The document that will be searched in the session.
        It defaults to `None`, in which case it tries to find
        the active document.
        If `doc` is a string, it will try to get the document by `Name`.

    Returns
    -------
    bool, App::Document
        A tuple containing the information on whether the search
        was successful. In this case, the boolean is `True`,
        and the second value is the document instance.

    False, None
        If there is no active document, or the string in `doc`
        doesn't correspond to an open document in the session.
    """
    FOUND = True

    if not doc:
        doc = App.activeDocument()
    if not doc:
        return not FOUND, None

    if isinstance(doc, str):
        try:
            doc = App.getDocument(doc)
        except NameError:
            _msg("document: {}".format(doc))
            _err(_tr("Wrong input: unknown document."))
            return not FOUND, None

    return FOUND, doc
Пример #12
0
    def joinFaces(objectslist, coplanarity=False, checked=False):
        """Make one big face from selected objects, if possible."""
        faces = []
        for obj in objectslist:
            faces.extend(obj.Shape.Faces)

        # check coplanarity if needed
        if not checked:
            coplanarity = DraftGeomUtils.is_coplanar(faces, 1e-3)
        if not coplanarity:
            _err(_tr("Faces must be coplanar to be refined"))
            return None

        # fuse faces
        fuse_face = faces.pop(0)
        for face in faces:
            fuse_face = fuse_face.fuse(face)

        face = DraftGeomUtils.concatenate(fuse_face)
        # to prevent create new object if concatenate fails
        if face.isEqual(fuse_face):
            face = None

        if face:
            # several coplanar and non-curved faces,
            # they can become a Draft Wire
            if (not DraftGeomUtils.hasCurves(face) and len(face.Wires) == 1):
                newobj = make_wire.make_wire(face.Wires[0],
                                             closed=True,
                                             face=True)
            # if not possible, we do a non-parametric union
            else:
                newobj = doc.addObject("Part::Feature", "Union")
                newobj.Shape = face
            add_list.append(newobj)
            delete_list.extend(objectslist)
            return newobj
        return None
Пример #13
0
def get_3d_view():
    """Return the current 3D view.

    Returns
    -------
    Gui::View3DInventor
        Return the current `ActiveView` in the active document,
        or the first `Gui::View3DInventor` view found.

        Return `None` if the graphical interface is not available.
    """
    if App.GuiUp:
        v = Gui.ActiveDocument.ActiveView
        if "View3DInventor" in str(type(v)):
            return v

        # print("Debug: Draft: Warning, not working in active view")
        v = Gui.ActiveDocument.mdiViewsOfType("Gui::View3DInventor")
        if v:
            return v[0]

    _wrn(_tr("No graphical interface"))
    return None
Пример #14
0
    def onDocumentRestored(self, obj):
        """Execute code when the document is restored.

        Add properties that don't exist and migrate old properties.
        """
        # If the ExtraPlacement property has never been added before
        # it will add it first, and set it to the base object's position
        # in order to produce the same displacement as before.
        # Then all the other properties will be processed.
        properties = obj.PropertiesList

        if "ExtraPlacement" not in properties:
            _tip = QT_TRANSLATE_NOOP(
                "App::Property", "Additional placement, shift and rotation, "
                "that will be applied to each copy")
            obj.addProperty("App::PropertyPlacement", "ExtraPlacement",
                            "Objects", _tip)
            obj.ExtraPlacement.Base = obj.Base.Placement.Base
            _info = "added property 'ExtraPlacement'"
            _wrn("v0.19, " + obj.Label + ", " + _tr(_info))

        self.set_properties(obj)
        self.migrate_properties_0v19(obj)
Пример #15
0
    def Activated(self, action="None"):
        """Execute when the command is called.

        Parameters
        ----------
        action: str
            Indicates the type of action to perform with the line object.
            It can be `'finish'`, `'close'`, or `'undo'`.
        """
        if hasattr(App, "activeDraftCommand"):
            _command = App.activeDraftCommand
        else:
            _msg(_tr("No active command."))
            return

        if (_command is not None
                and _command.featureName in ("Line", "Polyline", "BSpline",
                                             "BezCurve", "CubicBezCurve")):
            if action == "finish":
                _command.finish(False)
            elif action == "close":
                _command.finish(True)
            elif action == "undo":
                _command.undolast()
Пример #16
0
    def execute(self, obj):
        """Execute when the object is created or recomputed."""
        if not obj.Base or not obj.PathObject:
            return

        # placement of entire PathArray object
        array_placement = obj.Placement

        w = self.get_wires(obj.PathObject, obj.PathSubelements)
        if not w:
            _err(obj.PathObject.Label
                 + _tr(", path object doesn't have 'Edges'."))
            return

        base_rotation = obj.Base.Shape.Placement.Rotation
        final_rotation = base_rotation

        if (obj.Align and obj.AlignMode == "Tangent"
                and hasattr(obj, "TangentVector")):
            Xaxis = App.Vector(1.0, 0.0, 0.0)  # default TangentVector

            if not DraftVecUtils.equals(Xaxis, obj.TangentVector):
                # make rotation from TangentVector to X
                pre_rotation = App.Rotation(obj.TangentVector, Xaxis)
                final_rotation = base_rotation.multiply(pre_rotation)

        copy_placements = placements_on_path(final_rotation,
                                             w, obj.Count,
                                             obj.ExtraTranslation,
                                             obj.Align, obj.AlignMode,
                                             obj.ForceVertical,
                                             obj.VerticalVector)

        return super(PathArray, self).buildShape(obj,
                                                 array_placement,
                                                 copy_placements)
Пример #17
0
 def print_messages(self):
     """Print messages about the operation."""
     if len(self.selection) == 1:
         sel_obj = self.selection[0]
     else:
         # TODO: this should handle multiple objects.
         # For example, it could take the shapes of all objects,
         # make a compound and then use it as input for the array function.
         sel_obj = self.selection[0]
     _msg(_tr("Object:") + " {}".format(sel_obj.Label))
     _msg(_tr("Radial distance:") + " {}".format(self.r_distance))
     _msg(_tr("Tangential distance:") + " {}".format(self.tan_distance))
     _msg(_tr("Number of circular layers:") + " {}".format(self.number))
     _msg(_tr("Symmetry parameter:") + " {}".format(self.symmetry))
     _msg(
         _tr("Center of rotation:") + " ({0}, {1}, {2})".format(
             self.center.x, self.center.y, self.center.z))
     self.print_fuse_state(self.fuse)
     self.print_link_state(self.use_link)
Пример #18
0
 def print_messages(self):
     """Print messages about the operation."""
     if len(self.selection) == 1:
         sel_obj = self.selection[0]
     else:
         # TODO: this should handle multiple objects.
         # For example, it could take the shapes of all objects,
         # make a compound and then use it as input for the array function.
         sel_obj = self.selection[0]
     _msg(_tr("Object:") + " {}".format(sel_obj.Label))
     _msg(_tr("Number of X elements:") + " {}".format(self.n_x))
     _msg(
         _tr("Interval X:") +
         " ({0}, {1}, {2})".format(self.v_x.x, self.v_x.y, self.v_x.z))
     _msg(_tr("Number of Y elements:") + " {}".format(self.n_y))
     _msg(
         _tr("Interval Y:") +
         " ({0}, {1}, {2})".format(self.v_y.x, self.v_y.y, self.v_y.z))
     _msg(_tr("Number of Z elements:") + " {}".format(self.n_z))
     _msg(
         _tr("Interval Z:") +
         " ({0}, {1}, {2})".format(self.v_z.x, self.v_z.y, self.v_z.z))
     self.print_fuse_state(self.fuse)
     self.print_link_state(self.use_link)
Пример #19
0
    def validate_input(self, selection, number, angle, center):
        """Check that the input is valid.

        Some values may not need to be checked because
        the interface may not allow to input wrong data.
        """
        if not selection:
            _err(_tr("At least one element must be selected."))
            return False

        # TODO: this should handle multiple objects.
        # Each of the elements of the selection should be tested.
        obj = selection[0]
        if obj.isDerivedFrom("App::FeaturePython"):
            _err(_tr("Selection is not suitable for array."))
            _err(_tr("Object:") + " {}".format(selection[0].Label))
            return False

        if number < 2:
            _err(_tr("Number of elements must be at least 2."))
            return False

        if angle > 360:
            _wrn(
                _tr("The angle is above 360 degrees. "
                    "It is set to this value to proceed."))
            self.angle = 360
        elif angle < -360:
            _wrn(
                _tr("The angle is below -360 degrees. "
                    "It is set to this value to proceed."))
            self.angle = -360

        # The other arguments are not tested but they should be present.
        if center:
            pass

        self.fuse = self.form.checkbox_fuse.isChecked()
        self.use_link = self.form.checkbox_link.isChecked()
        return True
Пример #20
0
 def Activated(self):
     """Execute when the command is called."""
     super(LinkArray, self).Activated(name=_tr("Link array"))
Пример #21
0
    def __init__(self):
        self.name = "Orthogonal array"
        _log(_tr("Task panel:") + " {}".format(_tr(self.name)))

        # The .ui file must be loaded into an attribute
        # called `self.form` so that it is displayed in the task panel.
        ui_file = ":/ui/TaskPanel_OrthoArray.ui"
        self.form = Gui.PySideUic.loadUi(ui_file)

        icon_name = "Draft_Array"
        svg = ":/icons/" + icon_name
        pix = QtGui.QPixmap(svg)
        icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg))
        self.form.setWindowIcon(icon)
        self.form.setWindowTitle(_tr(self.name))

        self.form.label_icon.setPixmap(pix.scaled(32, 32))

        # -------------------------------------------------------------------
        # Default values for the internal function,
        # and for the task panel interface
        start_x = U.Quantity(100.0, App.Units.Length)
        start_y = start_x
        start_z = start_x
        length_unit = start_x.getUserPreferred()[2]

        self.v_x = App.Vector(start_x.Value, 0, 0)
        self.v_y = App.Vector(0, start_y.Value, 0)
        self.v_z = App.Vector(0, 0, start_z.Value)

        self.form.input_X_x.setProperty('rawValue', self.v_x.x)
        self.form.input_X_x.setProperty('unit', length_unit)
        self.form.input_X_y.setProperty('rawValue', self.v_x.y)
        self.form.input_X_y.setProperty('unit', length_unit)
        self.form.input_X_z.setProperty('rawValue', self.v_x.z)
        self.form.input_X_z.setProperty('unit', length_unit)

        self.form.input_Y_x.setProperty('rawValue', self.v_y.x)
        self.form.input_Y_x.setProperty('unit', length_unit)
        self.form.input_Y_y.setProperty('rawValue', self.v_y.y)
        self.form.input_Y_y.setProperty('unit', length_unit)
        self.form.input_Y_z.setProperty('rawValue', self.v_y.z)
        self.form.input_Y_z.setProperty('unit', length_unit)

        self.form.input_Z_x.setProperty('rawValue', self.v_z.x)
        self.form.input_Z_x.setProperty('unit', length_unit)
        self.form.input_Z_y.setProperty('rawValue', self.v_z.y)
        self.form.input_Z_y.setProperty('unit', length_unit)
        self.form.input_Z_z.setProperty('rawValue', self.v_z.z)
        self.form.input_Z_z.setProperty('unit', length_unit)

        self.n_x = 2
        self.n_y = 2
        self.n_z = 1

        self.form.spinbox_n_X.setValue(self.n_x)
        self.form.spinbox_n_Y.setValue(self.n_y)
        self.form.spinbox_n_Z.setValue(self.n_z)

        self.fuse = utils.get_param("Draft_array_fuse", False)
        self.use_link = utils.get_param("Draft_array_Link", True)

        self.form.checkbox_fuse.setChecked(self.fuse)
        self.form.checkbox_link.setChecked(self.use_link)
        # -------------------------------------------------------------------

        # Some objects need to be selected before we can execute the function.
        self.selection = None

        # This is used to test the input of the internal function.
        # It should be changed to True before we can execute the function.
        self.valid_input = False

        self.set_widget_callbacks()

        self.tr_true = QT_TRANSLATE_NOOP("Draft", "True")
        self.tr_false = QT_TRANSLATE_NOOP("Draft", "False")
Пример #22
0
 def reject(self):
     """Execute when clicking the Cancel button or pressing Escape."""
     _msg(_tr("Aborted:") + " {}".format(_tr(self.name)))
     self.finish()
Пример #23
0
 def __init__(self):
     super(Draft_Snap_Dimensions,
           self).__init__(name=_tr("Dimension display"))
Пример #24
0
 def __init__(self):
     super(Draft_Snap_Special,
           self).__init__(name=_tr("Special point snap"))
Пример #25
0
 def __init__(self):
     super(Draft_Snap_Ortho, self).__init__(name=_tr("Orthogonal snap"))
Пример #26
0
def dim_symbol(symbol=None, invert=False):
    """Return the specified dimension symbol.

    Parameters
    ----------
    symbol: int, optional
        It defaults to `None`, in which it gets the value from the parameter
        database, `get_param("dimsymbol", 0)`.

        A numerical value defines different markers
         * 0, `SoSphere`
         * 1, `SoMarkerSet` with a circle
         * 2, `SoSeparator` with a `soCone`
         * 3, `SoSeparator` with a `SoFaceSet`
         * 4, `SoSeparator` with a `SoLineSet`, calling `dim_dash`
         * Otherwise, `SoSphere`

    invert: bool, optional
        It defaults to `False`.
        If it is `True` and `symbol=2`, the cone will be rotated
        -90 degrees around the Z axis, otherwise the rotation is positive,
        +90 degrees.

    Returns
    -------
    Coin.SoNode
        A `Coin.SoSphere`, or `Coin.SoMarkerSet` (circle),
        or `Coin.SoSeparator` (cone, face, line)
        that will be used as a dimension symbol.
    """
    if symbol is None:
        symbol = utils.get_param("dimsymbol", 0)

    if symbol == 0:
        # marker = coin.SoMarkerSet()
        # marker.markerIndex = 80

        # Returning a sphere means that the bounding box will
        # be 3-dimensional; a marker will always be planar seen from any
        # orientation but it currently doesn't work correctly
        marker = coin.SoSphere()
        return marker
    elif symbol == 1:
        marker = coin.SoMarkerSet()
        # Should be the same as
        # marker.markerIndex = 10
        marker.markerIndex = Gui.getMarkerIndex("circle", 9)
        return marker
    elif symbol == 2:
        marker = coin.SoSeparator()
        t = coin.SoTransform()
        t.translation.setValue((0, -2, 0))
        t.center.setValue((0, 2, 0))
        if invert:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), -math.pi/2)
        else:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), math.pi/2)
        c = coin.SoCone()
        c.height.setValue(4)
        marker.addChild(t)
        marker.addChild(c)
        return marker
    elif symbol == 3:
        marker = coin.SoSeparator()
        c = coin.SoCoordinate3()
        c.point.setValues([(-1, -2, 0), (0, 2, 0),
                           (1, 2, 0), (0, -2, 0)])
        f = coin.SoFaceSet()
        marker.addChild(c)
        marker.addChild(f)
        return marker
    elif symbol == 4:
        return dimDash((-1.5, -1.5, 0), (1.5, 1.5, 0))
    else:
        _wrn(_tr("Symbol not implemented. Use a default symbol."))
        return coin.SoSphere()
Пример #27
0
def load_texture(filename, size=None, gui=App.GuiUp):
    """Return a Coin.SoSFImage to use as a texture for a 2D plane.

    This function only works if the graphical interface is available
    as the visual properties that can be applied to a shape
    are attributes of the view provider (`obj.ViewObject`).

    Parameters
    ----------
    filename: str
        A path to a pixel image file (PNG) that can be used as a texture
        on the face of an object.

    size: tuple of two int, or a single int, optional
        It defaults to `None`.
        If a tuple is given, the two values define the width and height
        in pixels to which the loaded image will be scaled.
        If it is a single value, it is used for both dimensions.

        If it is `None`, the size will be determined from the `QImage`
        created from `filename`.

        CURRENTLY the input `size` parameter IS NOT USED.
        It always uses the `QImage` to determine this information.

    gui: bool, optional
        It defaults to the value of `App.GuiUp`, which is `True`
        when the interface exists, and `False` otherwise.

        This value can be set to `False` to simulate
        when the interface is not available.

    Returns
    -------
    coin.SoSFImage
        An image object with the appropriate size, number of components
        (grayscale, grayscale and transparency, color,
        color and transparency), and byte data.

        It returns `None` if the interface is not available,
        or if there is a problem creating the image.
    """
    if gui:
        # from pivy import coin
        # from PySide import QtGui, QtSvg
        try:
            p = QtGui.QImage(filename)

            if p.isNull():
                _wrn("load_texture: " + _tr("image is Null"))

                if not os.path.exists(filename):
                    raise FileNotFoundError(-1,
                                            _tr("filename does not exist "
                                                "on the system or "
                                                "on the resource file"),
                                            filename)

            # This is buggy so it was de-activated.
            #
            # TODO: allow SVGs to use resolutions
            # if size and (".svg" in filename.lower()):
            #    # this is a pattern, not a texture
            #    if isinstance(size, int):
            #        size = (size, size)
            #    svgr = QtSvg.QSvgRenderer(filename)
            #    p = QtGui.QImage(size[0], size[1],
            #                     QtGui.QImage.Format_ARGB32)
            #    pa = QtGui.QPainter()
            #    pa.begin(p)
            #    svgr.render(pa)
            #    pa.end()
            # else:
            #    p = QtGui.QImage(filename)
            size = coin.SbVec2s(p.width(), p.height())
            buffersize = p.byteCount()
            width = size[0]
            height = size[1]
            numcomponents = int(float(buffersize) / (width * height))

            img = coin.SoSFImage()
            byteList = []
            # isPy2 = sys.version_info.major < 3
            isPy2 = six.PY2

            # The SoSFImage needs to be filled with bytes.
            # The pixel information is converted into a Qt color, gray,
            # red, green, blue, or transparency (alpha),
            # depending on the input image.
            #
            # If Python 2 is used, the color is turned into a character,
            # which is of type 'byte', and added to the byte list.
            # If Python 3 is used, characters are unicode strings,
            # so they need to be encoded into 'latin-1'
            # to produce the correct bytes for the list.
            for y in range(height):
                # line = width*numcomponents*(height-(y));
                for x in range(width):
                    rgb = p.pixel(x, y)
                    if numcomponents == 1 or numcomponents == 2:
                        gray = chr(QtGui.qGray(rgb))
                        if isPy2:
                            byteList.append(gray)
                        else:
                            byteList.append(gray.encode('latin-1'))

                        if numcomponents == 2:
                            alpha = chr(QtGui.qAlpha(rgb))
                            if isPy2:
                                byteList.append(alpha)
                            else:
                                byteList.append(alpha.encode('latin-1'))
                    elif numcomponents == 3 or numcomponents == 4:
                        red = chr(QtGui.qRed(rgb))
                        green = chr(QtGui.qGreen(rgb))
                        blue = chr(QtGui.qBlue(rgb))

                        if isPy2:
                            byteList.append(red)
                            byteList.append(green)
                            byteList.append(blue)
                        else:
                            byteList.append(red.encode('latin-1'))
                            byteList.append(green.encode('latin-1'))
                            byteList.append(blue.encode('latin-1'))

                        if numcomponents == 4:
                            alpha = chr(QtGui.qAlpha(rgb))
                            if isPy2:
                                byteList.append(alpha)
                            else:
                                byteList.append(alpha.encode('latin-1'))
                    # line += numcomponents

            _bytes = b"".join(byteList)
            img.setValue(size, numcomponents, _bytes)
        except FileNotFoundError as exc:
            _wrn("load_texture: {0}, {1}".format(exc.strerror,
                                                 exc.filename))
            return None
        except Exception as exc:
            _wrn(str(exc))
            _wrn("load_texture: " + _tr("unable to load texture"))
            return None
        else:
            return img
    return None
Пример #28
0
 def __init__(self):
     super(Draft_Snap_WorkingPlane,
           self).__init__(name=_tr("Working plane snap"))
Пример #29
0
def get_bbox(obj, debug=False):
    """Return a BoundBox from any object that has a Coin RootNode.

    Normally the bounding box of an object can be taken
    from its `Part::TopoShape`.
    ::
        >>> print(obj.Shape.BoundBox)

    However, for objects without a `Shape`, such as those
    derived from `App::FeaturePython` like `Draft Text` and `Draft Dimension`,
    the bounding box can be calculated from the `RootNode` of the viewprovider.

    Parameters
    ----------
    obj: App::DocumentObject
        Any object that has a `ViewObject.RootNode`.

    Returns
    -------
    Base::BoundBox
        It returns a `BoundBox` object which has information like
        minimum and maximum values of X, Y, and Z, as well as bounding box
        center.

    None
        If there is a problem it will return `None`.
    """
    _name = "get_bbox"
    utils.print_header(_name, "Bounding box", debug=debug)

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

    if isinstance(obj, str):
        obj_str = obj

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

    if debug:
        _msg("obj: {}".format(obj.Label))

    if (not hasattr(obj, "ViewObject")
            or not obj.ViewObject
            or not hasattr(obj.ViewObject, "RootNode")):
        _err(_tr("Does not have 'ViewObject.RootNode'."))

    # For Draft Dimensions
    # node = obj.ViewObject.Proxy.node
    node = obj.ViewObject.RootNode

    view = Gui.ActiveDocument.ActiveView
    region = view.getViewer().getSoRenderManager().getViewportRegion()
    action = coin.SoGetBoundingBoxAction(region)

    node.getBoundingBox(action)
    bb = action.getBoundingBox()

    # xlength, ylength, zlength = bb.getSize().getValue()
    xmin, ymin, zmin = bb.getMin().getValue()
    xmax, ymax, zmax = bb.getMax().getValue()

    return App.BoundBox(xmin, ymin, zmin, xmax, ymax, zmax)
Пример #30
0
 def __init__(self):
     super(ShowSnapBar, self).__init__(name=_tr("Show snap toolbar"))