I recently released my dwg batch import utility for 3ds Max Design called “Polyform Importer”. The purpose for creating the utility was to solve the problem of only being able to import one file at a time into 3ds Max. In this article, I will show you how to install it and then talk about how it works.
1. Navigate to the folder that you exported the project DWG files to
2. Download the Polyform Importer.ms script and drop it into any 3ds Max Design scene
3. From the main menu click Customize then click Customize User Interface
4. Click on the Menus tab
5. Click New… To create a new menu and name it Polyform Tools
6. In the Menus list on the left bottom section find Polyform Tools and drag it over to the main menu list on the left just after MAXScript
7. In your menus list click the + to expand the PolyformTools menu
8. In the Category drop-down list navigate to PolyformTools
9. Click and drag Polyform Importer underneath your new Polyform Tools menu in the menus list
10. Close the Customize User Interface window
11. You should now see the Polyform Tools menu option
12. If you’re not seeing the importer, go back through the steps and find where you may have made an error
For those of us who need to SEE it done, there is also this video. If YouTube is blocked at your work, try this
For you code geeks out there, here is the source. Feel free to modify or try stuff. If you make something cool with it, please share! It will only help make everyone better.
UI Element Setup…
global dwgList --global variable needed for name collection global importDrawingPath --global variable for path to imports -- macroScript Polyform_Importer category: "PolyFormTools" ( Rollout ImportExport "Import/Export" ( group "Directory and files" ( edittext txt_dir "Directory" align:#left across:2 width:225 button btn_browse "..." align:#right width:20 edittext txt_pre "Prefix:" text:"" tooltip:"Put your file prefix here" align:#left width:105 across:2 button btnUpdate "Update" enabled:false edittext txt_ext "Extension" text:"dwg" align:#left width:105 --edittext txt_suf "Sufffix: *" text:"" tooltip:"Put your suffix here" align:#left width:105 label lblNumFiles "No files selected" ) group "Import Options" ( checkbox chkFLM "Link File" checkbox chkIMP "Import" checked:true checkbox chkCreateMaxFile "Save import as .Max file" across:2 checkbox chkMergeXrefs "Merge Xrefs" enabled:false align:#right checkbox chk_prefixmodelname "File Name Prefix" tooltip:"This will prefix each object with the file that it came from" align:#left --offset:[-45,0] checkbox chkSmooth "Smooth Modifier" across:2 enabled:false edittext txt_NoSmoothType text:"beam,stair,steel" width:75 tooltip:"Do not apply smooth modifier to files with this prefix" checkbox chk_unparent "Unparent Objects" align:#left checked:true label lbl_status "Ready" ) group "Do it!" ( button btn_Import "GO" width:75 height:40 )
When I check a box or press a button do something
on chkFLM changed state do ( chkIMP.checked = false ) on chkIMP changed state do ( chkFLM.checked = false )
We can’t Import AND use the File Link Manager. If we check one, we will uncheck the other.
Toggle Checkbox when other Checkbox gets Checked
on chkCreateMaxFile changed state do ( if not chkMergeXrefs.enabled then chkMergeXrefs.enabled = true else chkMergeXrefs.enabled = false --Allockse from the forum suggested I modify this. Have not done it yet but I will! ) on chk_prefixmodelname changed state do ( if not chkSmooth.enabled then chkSmooth.enabled = true else chkSmooth.enabled = false )
Same idea behind then Prefix Model Name. If we check it, the Smooth checkbox enabled property is toggled. Why? Because we need the file name to apply the smooth modifier
Setting import directory, tell us how many files will be imported
on btn_browse pressed do ( local fpath = getSavePath initialDir:@"F:\Projects\Autodesk\Technical Conference\dataset" caption:"Select any file in the source directory:" --shellLaunch "explorer.exe" (getdir #scene) if fpath != undefined then ( local extension = txt_ext.text local pfix = if txt_pre.text == "" then pfix = "*" else pfix = txt_pre.text local thepath = fpath + "\\" + pfix + "." + extension local dcount = (for f in getfiles (thepath) collect f).count if dcount > 0 then ( lblNumFiles.text = dcount as string + " files will be imported" importDrawingPath = fpath + "\\" + pfix + "." + extension txt_dir.text = fpath ) ) btnUpdate.enabled = true )
When the user pressed the browse button the code checks to see how many dwg’s are in the directory and displays that on the label. After the directory is set, the update button is enabled.
Update the imported drawing count
on btnUpdate pressed do ( local pfix = if txt_pre.text == "" then pfix = "*" else pfix = txt_pre.text local thepath = (getfilenamepath importDrawingPath) + pfix + "." + txt_ext.text importDrawingPath = thePath local dcount = (for f in getfiles (thepath) collect f).count if dcount > 0 then ( lblNumFiles.text = dcount as string + " files will be imported" --txt_dir.text = thepath ) else ( lblNumFiles.text = "No files will be imported" ) )
When the user changes the value in the prefix text box to *PIP* or something like that, the resulting import number will be filtered down to all drawings that contain the letters PIP in the drawing name. This is NOT case sensitive.
Write results to log file function
on btn_Import pressed do ( fn writetolog dir larr fileLog= ( local t = localtime local exportlog = openfile fileLog mode:"a" format "%\n" t to:exportlog for i = 1 to larr.count do format "% % seconds\n" larr[i] larr[i] to:exportlog format "<--##############################-->\n" to:exportlog close exportlog )
During the import process, we are collecting data into an array. At the end we write to a text file that will be located in the same directory as the drawings.
Xref the DWG’s into a single drawing and merge them (if you want)
fn xrefobjs dirname mergebool = ( resetmaxfile #noprompt for f in (getFiles (dirName+"\\*.max")) do ( mf = xrefs.addNewXrefFile f if mergebool then merge mf ) )
If the Save import as .Max file option is checked, all of the imported drawings will be referenced into a new drawing at the end. This allows you to get a quick visual on the imported drawings. You can discard this file if you choose. It won’t affect the other drawings.
IMPORTING WAS HERE
fn importObjects filename nsmooth sm= ( local impobjs = for o in objects where o.isfrozen == false collect o for obj in impobjs where classof obj == Editable_mesh do obj.name = (substring obj.name (6+1) obj.name.count) for obj in impobjs where classof obj == Editable_mesh do obj.name = (filename + "_" + obj.name) local smootharr = #() if chkSmooth.checked == true then ( for ns = 1 to nsmooth.count do ( local cfilter = "*" + nsmooth[ns] + "*" -- ("*" + nsmooth[ns] + "*") for imp = impobjs.count to 1 by -1 where matchpattern impobjs[imp].name pattern:cfilter == true do ( deleteitem impobjs imp ) ) if impobjs.count > 0 then for i = 1 to impobjs.count where impobjs[i].modifiers.count == 0 do addmodifier impobjs sm ) local impobjs = for o in objects where o.isfrozen == false do freeze o )
This is the meat of the import process where we
- Rename objects to the-file-they-came-from_the-layer-they-are-on
- Apply smooth modifier to any object that does not contain the characters in the do-no-smooth-if text box
- Freeze the imported objects
Clean this mess up!
fn unparent = ( startobjects = objects.count thedel=#() for o in geometry do ( o.controller=prs() if classof o.parent == LinkComposite then ( o.parent = undefined ) else ( o.parent = undefined ) ) for sp in objects where classof sp == splineshape do append thedel sp for o in geometry where classof o == LinkComposite do converttomesh o --append thedel o for o in geometry where classof o == LinkComposite do append thedel o for o in objects where classof o == NURBSCurveshape do append thedel o -- local count = thedel.count delete thedel count )
This function deals with the cleanup and runs when the Unparent checkbox is checked. Make sure you do this.
- Unparent everything
- Convert any block objects to meshes
- Delete Block objects, Splines, and NURBS curves
If you find that this part is breaking your model. Please contact me. It would also help to send your model that is breaking it.
The rest of it
local startimp=timestamp() local theobj = #() local thedwg = #() local s = smooth() local noSmooth = filterstring txt_NoSmoothType.text "," s.autosmooth=true clearlistener() disablesceneredraw() local exportfilelog = txt_dir.text + "\\importlog.txt" local importFileList = txt_dir.text + "\\importFileList.txt" if doesFileExist exportfilelog == false then ( cf = createFile exportfilelog close cf ) for f in getfiles (importDrawingPath) do append thedwg f for tf = 1 to thedwg.count do ( local logarr = #() local mfn = getfilenamefile thedwg[tf] local startIntTime = timestamp() local filename = filenameFromPath thedwg[tf] if chkFLM.checked then ( filelinkmgr.attach thedwg[tf] ) else ( if chkCreateMaxFile.checked == true then ( resetmaxfile #noprompt savefile = txt_dir.text + "\\" + mfn + ".max" --@"C:\Dropbox\projects\iso15926\Plant3D Sample\exported acad file\" + mfn + ".max" if tf != 1 then importFile thedwg[tf] #noprompt else importFile thedwg[tf] append logarr #("File saved successfully: ", savefile) ) else ( if tf != 1 then importFile thedwg[tf] #noprompt else importFile thedwg[tf] append logarr #("File imported successfully: ", thedwg[tf]) ) ) -- -- if chk_unparent.checked == true then ( local thecount = unparent() lbl_Status.text = "Deleted " + thecount as string + " objects" ) if chk_prefixmodelname.state == true then local impobjs = importObjects mfn nosmooth s if chkCreateMaxFile.checked == true then savemaxfile savefile -- local finIntTime = timestamp() -- local intTotal = ((finIntTime-startIntTime)/1000) as float append logarr #("File Import Time: ", intTotal) writetolog txt_dir.text logarr exportfilelog format "imported % in %\n" filename intTotal ) -- local tend=timestamp() local mbool = false local intTotal = ((tend-startimp)/1000) as float if chkMergeXrefs.checked == true then mbool = true if chkCreateMaxFile.checked == true then xrefobjs txt_dir.text mbool format "imported % files in %\n seconds" thedwg.count intTotal lbl_Status.text = "Imported " + thedwg.count as string + " files in " + intTotal as string + " seconds" -- enablesceneredraw() -- )
This is the main portion of the import where we are getting files, throwing them into functions and returning values, timestamping, writing to the log file.
If you need furthur clarity on some of this code. Again, don’t hesitate to contact me. I would love to hear you comments and/or suggestions for improvement. They tell me that I have to say you are using this code at your own risk and if something gets messed up as a result of your using it incorrectly, its on you. Fortunately, that is not likely to happen unless you alter the code somehow.
Until next time!