From cb2355cd5148d7e5256aeed5b0bcfbcd7724f327 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 25 Jan 2021 10:09:29 -0500 Subject: [PATCH 1/2] First pass at SVG export --- README.md | 3 ++- cq-cli.py | 21 +++++++++++++++++++-- cqcodecs/cq_codec_step.py | 2 +- cqcodecs/cq_codec_stl.py | 2 +- cqcodecs/cq_codec_svg.py | 20 ++++++++++++++++++++ 5 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 cqcodecs/cq_codec_svg.py diff --git a/README.md b/README.md index 32b9943..ca2ffc0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If a development installation is desired, see the [Contributing](#contributing) ## Usage -usage: cq-cli.py [-h] [--codec CODEC] [--infile INFILE] [--outfile OUTFILE] [--errfile ERRFILE] [--params PARAMS] [--validate VALIDATE] +usage: cq-cli.py [-h] [--codec CODEC] [--infile INFILE] [--outfile OUTFILE] [--errfile ERRFILE] [--params PARAMS] [--outputopts OPTS] [--validate VALIDATE] Command line utility for converting CadQuery script output to various other output formats. @@ -49,6 +49,7 @@ optional arguments: * --outfile OUTFILE File to write the converted CadQuery output to. Prints to stdout if not specified. * --errfile ERRFILE File to write any errors to. Prints to stderr if not specified. * --params PARAMS A colon and semicolon delimited string (no spaces) of key/value pairs representing variables and their values in the CadQuery script. i.e. var1:10.0;var2:4.0; +* --outputopts OPTS A colon and semicolon delimited string (no spaces) of key/value pairs representing options to pass to the selected codec. i.e. width:100;height:200; * --validate VALIDATE Setting to true forces the CLI to only parse and validate the script and not produce converted output. ## Examples diff --git a/cq-cli.py b/cq-cli.py index 065dd9c..cfde52e 100755 --- a/cq-cli.py +++ b/cq-cli.py @@ -90,6 +90,7 @@ def main(): codec = None codec_module = None params = {} + output_opts = {} # Find the codecs that have been added. loaded_codecs = loader.load_codecs() @@ -101,6 +102,7 @@ def main(): parser.add_argument('--outfile', dest='outfile', help='File to write the converted CadQuery output to. Prints to stdout if not specified.') parser.add_argument('--errfile', dest='errfile', help='File to write any errors to. Prints to stderr if not specified.') parser.add_argument('--params', dest='params', help='A colon and semicolon delimited string (no spaces) of key/value pairs representing variables and their values in the CadQuery script. i.e. var1:10.0;var2:4.0;') + parser.add_argument('--outputopts', dest='opts', help='A colon and semicolon delimited string (no spaces) of key/value pairs representing options to pass to the selected codec. i.e. width:100;height:200;') parser.add_argument('--validate', dest='validate', help='Setting to true forces the CLI to only parse and validate the script and not produce converted output.') args = parser.parse_args() @@ -189,7 +191,22 @@ def main(): groups = args.params.split(';') for group in groups: param_parts = group.split(':') - params[param_parts[0]] = param_parts[1] + # Protect against a trailing semi-colon + if len(param_parts) == 2: + params[param_parts[0]] = param_parts[1] + + # + # Output options handling + # + # Check whether any output options were passed + if args.opts != None: + # Convert the string of options into a output_opts dictionary + groups = args.opts.split(';') + for group in groups: + opt_parts = group.split(':') + # Protect against a trailing semi-colon + if len(opt_parts) == 2: + output_opts[opt_parts[0]] = opt_parts[1] # # Parse and build the script. @@ -216,7 +233,7 @@ def main(): # Build, parse and let the selected codec convert the CQ output try: # Use the codec plugin to do the conversion - converted = codec_module.convert(build_result, outfile, errfile) + converted = codec_module.convert(build_result, outfile, errfile, output_opts) # If converted is None, assume that the output was written to file directly by the codec if converted != None: diff --git a/cqcodecs/cq_codec_step.py b/cqcodecs/cq_codec_step.py index 626e55d..6bdec53 100644 --- a/cqcodecs/cq_codec_step.py +++ b/cqcodecs/cq_codec_step.py @@ -3,7 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers -def convert(build_result, output_file=None, error_file=None): +def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_step.step") diff --git a/cqcodecs/cq_codec_stl.py b/cqcodecs/cq_codec_stl.py index 8efee74..14def2c 100644 --- a/cqcodecs/cq_codec_stl.py +++ b/cqcodecs/cq_codec_stl.py @@ -3,7 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers -def convert(build_result, output_file=None, error_file=None): +def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_stl.stl") diff --git a/cqcodecs/cq_codec_svg.py b/cqcodecs/cq_codec_svg.py new file mode 100644 index 0000000..c8d0431 --- /dev/null +++ b/cqcodecs/cq_codec_svg.py @@ -0,0 +1,20 @@ +import os, tempfile +from cadquery import exporters +import cadquery as cq +import cqcodecs.codec_helpers as helpers + +def convert(build_result, output_file=None, error_file=None, output_opts=None): + # Create a temporary file to put the STL output into + temp_dir = tempfile.gettempdir() + temp_file = os.path.join(temp_dir, "temp_svg.svg") + + # The exporters will add extra output that we do not want, so suppress it + with helpers.suppress_stdout_stderr(): + # Put the STEP output into the temp file + exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.SVG, output_opts) + + # Read the STEP output back in + with open(temp_file, 'r') as file: + step_str = file.read() + + return step_str \ No newline at end of file From f928cf5ac9b52d181ac43a7db04c3a0cf9d14d5c Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Fri, 29 Jan 2021 13:57:11 -0500 Subject: [PATCH 2/2] Finished SVG codec --- README.md | 4 ++++ cq-cli.py | 14 +++++++++++++- cqcodecs/cq_codec_svg.py | 2 +- tests/test_svg_codec.py | 12 ++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/test_svg_codec.py diff --git a/README.md b/README.md index ca2ffc0..493a87e 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,10 @@ optional arguments: ``` cat /input/path/script.py | cq-cli.py --codec step | wc -l ``` +7. Convert a CadQuery script to SVG, passing in output options to influence the resulting image. +``` +./cq-cli.py --codec svg --infile /input/path/script.py --outfile /output/path/newfile.svg --outputopts "width:100;height:100;marginLeft:12;marginTop:12;showAxes:False;projectionDir:(0.5,0.5,0.5);strokeWidth:0.25;strokeColor:(255,0,0);hiddenColor:(0,0,255);showHidden:True;" +``` ## Drawbacks diff --git a/cq-cli.py b/cq-cli.py index cfde52e..22de0df 100755 --- a/cq-cli.py +++ b/cq-cli.py @@ -206,7 +206,19 @@ def main(): opt_parts = group.split(':') # Protect against a trailing semi-colon if len(opt_parts) == 2: - output_opts[opt_parts[0]] = opt_parts[1] + op1 = opt_parts[1] + + # Handle the option data types properly + if op1 == "True" or op1 == "False": + op = opt_parts[1] == "True" + elif op1[:1] == "(": + op = tuple(map(float, opt_parts[1].replace("(", "").replace(")", "").split(','))) + elif "." in op1: + op = float(opt_parts[1]) + else: + op = int(opt_parts[1]) + + output_opts[opt_parts[0]] = op # # Parse and build the script. diff --git a/cqcodecs/cq_codec_svg.py b/cqcodecs/cq_codec_svg.py index c8d0431..cf9a5e5 100644 --- a/cqcodecs/cq_codec_svg.py +++ b/cqcodecs/cq_codec_svg.py @@ -11,7 +11,7 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): # The exporters will add extra output that we do not want, so suppress it with helpers.suppress_stdout_stderr(): # Put the STEP output into the temp file - exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.SVG, output_opts) + exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.SVG, opt=output_opts) # Read the STEP output back in with open(temp_file, 'r') as file: diff --git a/tests/test_svg_codec.py b/tests/test_svg_codec.py new file mode 100644 index 0000000..c8cbc16 --- /dev/null +++ b/tests/test_svg_codec.py @@ -0,0 +1,12 @@ +import tests.test_helpers as helpers + +def test_svg_codec(): + """ + Basic test of the SVG codec plugin. + """ + test_file = helpers.get_test_file_location("cube.py") + + command = ["python", "cq-cli.py", "--codec", "svg", "--infile", test_file, "--outputopts", "width:100;height:100;marginLeft:12;marginTop:12;showAxes:False;projectionDir:(0.5,0.5,0.5);strokeWidth:0.25;strokeColor:(255,0,0);hiddenColor:(0,0,255);showHidden:True;"] + out, err, exitcode = helpers.cli_call(command) + + assert out.decode().split('\n')[0].replace('\r', '') == "" \ No newline at end of file