From 1188423beb6b587cd53e10cd660d880feefffdde Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Tue, 26 Jul 2022 11:26:50 +0200 Subject: [PATCH 1/2] Draft: Fix handling of groups on move-copy and rotate-copy --- src/Mod/Draft/draftfunctions/move.py | 53 +++++++++------ src/Mod/Draft/draftfunctions/rotate.py | 91 +++++++++++++++++--------- src/Mod/Draft/draftutils/utils.py | 4 +- 3 files changed, 95 insertions(+), 53 deletions(-) diff --git a/src/Mod/Draft/draftfunctions/move.py b/src/Mod/Draft/draftfunctions/move.py index a826a9e02d..4f606fc482 100644 --- a/src/Mod/Draft/draftfunctions/move.py +++ b/src/Mod/Draft/draftfunctions/move.py @@ -38,21 +38,21 @@ import draftmake.make_line as make_line def move(objectslist, vector, copy=False): """move(objects,vector,[copy]) - + Move the objects contained in objects (that can be an object or a list of objects) in the direction and distance indicated by the given - vector. + vector. Parameters ---------- objectslist : list vector : Base.Vector - Delta Vector to move the clone from the original position. + Delta Vector to move the clone from the original position. copy : bool If copy is True, the actual objects are not moved, but copies - are created instead. + are created instead. Return ---------- @@ -67,8 +67,17 @@ def move(objectslist, vector, copy=False): newgroups = {} objectslist = utils.filter_objects_for_modifiers(objectslist, copy) + if copy: + doc = App.ActiveDocument + for obj in objectslist: + if obj.isDerivedFrom("App::DocumentObjectGroup") \ + and obj.Name not in newgroups.keys(): + newgroups[obj.Name] = doc.addObject(obj.TypeId, + utils.get_real_name(obj.Name)) + for obj in objectslist: newobj = None + # real_vector have been introduced to take into account # the possibility that object is inside an App::Part # TODO: Make Move work also with App::Link @@ -88,9 +97,12 @@ def move(objectslist, vector, copy=False): newobj.Z = obj.Z.Value + real_vector.z elif obj.isDerivedFrom("App::DocumentObjectGroup"): - pass + if copy: + newobj = newgroups[obj.Name] + else: + newobj = obj - elif hasattr(obj,'Shape'): + elif hasattr(obj, "Shape"): if copy: newobj = make_copy.make_copy(obj) else: @@ -98,14 +110,14 @@ def move(objectslist, vector, copy=False): pla = newobj.Placement pla.move(real_vector) - elif utils.get_type(obj) == "Annotation": + elif obj.isDerivedFrom("App::Annotation"): if copy: newobj = make_copy.make_copy(obj) else: newobj = obj newobj.Position = obj.Position.add(real_vector) - elif utils.get_type(obj) in ("Text", "DraftText"): + elif utils.get_type(obj) in ["Text", "DraftText"]: if copy: newobj = make_copy.make_copy(obj) else: @@ -121,37 +133,36 @@ def move(objectslist, vector, copy=False): newobj.End = obj.End.add(real_vector) newobj.Dimline = obj.Dimline.add(real_vector) - elif utils.get_type(obj) in ["AngularDimension"]: + elif utils.get_type(obj) == "AngularDimension": if copy: newobj = make_copy.make_copy(obj) else: newobj = obj newobj.Center = obj.Start.add(real_vector) - elif "Placement" in obj.PropertiesList: + elif hasattr(obj, "Placement"): if copy: newobj = make_copy.make_copy(obj) else: newobj = obj - pla = obj.Placement + pla = newobj.Placement pla.move(real_vector) if newobj is not None: newobjlist.append(newobj) + if copy: + for parent in obj.InList: + if parent.isDerivedFrom("App::DocumentObjectGroup") \ + and (parent in objectslist): + newgroups[parent.Name].addObject(newobj) + if utils.get_type(parent) == "Layer": + parent.Proxy.addObject(parent ,newobj) - if copy: - for p in obj.InList: - if p.isDerivedFrom("App::DocumentObjectGroup") and (p in objectslist): - g = newgroups.setdefault(p.Name,App.ActiveDocument.addObject(p.TypeId,p.Name)) - g.addObject(newobj) - break - if utils.get_type(p) == "Layer": - p.Proxy.addObject(p,newobj) - - if copy and utils.get_param("selectBaseObjects",False): + if copy and utils.get_param("selectBaseObjects", False): gui_utils.select(objectslist) else: gui_utils.select(newobjlist) + if len(newobjlist) == 1: return newobjlist[0] return newobjlist diff --git a/src/Mod/Draft/draftfunctions/rotate.py b/src/Mod/Draft/draftfunctions/rotate.py index b1b6b2ed19..fbd62fa31a 100644 --- a/src/Mod/Draft/draftfunctions/rotate.py +++ b/src/Mod/Draft/draftfunctions/rotate.py @@ -39,8 +39,8 @@ import draftmake.make_line as make_line import draftmake.make_copy as make_copy -def rotate(objectslist, angle, center=App.Vector(0,0,0), - axis=App.Vector(0,0,1), copy=False): +def rotate(objectslist, angle, center=App.Vector(0, 0, 0), + axis=App.Vector(0, 0, 1), copy=False): """rotate(objects,angle,[center,axis,copy]) Rotates the objects contained in objects (that can be a list of objects @@ -49,9 +49,9 @@ def rotate(objectslist, angle, center=App.Vector(0,0,0), Parameters ---------- - objectlist : list + objectslist : list - angle : list + angle : rotation angle (in degrees) center : Base.Vector @@ -76,8 +76,17 @@ def rotate(objectslist, angle, center=App.Vector(0,0,0), newgroups = {} objectslist = utils.filter_objects_for_modifiers(objectslist, copy) + if copy: + doc = App.ActiveDocument + for obj in objectslist: + if obj.isDerivedFrom("App::DocumentObjectGroup") \ + and obj.Name not in newgroups.keys(): + newgroups[obj.Name] = doc.addObject(obj.TypeId, + utils.get_real_name(obj.Name)) + for obj in objectslist: newobj = None + # real_center and real_axis are introduced to take into account # the possibility that object is inside an App::Part if hasattr(obj, "getGlobalPlacement"): @@ -89,61 +98,83 @@ def rotate(objectslist, angle, center=App.Vector(0,0,0), real_center = center real_axis = axis - if copy: - newobj = make_copy.make_copy(obj) - else: - newobj = obj if obj.isDerivedFrom("App::Annotation"): # TODO: this is very different from how move handle annotations # maybe we can uniform the two methods - if axis.normalize() == App.Vector(1,0,0): + if copy: + newobj = make_copy.make_copy(obj) + else: + newobj = obj + if axis.normalize() == App.Vector(1, 0, 0): newobj.ViewObject.RotationAxis = "X" newobj.ViewObject.Rotation = angle - elif axis.normalize() == App.Vector(0,1,0): + elif axis.normalize() == App.Vector(0, 1, 0): newobj.ViewObject.RotationAxis = "Y" newobj.ViewObject.Rotation = angle - elif axis.normalize() == App.Vector(0,-1,0): + elif axis.normalize() == App.Vector(0, -1, 0): newobj.ViewObject.RotationAxis = "Y" newobj.ViewObject.Rotation = -angle - elif axis.normalize() == App.Vector(0,0,1): + elif axis.normalize() == App.Vector(0, 0, 1): newobj.ViewObject.RotationAxis = "Z" newobj.ViewObject.Rotation = angle - elif axis.normalize() == App.Vector(0,0,-1): + elif axis.normalize() == App.Vector(0, 0, -1): newobj.ViewObject.RotationAxis = "Z" newobj.ViewObject.Rotation = -angle + elif utils.get_type(obj) == "Point": - v = App.Vector(obj.X,obj.Y,obj.Z) + if copy: + newobj = make_copy.make_copy(obj) + else: + newobj = obj + v = App.Vector(newobj.X, newobj.Y, newobj.Z) rv = v.sub(real_center) rv = DraftVecUtils.rotate(rv, math.radians(angle), real_axis) v = real_center.add(rv) newobj.X = v.x newobj.Y = v.y newobj.Z = v.z + elif obj.isDerivedFrom("App::DocumentObjectGroup"): - pass - elif hasattr(obj,"Placement"): - #FreeCAD.Console.PrintMessage("placement rotation\n") + if copy: + newobj = newgroups[obj.Name] + else: + newobj = obj + + elif hasattr(obj, "Placement"): + # App.Console.PrintMessage("placement rotation\n") + if copy: + newobj = make_copy.make_copy(obj) + else: + newobj = obj shape = Part.Shape() - shape.Placement = obj.Placement + shape.Placement = newobj.Placement shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle) newobj.Placement = shape.Placement - elif hasattr(obj,'Shape') and (utils.get_type(obj) not in ["WorkingPlaneProxy","BuildingPart"]): - #think it make more sense to try first to rotate placement and later to try with shape. no? - shape = obj.Shape.copy() + + elif hasattr(obj, "Shape"): + if copy: + newobj = make_copy.make_copy(obj) + else: + newobj = obj + shape = newobj.Shape.copy() shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle) newobj.Shape = shape - if copy: - gui_utils.formatObject(newobj,obj) + if newobj is not None: newobjlist.append(newobj) - if copy: - for p in obj.InList: - if p.isDerivedFrom("App::DocumentObjectGroup") and (p in objectslist): - g = newgroups.setdefault(p.Name, App.ActiveDocument.addObject(p.TypeId, p.Name)) - g.addObject(newobj) - break + if copy: + for parent in obj.InList: + if parent.isDerivedFrom("App::DocumentObjectGroup") \ + and (parent in objectslist): + newgroups[parent.Name].addObject(newobj) + if utils.get_type(parent) == "Layer": + parent.Proxy.addObject(parent ,newobj) + + if copy and utils.get_param("selectBaseObjects", False): + gui_utils.select(objectslist) + else: + gui_utils.select(newobjlist) - gui_utils.select(newobjlist) if len(newobjlist) == 1: return newobjlist[0] return newobjlist diff --git a/src/Mod/Draft/draftutils/utils.py b/src/Mod/Draft/draftutils/utils.py index 8e8aa5890a..64a8a32921 100644 --- a/src/Mod/Draft/draftutils/utils.py +++ b/src/Mod/Draft/draftutils/utils.py @@ -391,9 +391,9 @@ def get_real_name(name): The returned string cannot be empty; it will have at least one letter. """ - for i in range(1, len(name)): + for i in range(1, len(name) + 1): if name[-i] not in '1234567890': - return name[:len(name) - (i-1)] + return name[:len(name) - (i - 1)] return name From 7bb485e6b77f7e071d5f877b94445fbbb44d5a89 Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Thu, 28 Jul 2022 13:46:26 +0200 Subject: [PATCH 2/2] Update rotate.py Workaround for `faulty` implementation of Base.Placement.rotate(center, axis, angle). See: https://forum.freecadweb.org/viewtopic.php?p=613196#p613196 --- src/Mod/Draft/draftfunctions/rotate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Draft/draftfunctions/rotate.py b/src/Mod/Draft/draftfunctions/rotate.py index fbd62fa31a..48d8c93aa6 100644 --- a/src/Mod/Draft/draftfunctions/rotate.py +++ b/src/Mod/Draft/draftfunctions/rotate.py @@ -146,10 +146,10 @@ def rotate(objectslist, angle, center=App.Vector(0, 0, 0), newobj = make_copy.make_copy(obj) else: newobj = obj - shape = Part.Shape() - shape.Placement = newobj.Placement - shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle) - newobj.Placement = shape.Placement + # Workaround for `faulty` implementation of Base.Placement.rotate(center, axis, angle). + # See: https://forum.freecadweb.org/viewtopic.php?p=613196#p613196 + offset_rotation = App.Placement(App.Vector(0, 0, 0), App.Rotation(real_axis, angle), real_center) + newobj.Placement = offset_rotation * newobj.Placement elif hasattr(obj, "Shape"): if copy: @@ -157,7 +157,7 @@ def rotate(objectslist, angle, center=App.Vector(0, 0, 0), else: newobj = obj shape = newobj.Shape.copy() - shape.rotate(DraftVecUtils.tup(real_center), DraftVecUtils.tup(real_axis), angle) + shape.rotate(real_center, real_axis, angle) newobj.Shape = shape if newobj is not None: