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
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)
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()
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)
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))
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()
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"))
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
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()
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()
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
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
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
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)
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()
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)
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)
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)
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
def Activated(self): """Execute when the command is called.""" super(LinkArray, self).Activated(name=_tr("Link array"))
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")
def reject(self): """Execute when clicking the Cancel button or pressing Escape.""" _msg(_tr("Aborted:") + " {}".format(_tr(self.name))) self.finish()
def __init__(self): super(Draft_Snap_Dimensions, self).__init__(name=_tr("Dimension display"))
def __init__(self): super(Draft_Snap_Special, self).__init__(name=_tr("Special point snap"))
def __init__(self): super(Draft_Snap_Ortho, self).__init__(name=_tr("Orthogonal snap"))
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()
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
def __init__(self): super(Draft_Snap_WorkingPlane, self).__init__(name=_tr("Working plane snap"))
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)
def __init__(self): super(ShowSnapBar, self).__init__(name=_tr("Show snap toolbar"))