Fusion2PyBullet-Redux/Bullet_URDF_Exporter/utils/utils.py
2021-09-25 15:56:25 -04:00

261 lines
8.5 KiB
Python

# -*- coding: utf-8 -*-
"""
Copy to new components and export stls.
@syuntoku
@yanshil
"""
import adsk, adsk.core, adsk.fusion
import os.path, re
from xml.etree import ElementTree
from xml.dom import minidom
def export_stl(_app, save_dir):
"""
export stl files into "sace_dir/"
Parameters
----------
_app: adsk.core.Application.get()
save_dir: str
directory path to save
"""
def traverse( occ):
# recursive method to get all bodies from components and sub-components
body = adsk.fusion.BRepBody.cast(None)
liste = []
if occ.childOccurrences and occ.isLightBulbOn:
for child in occ.childOccurrences:
liste = liste + traverse(child)
if occ.isLightBulbOn:
liste = liste + [body for body in occ.bRepBodies if body.isLightBulbOn and occ.component.isBodiesFolderLightBulbOn]
return liste
des: adsk.fusion.Design = _app.activeProduct
root: adsk.fusion.Component = des.rootComponent
showBodies = []
body = adsk.fusion.BRepBody.cast(None)
if root.isBodiesFolderLightBulbOn:
lst = [body for body in root.bRepBodies if body.isLightBulbOn]
if len(lst) > 0:
showBodies.append(['root', lst])
occ = adsk.fusion.Occurrence.cast(None)
for occ in root.allOccurrences:
if not occ.assemblyContext and occ.isLightBulbOn:
lst = [body for body in occ.bRepBodies if body.isLightBulbOn and occ.component.isBodiesFolderLightBulbOn]
if occ.childOccurrences:
for child in occ.childOccurrences:
lst = lst + traverse(child)
if len(lst) > 0:
showBodies.append([occ.name, lst])
# get clone body
tmpBrepMng = adsk.fusion.TemporaryBRepManager.get()
tmpBodies = []
for name, bodies in showBodies:
lst = [tmpBrepMng.copy(body) for body in bodies]
if len(lst) > 0:
tmpBodies.append([name, lst])
# create export Doc - DirectDesign
fusionDocType = adsk.core.DocumentTypes.FusionDesignDocumentType
expDoc: adsk.fusion.FusionDocument = _app.documents.add(fusionDocType)
expDes: adsk.fusion.Design = expDoc.design
expDes.designType = adsk.fusion.DesignTypes.DirectDesignType
# get export rootComponent
expRoot: adsk.fusion.Component = expDes.rootComponent
# paste clone body
mat0 = adsk.core.Matrix3D.create()
for name, bodies in tmpBodies:
occ = expRoot.occurrences.addNewComponent(mat0)
comp = occ.component
comp.name = name
for body in bodies:
comp.bRepBodies.add(body)
# export stl
try:
os.mkdir(save_dir + '/meshes')
except:
pass
exportFolder = save_dir + '/meshes'
exportMgr = des.exportManager
for occ in expRoot.allOccurrences:
if "base_link" in occ.component.name:
expName = "base_link"
else:
expName = re.sub('[ :()]', '_', occ.component.name)
expPath = os.path.join(exportFolder, '{}.stl'.format(expName))
stlOpts = exportMgr.createSTLExportOptions(occ, expPath)
exportMgr.execute(stlOpts)
# remove export Doc
expDoc.close(False)
## https://github.com/django/django/blob/master/django/utils/text.py
def get_valid_filename(s):
"""
Return the given string converted to a string that can be used for a clean
filename. Remove leading and trailing spaces; convert other spaces to
underscores; and remove anything that is not an alphanumeric, dash,
underscore, or dot.
>>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg'
"""
s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
def copy_occs(root):
"""
duplicate all the components
"""
def copy_body(allOccs, occs):
"""
copy the old occs to new component
"""
bodies = occs.bRepBodies
transform = adsk.core.Matrix3D.create()
# Create new components from occs
# This support even when a component has some occses.
new_occs = allOccs.addNewComponent(transform) # this create new occs
if occs.component.name == 'base_link':
occs.component.name = 'old_component'
new_occs.component.name = 'base_link'
else:
key = get_valid_filename(occs.fullPathName)
new_occs.component.name = key
# new_occs.component.name = re.sub('[ :()]', '_', occs.name)
new_occs = allOccs.item((allOccs.count-1))
for i in range(bodies.count):
body = bodies.item(i)
body.copyToComponent(new_occs)
allOccs = root.occurrences
# allOccs = root.allOccurrences
oldOccs = []
# coppy_list = [occs for occs in allOccs]
coppy_list = [occs for occs in root.allOccurrences]
for occs in coppy_list:
if occs.bRepBodies.count > 0:
copy_body(allOccs, occs)
oldOccs.append(occs)
for occs in oldOccs:
occs.component.name = 'old_component'
# def export_stl(design, save_dir, components):
# """
# export stl files into "sace_dir/"
# Parameters
# ----------
# design: adsk.fusion.Design.cast(product)
# save_dir: str
# directory path to save
# components: design.allComponents
# """
# # create a single exportManager instance
# exportMgr = design.exportManager
# # get the script location
# try: os.mkdir(save_dir + '/meshes')
# except: pass
# scriptDir = save_dir + '/meshes'
# # export the occurrence one by one in the component to a specified file
# for component in components:
# allOccus = component.allOccurrences
# for occ in allOccus:
# ## Don't export nested component
# if occ.childOccurrences.count > 0:
# continue
# if 'old_component' not in occ.component.name:
# try:
# key = get_valid_filename(occ.fullPathName)
# key = key[:-1] ## Will generate an extra "1" in the end, remove it
# print("Export file: {}".format(key))
# # fileName = scriptDir + "/" + occ.component.name
# fileName = scriptDir + "/" + key
# # create stl exportOptions
# stlExportOptions = exportMgr.createSTLExportOptions(occ, fileName)
# stlExportOptions.sendToPrintUtility = False
# stlExportOptions.isBinaryFormat = True
# # options are .MeshRefinementLow .MeshRefinementMedium .MeshRefinementHigh
# stlExportOptions.meshRefinement = adsk.fusion.MeshRefinementSettings.MeshRefinementLow
# exportMgr.execute(stlExportOptions)
# except:
# print('Component ' + occ.component.name + ' has something wrong.')
def file_dialog(ui):
"""
display the dialog to save the file
"""
# Set styles of folder dialog.
folderDlg = ui.createFolderDialog()
folderDlg.title = 'Fusion Folder Dialog'
# Show folder dialog
dlgResult = folderDlg.showDialog()
if dlgResult == adsk.core.DialogResults.DialogOK:
return folderDlg.folder
return False
def origin2center_of_mass(inertia, center_of_mass, mass):
"""
convert the moment of the inertia about the world coordinate into
that about center of mass coordinate
Parameters
----------
moment of inertia about the world coordinate: [xx, yy, zz, xy, yz, xz]
center_of_mass: [x, y, z]
Returns
----------
moment of inertia about center of mass : [xx, yy, zz, xy, yz, xz]
"""
x = center_of_mass[0]
y = center_of_mass[1]
z = center_of_mass[2]
translation_matrix = [y**2+z**2, x**2+z**2, x**2+y**2,
-x*y, -y*z, -x*z]
return [ i - mass*t for i, t in zip(inertia, translation_matrix)]
def prettify(elem):
"""
Return a pretty-printed XML string for the Element.
Parameters
----------
elem : xml.etree.ElementTree.Element
Returns
----------
pretified xml : str
"""
rough_string = ElementTree.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent=" ")