Introduction: VBscript to Automate Convesion To/from STL, STP, DAE and IGES Files Via FreeCAD
Finally I found a way to do conversions between different 3D files without wasting time!
Supplies
Link to download the script:
https://mega.nz/file/O4kWVLCC#p7L71F6waeni2dAxE2qLWPrKde0UxHMrY8qka0gj65g
Step 1: My Goal
I use Tinkercad to realize my 3D projects, so I make intensive use of STL files, but I was asked many times to render my STL in STEP, IGES or DAE format.
That's really a tedious work, due to large number of items to process.
To convert STL to other file type I use FreeCAD, whose flexibility let me make several types of conversion between formats, but it's a time consuming operation, of course.
I decided to face the problem one time for all and write down some script to automatize the conversions.
You can place this script wherever you want in your disk.
Step 2: The VBS Script
' Created by Francesco Francescangeli
' 2021-10-18
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objPopup = CreateObject("WScript.Shell")
Set Arg = Wscript.Arguments
Const ForReading = 1, ForWriting = 2
const ShowWindow = 1, DontShowWindow = 0, WaitUntilFinished = true, DontWaitUntilFinished = false
INsupported = "STL,STP,DAE,IGES"
OUTsupported = INsupported
' Check all is OK
'====================================================================================================================
If Arg.count < 4 Then
wscript.echo "Missing parameters!" & vbCrLf & "Syntax:" & vbCrLf & "CONVERT.VBS [INtype] [OUTtype] [Full INpath] [Full OUTpath]"
WScript.Quit
End If
INfiletype = UCase(Arg(0))
OUTfiletype = UCase(Arg(1))
INdir = Arg(2)
INdir = Replace(INdir, "\", "/")
OUTdir = Arg(3)
OUTdir = Replace(OUTdir, "\", "/") & "/"
Set objFolder = objFSO.GetFolder(INdir)
numFiles = objFolder.Files.Count
If numFiles = 0 Then
wscript.echo "Input directory empty!"
WScript.Quit
End If
If INfiletype = OUTfiletype Then
wscript.echo "IN and OUT file format is identical!"
WScript.Quit
End If
If InStr(INsupported, INfiletype) = 0 Or InStr(OUTsupported, OUTfiletype) = 0 Then
wscript.echo "Input file type not supported!"
WScript.Quit
End If
Set allFiles = objFolder.Files
numTot = 0
For Each objFile in allFiles
If UCase(objFSO.GetExtensionName(objFile.Name)) = INfiletype Then
numTot = numTot + 1
End If
Next
If numTot = 0 Then
wscript.echo "No " & INfiletype & " file found!"
WScript.Quit
End If
'====================================================================================================================
'Functions
'====================================================================================================================
Function ControlName(FileName)
If IsNumeric(Mid(FileName,1,1)) Then
ControlName = "_" & Mid(FileName,2)
Else
ControlName = FileName
End If
End Function
Function sendIN(str)
MsgLine = Trim(str)
x = objPopup.Popup(MsgLine, 3, "Work in progress" , 64)
End Function
Function sendEND(str)
MsgLine = Trim(str)
x = objPopup.Popup(MsgLine, 10, "Job completed!" , 64)
End Function
Function FileConv(extIN, extOUT, nameIN, nameOUT, namePart, path)
FileConv = false
If objFSO.FileExists(nameOUT) Then
objFSO.DeleteFile(nameOUT)
End If
Set filetxt = objFSO.CreateTextFile(ConvScript, ForWriting)
Select Case extIN
Case "STL"
Select Case extOUT
Case "STP"
filetxt.WriteLine("import FreeCAD, Mesh, Part, Import")
filetxt.WriteLine("Mesh.open('" & nameIN & "')")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').addObject('Part::Feature', '" & namePart & "001')")
filetxt.WriteLine("__shape__ = Part.Shape()")
filetxt.WriteLine("__shape__.makeShapeFromMesh(FreeCAD.getDocument('Unnamed').getObject('" & namePart & "').Mesh.Topology, 0.1)")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001').Shape = __shape__")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001').purgeTouched()")
filetxt.WriteLine("del __shape__")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001'))")
filetxt.WriteLine("Import.export(__objs__, '" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
Case "DAE"
filetxt.WriteLine("import FreeCAD, Mesh, importDAE")
filetxt.WriteLine("Mesh.open(u'" & nameIN & "')")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('Unnamed').getObject('" & namePart & "'))")
filetxt.WriteLine("importDAE.export(__objs__, u'" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
Case "IGES"
filetxt.WriteLine("import FreeCAD, Mesh, Part")
filetxt.WriteLine("Mesh.open(u'" & nameIN & "')")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').addObject('Part::Feature', '" & namePart & "001')")
filetxt.WriteLine("__shape__=Part.Shape()")
filetxt.WriteLine("__shape__.makeShapeFromMesh(FreeCAD.getDocument('Unnamed').getObject('" & namePart & "').Mesh.Topology, 0.1)")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001').Shape=__shape__")
filetxt.WriteLine("FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001').purgeTouched()")
filetxt.WriteLine("del __shape__")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('Unnamed').getObject('" & namePart & "001'))")
filetxt.WriteLine("Part.export(__objs__, u'" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
End Select
Case "STP"
Select Case extOUT
Case "STL"
filetxt.WriteLine("import FreeCAD, Mesh, Part")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("Mesh.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
Case "DAE"
filetxt.WriteLine("import FreeCAD, Mesh, Part, importDAE")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("importDAE.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
Case "IGES"
filetxt.WriteLine("import FreeCAD, Part")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("Part.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
End Select
Case "DAE"
Select Case extOUT
Case "STL"
filetxt.WriteLine("import FreeCAD, Mesh, importDAE")
filetxt.WriteLine("importDAE.open(u'" & nameIN & "')")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('" & namePart & "').getObject('Mesh'))")
filetxt.WriteLine("Mesh.export(__objs__, u'" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
Case "STP"
filetxt.WriteLine("import FreeCAD, importDAE, Part, Import")
filetxt.WriteLine("importDAE.open(u'" & nameIN & "')")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').addObject('Part::Feature', 'Mesh001')")
filetxt.WriteLine("__shape__=Part.Shape()")
filetxt.WriteLine("__shape__.makeShapeFromMesh(FreeCAD.getDocument('" & namePart & "').getObject('Mesh').Mesh.Topology, 0.1)")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').getObject('Mesh001').Shape=__shape__")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').getObject('Mesh001').purgeTouched()")
filetxt.WriteLine("del __shape__")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('" & namePart & "').getObject('Mesh001'))")
filetxt.WriteLine("Import.export(__objs__, u'" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
Case "IGES"
filetxt.WriteLine("import FreeCAD, importDAE, Part")
filetxt.WriteLine("importDAE.open(u'" & nameIN & "')")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').addObject('Part::Feature', 'Mesh001')")
filetxt.WriteLine("__shape__=Part.Shape()")
filetxt.WriteLine("__shape__.makeShapeFromMesh(FreeCAD.getDocument('" & namePart & "').getObject('Mesh').Mesh.Topology, 0.1)")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').getObject('Mesh001').Shape=__shape__")
filetxt.WriteLine("FreeCAD.getDocument('" & namePart & "').getObject('Mesh001').purgeTouched()")
filetxt.WriteLine("del __shape__")
filetxt.WriteLine("__objs__ = []")
filetxt.WriteLine("__objs__.append(FreeCAD.getDocument('" & namePart & "').getObject('Mesh001'))")
filetxt.WriteLine("Part.export(__objs__, u'" & path & nameOUT & "')")
filetxt.WriteLine("del __objs__")
End Select
Case "IGES"
Select Case extOUT
Case "STL"
filetxt.WriteLine("import FreeCAD, Part, Mesh")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("Mesh.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
Case "STP"
filetxt.WriteLine("import FreeCAD, Part, Import")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("Import.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
Case "DAE"
filetxt.WriteLine("import FreeCAD, Part, importDAE")
filetxt.WriteLine("shape = Part.Shape()")
filetxt.WriteLine("shape.read('" & nameIN & "')")
filetxt.WriteLine("doc = App.newDocument(""Doc"")")
filetxt.WriteLine("pf = doc.addObject(""Part::Feature"",""MyShape"")")
filetxt.WriteLine("pf.Shape = shape")
filetxt.WriteLine("importDAE.export([pf], " & chr(34) & path & nameOUT & chr(34) & ")")
End Select
End Select
filetxt.Close
If objFSO.FileExists(ConvScript) Then
FileConv = true
End If
End Function
'====================================================================================================================
DestDir = "C:\Users\ff\AppData\Roaming\FreeCAD\Macro\"
ConvScript = DestDir & "FILECONV.FCMACRO"
CurDir = objFSO.GetAbsolutePathName(".") & "\"
numDone = 0
For Each objFile in allFiles
nameFile = ControlName(objFSO.GetBaseName(objFile.Name))
If UCase(objFSO.GetExtensionName(objFile.Name)) = INfiletype Then
if FileConv(INfiletype, OUTfiletype, INdir & "/" & objFile.Name, objFSO.GetBaseName(objFile.Name) & "." & OUTfiletype, objFSO.GetBaseName(objFile.Name), OUTdir) Then
sendIN("Please wait..." & vbCrLf & vbCrLf & "Converting:" & vbCrLf & objFile.Name)
objShell.Run """C:\Program Files\FreeCAD 0.18\bin\freecadcmd"" " & ConvScript, DontShowWindow, WaitUntilFinished
numDone = numDone + 1
If numDone = numTot Then
sendEND("All files processed.")
End If
If objFSO.FileExists(DestDir & ConvScript) Then
objFSO.DeleteFile(DestDir & ConvScript)
End If
End If
End If
Next
Step 3: VBS Arguments
INfiletype = UCase(Arg(0))
The first argument to pass to script is the file type to convert from (STL, STP, DAE, IGES)
OUTfiletype = UCase(Arg(1))
The 2nd one to pass to script is the file type to convert to (STL, STP, DAE, IGES)
INdir = Arg(2)
The 3rd one is the full path of directory containing the files to convert from in the form
C:\***\***\SourceDir (no trailing backslash).
OUTdir = Arg(3)
The 4th argument to pass to script is the destination path in the form C:\***\***\DestinationDir (no trailing backslash).
It's ininfluent that inside the source dir reside other types of files, they're filtered out by the script.
Example:
C:\convert.vbs stp iges C:\myfiles\stpfiles C:\myfiles\igesfiles
Step 4: Here It Comes...
Let's say we have:
- FreeCAD installed
Mine is 0.18 release, so if your is different you'll have to modify the line in script according to:
objShell.Run """C:\Program Files\FreeCAD 0.18\bin\freecadcmd"" " & ConvScript, DontShowWindow, WaitUntilFinished
_________________________________________________________________________
1) Open Command Prompt (cmd.exe)
2) execute (i.e.):
C:\(path to convert.vbs)\convert.vbs stp iges C:\myfiles\stpfiles C:\myfiles\igesfiles
3) a number of info popup, informing you about work progress
4) when done, a new popup will show you how many files have been processed.
That's all!




