Part-o-magic [New: Selection tools, container duplication]

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Locked
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Part-o-magic (again) [new feature - ShapeGroup(Compound) container]

Post by triplus »

DeepSOIC wrote:
triplus wrote:I am guessing entering the shape group edit mode and doing whatever users wants instead isn't an option?
Actually, it is!
In its current form or possible in the future? As setting Operation property to None does enable me to do something like that. But i can't place the result after when using Assembly 2.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Part-o-magic (again) [new feature - ShapeGroup(Compound) container]

Post by DeepSOIC »

triplus wrote:In its current form or possible in the future? As setting Operation property to None does enable me to do something like that.
In current form. Just leave the operation in "Compound". Activate the group and fuse some stuff that it already contains. The originals should be withdrawn from the result by this bit of "smartness" code:

Code: Select all

    def advanceTip(self, selfobj, new_object):
        if new_object.Name.startswith("ShapeBinder"): return
        import copy
        # general idea: New object is always added to the tip. If new object is an operation applied to an old object, old object is withdrawn from tip.
        old_tip = selfobj.Tip
        new_tip = copy.copy(old_tip)
        if new_object in old_tip: return # unlikely to happen. It's just a fail-safe.
        new_tip.append(new_object)
        for obj in set(new_object.OutList): # set() is here to remove duplicates, otherwise exception may arise when removing an already removed object
            if obj in old_tip:
                new_tip.remove(obj)
        
        if new_tip == old_tip: return
        selfobj.Tip = new_tip
ShapeGroup also has a Tip like Module and Body do, but it is a list rather than a single link. It is not user-editable as of now, but I plan to introduce a way to update Tip based on visibility (it will probably be a context menu command).
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Part-o-magic (again) [new feature - ShapeGroup(Compound) container]

Post by triplus »

DeepSOIC wrote:In current form. Just leave the operation in "Compound". Activate the group and fuse some stuff that it already contains.
Indeed they are there on the toolbar. Commands to enter and leave the edit mode. I have overlooked that.
ShapeGroup also has a Tip like Module and Body do, but it is a list rather than a single link. It is not user-editable as of now, but I plan to introduce a way to update Tip based on visibility (it will probably be a context menu command).
Or remove it altogether like the Operation property. For us the inexperienced users not to get lost in it. We just want to put things we can edit in it and after to be able to place them around when we are not editing them. ;)
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Part-o-magic (again)

Post by DeepSOIC »

Example project, showcasing Module container.
rotating plate.png
rotating plate.png (556.57 KiB) Viewed 1776 times
rotating plate v01.FCStd
(39.09 KiB) Downloaded 61 times
User avatar
easyw-fc
Veteran
Posts: 3629
Joined: Thu Jul 09, 2015 9:34 am

Re: Part-o-magic (again)

Post by easyw-fc »

DeepSOIC wrote:Example project, showcasing Module container.
Hi, very nice WB...
I tested latest on win10 and FreeCAD_0.17.10423_x64_dev_win but I miss 2 icons...
pom-icons.png
pom-icons.png (88.32 KiB) Viewed 1759 times
would you please check it?
Thx
Maurice
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Part-o-magic (again)

Post by DeepSOIC »

easyw-fc wrote:but I miss 2 icons
These are super new tools, I'm working on the icons.
User avatar
easyw-fc
Veteran
Posts: 3629
Joined: Thu Jul 09, 2015 9:34 am

Re: Part-o-magic (again)

Post by easyw-fc »

DeepSOIC wrote:
easyw-fc wrote:but I miss 2 icons
These are super new tools, I'm working on the icons.
I thought it was a problem in my installation...
thx :)
User avatar
easyw-fc
Veteran
Posts: 3629
Joined: Thu Jul 09, 2015 9:34 am

Re: Part-o-magic (again) [new feature - ShapeGroup(Compound) container]

Post by easyw-fc »

easyw-fc wrote: ATM I found a small issue... I can apply colors to sub-parts, but they get lost when exporting the file as STEP... Is there something that can be improved?
DeepSOIC wrote:I'm afraid, to support colors, I may have to move over to c++.
Hi DeepSOIC
I tried to do a simple copy of a ShapeGroup conserving colors with a Macro in python and I can do it just applying multiply Placements to the Group and included objects
shapegroup-test-base.FCStd
(6.79 KiB) Downloaded 50 times
here the macro I used for a single copy with colors

Code: Select all

# -*- coding: utf-8 -*-
# creating simple copy of App::Part
# https://forum.freecadweb.org/viewtopic.php?f=10&t=2530
# https://forum.freecadweb.org/viewtopic.php?t=3561
## https://forum.freecadweb.org/viewtopic.php?t=11014
#
 
__title__   = "simple copy App::Part"
__author__  = "maurice"
__url__     = "kicad stepup"
__version__ = "0.3"
__date__    = "03.2017"
 
## todo:
# add pause observer
# add multi level (it works only with one nested ShapeGroup)
 
import FreeCAD, FreeCADGui, Draft, Part
import PySide
from PySide import QtGui, QtCore
#import OpenSCADUtils

disable_PoM_Observer = False
try:
    import PartOMagic
    import PartOMagic.Gui.Observer as Observer
    disable_PoM_Observer = True
except:
    FreeCAD.Console.PrintMessage("PoM not present\n")

def say(*msg):
    FreeCAD.Console.PrintMessage(" ".join(map(str,msg)) + "\n")
    #FreeCAD.Console.PrintMessage(msg)
    #FreeCAD.Console.PrintMessage('\n')

def clear_console():
    #clearing previous messages
    mw=Gui.getMainWindow()
    c=mw.findChild(QtGui.QPlainTextEdit, "Python console")
    c.clear()
    r=mw.findChild(QtGui.QTextEdit, "Report view")
    r.clear()

def simple_copy(obj):

    s=obj.Shape
    App.ActiveDocument.addObject('Part::Feature',obj.Name+"_cp").Shape=s
    FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
    FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
    FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
    FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
    FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
    new_label=obj.Label
    FreeCAD.ActiveDocument.ActiveObject.Label=new_label
    FreeCAD.ActiveDocument.recompute()

    
def simple_copy_placement(obj,pchild,proot):

    s=obj.Shape
    t=s.copy()
    r=s.copy()
    r.Placement=FreeCAD.Placement(proot)
    t.Placement=r.Placement.multiply(t.Placement)  #incremental Placement
    App.ActiveDocument.addObject('Part::Feature',obj.Name+"_cp").Shape=t
    FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
    FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
    FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
    FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
    FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
    new_label=obj.Label
    FreeCAD.ActiveDocument.ActiveObject.Label=new_label
    
def removesubtree(objs):
    def addsubobjs(obj,toremoveset):
        toremove.add(obj)
        for subobj in obj.OutList:
            addsubobjs(subobj,toremoveset)

    import FreeCAD
    toremove=set()
    for obj in objs:
        addsubobjs(obj,toremove)
    checkinlistcomplete =False
    while not checkinlistcomplete:
        for obj in toremove:
            if (obj not in objs) and (frozenset(obj.InList) - toremove):
                toremove.remove(obj)
                break
        else:
            checkinlistcomplete = True
    for obj in toremove:
        obj.Document.removeObject(obj.Name)

##

clear_console()

selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
coords = []
j = 0

plcmt=[]
if len(objs) >= 1:
    for obj in objs:
        #s = objs[0].Shape
        say (obj.TypeId)
        #say(App.ActiveDocument.getObject(obj.Name).InList)
        if "App::Part" in obj.TypeId:
            say ("App::Part")
            say (obj.Placement)
            plcmt.append(obj.Placement)
            grp=App.ActiveDocument.getObject(obj.Name).OutList
            for i in grp:
                if "Part" in i.TypeId:
                    say("Name="+i.Name+" Label="+i.Label)
                    say (i.Placement)
                    plcmt.append(i.Placement)
        if "ShapeGroup" in obj.Name:
            say ("ShapeGroup")
            say (obj.Placement)
            plcmt.append(obj.Placement)
            grp=App.ActiveDocument.getObject(obj.Name).OutList
            Lbl_list=[]
            for i in grp:
                if "Part" in i.TypeId:
                    #if "ShapeGroup" not in i.Name:
                    say("Name="+i.Name+" Label="+i.Label)
                    say (i.Placement)
                    #if Lbl_prev != i.Label:
                    #    plcmt.append(i.Placement)
                    if i.Label not in Lbl_list:
                        plcmt.append(i.Placement)
                    Lbl_list.append(i.Label)
                    #Lbl_prev = i.Label
            
    #App.ActiveDocument.recompute()
else:
    say("Select an object !")

compound_list=[]   
main_label="_"
say(plcmt)
if len(objs) >= 1:
    for obj in objs:
        #s = objs[0].Shape
        say (obj.TypeId)
        #say(App.ActiveDocument.getObject(obj.Name).InList)
        if "App::Part" in obj.TypeId:
            say ("App::Part")
            main_label=obj.Label
            say (obj.Placement)
            #plcmt.append(obj.Placement)
            grp=App.ActiveDocument.getObject(obj.Name).OutList
            for i in grp:
                if "Part" in i.TypeId:
                    say("Name="+i.Name+" Label="+i.Label)
                    say (i.Placement)
                    #plcmt.append(i.Placement)
                    simple_copy_placement(i,i.Placement,plcmt[0])
        if "ShapeGroup" in obj.Name:
            say ("ShapeGroup")
            main_label=obj.Label
            say (obj.Placement)
            #plcmt.append(obj.Placement)
            grp=App.ActiveDocument.getObject(obj.Name).OutList
            Lbl_prev = ""
            Lbl_list=[]
            for i in grp:
                if "Part" in i.TypeId:
                    say("Name="+i.Name+" Label="+i.Label)
                    say (i.Placement)
                    #if Lbl_prev != i.Label:
                    #    plcmt.append(i.Placement)
                    if i.Label not in Lbl_list:
                        #plcmt.append(i.Placement)
                        simple_copy_placement(i,i.Placement,plcmt[0])
                        compound_list.append(FreeCAD.ActiveDocument.ActiveObject)
                    Lbl_list.append(i.Label)
                    #Lbl_prev = i.Label

    #App.ActiveDocument.recompute()
else:
    say("Select an object !")

for p in compound_list:
    say (p.Label)
    
FreeCAD.activeDocument().addObject("Part::Compound",'MultiPart')
FreeCAD.activeDocument().ActiveObject.Links = compound_list #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
FreeCAD.ActiveDocument.recompute()
mycompound=FreeCAD.activeDocument().ActiveObject
for obj in FreeCAD.activeDocument().Objects:
    # do what you want to automate
    FreeCADGui.Selection.removeSelection(obj)

FreeCADGui.Selection.addSelection(mycompound)
objC=FreeCAD.ActiveDocument.getObject('MultiPart')
#App.ActiveDocument.copyObject(App.ActiveDocument.MultiPart, False)
simple_copy(objC)
FreeCAD.ActiveDocument.ActiveObject.Label=main_label+" simple copy"

PoMObs_status = False
if Observer.isRunning():
    PoMObs_status=True
#if PoMObs_status:
    Observer.stop()
    say("disabling PoM Observer")
    
removesubtree(FreeCADGui.Selection.getSelection())
FreeCAD.ActiveDocument.recompute()
if PoMObs_status:
    Observer.start()
    say("enabling PoM Observer")
ATM the macro can make a single copy of just one level of ShapeGroup, I cannot make a simple copy with colors of nested ShapeGroups...
Unfortunately I don't know how to recursive efficiently the nested structure... :?

Anyway what I wanted to post here was just an early approach to have a simple copy with colors of the new ShapeGroup object just using python...
May be it would be an easier approach changing some part of C++ code ...

Maurice
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Part-o-magic (again)

Post by triplus »

Looking good.

P.S.As for the container part. Do you have any plans to upstream it? Are there any plans to change the behaviour and to preserve feature hierarchy?
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Part-o-magic (again)

Post by DeepSOIC »

triplus wrote:P.S. As for the container part. Do you have any plans to upstream it? Are there any plans to change the behaviour and to preserve feature hierarchy?
Upstream meaning merge into master FreeCAD? Maybe, but only when automatic sorting of new objects into active group is implemented. What workbench should they land to? Assembly? or spread over various containers across workbenches?

As for feature hierarchy, I don't know why does it behave like it does (flattens out everything). In C++ version of Module, I didn't have that problem. I think fixing it is most likely a C++ work.
Locked