This repository has been archived by the owner on Feb 9, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 56
/
cq_cmd.py
197 lines (159 loc) · 6.66 KB
/
cq_cmd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#
# cadquery command line interface
# usage: cq_cmd [-h] [--param-file inputfile ] [--format STEP|STL ] [--output filename] filename
# if input file contains multiple inputs, multiple outputs are created
# if no input filename is provided, stdin is read instead
# if no output filename is provided, output goes to stdout
# default output format is STEP
#
from __future__ import print_function
import sys,os
from cadquery import cqgi,exporters
import argparse
import os.path
import json
import tempfile
class FilepathShapeWriter(object):
#a shape writer that writes a new file in a directory for each object
def __init__(self,file_pattern, shape_format):
self.shape_format=shape_format
self.file_pattern=file_pattern
self.counter = 1
def _compute_file_name(self):
return self.file_pattern % ({ "counter": self.counter,"format": self.shape_format } )
def write_shapes(self,shape_list):
for result in shape_list:
shape = result.shape
file_name = self._compute_file_name()
info("Writing %s Output to '%s'" % (self.shape_format, file_name))
s = open(file_name,'w')
exporters.exportShape(shape,self.shape_format,s)
s.flush()
s.close()
class StdoutShapeWriter(object):
#has extra code to prevent freecad crap from junking up stdout
def __init__(self,shape_format ):
self.shape_format = shape_format
def write_shapes(self,shape_list):
#f = open('/tmp/cqtemp','w')
#with suppress_stdout_stderr():
exporters.exportShape(shape_list[0].shape,self.shape_format,sys.stdout)
#f.flush()
#f.close()
#f = open('/tmp/cqtemp')
#sys.stdout.write(f.read())
def create_shape_writer(out_spec,shape_format):
if out_spec == 'stdout':
return StdoutShapeWriter(shape_format)
else:
return FilepathShapeWriter(out_spec,shape_format)
class ErrorCodes(object):
SCRIPT_ERROR=2
UNKNOWN_ERROR=3
INVALID_OUTPUT_DESTINATION=4
INVALID_OUTPUT_FORMAT=5
INVALID_INPUT=6
MULTIPLE_RESULTS=7
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def error(msg,exit_code=1):
eprint("ERROR %d: %s" %( exit_code, msg))
sys.exit(exit_code)
def warning(msg):
eprint("WARNING: %s" % msg)
def info(msg):
eprint("INFO: %s" % msg)
def read_file_as_string(file_name):
if os.path.isfile(file_name):
f = open(file_name)
s = f.read()
f.close()
return s
else:
return None
class ParameterHandler(object):
def __init__(self):
self.params = {}
def apply_file(self,file_spec):
if file_spec is not None:
p = read_file_as_string(file_spec)
if p is not None:
d = json.loads(p)
self.params.update(d)
def apply_string(self,param_string):
if param_string is not None:
r = json.loads(param_string)
self.params.update(r)
def get(self):
return self.params
def read_input_script(file_name):
if file_name != "stdin":
s = read_file_as_string(file_name)
if s is None:
error("%s does not appear to be a readable file." % file_name,ErrorCodes.INVALID_INPUT)
else:
return s
else:
s = sys.stdin.read()
return s
def check_input_format(input_format):
valid_types = [exporters.ExportTypes.TJS,exporters.ExportTypes.AMF,
exporters.ExportTypes.STEP,exporters.ExportTypes.STL,exporters.ExportTypes.TJS ]
if input_format not in valid_types:
error("Invalid Input format '%s'. Valid values: %s" % ( input_format, str(valid_types)) ,
ErrorCodes.INVALID_OUTPUT_FORMAT)
def describe_parameters(user_params, script_params):
if len(script_params)> 0:
parameter_names = ",".join(list(script_params.keys()))
info("This script provides parameters %s, which can be customized at build time." % parameter_names)
else:
info("This script provides no customizable build parameters.")
if len(user_params) > 0:
info("User Supplied Parameter Values ( Override Model Defaults):")
for k,v in user_params.items():
info("\tParameter: %s=%s" % (k,v))
else:
info("The script will run with default variable values")
info("use --param_file to provide a json file that contains values to override the defaults")
def run(args):
info("Reading from file '%s'" % args.in_spec)
input_script = read_input_script(args.in_spec)
script_name = 'stdin' if args.in_spec is None else args.in_spec
cq_model = cqgi.parse(input_script)
info("Parsed Script '%s'." % script_name)
param_handler = ParameterHandler()
param_handler.apply_file(args.param_file)
param_handler.apply_string(args.params)
user_params = param_handler.get()
describe_parameters(user_params,cq_model.metadata.parameters)
check_input_format(args.format)
build_result = cq_model.build(build_parameters=user_params)
info("Output Format is '%s'. Use --output-format to change it." % args.format)
info("Output Path is '%s'. Use --out_spec to change it." % args.out_spec)
if build_result.success:
result_list = build_result.results
info("Script Generated %d result Objects" % len(result_list))
shape_writer = create_shape_writer(args.out_spec,args.format)
shape_writer.write_shapes(result_list)
else:
error("Script Error: '%s'" % build_result.exception,ErrorCodes.SCRIPT_ERROR)
if __name__=='__main__':
desc="""
CQ CMD. Runs a cadquery python file, and produces a 3d object.
A script can be provided as a file or as standard input.
Each object created by the script is written the supplied output directory.
"""
filename_pattern_help="""
Filename pattern to use when creating output files.
The sequential file number and the format are available.
Default: cqobject-%%(counter)d.%%(format)s
Use stdout to write to stdout ( can't be used for multiple results though)
"""
parser = argparse.ArgumentParser(description=desc)
parser.add_argument("--format", action="store",default="STEP",help="Output Object format (TJS|STEP|STL|SVG)")
parser.add_argument("--param_file", action="store",help="Parameter Values File, in JSON format")
parser.add_argument("--params",action="store", help="JSON encoded parameter values. They override values provided in param_file")
parser.add_argument("--in_spec", action="store", required=True, help="Input File path. Use stdin to read standard in")
parser.add_argument("--out_spec", action="store",default="./cqobject-%(counter)d.%(format)s",help=filename_pattern_help)
args = parser.parse_args()
run(args)