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 @@
+
+
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