Created
September 27, 2015 07:18
-
-
Save runsun/995250a8002386ab9abc to your computer and use it in GitHub Desktop.
Run an openscad file once or n times and save shape output to file(s)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################################################## | |
## runscad.py | |
## | |
## Run an openscad file once or n times and save shape output to file(s) | |
## | |
## by Runsun Pan (2015.9.25) | |
###########################################3############################## | |
import sys, os, re | |
narg = len(sys.argv) | |
if narg<3: | |
print ''' | |
runscad.py | |
>>> python runscad_animate.py <scad_file> <output_file> <opt> <opt> ... | |
For example: | |
>>> python runscad.py tmp.scad out.png n=3 D=t=0.2*(%(n)s-1);run() | |
outfile: | |
Setting outfile to xxx.png will save the shape to xxx.png. But if | |
n (number of runs)>0, it will run n times and save to | |
xxx00001.png, xxx00002.png, xxx00003.png ... | |
This is done by converting "." to "00001.", so the outfile name | |
must have a ".". | |
opt: | |
Options: All name/value pairs are in 'name=value' format or simply 'name' | |
if it's a flag (for example, version). Pairs are separated by spaces: | |
imgsize=100,200 version D="..." dryrun | |
opt has 2 parts: | |
(1) Original openscad command line options: | |
d=deps_file | |
m=make_command | |
D=a=2;b=3;run(); | |
version | |
info | |
camera=translatex,y,z,rotx,y,z,dist | camera=eyex,y,z,centerx,y,z | |
imgsize=width,height | |
projection=(o)rtho|(p)ersp] | |
render | preview[=throwntogether] | |
csglimit=num | |
(2) runscad.py options: | |
dryrun: | |
Debug flag. When set, it will not call openscad but will output | |
parameters and settings for debugging. | |
>>> python runscad.py tmp.scad dump.png D="a=3;run();" dryrun | |
n: # of repeat run. To run it 3 times: | |
>>> python runscad.py tmp.scad dump.png D="a=3;run();" n=3 | |
If n >0, we also get two internal vars: | |
i: index of run in each repeating run | |
t: i*1.0/n. It is between 0~1. This can be used to run animation. | |
n,i,t can be sent to your scad file by giving them in the D option: | |
D="index=%(i)s;time_fraction=%(t)s;nRun=%(n)s" | |
>>> python runscad.py tmp.scad dump.png D="n=%(n)s" n=3 | |
Dquote: either "'" or '"' | |
The D to send statements to openscad and is used as: | |
python runscad.py tmp.scad out.scad D="a=3;" | |
wihch is converted to an openscad command-line: | |
openscad tmp.scad out.scad -D "a=3;" | |
But if you want to send string by attempting : | |
python runscad.py tmp.scad out.scad D="a=\"left\";" | |
which creates a syntex error: | |
openscad tmp.scad out.scad -D "a="left";" | |
To avoid this, set Dquote="'": | |
python runscad.py tmp.scad out.scad D="a=3;" Dquote="'" | |
which converts to the following command line: | |
openscad tmp.scad out.scad -D 'a="left";' | |
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_OpenSCAD_in_a_command_line_environment | |
" | |
''' | |
else: | |
scadfile = sys.argv[1] | |
outfile = sys.argv[2] | |
print "\n* num of args = ", narg | |
p = re.compile("^([a-zA-Z]*)=(.*)") # match "o somefile.scad" or "camera=..." | |
print "\n* Extract opt:" | |
opt = [ p.match(x)!=None and p.match(x).groups() or (x,"") for x in sys.argv[3:] | |
] | |
print " opt = ", opt | |
print "* Convert opt to dict:" | |
opt = dict( opt ) | |
print " opt = ", opt | |
if 'o' in opt: | |
print "* Remove the 'o' setting from opt --- which should be set in outfile=..." | |
del opt['o'] | |
n = int(opt.get('n',0)) | |
print "* n is found to be %s"%n | |
if 'n' in opt: | |
print "* Remove n from opt:" | |
del opt['n'] | |
print " opt = ", opt | |
Dquote= opt.get('Dquote','"') | |
if 'Dquote' in opt: | |
print "* Remove Dquote from opt:" | |
del opt['Dquote'] | |
print " opt = ", opt | |
dryrun= False | |
if 'dryrun' in opt: | |
dryrun=True | |
print "* dryrun is found to be true. Remove Dquote from opt:" | |
del opt['dryrun'] | |
print " opt = ", opt | |
print "* Convert python dict to openscad command line:" | |
opt = [ k in ("o","d","m","D") | |
and "-"+k+ " "+ (k=="D" and Dquote or '')+ opt[k]+ (k=="D" and Dquote or '') | |
or "--"+k + (opt[k] and ("="+opt[k]) or "") | |
for k in opt ] | |
print " opt = ", opt | |
opt = " ".join( opt ) | |
print " opt = ", opt | |
if dryrun: | |
print "\nStart dryrun --- openscad is not executed" | |
for i in range(n): | |
print "\nn=", n, ", i=", i | |
t = i*1.0/n | |
_outfile = n and outfile.replace(".", str(i+1).rjust(5,'0')+".") or outfile | |
optvars = {"i":i,"n":n,"t":t,"outfile":_outfile} | |
print "* vars available to -D: ", optvars | |
params={ "scadfile": scadfile | |
, "outfile" : _outfile | |
, "opt": opt%optvars | |
} | |
cmd = 'openscad %(scadfile)s -o %(outfile)s %(opt)s '%params | |
if not dryrun: | |
os.system(cmd) | |
print "* cmd=", cmd | |
############################## |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An actual use case in animation gif generation :
The scad code handling 3d animation:
Your scad code: animate_gif.scad
Use animation parameters in your scad:
3 animation parameters, i (index), n (# of frames) and t (time fraction), can be sent from commandline to your scad using the python-style string substitution format:
and then in your scad file:
Do a dryrun to check parameters with n set to just 3:
Output of dryrun to the shell:
* num of args = 9
* Extract opt:
opt = [('n', '3'), ('D', 'run(t=%(t)s);'), ('Dquote', "'"), ('camera', '0,0,0,0,0,0,140'), ('imgsize', '250,250'), ('dryrun', '')]
opt = {'dryrun': '', 'imgsize': '250,250', 'Dquote': "'", 'n': '3', 'camera': '0,0,0,0,0,0,140', 'D': 'run(t=%(t)s);'}
opt = {'dryrun': '', 'imgsize': '250,250', 'Dquote': "'", 'camera': '0,0,0,0,0,0,140', 'D': 'run(t=%(t)s);'}
opt = {'dryrun': '', 'imgsize': '250,250', 'camera': '0,0,0,0,0,0,140', 'D': 'run(t=%(t)s);'}
opt = {'imgsize': '250,250', 'camera': '0,0,0,0,0,0,140', 'D': 'run(t=%(t)s);'}
opt = ['--imgsize=250,250', '--camera=0,0,0,0,0,0,140', "-D 'run(t=%(t)s);'"]
opt = --imgsize=250,250 --camera=0,0,0,0,0,0,140 -D 'run(t=%(t)s);'
Start dryrun --- openscad is not executed
n= 3 , i= 0
n= 3 , i= 1
n= 3 , i= 2
Generate 3 png files for a test run:
Before we go into full production, which could take long depending on your scad, we do a 3-file test run:
Check the generated png files to see if they look ok. Adjust parameters properly (in your scad file and in the parameters given to runscad.py). A good parameter to try is
imgsize=400,400
for runscad.py.Actual execution to generate 120 png files:
Convert pngs to animating gif:
The command
convert
is part of ImageMagick. Try out different values for delay and crop. For crop:where the starting 0 is on the top-left corner.
For delay: a combination of n=120 and delay=10 gives a smooth ride like what's shown blow.
The gif: