Create a gist now

Instantly share code, notes, and snippets.

@hyOzd /
Last active Mar 27, 2016

What would you like to do?
An experimental FreeCAD macro that will export visible objects as X3D
# This is an experimental FreeCAD macro that will export current scene
# as X3D file. Only the visible objects that can be converted to mesh
# will be exported with their color.
import FreeCAD
import FreeCADGui
import xml.etree.ElementTree as et
from PySide.QtGui import QFileDialog
import os
def getShapeNode(vertices, faces, diffuseColor=None):
"""Returns a <Shape> node for given mesh data.
vertices: list of vertice coordinates as `Vector` type
faces: list of tuple of vertice indexes ex: (1, 2, 3)
diffuseColor: tuple in the form of (R, G, B)"""
shapeNode = et.Element('Shape')
faceNode = et.SubElement(shapeNode, 'IndexedFaceSet')
faceNode.set('coordIndex', ' '.join(["%d %d %d -1" % face for face in faces]))
coordinateNode = et.SubElement(faceNode, 'Coordinate')
' '.join(["%f %f %f" % (p.x, p.y, p.z) for p in vertices]))
if diffuseColor:
appearanceNode = et.SubElement(shapeNode, 'Appearance')
materialNode = et.SubElement(appearanceNode, 'Material')
materialNode.set('diffuseColor', "%f %f %f" % diffuseColor)
return shapeNode
def exportX3D(objects, filepath):
"""Export given list of objects to a X3D file.
Each object is a dictionary in this form:
points : [Vector, Vector...],
faces : [(pi, pi, pi), ...], # pi: point index
color : (R, G, B) # number range is 0-1.0
fileNode = et.Element('X3D')
fileNode.set('profile', 'Interchange')
fileNode.set('version', '3.3')
sceneNode = et.SubElement(fileNode, 'Scene')
for o in objects:
shapeNode = getShapeNode(o["points"], o["faces"], o["color"])
with open(filepath, "wr") as f:
def getDocumentDir(doc):
"""Returns directory for given document. `None` if the file is not
saved yet."""
if doc.FileName:
return os.path.dirname(doc.FileName)
return None
def run():
doc = FreeCAD.activeDocument()
objects = []
for o in doc.Objects:
if o.ViewObject.Visibility:
if hasattr(o, "Shape"):
mesh = o.Shape.tessellate(1)
if (not mesh[0]) or (not mesh[1]):
continue # some objects (such as Part:Circle)
# generate empty mesh, skip them
"points": mesh[0],
"faces": mesh[1],
"color": o.ViewObject.ShapeColor[0:3]
if objects:
savefile = QFileDialog.getSaveFileName(
parent = FreeCADGui.getMainWindow(),
caption = "Export X3D file",
dir = getDocumentDir(doc))[0]
exportX3D(objects, savefile)
raise Exception("There is nothing to export!")
if __name__ == "__main__":

Works for me. Well done. What's the license on this? I'd be interested in seeing if I could get this integrated into CadQuery as an export option at some point.


hyOzd commented May 30, 2015

I didn't bother adding a license to this. But I can add GPL license. Does this work for you?

jmwright commented Mar 1, 2016

@hyOzd Sorry, I never got a notification about your answer. Adding a license would be great, but you can also just let me know if it's ok to evaluate working this into CadQuery. I'm not sure if I'll get it done, but I'm going to experiment with X3D support a bit. Thanks.


hyOzd commented Mar 27, 2016

@jmwright no problem at all. About the notifications, github doesn't send notifications on gist comments :/

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