From 8e5a1520cd5e901f514c382ad17e77d64727896a Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 10 Dec 2014 22:13:34 +0100 Subject: [PATCH 1/4] Moved DXF export scripts to separate directory. --- Makefile | 3 ++- support/dxf_export/__init__.py | 0 {dxf_export => support/dxf_export}/__main__.py | 0 {dxf_export => support/dxf_export}/better_dxf_outlines.py | 0 {dxf_export => support/dxf_export}/bezmisc.py | 0 {dxf_export => support/dxf_export}/cspsubdiv.py | 0 {dxf_export => support/dxf_export}/cubicsuperpath.py | 0 {dxf_export => support/dxf_export}/dxf_templates.py | 0 {dxf_export => support/dxf_export}/ffgeom.py | 0 {dxf_export => support/dxf_export}/inkex.py | 0 {dxf_export => support/dxf_export}/simplepath.py | 0 {dxf_export => support/dxf_export}/simplestyle.py | 0 {dxf_export => support/dxf_export}/simpletransform.py | 0 13 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 support/dxf_export/__init__.py rename {dxf_export => support/dxf_export}/__main__.py (100%) rename {dxf_export => support/dxf_export}/better_dxf_outlines.py (100%) rename {dxf_export => support/dxf_export}/bezmisc.py (100%) rename {dxf_export => support/dxf_export}/cspsubdiv.py (100%) rename {dxf_export => support/dxf_export}/cubicsuperpath.py (100%) rename {dxf_export => support/dxf_export}/dxf_templates.py (100%) rename {dxf_export => support/dxf_export}/ffgeom.py (100%) rename {dxf_export => support/dxf_export}/inkex.py (100%) rename {dxf_export => support/dxf_export}/simplepath.py (100%) rename {dxf_export => support/dxf_export}/simplestyle.py (100%) rename {dxf_export => support/dxf_export}/simpletransform.py (100%) diff --git a/Makefile b/Makefile index 1b50f45..5a77c48 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ INKSCAPE ?= inkscape OPENSCAD ?= openscad +PYTHON ?= python2 # Used by dxf_export/main.sh export INKSCAPE @@ -36,7 +37,7 @@ $(foreach i,$(COMPILED_SCAD_FILES),$(eval $(i): $(filter $(dir $(i))%,$(LIBRARY_ # Rule to convert an SVG file to a DXF file. %.dxf: %.svg - python2 dxf_export $< $@ + PYTHONPATH="support:$$PYTHONPATH" $(PYTHON) -m dxf_export $< $@ # Rule to compile an OpenSCAD file to an STL file. %.stl: %.scad diff --git a/support/dxf_export/__init__.py b/support/dxf_export/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dxf_export/__main__.py b/support/dxf_export/__main__.py similarity index 100% rename from dxf_export/__main__.py rename to support/dxf_export/__main__.py diff --git a/dxf_export/better_dxf_outlines.py b/support/dxf_export/better_dxf_outlines.py similarity index 100% rename from dxf_export/better_dxf_outlines.py rename to support/dxf_export/better_dxf_outlines.py diff --git a/dxf_export/bezmisc.py b/support/dxf_export/bezmisc.py similarity index 100% rename from dxf_export/bezmisc.py rename to support/dxf_export/bezmisc.py diff --git a/dxf_export/cspsubdiv.py b/support/dxf_export/cspsubdiv.py similarity index 100% rename from dxf_export/cspsubdiv.py rename to support/dxf_export/cspsubdiv.py diff --git a/dxf_export/cubicsuperpath.py b/support/dxf_export/cubicsuperpath.py similarity index 100% rename from dxf_export/cubicsuperpath.py rename to support/dxf_export/cubicsuperpath.py diff --git a/dxf_export/dxf_templates.py b/support/dxf_export/dxf_templates.py similarity index 100% rename from dxf_export/dxf_templates.py rename to support/dxf_export/dxf_templates.py diff --git a/dxf_export/ffgeom.py b/support/dxf_export/ffgeom.py similarity index 100% rename from dxf_export/ffgeom.py rename to support/dxf_export/ffgeom.py diff --git a/dxf_export/inkex.py b/support/dxf_export/inkex.py similarity index 100% rename from dxf_export/inkex.py rename to support/dxf_export/inkex.py diff --git a/dxf_export/simplepath.py b/support/dxf_export/simplepath.py similarity index 100% rename from dxf_export/simplepath.py rename to support/dxf_export/simplepath.py diff --git a/dxf_export/simplestyle.py b/support/dxf_export/simplestyle.py similarity index 100% rename from dxf_export/simplestyle.py rename to support/dxf_export/simplestyle.py diff --git a/dxf_export/simpletransform.py b/support/dxf_export/simpletransform.py similarity index 100% rename from dxf_export/simpletransform.py rename to support/dxf_export/simpletransform.py From 60b25ad13d0fdee926006bc728b031c4da1fb931 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 10 Dec 2014 22:18:14 +0100 Subject: [PATCH 2/4] Extracted common functions to separate module. --- support/dxf_export/__main__.py | 26 +++++--------------------- support/lib/__init__.py | 0 support/lib/util.py | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 support/lib/__init__.py create mode 100644 support/lib/util.py diff --git a/support/dxf_export/__main__.py b/support/dxf_export/__main__.py index ea6c7ad..76c2121 100644 --- a/support/dxf_export/__main__.py +++ b/support/dxf_export/__main__.py @@ -1,15 +1,6 @@ -import sys, os, xml.etree.ElementTree, subprocess, tempfile, contextlib, shutil -import better_dxf_outlines - - -@contextlib.contextmanager -def TemporaryDirectory(): - dir = tempfile.mkdtemp() - - try: - yield dir - finally: - shutil.rmtree(dir) +import sys, os, xml.etree.ElementTree, shutil +from lib import util +from . import better_dxf_outlines def _export_dxf(in_path, out_path): @@ -28,13 +19,6 @@ def _get_inkscape_layer_count(svg_path): return len(layers) -def _command(args): - process = subprocess.Popen(args) - process.wait() - - assert not process.returncode - - def _inkscape(svg_path, verbs): def iter_args(): yield os.environ['INKSCAPE'] @@ -45,7 +29,7 @@ def _inkscape(svg_path, verbs): yield svg_path - _command(list(iter_args())) + util.command(list(iter_args())) def _unfuck_svg_document(temp_svg_path): @@ -82,7 +66,7 @@ def _unfuck_svg_document(temp_svg_path): def main(in_path, out_path): - with TemporaryDirectory() as temp_dir: + with util.TemporaryDirectory() as temp_dir: temp_svg_path = os.path.join(temp_dir, 'temp.svg') shutil.copyfile(in_path, temp_svg_path) diff --git a/support/lib/__init__.py b/support/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/support/lib/util.py b/support/lib/util.py new file mode 100644 index 0000000..a3bc3dc --- /dev/null +++ b/support/lib/util.py @@ -0,0 +1,18 @@ +import contextlib, subprocess, tempfile, shutil + + +@contextlib.contextmanager +def TemporaryDirectory(): + dir = tempfile.mkdtemp() + + try: + yield dir + finally: + shutil.rmtree(dir) + + +def command(args): + process = subprocess.Popen(args) + process.wait() + + assert not process.returncode From f9fa53eef8e1183c4f7e3f9e0dd463ec1babdc86 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Dec 2014 11:44:29 +0100 Subject: [PATCH 3/4] Added support for recording dependencies while compiling OpenSCAD files. --- .gitignore | 1 + Makefile | 30 ++++++++++++++--------------- support/lib/util.py | 20 ++++++++++++++++++- support/openscad/__init__.py | 0 support/openscad/__main__.py | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 support/openscad/__init__.py create mode 100644 support/openscad/__main__.py diff --git a/.gitignore b/.gitignore index 90abfc2..1f16155 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyc *.dxf *.stl +*.d # Generated files /src/generated/ diff --git a/Makefile b/Makefile index 5a77c48..c91ea47 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,10 @@ INKSCAPE ?= inkscape OPENSCAD ?= openscad PYTHON ?= python2 +PYTHON_CMD := PYTHONPATH="support:$$PYTHONPATH" $(PYTHON) + # Used by dxf_export/main.sh -export INKSCAPE +export INKSCAPE OPENSCAD # Run generate_scad.sh to get the names of all OpenSCAD files that should be generated using that same script. GENERATED_FILES := $(addsuffix .scad,$(basename $(shell ./generate_sources.sh))) @@ -14,34 +16,32 @@ GENERATED_SCAD_FILES := $(filter %.scad, $(GENERATED_FILES)) SVG_FILES := $(shell find src -name '*.svg') $(GENERATED_SVG_FILES) # Only OpenSCAD files whose names do not start with `_' are compiled to STL. -SCAD_FILES := $(shell find src -name '*.scad') $(GENERATED_SCAD_FILES) -LIBRARY_SCAD_FILES := $(foreach i,$(SCAD_FILES),$(if $(filter _%,$(notdir $(i))),$(i))) -COMPILED_SCAD_FILES := $(filter-out $(LIBRARY_SCAD_FILES),$(SCAD_FILES)) +COMPILED_SCAD_FILES := $(foreach i,$(shell find src -name '*.scad') $(GENERATED_SCAD_FILES),$(if $(filter-out _%,$(notdir $(i))),$(i))) + +# Makefiles which are generated while compiling to record dependencies. +DEPENDENCY_FILES := $(patsubst %.scad,%.d,$(COMPILED_SCAD_FILES)) # All files that may be generated from the source files. STL_FILES := $(patsubst %.scad,%.stl,$(COMPILED_SCAD_FILES)) DXF_FILES := $(patsubst %.svg,%.dxf,$(SVG_FILES)) # Everything. Also generates files which aren't compiled to anything else. -all: $(STL_FILES) $(GENERATED_FILES) +all: $(GENERATED_FILES) $(DXF_FILES) $(STL_FILES) # Everything^-1. clean: - rm -rf $(DXF_FILES) $(STL_FILES) $(GENERATED_FILES) + rm -rf $(GENERATED_FILES) $(DXF_FILES) $(STL_FILES) $(DEPENDENCY_FILES) -# Needs to be included after target all has been defined. --include config.mk - -# Assume that any compiled OpenSCAD file may depend on any non-compiled OpenSCAD file in the same directory. -$(foreach i,$(COMPILED_SCAD_FILES),$(eval $(i): $(filter $(dir $(i))%,$(LIBRARY_SCAD_FILES) $(DXF_FILES)))) +# Include the local configuration file and the dependency files. Needs to be included after the `all' target has been defined. +-include config.mk $(DEPENDENCY_FILES) # Rule to convert an SVG file to a DXF file. %.dxf: %.svg - PYTHONPATH="support:$$PYTHONPATH" $(PYTHON) -m dxf_export $< $@ + $(PYTHON_CMD) -m dxf_export $< $@ -# Rule to compile an OpenSCAD file to an STL file. -%.stl: %.scad - $(OPENSCAD) -o $@ $< +# Rule to compile an OpenSCAD file to an STL file. We require all DXF files to exist before an OpenSCAD file can be used to generate an STL file. Additional dependencies are read from the included makefiles generated during compiling. +%.stl: %.scad | $(DXF_FILES) + $(PYTHON_CMD) -m openscad $< $@ $*.d # Rule for automaticlaly generated OpenSCAD files. $(GENERATED_FILES): generate_sources.sh diff --git a/support/lib/util.py b/support/lib/util.py index a3bc3dc..bede240 100644 --- a/support/lib/util.py +++ b/support/lib/util.py @@ -1,4 +1,4 @@ -import contextlib, subprocess, tempfile, shutil +import contextlib, subprocess, tempfile, shutil, re, os @contextlib.contextmanager @@ -16,3 +16,21 @@ def command(args): process.wait() assert not process.returncode + + +def bash_escape_string(string): + return "'{}'".format(re.sub("'", "'\"'\"'", string)) + + +def write_file(path, data): + temp_path = path + '~' + + with open(temp_path, 'wb') as file: + file.write(data) + + os.rename(temp_path, path) + + +def read_file(path): + with open(path, 'rb') as file: + return file.read() diff --git a/support/openscad/__init__.py b/support/openscad/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/support/openscad/__main__.py b/support/openscad/__main__.py new file mode 100644 index 0000000..08b2ab6 --- /dev/null +++ b/support/openscad/__main__.py @@ -0,0 +1,37 @@ +import os, sys +from lib import util + + +def _openscad(in_path, out_path, deps_path): + util.command([os.environ['OPENSCAD'], '-o', out_path, '-d', deps_path, in_path]) + + +def _write_dependencies(path, target, dependencies): + util.write_file(path, '{}: {}\n'.format(target, ' '.join(dependencies)).encode()) + + +def main(in_path, out_path, deps_path): + cwd = os.getcwd() + + def relpath(path): + return os.path.relpath(path, cwd) + + with util.TemporaryDirectory() as temp_dir: + temp_deps_path = os.path.join(temp_dir, 'deps') + temp_mk_path = os.path.join(temp_dir, 'mk') + temp_files_path = os.path.join(temp_dir, 'files') + + _openscad(in_path, out_path, temp_deps_path) + + mk_content = '%:; echo "$@" >> {}'.format(util.bash_escape_string(temp_files_path)) + + util.write_file(temp_mk_path, mk_content.encode()) + util.command(['make', '-s', '-B', '-f', temp_mk_path, '-f', temp_deps_path]) + + deps = set(map(relpath, util.read_file(temp_files_path).decode().splitlines())) + ignored_files = set(map(relpath, [temp_deps_path, temp_mk_path, in_path, out_path])) + + _write_dependencies(deps_path, relpath(out_path), deps - ignored_files) + + +main(*sys.argv[1:]) From b69003800917a93c5c2b240ede6f83b80f1095cc Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Dec 2014 11:44:51 +0100 Subject: [PATCH 4/4] Added more example files to showcase dependency tracking. --- src/_settings.scad | 2 ++ src/example.scad | 17 ----------------- src/example_1.scad | 6 ++++++ src/example_2.scad | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 src/_settings.scad delete mode 100644 src/example.scad create mode 100644 src/example_1.scad create mode 100644 src/example_2.scad diff --git a/src/_settings.scad b/src/_settings.scad new file mode 100644 index 0000000..1f84b17 --- /dev/null +++ b/src/_settings.scad @@ -0,0 +1,2 @@ +plate_height = 2; +struts_height = 1; diff --git a/src/example.scad b/src/example.scad deleted file mode 100644 index e4e5022..0000000 --- a/src/example.scad +++ /dev/null @@ -1,17 +0,0 @@ -module extrude_layer(layer, height) { - linear_extrude(height = height) - import("example.dxf", layer = layer); -} - -render(convexity = 10) { - union() { - difference() { - extrude_layer("base", 2); - - translate([0, 0, -1e6]) - extrude_layer("text", 2e6); - } - - extrude_layer("struts", 1); - } -} diff --git a/src/example_1.scad b/src/example_1.scad new file mode 100644 index 0000000..b6e8931 --- /dev/null +++ b/src/example_1.scad @@ -0,0 +1,6 @@ +include <_settings.scad> + +render(convexity = 10) { + linear_extrude(plate_height) + import("example.dxf", layer = "text"); +} diff --git a/src/example_2.scad b/src/example_2.scad new file mode 100644 index 0000000..2dd57e6 --- /dev/null +++ b/src/example_2.scad @@ -0,0 +1,14 @@ +include <_settings.scad> + +render(convexity = 10) { + union() { + linear_extrude(plate_height) + difference() { + import("example.dxf", layer = "base"); + import("example.dxf", layer = "text"); + } + + linear_extrude(struts_height) + import("example.dxf", layer = "struts"); + } +}