Draft: add support for point link array

This commit is contained in:
Zheng, Lei
2020-08-22 10:36:06 +08:00
committed by Yorik van Havre
parent 423c374258
commit e3e7686773
7 changed files with 471 additions and 50 deletions

View File

@@ -64,6 +64,7 @@
<file>icons/Draft_PlaneProxy.svg</file>
<file>icons/Draft_Point.svg</file>
<file>icons/Draft_PointArray.svg</file>
<file>icons/Draft_PointLinkArray.svg</file>
<file>icons/Draft_PolarArray.svg</file>
<file>icons/Draft_PolarLinkArray.svg</file>
<file>icons/Draft_Polygon.svg</file>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -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):

View File

@@ -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())
## @}

View File

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

View File

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

View File

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