import os
import stl
from stl import mesh
import subprocess
[docs]class OpenSCAD(object):
"""Management class for OpenSCAD command line interface"""
def __init__(self):
pass
[docs] def get_version(self):
"""return installed OpenScAD version"""
result = subprocess.run(['openscad', '--version'], capture_output=True)
version = result.stderr.decode().split()[2]
return version
[docs] def gen_stl(self, scad_path):
""" Generate STL file from specified SCAD file"""
print("Generating STL file from ", scad_path)
err_code = 1
if not os.path.isfile(scad_path):
return err_code
if not scad_path.endswith(".scad"):
return err_code
base, ext = scad_path.split(".")
stl_path = base+".stl"
cmd = [
'openscad',
scad_path,
"-o",
stl_path
]
result = subprocess.run(cmd, capture_output=True)
err_code = result.returncode
return err_code
def _get_bounds(self):
"""set internal bounds variables"""
minx = maxx = miny = maxy = minz = maxz = None
obj = self.mesh
for p in obj.points:
if minx is None:
minx = p[stl.Dimension.X]
maxx = p[stl.Dimension.X]
miny = p[stl.Dimension.Y]
maxy = p[stl.Dimension.Y]
minz = p[stl.Dimension.Z]
maxz = p[stl.Dimension.Z]
else:
maxx = max(p[stl.Dimension.X], maxx)
minx = min(p[stl.Dimension.X], minx)
maxy = max(p[stl.Dimension.Y], maxy)
miny = min(p[stl.Dimension.Y], miny)
maxz = max(p[stl.Dimension.Z], maxz)
minz = min(p[stl.Dimension.Z], minz)
self.minx = minx
self.maxx = maxx
self.miny = miny
self.maxy = maxy
self.minz = minz
self.maxz = maxz
[docs] def dump_to_json(self, json_path):
"""write mas properties data to specified JSON file"""
json = "{\n"
json += ' "maxx": "%s",\n' % self.maxx
json += ' "minx": "%s",\n' % self.minx
json += ' "maxy": "%s",\n' % self.maxy
json += ' "miny": "%s",\n' % self.miny
json += ' "maxz": "%s",\n' % self.maxz
json += ' "minz": "%s",\n' % self.minz
json += ' "volume": "%s",\n' % self.volume
json += ' "cgx": "%s",\n' % self.cgx
json += ' "cgy": "%s",\n' % self.cgy
json += ' "cgz": "%s",\n' % self.cgz
json += ' "ixx": "%s",\n' % self.ixx
json += ' "ixy": "%s",\n' % self.ixy
json += ' "ixz": "%s",\n' % self.ixz
json += ' "iyx": "%s",\n' % self.iyx
json += ' "iyy": "%s",\n' % self.iyy
json += ' "iyz": "%s",\n' % self.iyz
json += ' "izx": "%s",\n' % self.izx
json += ' "izy": "%s",\n' % self.izy
json += ' "izz": "%s"\n' % self.izz
json += '}\n'
with open(json_path, 'w') as fout:
fout.write(json)
[docs] def get_properties(self, scad_file):
"""Calculate mass properties from specified SCAD file"""
scad_path = os.path.abspath(scad_file)
err_code = self.gen_stl(scad_path)
base, ext = scad_path.split(".")
stl_file = base + ".stl"
self.json_file = base + ".json"
self.mesh = mesh.Mesh.from_file(stl_file)
self._get_bounds()
volume, cog, inertia = self.mesh.get_mass_properties()
self.cgx, self.cgy, self.cgz = cog
self.volume = volume
self.ixx, self.ixy, self.ixz = inertia[0]
self.iyx, self.iyy, self.iyz = inertia[1]
self.izx, self.izy, self.izz = inertia[2]
self.dump_to_json(self.json_file)
return err_code
[docs] def get_bounds(self):
"""Return bounds data as a list"""
return [
self.maxx, self.minx,
self.maxy, self.miny,
self.maxz, self.minz
]
if __name__ == '__main__':
mgr = OpenSCAD()
print(mgr.get_version())
mgr.get_properties("../tests/test_data/spar.scad")
mgr.dump_to_json("../tests/test_data/spar.json")