Skip to content

Instantly share code, notes, and snippets.

@mdeweerd
Forked from slazav/convert_shape.py
Last active December 3, 2023 15:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mdeweerd/d14274ac53b64f23d983b5fdabed8f9e to your computer and use it in GitHub Desktop.
Save mdeweerd/d14274ac53b64f23d983b5fdabed8f9e to your computer and use it in GitHub Desktop.
Convert OpenSCAD files to STEP or IGES using FreeCAD python library
#!/usr/bin/env /cygdrive/c/Program Files/FreeCAD 0.21/bin/python
#!/usr/bin/env /cygdrive/c/Program Files/FreeCAD 0.20/bin/python
#!/usr/bin/env python3
#!/usr/bin/env /cygdrive/c/Program Files/FreeCAD 0.20/bin/FreeCAD
#!/usr/bin/env /cygdrive/c/Program Files/FreeCAD 0.20/bin/FreeCADCmd
#!/usr/bin/freecad
#!/usr/bin/python
# (Options above for reminder, easy exchange of lines to adapt to local platform).
# /!\ Launch this script using the python provided/used by FreeCAD
# (Select/add the appropriate line above)
#
#
# "Quick" and dirty script to convert from one format to the other,
# including OpenSCAD to STEP conversion
# For STEP output with color, this script must be run using FreeCAD, not FreeCADCmd, not python .
# Also works with the latter two, but without color in STEP output.
#
# Original https://gist.github.com/slazav/4853bd36669bb9313ddb83f51ee1cb82 - slazav/convert_shape.py
# Fork (this version): https://gist.github.com/d14274ac53b64f23d983b5fdabed8f9e
#
#
import atexit
import os
import re
import sys
# Exit this program when we can catch an error
def at_exit():
sys.exit(3)
# Register the exit script (does not catch everything though).
atexit.register(at_exit)
# Says if this was run with the FreeCAD Gui available.
hasGui = False
guiIsPossible = False
# Check if running from the Gui, cleanup sys.argv .
freecadPattern = re.compile(r"FreeCAD(Cmd)?(\.exe)?$", re.IGNORECASE)
freecadCmdPattern = re.compile(r"freecadcmd(\.exe)?$", re.IGNORECASE)
if freecadPattern.search(sys.argv[0]):
if not freecadCmdPattern.search(sys.argv[0]):
hasGui = True
# Remove freecad's path
sys.argv.pop(0)
# TODO: remove other arguments (-c, --console, etc) - workaround: do not use them
else:
paths = [
"/usr/lib64/freecad/lib",
"C:/Program Files/FreeCAD 0.21/bin",
"C:/Program Files/FreeCAD 0.20/bin",
"C:/Program Files/FreeCAD 0.19/bin",
"C:/Program Files/FreeCAD 0.18/bin",
]
for p in paths:
if os.path.exists(p):
FREECADPATH = p
break
if FREECADPATH is not None:
print("Using FreeCAD.so from " + FREECADPATH)
sys.path.insert(0, FREECADPATH)
os.environ["PYTHON_PATH"] = FREECADPATH
guiIsPossible = True
author = "MDW"
company = "https://gist.github.com/d14274ac53b64f23d983b5fdabed8f9e"
if os.getenv("AUTHOR") is not None:
author = os.getenv("AUTHOR")
if os.getenv("COMPANY") is not None:
company = os.getenv("COMPANY")
# Check if started with appropriate parameters
if len(sys.argv) < 3:
print("Usage: %s <in_file> <out_file>" % (sys.argv[0]),)
sys.exit(1)
iname = sys.argv[1]
oname = sys.argv[2]
import FreeCAD
# Further checking of the parameters, especially the output
isMesh = False
# determine format from extension
if oname[-5:] == ".iges":
file_type = "iges"
elif oname[-5:] == ".step":
file_type = "step"
if guiIsPossible:
import FreeCADGui
FreeCADGui.showMainWindow()
hasGui = True
elif oname[-4:] == ".dae":
file_type = "dae"
elif oname[-4:] == ".wrl":
file_type = "wrl"
isMesh = True
else:
print("Output file should have .step, .dae, .wrl or .iges extension")
sys.exit(1)
# Export the parameters to a file (debug):
# p=FreeCAD.ParamGet("User parameter:BaseApp")
# p.Export("e.tmp")
if iname[-5:] == ".scad":
# OpenSCAD import settings according to
# https://forum.lulzbot.com/viewtopic.php?t=243
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
p.SetBool("useViewProviderTree", True)
p.SetBool("useMultmatrixFeature", True)
# For some reason conversion does not work with cylinders created from
# extruded 2d circles.
# So I set MaxFN large enough and use smaller $fn in my step files to
# export such cylinders as polygons.
# If you use only normal cylinders, no need to use so large number here.
p.SetInt("useMaxFN", 50)
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
p.SetString("Author", author)
p.SetString("Company", company)
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
p.SetBool("ReadShapeCompoundMode", False)
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import")
p.SetBool("ExportLegacy", False)
p.SetBool("ExpandCompound", False)
p.SetInt("ImportMode", 0)
# Set a scheme for the STEP output:
# p.SetString("Scheme","AP203")
# p.SetString("Scheme", "AP214CD")
# p.SetString("Scheme","AP214DIS")
# p.SetString("Scheme","AP214IS")
p.SetString("Scheme", "AP242DIS")
# Export modified parameters to a file:
# p=FreeCAD.ParamGet("User parameter:BaseApp")
# p.Export("final.tmp")
# This should read any type of file
FreeCAD.loadFile(iname)
data = None
if False:
for p in App.ActiveDocument.RootObjects:
# find root object and export the shape
if len(p.InList) == 0:
print(p.__class__.__name__)
# iterate through all objects
allObjects = []
for o in App.ActiveDocument.RootObjects:
# find root object and export the shape
if len(o.InList) == 0 and hasattr(o, "Shape") and o.Visibility:
# print(o.__class__.__name__)
# print (o.Visibility)
if data is None:
data = o
allObjects.append(o)
# print(allObjects)
# Transform meshes (not perfect, WIP)
mesh = None
if data is not None and isMesh:
import Import
import MeshPart
# shape = data[0][0].Shape
shape = data.Shape
mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=0.1, Segments=True)
if 0:
shape_colors = data[0][1]
face_colors = [(0, 0, 0)] * mesh.CountFacets
for i in range(mesh.countSegments()):
color = shape_colors[i]
segm = mesh.getSegment(i)
for j in segm:
face_colors[j] = color
# mesh.write(Filename="new_example.obj", Material=face_colors, Format="obj")
#
# Generate the output
if data is None:
print("Error: can't find any object")
sys.exit(1)
else:
# print("Trying to write '{}'".format(oname))
if file_type == "step":
done = False
if hasGui:
# Try our best option first!
try:
import ImportGui
ImportGui.export(
allObjects, name=oname, keepPlacement=True
) # , legacy=True, keepPlacement=True, exportHidden=True)
done = True
except Exception as e:
print("export using ImportGui did not work", e)
if not done:
try:
data.Shape.exportStep(oname)
done = True
except Exception as e:
print("exportStep on shape did not work", e)
if not done:
try:
import Import
Import.export(
obj=[data],
name=oname,
legacy=True,
keepPlacement=True,
exportHidden=True,
)
done = True
except Exception as e:
print("export using Import did not work", e)
elif file_type == "iges":
data.Shape.exportIges(oname)
elif file_type == "dae":
import importDAE
# mesh.write(Filename=oname)
importDAE.export(data, oname) # .write(Filename=oname)
elif file_type == "wrl":
mesh.write(Filename=oname)
sys.exit(0)
sys.exit(2)
@yi-Xu-0100
Copy link

I try the Import.export and It still can not export step with color, is right?

I found it from https://forum.freecad.org/viewtopic.php?f=22&t=58071

Does this problem have solved?

@mdeweerd
Copy link
Author

mdeweerd commented Dec 3, 2023

I checked - it's been a while since I used this.

Do note that there are 2 "issues:

  • Generating a STEP with colors;
  • Viewing a STEP with colors.

While I managed to generate STEP with colors with older versions of FreeCAD, they were not (always) viewed in color in FreeCAD.
However, I could view them in color in KiCAD and they also in other tools.

I just tested FreeCAD 0.21.1: It generates more efficient STEP files and the STEP files with color are shown with color.

Not that the script tries several methods, the first one is ImportGui.export - in my case (on windows), FreeCAD opens a window which is closed almost immediately - so I think it works with the ImportGui.export method.

I am not 100% sure, but I think the ImportGui.Export provided better results - I would have prioritized the non-gui method if it didn't.

EDIT: I updated the script to call 0.21 (first line), add the 0.21 library as a library search path (windows), fix a spelling error, and also apply python formatting (black, flake, etc).

@yi-Xu-0100
Copy link

@mdeweerd Thanks for your reply, I just confused about the same function but not have same output(ImportGui.export and Import.export), and I will try to use the ImportGui.export to do it until I found anymore solution. ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment