diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 1e4727904a..86c265d758 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -64,6 +64,7 @@ icons/Draft_PlaneProxy.svg icons/Draft_Point.svg icons/Draft_PointArray.svg + icons/Draft_PointLinkArray.svg icons/Draft_PolarArray.svg icons/Draft_PolarLinkArray.svg icons/Draft_Polygon.svg diff --git a/src/Mod/Draft/Resources/icons/Draft_PointLinkArray.svg b/src/Mod/Draft/Resources/icons/Draft_PointLinkArray.svg new file mode 100644 index 0000000000..f4f9424db6 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_PointLinkArray.svg @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Sat Dec 10 18:31:32 2011 +0000 + + + [yorikvanhavre] + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + FreeCAD/src/Mod/Draft/Resources/icons/Draft_Array.svg + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + [agryson] Alexander Gryson + + + Six rectangles in a 2 x 3 linear array + + + rectangle + array + + + + + + + + + + diff --git a/src/Mod/Draft/draftguitools/gui_arrays.py b/src/Mod/Draft/draftguitools/gui_arrays.py index 57d772ed0f..e9f925ecf0 100644 --- a/src/Mod/Draft/draftguitools/gui_arrays.py +++ b/src/Mod/Draft/draftguitools/gui_arrays.py @@ -55,7 +55,7 @@ class ArrayGroup: return ("Draft_OrthoArray", "Draft_PolarArray", "Draft_CircularArray", "Draft_PathArray", "Draft_PathLinkArray", - "Draft_PointArray", + "Draft_PointArray", "Draft_PointLinkArray") "Draft_PathTwistedArray", "Draft_PathTwistedLinkArray") def GetResources(self): diff --git a/src/Mod/Draft/draftguitools/gui_pointarray.py b/src/Mod/Draft/draftguitools/gui_pointarray.py index 1375226f72..49efd09ade 100644 --- a/src/Mod/Draft/draftguitools/gui_pointarray.py +++ b/src/Mod/Draft/draftguitools/gui_pointarray.py @@ -56,7 +56,18 @@ True if Draft_rc.__name__ else False class PointArray(gui_base_original.Modifier): - """Gui Command for the Point array tool.""" + """Gui Command for the Point array tool. + + Parameters + ---------- + use_link: bool, optional + It defaults to `False`. If it is `True`, the created object + will be a `Point link array`. + """ + + def __init__(self, use_link=False): + super(PointArray, self).__init__() + self.use_link = use_link def GetResources(self): """Set icon, menu and tooltip.""" @@ -78,9 +89,9 @@ class PointArray(gui_base_original.Modifier): 'MenuText': QT_TRANSLATE_NOOP("Draft_PointArray", _menu), 'ToolTip': QT_TRANSLATE_NOOP("Draft_PointArray", _tip)} - def Activated(self): + def Activated(self, name="Point array"): """Execute when the command is called.""" - self.name = "Point array" + 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 @@ -120,7 +131,8 @@ class PointArray(gui_base_original.Modifier): _cmd += "(" _cmd += "App.ActiveDocument." + base_object.Name + ", " _cmd += "App.ActiveDocument." + point_object.Name + ", " - _cmd += "extra=" + str(extra) + _cmd += "extra=" + str(extra) + ", " + _cmd += 'use_link=' + str(self.use_link) _cmd += ")" _cmd_list = ["_obj_ = " + _cmd, @@ -135,4 +147,26 @@ class PointArray(gui_base_original.Modifier): Gui.addCommand('Draft_PointArray', PointArray()) +class PointLinkArray(PointArray): + """Gui Command for the PointLinkArray tool based on the PointArray tool.""" + + def __init__(self): + super(PointLinkArray, self).__init__(use_link=True) + + def GetResources(self): + """Set icon, menu and tooltip.""" + _tip = ("Like the PointArray tool, but creates a 'Point link array' instead.\n" + "A 'Point link array' is more efficient when handling many copies.") + + return {'Pixmap': 'Draft_PointLinkArray', + 'MenuText': QT_TRANSLATE_NOOP("Draft_PointLinkArray", "PointLinkArray"), + 'ToolTip': QT_TRANSLATE_NOOP("Draft_PointLinkArray", _tip)} + + def Activated(self): + """Execute when the command is called.""" + super(PointLinkArray, self).Activated(name="Point link array") + + +Gui.addCommand('Draft_PointLinkArray', PointLinkArray()) + ## @} diff --git a/src/Mod/Draft/draftmake/make_pointarray.py b/src/Mod/Draft/draftmake/make_pointarray.py index cee733d824..1935d26cec 100644 --- a/src/Mod/Draft/draftmake/make_pointarray.py +++ b/src/Mod/Draft/draftmake/make_pointarray.py @@ -45,9 +45,10 @@ from draftobjects.pointarray import PointArray if App.GuiUp: from draftviewproviders.view_array import ViewProviderDraftArray + from draftviewproviders.view_draftlink import ViewProviderDraftLink -def make_point_array(base_object, point_object, extra=None): +def make_point_array(base_object, point_object, extra=None, use_link=True): """Make a Draft PointArray object. Distribute copies of a `base_object` in the points @@ -154,19 +155,29 @@ def make_point_array(base_object, point_object, extra=None): elif isinstance(extra, App.Rotation): extra = App.Placement(App.Vector(), extra) - new_obj = doc.addObject("Part::FeaturePython", "PointArray") - PointArray(new_obj) + if use_link: + # The PointArray class must be called in this special way + # to make it a LinkArray + new_obj = doc.addObject("Part::FeaturePython", "PointArray", + PointArray(None), None, True) + else: + 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 use_link: + ViewProviderDraftLink(new_obj.ViewObject) + else: + ViewProviderDraftArray(new_obj.ViewObject) + gui_utils.format_object(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) + 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) diff --git a/src/Mod/Draft/draftobjects/pointarray.py b/src/Mod/Draft/draftobjects/pointarray.py index e01f6030a8..f3ecac55d7 100644 --- a/src/Mod/Draft/draftobjects/pointarray.py +++ b/src/Mod/Draft/draftobjects/pointarray.py @@ -45,7 +45,7 @@ import draftutils.utils as utils from draftutils.messages import _wrn, _err from draftutils.translate import translate, _tr -from draftobjects.base import DraftObject +from draftobjects.draftlink import DraftLink # Delay import of module until first use because it is heavy Part = lz.LazyLoader("Part", globals(), "Part") @@ -54,12 +54,17 @@ Part = lz.LazyLoader("Part", globals(), "Part") # @{ -class PointArray(DraftObject): +class PointArray(DraftLink): """The Draft Point Array object.""" def __init__(self, obj): super(PointArray, self).__init__(obj, "PointArray") + + def attach(self, obj): + """Set up the properties when the object is attached.""" self.set_properties(obj) + super(PointArray, self).attach(obj) + obj.configLinkProperty(ElementCount='Count') def set_properties(self, obj): """Set properties only if they don't exist.""" @@ -109,19 +114,22 @@ class PointArray(DraftObject): _tip) obj.ExtraPlacement = App.Placement() + if self.use_link and "ExpandArray" not in properties: + _tip = _tr("Show the individual array elements " + "(only for Link arrays)") + obj.addProperty("App::PropertyBool", + "ExpandArray", + "Objects", + _tip) + obj.setPropertyStatus('Shape', 'Transient') + def execute(self, obj): """Run when the object is created or recomputed.""" - if not hasattr(obj.Base, 'Shape'): - _err(_tr("Base object doesn't have a 'Shape', " - "it cannot be used for an array.")) - obj.Count = 0 - return pt_list, count = get_point_list(obj.PointObject) - shape = build_copies(obj.Base, pt_list, obj.ExtraPlacement) + pls = build_placements(obj.Base, pt_list, obj.ExtraPlacement) - obj.Shape = shape - obj.Count = count + return super(PointArray, self).buildShape(obj, obj.Placement, pls) def onDocumentRestored(self, obj): """Execute code when the document is restored. @@ -147,6 +155,7 @@ class PointArray(DraftObject): self.set_properties(obj) self.migrate_properties_0v19(obj) + return super(PointArray, self).onDocumentRestored(obj) def migrate_properties_0v19(self, obj): """Migrate properties.""" @@ -231,33 +240,30 @@ def get_point_list(point_object): count = len(pt_list) return pt_list, count - -def build_copies(base_object, pt_list=None, placement=App.Placement()): - """Build a compound of copies from the base object and list of points. +def build_placements(base_object, pt_list=None, placement=App.Placement()): + """Build a placements from the base object and list of points. Returns ------- - Part::TopoShape - The compound shape created by `Part.makeCompound`. + list(App.Placement) """ if not pt_list: _err(translate("Draft", "Point object doesn't have a discrete point, " "it cannot be used for an array.")) - shape = base_object.Shape.copy() - return shape + return [] - copies = list() + pls = list() for point in pt_list: - new_shape = base_object.Shape.copy() - original_rotation = new_shape.Placement.Rotation + new_pla = base_object.Placement.copy() + original_rotation = new_pla.Rotation # Reset the position of the copy, and combine the original rotation # with the provided rotation. Two rotations (quaternions) # are combined by multiplying them. - new_shape.Placement.Base = placement.Base - new_shape.Placement.Rotation = original_rotation * placement.Rotation + new_pla.Base = placement.Base + new_pla.Rotation = original_rotation * placement.Rotation if point.TypeId == "Part::Vertex": # For this object the final position is the value of the Placement @@ -288,7 +294,33 @@ def build_copies(base_object, pt_list=None, placement=App.Placement()): # translate by the X, Y, Z coordinates place = App.Vector(point.X, point.Y, point.Z) - new_shape.translate(place) + new_pla.translate(place) + + pls.append(new_pla) + + return pls + +def build_copies(base_object, pt_list=None, placement=App.Placement()): + """Build a compound of copies from the base object and list of points. + + Returns + ------- + Part::TopoShape + The compound shape created by `Part.makeCompound`. + """ + + if not pt_list: + _err(translate("Draft", + "Point object doesn't have a discrete point, " + "it cannot be used for an array.")) + shape = base_object.Shape.copy() + return shape + + copies = list() + + for pla in build_copies(base_object, pt_list, placement): + new_shape = base_object.Shape.copy() + new_shape.Placement = pla copies.append(new_shape) diff --git a/src/Mod/Draft/draftviewproviders/view_draftlink.py b/src/Mod/Draft/draftviewproviders/view_draftlink.py index bd163487d6..60b54a7b65 100644 --- a/src/Mod/Draft/draftviewproviders/view_draftlink.py +++ b/src/Mod/Draft/draftviewproviders/view_draftlink.py @@ -28,24 +28,14 @@ ## \addtogroup draftviewproviders # @{ +from draftviewproviders.view_base import ViewProviderDraft - -class ViewProviderDraftLink: +class ViewProviderDraftLink(ViewProviderDraft): """ A view provider for link type object. """ def __init__(self,vobj): - self.Object = vobj.Object - vobj.Proxy = self - - def attach(self,vobj): - self.Object = vobj.Object - - def __getstate__(self): - return None - - def __setstate__(self, state): - return None + super(ViewProviderDraftLink, self).__init__(vobj) def getIcon(self): tp = self.Object.Proxy.Type @@ -60,6 +50,8 @@ class ViewProviderDraftLink: return ":/icons/Draft_PathLinkArray.svg" elif tp == 'PathTwistedArray': return ":/icons/Draft_PathTwistedLinkArray.svg" + elif tp == 'PointArray': + return ":/icons/Draft_PointLinkArray.svg" def claimChildren(self): obj = self.Object @@ -68,7 +60,7 @@ class ViewProviderDraftLink: else: expand = obj.ShowElement if not expand: - return [obj.Base] + return super(ViewProviderDraftLink, self).claimChildren() else: return obj.ElementList