Merge pull request #19487 from Roy-043/Draft-make-arrays-explodable

Draft: make arrays explodable
This commit is contained in:
Roy-043
2025-02-10 16:16:18 +01:00
committed by GitHub
6 changed files with 141 additions and 52 deletions

View File

@@ -32,6 +32,7 @@ See also the `upgrade` function.
# @{
import FreeCAD as App
from draftfunctions import cut
from draftmake import make_copy
from draftutils import utils
from draftutils import params
from draftutils import gui_utils
@@ -85,13 +86,33 @@ def downgrade(objects, delete=False, force=None):
# actions definitions
def explode(obj):
"""Explode a Draft block."""
pl = obj.Placement
for o in obj.Components:
o.Placement = pl.multiply(o.Placement)
if App.GuiUp:
o.ViewObject.Visibility = True
"""Explode a Draft block or array."""
obj_pl = obj.Placement
# block:
if getattr(obj, "Components", []):
delete_list.append(obj)
for comp in obj.Components:
comp.Placement = obj_pl.multiply(comp.Placement)
comp.Visibility = True
return True
# array:
if getattr(obj, "Base", None) is None:
return False
if not hasattr(obj, "PlacementList"):
return False
base = obj.Base
delete_list.append(obj)
if getattr(obj, "ExpandArray", False):
for lnk in obj.ElementList:
new = make_copy.make_copy(base)
new.Placement = obj_pl.multiply(lnk.Placement)
new.Visibility = True
delete_list.append(lnk)
else:
for arr_pl in obj.PlacementList:
new = make_copy.make_copy(base)
new.Placement = obj_pl.multiply(arr_pl)
new.Visibility = True
return True
def cut2(objects):
@@ -240,15 +261,22 @@ def downgrade(objects, delete=False, force=None):
shapify = utils.shapify
result = eval(force)(objects)
else:
_msg(translate("draft","Upgrade: Unknown force method:") + " " + force)
_msg(translate("draft", "Upgrade: Unknown force method:") + " " + force)
result = None
else:
# applying transformation automatically
# we have a block, we explode it
if len(objects) == 1 and utils.get_type(objects[0]) == "Block":
result = explode(objects[0])
if result:
_msg(translate("draft","Found 1 block: exploding it"))
_msg(translate("draft", "Found 1 block: exploding it"))
# we have an array, we explode it
elif len(objects) == 1 \
and "Array" in utils.get_type(objects[0]) \
and hasattr(objects[0], "PlacementList"):
result = explode(objects[0])
if result:
_msg(translate("draft", "Found 1 array: exploding it"))
# we have one multi-solids compound object: extract its solids
elif len(objects) == 1 \
@@ -257,7 +285,7 @@ def downgrade(objects, delete=False, force=None):
result = splitCompounds(objects)
# print(result)
if result:
_msg(translate("draft","Found 1 multi-solids compound: exploding it"))
_msg(translate("draft", "Found 1 multi-solids compound: exploding it"))
# special case, we have one parametric object: we "de-parametrize" it
elif len(objects) == 1 \
@@ -266,7 +294,7 @@ def downgrade(objects, delete=False, force=None):
and not objects[0].isDerivedFrom("PartDesign::Feature"):
result = utils.shapify(objects[0])
if result:
_msg(translate("draft","Found 1 parametric object: breaking its dependencies"))
_msg(translate("draft", "Found 1 parametric object: breaking its dependencies"))
add_list.append(result)
# delete_list.append(objects[0])
@@ -274,35 +302,35 @@ def downgrade(objects, delete=False, force=None):
elif len(objects) == 2:
result = cut2(objects)
if result:
_msg(translate("draft","Found 2 objects: subtracting them"))
_msg(translate("draft", "Found 2 objects: subtracting them"))
elif len(faces) > 1:
# one object with several faces: split it
if len(objects) == 1:
result = splitFaces(objects)
if result:
_msg(translate("draft","Found several faces: splitting them"))
_msg(translate("draft", "Found several faces: splitting them"))
# several objects: remove all the faces from the first one
else:
result = subtr(objects)
if result:
_msg(translate("draft","Found several objects: subtracting them from the first one"))
_msg(translate("draft", "Found several objects: subtracting them from the first one"))
# only one face: we extract its wires
elif len(faces) > 0:
result = getWire(objects[0])
if result:
_msg(translate("draft","Found 1 face: extracting its wires"))
_msg(translate("draft", "Found 1 face: extracting its wires"))
# no faces: split wire into single edges
elif not onlyedges:
result = splitWires(objects)
if result:
_msg(translate("draft","Found only wires: extracting their edges"))
_msg(translate("draft", "Found only wires: extracting their edges"))
# no result has been obtained
if not result:
_msg(translate("draft","No more downgrade possible"))
_msg(translate("draft", "No more downgrade possible"))
if delete:
for o in delete_list:

View File

@@ -65,15 +65,18 @@ class Array(DraftLink):
def onDocumentRestored(self, obj):
super(Array, self).onDocumentRestored(obj)
if hasattr(obj, "Count"):
# Count property was added in v0.21 and PlacementList property was added
# for non-link arrays in v1.1, obj should be OK if both are present:
if hasattr(obj, "Count") and hasattr(obj, "PlacementList"):
return
self.update_properties_0v21(obj)
def update_properties_0v21(self, obj):
if not hasattr(obj, "Count"):
_wrn("v0.21, " + obj.Label + ", " + translate("draft", "added property 'Count'"))
if not hasattr(obj, "PlacementList"):
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'"))
self.set_general_properties(obj)
self.execute(obj) # Required to update Count to the correct value.
_wrn("v0.21, " + obj.Label + ", "
+ translate("draft", "added property 'Count'"))
self.execute(obj) # Required to update Count and/or PlacementList.
def set_properties(self, obj):
"""Set properties only if they don't exist."""
@@ -141,6 +144,16 @@ class Array(DraftLink):
obj.Count = 0
obj.setEditorMode("Count", 1) # Read only
if not self.use_link:
if "PlacementList" not in properties:
_tip = QT_TRANSLATE_NOOP("App::Property",
"The placement for each array element")
obj.addProperty("App::PropertyPlacementList",
"PlacementList",
"Objects",
_tip)
obj.PlacementList = []
def set_ortho_properties(self, obj):
"""Set orthogonal properties only if they don't exist."""
properties = obj.PropertiesList

View File

@@ -204,8 +204,10 @@ class DraftLink(DraftObject):
and getattr(obj, 'AlwaysSyncPlacement', False):
for pla,child in zip(pls,obj.ElementList):
child.Placement = pla
elif obj.Count != len(pls):
obj.Count = len(pls)
else:
obj.PlacementList = pls
if obj.Count != len(pls):
obj.Count = len(pls)
if obj.Base:
shape = getattr(obj.Base, 'Shape', None)

View File

@@ -262,6 +262,16 @@ class PathArray(DraftLink):
obj.ExpandArray = False
obj.setPropertyStatus('Shape', 'Transient')
if not self.use_link:
if "PlacementList" not in properties:
_tip = QT_TRANSLATE_NOOP("App::Property",
"The placement for each array element")
obj.addProperty("App::PropertyPlacementList",
"PlacementList",
"Objects",
_tip)
obj.PlacementList = []
def set_align_properties(self, obj, properties):
"""Set general properties only if they don't exist."""
if "ExtraTranslation" not in properties:
@@ -541,37 +551,39 @@ class PathArray(DraftLink):
def onDocumentRestored(self, obj):
super().onDocumentRestored(obj)
# Run updates in order:
self.ensure_updated(obj)
def ensure_updated(self, obj):
# ReversePath was added together with several Spacing properties in v1.1.
# V1.1 props should be OK if it is present.
if hasattr(obj, "ReversePath"):
# ReversePath was added together with several Spacing properties in v1.1,
# and PlacementList property was added for non-link arrays in v1.1,
# obj should be OK if both are present:
if hasattr(obj, "ReversePath") and hasattr(obj, "PlacementList"):
return
# Fuse property was added in v1.0. Check if it is already present to
# correctly issue warning.
fuse_was_present = hasattr(obj, "Fuse")
self.set_properties(obj)
if hasattr(obj, "PathObj"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathObj' property to 'PathObject'"))
if hasattr(obj, "PathSubs"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathSubs' property to 'PathSubelements'"))
if hasattr(obj, "Xlate"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'Xlate' property to 'ExtraTranslation'"))
if not hasattr(obj, "Fuse"):
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
if obj.getGroupOfProperty("Count") != "Spacing":
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "moved 'Count' property to 'Spacing' subsection"))
if not hasattr(obj, "ReversePath"):
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added 'ReversePath', 'SpacingMode', 'SpacingUnit', 'UseSpacingPattern' and 'SpacingPattern' properties"))
if not hasattr(obj, "PlacementList"):
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'"))
self.set_properties(obj)
obj.setGroupOfProperty("Count", "Spacing")
if hasattr(obj, "PathObj"):
obj.PathObject = obj.PathObj
obj.removeProperty("PathObj")
if hasattr(obj, "PathSubs"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PathSubs' property to 'PathSubelements'"))
obj.PathSubelements = obj.PathSubs
obj.removeProperty("PathSubs")
if hasattr(obj, "Xlate"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'Xlate' property to 'ExtraTranslation'"))
obj.ExtraTranslation = obj.Xlate
obj.removeProperty("Xlate")
if not fuse_was_present:
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
obj.setGroupOfProperty("Count", "Spacing")
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "moved 'Count' to 'Spacing' subsection"))
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added 'ReversePath', 'SpacingMode', 'SpacingUnit', 'UseSpacingPattern' and 'SpacingPattern' properties"))
self.execute(obj) # Required to update PlacementList.
# Alias for compatibility with v0.18 and earlier

View File

@@ -127,6 +127,16 @@ class PathTwistedArray(DraftLink):
obj.ExpandArray = False
obj.setPropertyStatus('Shape', 'Transient')
if not self.use_link:
if "PlacementList" not in properties:
_tip = QT_TRANSLATE_NOOP("App::Property",
"The placement for each array element")
obj.addProperty("App::PropertyPlacementList",
"PlacementList",
"Objects",
_tip)
obj.PlacementList = []
def linkSetup(self, obj):
"""Set up the object as a link object."""
super().linkSetup(obj)
@@ -134,11 +144,18 @@ class PathTwistedArray(DraftLink):
def onDocumentRestored(self, obj):
super().onDocumentRestored(obj)
# Fuse property was added in v1.0, obj should be OK if it is present:
if hasattr(obj, "Fuse"):
# Fuse property was added in v1.0 and PlacementList property was added
# for non-link arrays in v1.1, obj should be OK if both are present:
if hasattr(obj, "Fuse") and hasattr(obj, "PlacementList"):
return
if not hasattr(obj, "Fuse"):
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
if not hasattr(obj, "PlacementList"):
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'"))
self.set_properties(obj)
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
self.execute(obj) # Required to update PlacementList.
def execute(self, obj):
"""Execute when the object is created or recomputed."""

View File

@@ -114,6 +114,16 @@ class PointArray(DraftLink):
_tip)
obj.setPropertyStatus('Shape', 'Transient')
if not self.use_link:
if "PlacementList" not in properties:
_tip = QT_TRANSLATE_NOOP("App::Property",
"The placement for each array element")
obj.addProperty("App::PropertyPlacementList",
"PlacementList",
"Objects",
_tip)
obj.PlacementList = []
def execute(self, obj):
"""Run when the object is created or recomputed."""
if self.props_changed_placement_only(obj) \
@@ -132,18 +142,25 @@ class PointArray(DraftLink):
def onDocumentRestored(self, obj):
super().onDocumentRestored(obj)
# Fuse property was added in v1.0, obj should be OK if it is present:
if hasattr(obj, "Fuse"):
# Fuse property was added in v1.0 and PlacementList property was added
# for non-link arrays in v1.1, obj should be OK if both are present:
if hasattr(obj, "Fuse") and hasattr(obj, "PlacementList"):
return
if not hasattr(obj, "ExtraPlacement"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "added 'ExtraPlacement' property"))
self.set_properties(obj)
if hasattr(obj, "PointList"):
_wrn("v0.19, " + obj.Label + ", " + translate("draft", "migrated 'PointList' property to 'PointObject'"))
if not hasattr(obj, "Fuse"):
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
if not hasattr(obj, "PlacementList"):
_wrn("v1.1, " + obj.Label + ", " + translate("draft", "added hidden property 'PlacementList'"))
self.set_properties(obj)
if hasattr(obj, "PointList"):
obj.PointObject = obj.PointList
obj.removeProperty("PointList")
_wrn("v1.0, " + obj.Label + ", " + translate("draft", "added 'Fuse' property"))
self.execute(obj) # Required to update PlacementList.
def remove_equal_vecs (vec_list):
"""Remove equal vectors from a list.