a FreeCAD utility to convert an assembly to a Part Hierarchy of objects, simply removing all the constraints (Requirements realthunder Assembly3 build)
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
# asm3_to_part_hierarchy.py | |
__Author__ = 'easyw Maurice' | |
__License__ = 'LGPL2+ https://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License' | |
''' | |
a FreeCAD utility to convert an assembly to a Part Hierarchy of objects, | |
simply removing all the constraints | |
Requirements realthunder Assembly3 build | |
https://github.com/realthunder/FreeCAD_assembly3 | |
''' | |
# partially based on 'galou_breizh' 'Deep Copy' Macro | |
# __Web__ = 'https://www.freecadweb.org/wiki/index.php?title=Macro_DeepCopy' | |
# Gui.activateWorkbench("Assembly3Workbench") | |
# a=App.ActiveDocument.getObject('Assembly') | |
# a.Group | |
# p=a.Group[2] | |
# p.Group | |
# p.Group[2].Label | |
# p.Group[2].TypeId | |
# p.Group[2].Name | |
import FreeCAD as app | |
import FreeCADGui as gui | |
__a2pversion__ = '1.1.1' | |
def fcc_prn(message): | |
FreeCAD.Console.PrintMessage('{}\n'.format(message)) | |
def fcc_wprn(message): | |
FreeCAD.Console.PrintWarning('{}\n'.format(message)) | |
Links_available = False | |
try: | |
from freecad.asm3 import assembly as asm | |
Links_available = True | |
fcc_prn('A3 available') | |
except: | |
fcc_wprn('A3 not available') | |
### | |
def get_all_subobjs(o): | |
"""Recursively get all subobjects | |
Subobjects of objects having a Shape attribute are not included otherwise each | |
single feature of the object would be copied. The result is that bodies, | |
compounds, and the result of boolean operations will be converted into a | |
simple copy of their shape. | |
""" | |
# Depth-first search algorithm. | |
discovered = [] | |
# We do not need an extra copy for stack because OutList is already a copy. | |
if hasattr(o,'Group') and o.TypeId != 'App::Part': | |
fcc_prn('Assembly container'); | |
#fcc_prn(o.Label) | |
stack = o.Group[2].Group | |
else: | |
fcc_prn('Part or Body container') | |
stack = o.OutList | |
#stack = o.OutList | |
#for s in stack: | |
# fcc_prn(s.Label) | |
while stack: | |
v = stack.pop(0) | |
if v not in discovered: | |
discovered.append(v) | |
if (not hasattr(v, 'Shape') or v.Name.startswith('Assembly')): | |
stack += v.OutList | |
#fcc_wprn(discovered) | |
return discovered | |
### | |
def deep_simply_assy_sel(doc): | |
for sel_object in gui.Selection.getSelectionEx(): | |
deep_simply_assy(doc, sel_object.Object) | |
### | |
def deep_simply_assy(doc, part): | |
if part.TypeId != 'Part::FeaturePython' and not part.Name.startswith('Assembly') and part.TypeId != 'App::Part': | |
# Part is not an Assembly part, return. | |
fcc_prn('found Body, not Assembly or Part DN') | |
return 0 | |
copied_subobjects = [] | |
part_containers = [] | |
doc.Tip = FreeCAD.activeDocument().addObject('App::Part',part.Name+'_copy') | |
pName = part.Name+'_copy' | |
gui.activeView().setActiveObject('part', doc.getObject(pName)) | |
doc.getObject(pName).Label = part.Label+'_copy' | |
doc.getObject(pName).Placement = part.Placement | |
part_containers.append([doc.getObject(pName),part]) | |
for o in get_all_subobjs(part): | |
cs, pc = simple_copy_subobj(doc, o) | |
copied_subobjects += cs | |
part_containers += pc | |
make_compound = True #False | |
#if make_compound: | |
# compound = doc.addObject('Part::Compound', part.Label + '.copy') | |
# compound.Links = copied_subobjects | |
#stop | |
copy_inside=True | |
if copy_inside: | |
for p in part_containers: #adding Parts containers | |
#fcc_prn(p[0].Label) | |
if p[1].Name.startswith('Assembly'): | |
outlist = p[1].OutList[2].OutList #Parts of Assembly | |
else: | |
outlist = p[1].OutList | |
for o in outlist: #Recursive: | |
if o.TypeId == 'App::Part': | |
#fcc_prn(o.Label); fcc_wprn(o.Name);fcc_wprn(p[0].Label) | |
if o in outlist: | |
doc.getObject(p[0].Name).addObject(doc.getObject(o.Name+'_copy')) | |
for p in part_containers: | |
#fcc_prn(p[0].Label) | |
if p[1].Name.startswith('Assembly'): | |
outlist = p[1].OutList[2].OutList #Parts of Assembly | |
else: | |
outlist = p[1].OutList | |
for o in outlist: | |
if o.TypeId != 'App::Origin' and o.TypeId != 'Sketcher::SketchObject' \ | |
and o.TypeId != 'App::Plane' and o.TypeId != 'App::Line'\ | |
and o.TypeId != 'App::Part'\ | |
and doc.getObject(o.Name+'_copy') is not None: | |
if o in outlist: | |
#fcc_prn(o.Label); fcc_wprn(o.Name);fcc_wprn(p[0].Label) | |
doc.getObject(p[0].Name).addObject(doc.getObject(o.Name+'_copy')) | |
doc.recompute() | |
return 1 | |
## | |
def simple_copy_subobj(doc, o): | |
"""Copy the shape of an object | |
Some GUI attributes are also copied | |
""" | |
copied_object = [] | |
prt_containers = [] | |
if (not hasattr(o, 'Shape') or o.Shape.isNull()) and o.TypeId != 'App::Link': # or not o.Name.startswith('Assembly'): | |
if o.TypeId == 'App::Part' or (hasattr(o,'Group') and o.Name.startswith('Assembly')): | |
doc.Tip = App.activeDocument().addObject('App::Part',o.Name+'_copy') | |
pName = o.Name+'_copy' | |
gui.activeView().setActiveObject('part', doc.getObject(pName)) | |
#pName = doc.ActiveObject.Name | |
# doc.getObject(pName).Label = o.Label + '_copy' | |
prt_containers.append([doc.getObject(pName),o]) | |
doc.getObject(pName).Placement = o.Placement | |
doc.getObject(pName).Label = o.Label+'_copy' | |
#print ('running Part here') | |
#print (prt_containers) | |
return copied_object, prt_containers | |
vo_o = o.ViewObject | |
if o.TypeId != 'Sketcher::SketchObject':# and o.TypeId != 'App::Link': | |
try: | |
#if 1: | |
#print ('running here'); print(o.Label); print (o.Name); print (o.TypeId) | |
copy = doc.addObject('Part::Feature', o.Name + '_copy') | |
if o.TypeId != 'App::Link': | |
copy.Shape = o.Shape #.copy() | |
else: | |
#fcc_wprn(o.TypeId) | |
#fcc_wprn (o.OutList[0].Label) | |
#FreeCAD.ActiveDocument.recompute() | |
copy.Shape = Part.getShape(o.OutList[0]) #.copy() | |
#copy.Shape = o.Outlist[0].Shape | |
vo_o = o.OutList[0].ViewObject | |
#s = Part.getShape(o) | |
copy.Placement = o.Placement | |
#Part.show(copy.Shape) | |
#print ('running again here') | |
copy.Label = o.Label + '_copy' | |
# copy.Placement = o.getGlobalPlacement() | |
# copy.Placement = Part.getShape(o).Placement | |
vo_copy = copy.ViewObject | |
vo_copy.ShapeColor = vo_o.ShapeColor | |
vo_copy.LineColor = vo_o.LineColor | |
vo_copy.PointColor = vo_o.PointColor | |
vo_copy.DiffuseColor = vo_o.DiffuseColor | |
vo_copy.Transparency = vo_o.Transparency | |
if 0: | |
fcc_prn('Obj:') | |
fcc_prn(o.Label) | |
fcc_prn('InList:') | |
for ob in o.InList: | |
fcc_prn(ob.Label) | |
fcc_prn('InListRecursive:') | |
for ob in o.InListRecursive: | |
fcc_prn(o.Label) | |
#if Links_available: | |
# fcc_wprn(o.Label) | |
# fcc_prn(o.isElementVisible(o.Name)) | |
# if o.isElementVisible(o.Name) == 1: | |
# vo_copy.Visibility = True | |
# else: | |
# vo_copy.Visibility = False | |
#else: | |
# vo_copy.Visibility = vo_o.Visibility #gui.activeDocument().getObject(o.Name).Visibility | |
#print(o.Label);print(gui.activeDocument().getObject(o.Name).Visibility) | |
except AttributeError: | |
fcc_wprn('ERROR') | |
pass | |
else: | |
copied_object = [copy] | |
return copied_object, prt_containers | |
### | |
import time | |
doc = app.activeDocument() | |
sel = FreeCADGui.Selection.getSelection() | |
selEx = FreeCADGui.Selection.getSelectionEx() | |
current_milli_time = lambda: int(round(time.time() * 1000)) | |
start_milli_time = current_milli_time() | |
## deep_copy_assy_sel(doc) | |
fcc_prn('Assembly to PartDN release '+__a2pversion__) | |
sel = FreeCADGui.Selection.getSelection() | |
if not sel: | |
fcc_wprn("Select an Assembly container to simplify it to Part Design Next container(s)") | |
else: | |
#deep_simply_assy_sel(doc) | |
for sel_object in gui.Selection.getSelectionEx(): | |
result=deep_simply_assy(doc, sel_object.Object) | |
if result: | |
gui.activeDocument().getObject(sel_object.Object.Name).Visibility = False | |
#gui.Selection.setVisible() | |
fcc_prn(sel_object.Object.Label + ' Assembly container copied') | |
end_milli_time = current_milli_time() | |
running_time=(end_milli_time-start_milli_time)/1000 | |
fcc_wprn('running time:'+str(running_time)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment