# -*- 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=" ")