From 1d75fccd12b81d3a4625b3288f1b02b8ce1a07c1 Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Fri, 4 Jul 2014 17:09:46 +0200 Subject: [PATCH] Initial commit --- Makefile | 111 + commands.html | 447 ++ src/CMakeLists.txt | 10 + src/apps/README | 15 + src/apps/bundle.py | 62 + src/apps/cba.icns | Bin 0 -> 115172 bytes src/apps/cba_icon.png | Bin 0 -> 9391 bytes src/core/CMakeLists.txt | 28 + src/core/array_direction.c | 52 + src/core/array_distances.c | 71 + src/core/array_edges.c | 52 + src/core/array_info.c | 39 + src/core/array_offset.c | 67 + src/core/array_png.c | 43 + src/core/array_slice.c | 48 + src/core/array_states_png.c | 47 + src/core/fab.c | 2376 +++++++++++ src/core/fab.h | 150 + src/core/gif_info.c | 120 + src/core/gif_png.c | 346 ++ src/core/gif_stl.c | 717 ++++ src/core/path_array.c | 69 + src/core/path_camm.c | 128 + src/core/path_dxf.c | 149 + src/core/path_epi.c | 182 + src/core/path_eps.c | 182 + src/core/path_g.c | 273 ++ src/core/path_info.c | 41 + src/core/path_join.c | 64 + src/core/path_oms.c | 120 + src/core/path_ord.c | 164 + src/core/path_png.c | 45 + src/core/path_rml.c | 196 + src/core/path_sbp.c | 238 ++ src/core/path_time.c | 174 + src/core/path_uni.c | 166 + src/core/png_distances.c | 77 + src/core/png_drl.c | 267 ++ src/core/png_ex.c | 66 + src/core/png_grb.c | 125 + src/core/png_halftone.c | 108 + src/core/png_offset.c | 85 + src/core/png_path.c | 671 +++ src/core/png_scale.c | 48 + src/core/png_size.c | 59 + src/core/stl_info.c | 35 + src/core/stl_path.c | 64 + src/core/stl_png.c | 76 + src/core/svg_path.c | 1255 ++++++ src/core/test.c | 18 + src/core/vol_gif.c | 265 ++ src/core/vol_stl.c | 667 +++ src/guis/CMakeLists.txt | 26 + src/guis/cad_ui | 1406 +++++++ src/guis/fab | 170 + src/guis/fab.html | 6539 +++++++++++++++++++++++++++++ src/guis/fabserver | 369 ++ src/guis/make_cad_camm | 59 + src/guis/make_cad_drl | 55 + src/guis/make_cad_dxf | 58 + src/guis/make_cad_epi | 58 + src/guis/make_cad_eps | 61 + src/guis/make_cad_g | 58 + src/guis/make_cad_grb | 55 + src/guis/make_cad_ord | 58 + src/guis/make_cad_png | 56 + src/guis/make_cad_rml | 58 + src/guis/make_cad_sbp | 58 + src/guis/make_cad_snap | 58 + src/guis/make_cad_stl | 52 + src/guis/make_cad_uni | 58 + src/guis/make_gif_stl | 52 + src/guis/make_math_camm | 58 + src/guis/make_math_drl | 55 + src/guis/make_math_dxf | 58 + src/guis/make_math_epi | 58 + src/guis/make_math_eps | 61 + src/guis/make_math_g | 58 + src/guis/make_math_grb | 55 + src/guis/make_math_ord | 58 + src/guis/make_math_rml | 58 + src/guis/make_math_sbp | 58 + src/guis/make_math_stl | 52 + src/guis/make_math_uni | 58 + src/guis/make_png_camm | 55 + src/guis/make_png_drl | 52 + src/guis/make_png_dxf | 55 + src/guis/make_png_epi | 55 + src/guis/make_png_epi_halftone | 55 + src/guis/make_png_eps | 58 + src/guis/make_png_eps_halftone | 58 + src/guis/make_png_g | 55 + src/guis/make_png_grb | 52 + src/guis/make_png_oms | 55 + src/guis/make_png_ord | 55 + src/guis/make_png_plt | 55 + src/guis/make_png_png | 52 + src/guis/make_png_rml | 55 + src/guis/make_png_sbp | 55 + src/guis/make_png_snap | 55 + src/guis/make_png_uni | 55 + src/guis/make_png_uni_halftone | 55 + src/guis/make_stl_g | 58 + src/guis/make_stl_png | 64 + src/guis/make_stl_rml | 58 + src/guis/make_stl_sbp | 58 + src/guis/make_stl_snap | 58 + src/guis/make_svg_camm | 55 + src/guis/make_svg_epi | 55 + src/guis/make_svg_g | 55 + src/guis/make_svg_oms | 55 + src/guis/make_svg_ord | 55 + src/guis/make_svg_rml | 55 + src/guis/make_svg_sbp | 55 + src/guis/make_svg_snap | 55 + src/guis/make_svg_uni | 55 + src/guis/rml_send_gui | 524 +++ src/py/CMakeLists.txt | 21 + src/py/cad_shapes.py | 497 +++ src/py/cad_text.py | 541 +++ src/py/fab_mods.py | 126 + src/py/fab_set.py | 1299 ++++++ src/py/math_string.py | 57 + src/py/panel_cad.py | 104 + src/py/panel_cad_png.py | 149 + src/py/panel_cad_stl.py | 124 + src/py/panel_control.py | 68 + src/py/panel_gif.py | 153 + src/py/panel_gif_stl.py | 137 + src/py/panel_math.py | 104 + src/py/panel_math_png.py | 143 + src/py/panel_math_stl.py | 137 + src/py/panel_path.py | 411 ++ src/py/panel_path_camm.py | 120 + src/py/panel_path_dxf.py | 73 + src/py/panel_path_epi.py | 248 ++ src/py/panel_path_eps.py | 76 + src/py/panel_path_g.py | 167 + src/py/panel_path_oms.py | 113 + src/py/panel_path_ord.py | 91 + src/py/panel_path_plt.py | 121 + src/py/panel_path_rml.py | 140 + src/py/panel_path_sbp.py | 154 + src/py/panel_path_snap.py | 633 +++ src/py/panel_path_snap_apa.py | 574 +++ src/py/panel_path_uni.py | 123 + src/py/panel_png.py | 242 ++ src/py/panel_png_drl.py | 75 + src/py/panel_png_grb.py | 75 + src/py/panel_png_path.py | 346 ++ src/py/panel_png_path_halftone.py | 121 + src/py/panel_png_png.py | 100 + src/py/panel_stl.py | 153 + src/py/panel_stl_png.py | 210 + src/py/panel_svg.py | 104 + src/py/panel_svg_path.py | 189 + src/py/png_l.py | 94 + src/scripts/CMakeLists.txt | 11 + src/scripts/cad_math | 92 + src/scripts/cad_path | 97 + src/scripts/cad_png | 34 + src/scripts/cad_view | 42 + src/scripts/eagle_png | 185 + src/scripts/fab_send | 72 + src/scripts/fab_update | 90 + src/scripts/math_png_py | 656 +++ src/scripts/math_stl_py | 465 ++ src/scripts/path_view | 43 + src/scripts/png_tile | 23 + src/scripts/rml_move | 33 + src/solver/CMakeLists.txt | 47 + src/solver/Makefile | 40 + src/solver/color_nodes.cpp | 78 + src/solver/color_nodes.hpp | 13 + src/solver/edgesolver.cpp | 179 + src/solver/edgesolver.hpp | 62 + src/solver/fab_interval.hpp | 101 + src/solver/fabvars.cpp | 570 +++ src/solver/fabvars.hpp | 205 + src/solver/geometry.cpp | 260 ++ src/solver/geometry.hpp | 167 + src/solver/imagesolver.cpp | 210 + src/solver/imagesolver.hpp | 48 + src/solver/logic_nodes.cpp | 187 + src/solver/logic_nodes.hpp | 16 + src/solver/math_dot.cpp | 35 + src/solver/math_png.cpp | 64 + src/solver/math_ray.cpp | 69 + src/solver/math_stats.cpp | 63 + src/solver/math_stl.cpp | 64 + src/solver/math_svg.cpp | 66 + src/solver/math_tree.cpp | 243 ++ src/solver/math_tree.hpp | 177 + src/solver/node.cpp | 307 ++ src/solver/node.hpp | 221 + src/solver/node_macro.hpp | 34 + src/solver/numeric_nodes.cpp | 559 +++ src/solver/numeric_nodes.hpp | 98 + src/solver/opcodes.cpp | 157 + src/solver/opcodes.hpp | 60 + src/solver/parser.cpp | 1248 ++++++ src/solver/parser.hpp | 272 ++ src/solver/progress_bar.cpp | 36 + src/solver/progress_bar.hpp | 44 + src/solver/raycaster.cpp | 99 + src/solver/raycaster.hpp | 34 + src/solver/region.cpp | 106 + src/solver/region.hpp | 78 + src/solver/solver.cpp | 36 + src/solver/solver.hpp | 75 + src/solver/switches.hpp | 15 + src/solver/task_buffer.cpp | 158 + src/solver/task_buffer.hpp | 109 + src/solver/thread_manager.cpp | 87 + src/solver/thread_manager.hpp | 53 + src/solver/translator_nodes.cpp | 139 + src/solver/translator_nodes.hpp | 14 + src/solver/trisolver.cpp | 202 + src/solver/trisolver.hpp | 64 + src/solver/volsolver.cpp | 115 + src/solver/volsolver.hpp | 51 + 221 files changed, 40922 insertions(+) create mode 100644 Makefile create mode 100644 commands.html create mode 100644 src/CMakeLists.txt create mode 100644 src/apps/README create mode 100755 src/apps/bundle.py create mode 100644 src/apps/cba.icns create mode 100644 src/apps/cba_icon.png create mode 100644 src/core/CMakeLists.txt create mode 100644 src/core/array_direction.c create mode 100644 src/core/array_distances.c create mode 100644 src/core/array_edges.c create mode 100644 src/core/array_info.c create mode 100644 src/core/array_offset.c create mode 100644 src/core/array_png.c create mode 100644 src/core/array_slice.c create mode 100644 src/core/array_states_png.c create mode 100644 src/core/fab.c create mode 100644 src/core/fab.h create mode 100644 src/core/gif_info.c create mode 100644 src/core/gif_png.c create mode 100644 src/core/gif_stl.c create mode 100644 src/core/path_array.c create mode 100644 src/core/path_camm.c create mode 100644 src/core/path_dxf.c create mode 100644 src/core/path_epi.c create mode 100644 src/core/path_eps.c create mode 100644 src/core/path_g.c create mode 100644 src/core/path_info.c create mode 100644 src/core/path_join.c create mode 100644 src/core/path_oms.c create mode 100644 src/core/path_ord.c create mode 100644 src/core/path_png.c create mode 100644 src/core/path_rml.c create mode 100644 src/core/path_sbp.c create mode 100644 src/core/path_time.c create mode 100644 src/core/path_uni.c create mode 100644 src/core/png_distances.c create mode 100644 src/core/png_drl.c create mode 100644 src/core/png_ex.c create mode 100644 src/core/png_grb.c create mode 100644 src/core/png_halftone.c create mode 100644 src/core/png_offset.c create mode 100644 src/core/png_path.c create mode 100644 src/core/png_scale.c create mode 100644 src/core/png_size.c create mode 100644 src/core/stl_info.c create mode 100644 src/core/stl_path.c create mode 100644 src/core/stl_png.c create mode 100644 src/core/svg_path.c create mode 100644 src/core/test.c create mode 100644 src/core/vol_gif.c create mode 100644 src/core/vol_stl.c create mode 100644 src/guis/CMakeLists.txt create mode 100755 src/guis/cad_ui create mode 100755 src/guis/fab create mode 100644 src/guis/fab.html create mode 100755 src/guis/fabserver create mode 100755 src/guis/make_cad_camm create mode 100755 src/guis/make_cad_drl create mode 100755 src/guis/make_cad_dxf create mode 100755 src/guis/make_cad_epi create mode 100755 src/guis/make_cad_eps create mode 100755 src/guis/make_cad_g create mode 100755 src/guis/make_cad_grb create mode 100755 src/guis/make_cad_ord create mode 100755 src/guis/make_cad_png create mode 100755 src/guis/make_cad_rml create mode 100755 src/guis/make_cad_sbp create mode 100755 src/guis/make_cad_snap create mode 100755 src/guis/make_cad_stl create mode 100755 src/guis/make_cad_uni create mode 100644 src/guis/make_gif_stl create mode 100755 src/guis/make_math_camm create mode 100755 src/guis/make_math_drl create mode 100755 src/guis/make_math_dxf create mode 100755 src/guis/make_math_epi create mode 100755 src/guis/make_math_eps create mode 100755 src/guis/make_math_g create mode 100755 src/guis/make_math_grb create mode 100755 src/guis/make_math_ord create mode 100755 src/guis/make_math_rml create mode 100755 src/guis/make_math_sbp create mode 100755 src/guis/make_math_stl create mode 100755 src/guis/make_math_uni create mode 100755 src/guis/make_png_camm create mode 100755 src/guis/make_png_drl create mode 100755 src/guis/make_png_dxf create mode 100755 src/guis/make_png_epi create mode 100755 src/guis/make_png_epi_halftone create mode 100755 src/guis/make_png_eps create mode 100755 src/guis/make_png_eps_halftone create mode 100755 src/guis/make_png_g create mode 100755 src/guis/make_png_grb create mode 100755 src/guis/make_png_oms create mode 100755 src/guis/make_png_ord create mode 100755 src/guis/make_png_plt create mode 100755 src/guis/make_png_png create mode 100755 src/guis/make_png_rml create mode 100755 src/guis/make_png_sbp create mode 100755 src/guis/make_png_snap create mode 100755 src/guis/make_png_uni create mode 100755 src/guis/make_png_uni_halftone create mode 100755 src/guis/make_stl_g create mode 100755 src/guis/make_stl_png create mode 100755 src/guis/make_stl_rml create mode 100755 src/guis/make_stl_sbp create mode 100755 src/guis/make_stl_snap create mode 100755 src/guis/make_svg_camm create mode 100755 src/guis/make_svg_epi create mode 100755 src/guis/make_svg_g create mode 100755 src/guis/make_svg_oms create mode 100755 src/guis/make_svg_ord create mode 100755 src/guis/make_svg_rml create mode 100755 src/guis/make_svg_sbp create mode 100755 src/guis/make_svg_snap create mode 100755 src/guis/make_svg_uni create mode 100755 src/guis/rml_send_gui create mode 100644 src/py/CMakeLists.txt create mode 100644 src/py/cad_shapes.py create mode 100644 src/py/cad_text.py create mode 100644 src/py/fab_mods.py create mode 100644 src/py/fab_set.py create mode 100644 src/py/math_string.py create mode 100644 src/py/panel_cad.py create mode 100644 src/py/panel_cad_png.py create mode 100644 src/py/panel_cad_stl.py create mode 100644 src/py/panel_control.py create mode 100644 src/py/panel_gif.py create mode 100644 src/py/panel_gif_stl.py create mode 100644 src/py/panel_math.py create mode 100644 src/py/panel_math_png.py create mode 100644 src/py/panel_math_stl.py create mode 100644 src/py/panel_path.py create mode 100644 src/py/panel_path_camm.py create mode 100644 src/py/panel_path_dxf.py create mode 100644 src/py/panel_path_epi.py create mode 100644 src/py/panel_path_eps.py create mode 100644 src/py/panel_path_g.py create mode 100644 src/py/panel_path_oms.py create mode 100644 src/py/panel_path_ord.py create mode 100755 src/py/panel_path_plt.py create mode 100644 src/py/panel_path_rml.py create mode 100644 src/py/panel_path_sbp.py create mode 100644 src/py/panel_path_snap.py create mode 100644 src/py/panel_path_snap_apa.py create mode 100644 src/py/panel_path_uni.py create mode 100644 src/py/panel_png.py create mode 100644 src/py/panel_png_drl.py create mode 100644 src/py/panel_png_grb.py create mode 100644 src/py/panel_png_path.py create mode 100644 src/py/panel_png_path_halftone.py create mode 100644 src/py/panel_png_png.py create mode 100644 src/py/panel_stl.py create mode 100644 src/py/panel_stl_png.py create mode 100644 src/py/panel_svg.py create mode 100644 src/py/panel_svg_path.py create mode 100755 src/py/png_l.py create mode 100644 src/scripts/CMakeLists.txt create mode 100755 src/scripts/cad_math create mode 100755 src/scripts/cad_path create mode 100755 src/scripts/cad_png create mode 100755 src/scripts/cad_view create mode 100755 src/scripts/eagle_png create mode 100755 src/scripts/fab_send create mode 100755 src/scripts/fab_update create mode 100755 src/scripts/math_png_py create mode 100755 src/scripts/math_stl_py create mode 100755 src/scripts/path_view create mode 100755 src/scripts/png_tile create mode 100755 src/scripts/rml_move create mode 100755 src/solver/CMakeLists.txt create mode 100644 src/solver/Makefile create mode 100644 src/solver/color_nodes.cpp create mode 100644 src/solver/color_nodes.hpp create mode 100644 src/solver/edgesolver.cpp create mode 100644 src/solver/edgesolver.hpp create mode 100644 src/solver/fab_interval.hpp create mode 100644 src/solver/fabvars.cpp create mode 100644 src/solver/fabvars.hpp create mode 100644 src/solver/geometry.cpp create mode 100644 src/solver/geometry.hpp create mode 100644 src/solver/imagesolver.cpp create mode 100644 src/solver/imagesolver.hpp create mode 100644 src/solver/logic_nodes.cpp create mode 100644 src/solver/logic_nodes.hpp create mode 100644 src/solver/math_dot.cpp create mode 100644 src/solver/math_png.cpp create mode 100644 src/solver/math_ray.cpp create mode 100644 src/solver/math_stats.cpp create mode 100644 src/solver/math_stl.cpp create mode 100644 src/solver/math_svg.cpp create mode 100644 src/solver/math_tree.cpp create mode 100644 src/solver/math_tree.hpp create mode 100644 src/solver/node.cpp create mode 100644 src/solver/node.hpp create mode 100644 src/solver/node_macro.hpp create mode 100644 src/solver/numeric_nodes.cpp create mode 100644 src/solver/numeric_nodes.hpp create mode 100644 src/solver/opcodes.cpp create mode 100644 src/solver/opcodes.hpp create mode 100644 src/solver/parser.cpp create mode 100644 src/solver/parser.hpp create mode 100644 src/solver/progress_bar.cpp create mode 100644 src/solver/progress_bar.hpp create mode 100644 src/solver/raycaster.cpp create mode 100644 src/solver/raycaster.hpp create mode 100644 src/solver/region.cpp create mode 100644 src/solver/region.hpp create mode 100644 src/solver/solver.cpp create mode 100644 src/solver/solver.hpp create mode 100644 src/solver/switches.hpp create mode 100644 src/solver/task_buffer.cpp create mode 100644 src/solver/task_buffer.hpp create mode 100644 src/solver/thread_manager.cpp create mode 100644 src/solver/thread_manager.hpp create mode 100644 src/solver/translator_nodes.cpp create mode 100644 src/solver/translator_nodes.hpp create mode 100644 src/solver/trisolver.cpp create mode 100644 src/solver/trisolver.hpp create mode 100644 src/solver/volsolver.cpp create mode 100644 src/solver/volsolver.hpp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..13bbf1a --- /dev/null +++ b/Makefile @@ -0,0 +1,111 @@ +# The lines below extract out program names from the cmake cache +# This is used to automatically generate a documentation page. +C_ = $(shell sed -n -e 's/;/ /g' \ + -e 's/SOLVER_EXECUTABLES:STRING=//gp' \ + -e 's/PROGRAMS:STRING=//gp' \ + build/CMakeCache.txt) +C = $(addprefix bin/, $(C_)) + +Python_ = $(shell sed -n -e 's/;/ /g' \ + -e 's/PYs:STRING=//gp' \ + build/CMakeCache.txt) +Python = $(addprefix bin/, $(Python_)) + + +scripts_ = $(shell sed -n -e 's/;/ /g' \ + -e 's/SCRIPTS:STRING=//gp' \ + build/CMakeCache.txt) +scripts = $(addprefix bin/, $(scripts_)) + +GUIs_ = $(shell sed -n -e 's/;/ /g' \ + -e 's/GUIs:STRING=//gp' \ + build/CMakeCache.txt) +GUIs = $(addprefix bin/, $(GUIs_)) + +PWD := $(shell pwd) + +help: + @echo "Makefile options:" + @echo " make fab Compile all files and copy scripts from src to bin" + @echo " make doc Saves command names and docstrings into commands.html" + @echo " make zip Bundles relevant files in fab.zip" + @echo " make dist Copies files to Web directory" + @echo " make install Copies files to /usr/local/bin" + @echo " make clean Removes compiled executables and scripts from bin" + @echo " make wxpython2.9 Downloads, compiles, and installs wxpython 2.9.4.1" + @echo " (Linux only)" + +fab: + @echo "Building with CMake" + @mkdir -p build + + @cd build; \ + cmake ../src; \ + make -j4; \ + make install | sed "s@$(PWD)/src/../@@g" + +doc: commands.html +commands.html: fab + @# Dump all of the command names + @echo " Storing command names" + @echo "\n\n
\ncommands:" > commands.html
+	@for name in $(C) $(scripts) $(GUIs); do               \
+	    echo "   "$$name >> commands.html;                 \
+	done
+	  
+	@echo "" >> commands.html
+	
+	@# Dump command docstrings
+	@echo "	Storing command docstrings"
+	@for name in $(C) $(scripts) ; do                        \
+	   ./$$name >> commands.html;                           \
+	   echo "" >> commands.html;                            \
+	done
+
+
+zip: commands.html
+	rm -f fab_src.zip
+	rm -rf src/apps/dist
+	rm -rf src/apps/build
+	
+#	@echo "Copying revision number to kokopelli About panel"
+#	@if which hg &>/dev/null && hg summary &> /dev/null; \
+#	 then \
+#	    sed "s/CHANGESET = .*/CHANGESET = '`hg id --num`:`hg id --id`'/g" \
+#	    src/guis/koko/__init__.py > tmp; \
+#	    mv tmp src/guis/koko/__init__.py; \
+#	 fi
+	
+	zip -r fab_src.zip commands.html Makefile src
+	
+#	@sed "s/CHANGESET = .*/CHANGESET = None/g" \
+#	    src/guis/koko/__init__.py > tmp; \
+#	    mv tmp src/guis/koko/__init__.py; \
+
+dist: zip
+	cp fab_src.zip ../../Web/fab_src.zip
+	cp commands.html ../../Web/
+	sed -e "s/Snapshot from [^\)]*/Snapshot from `date '+%B %d, %Y, %I:%M%p'`/g" \
+	    ../../Web/downloads.html > ../../Web/_downloads.html
+	mv ../../Web/_downloads.html ../../Web/downloads.html
+
+install: fab
+	@echo "Installing executables and scripts to /usr/local/bin"
+	@if [ -e "/usr/local/bin/fab_send" ]; \
+	then \
+	    mv /usr/local/bin/fab_send /usr/local/bin/fab_send.old; \
+	fi
+	@cp -r bin/* /usr/local/bin/
+	@if [ -e "/usr/local/bin/fab_send.old" ]; \
+	then \
+	    mv /usr/local/bin/fab_send /usr/local/bin/fab_send.new; \
+	    mv /usr/local/bin/fab_send.old /usr/local/bin/fab_send; \
+	    echo "Note:"; \
+	    echo "   Pre-existing fab_send has not been overwritten, and"; \
+	    echo "   the new version of fab_send has been named fab_send.new"; \
+	fi
+
+clean:
+	@echo "Deleting build directory"
+	@rm -rf build
+	
diff --git a/commands.html b/commands.html
new file mode 100644
index 0000000..a080d5b
--- /dev/null
+++ b/commands.html
@@ -0,0 +1,447 @@
+
+
+
+commands:
+   bin/vol_gif
+   bin/vol_stl
+   bin/gif_info
+   bin/gif_png
+   bin/gif_stl
+   bin/stl_info
+   bin/stl_png
+   bin/stl_path
+   bin/png_size
+   bin/png_scale
+   bin/png_distances
+   bin/png_offset
+   bin/png_grb
+   bin/png_drl
+   bin/png_path
+   bin/png_halftone
+   bin/svg_path
+   bin/path_eps
+   bin/path_dxf
+   bin/path_png
+   bin/path_rml
+   bin/path_sbp
+   bin/path_g
+   bin/path_camm
+   bin/path_epi
+   bin/path_uni
+   bin/path_oms
+   bin/path_ord
+   bin/path_join
+   bin/path_array
+   bin/path_info
+   bin/path_time
+   bin/math_png
+   bin/math_dot
+   bin/math_stl
+   bin/math_svg
+   bin/cad_png
+   bin/cad_view
+   bin/path_view
+   bin/rml_move
+   bin/fab_send
+   bin/fab_update
+   bin/cad_math
+   bin/math_png_py
+   bin/math_stl_py
+   bin/png_tile
+   bin/eagle_png
+   bin/fab
+   bin/fab.html
+   bin/fabserver
+   bin/make_cad_png
+   bin/make_cad_eps
+   bin/make_cad_stl
+   bin/make_cad_camm
+   bin/make_cad_rml
+   bin/make_cad_epi
+   bin/make_cad_uni
+   bin/make_cad_sbp
+   bin/make_cad_g
+   bin/make_cad_ord
+   bin/make_cad_grb
+   bin/make_cad_drl
+   bin/make_math_camm
+   bin/make_math_epi
+   bin/make_math_g
+   bin/make_math_ord
+   bin/make_math_eps
+   bin/make_math_uni
+   bin/make_math_rml
+   bin/make_math_sbp
+   bin/make_math_grb
+   bin/make_math_drl
+   bin/make_png_png
+   bin/make_png_eps
+   bin/make_png_epi
+   bin/make_png_uni
+   bin/make_png_grb
+   bin/make_png_epi_halftone
+   bin/make_png_uni_halftone
+   bin/make_png_rml
+   bin/make_png_sbp
+   bin/make_png_ord
+   bin/make_png_camm
+   bin/make_png_plt
+   bin/make_png_g
+   bin/make_png_drl
+   bin/make_png_oms
+   bin/make_stl_png
+   bin/make_stl_rml
+   bin/make_stl_sbp
+   bin/make_stl_g
+   bin/make_svg_camm
+   bin/make_svg_epi
+   bin/make_svg_uni
+   bin/make_svg_oms
+   bin/make_svg_g
+   bin/make_svg_rml
+   bin/make_svg_sbp
+   bin/make_svg_ord
+   bin/make_png_snap
+   bin/make_cad_snap
+   bin/make_stl_snap
+   bin/make_svg_snap
+   bin/make_png_eps_halftone
+   bin/make_cad_dxf
+   bin/make_math_dxf
+   bin/make_math_stl
+   bin/make_png_dxf
+   bin/make_gif_stl
+   bin/cad_ui
+   bin/rml_send_gui
+
+command line: vol_gif in.vol out.gif nx ny nz [format [type [arg [size [dx dy dz [x0 y0 z0 [rx ry rz]]]]]]]
+   in.vol = input volume file
+   out.gif = output GIF file
+   nx,ny,nz = x,y,z input voxel number
+   format = 'f' for float 32, 'i' for uint16_t (default 'f')
+   type = 's' for section, 'h' for height (default 's')
+   arg = gamma for 's', threshold for 'h' (default 1)
+   size = mm per voxel (default 1)
+   dx,dy,dz = x,y,z output voxel number (default all)
+   x0,y0,z0 = x,y,z output voxel origin (default 0)
+   to be implemented: rx,ry,rz = view rotation angles (degrees; default 0)
+
+command line: vol_stl in.vol out.stl nx ny nz [format [threshold [size [points [angle]]]]]
+   in.vol = input VOL file
+   out.stl = output STL file
+   nx,ny,nz = x,y,z input voxel number
+   format = 'f' for float 32, 'i' for uint16_t (default 'f')
+   threshold: surface intensity threshold (0 = min, 1 = max, default 0.5))
+   size = voxel size (mm, default from file))
+   points = points to interpolate per point (default 0)
+   to be implemented: angle = minimum relative face angle to decimate vertices (default 0)
+
+command line: gif_info in.gif
+   in.gif = input GIF file
+
+command line: gif_png in.gif out.png [type [arg [points [size [rx ry rz]]]]]
+   in.gif = input gif file
+   out.png = output PNG file
+   type = 'z' of density, 'h' for height (default z)
+   arg = type argument
+      'z': gamma (default 1)
+      'h': threshold (0 = min, 1 = max, default 0.5)
+   points = points to interpolate per point (linear, default 0)
+   size = voxel size (mm, default from file))
+   to be implemented: rx,ry,rz = x,y,z rotation angles (degrees; default 0)
+
+command line: gif_stl in.gif out.stl [threshold [size [points [angle]]]]
+   in.gif = input GIF section file
+   out.stl = output STL file
+   threshold: surface intensity threshold (0 = min, 1 = max, default 0.5))
+   size = voxel size (mm, default from file))
+   points = points to interpolate per point (default 0)
+   to be implemented: angle = minimum relative face angle to decimate vertices (default 0)
+
+command line: stl_info in.stl
+   in.stl = input binary STL file
+
+command line: stl_png in.stl out.png [units [resolution [axis]]]
+   in.stl = input binary STL file
+   out.png = output PNG file
+   units = file units (optional, mm/unit, default 1)
+   resolution = image resolution (optional, pixels/mm, default 10)
+   axis = projection axis (optional, top or bottom, x|X|y|Y|z|Z, default z)
+
+command line: stl_path in.stl out.path [units [resolution]]]
+   in.stl = input binary STL file
+   out.png = output PNG file
+   units = file units (optional, mm/unit, default 1)
+   resolution = image resolution (optional, pixels/mm, default 10)
+
+command line: png_size in.png [dx [dy]]
+   in.png = input PNG file
+   dx = set width (optional, mm)
+   dy = set height (optional, mm)
+
+command line: png_scale in.png out.png low high
+   in.png = input PNG file
+   out.png = output PNG file
+   low = rescaled intensity minimum (0-1)
+   high = rescaled intensity maximum (0-1)
+
+command line: png_distances in.png out.png [intensity [distances]]
+   in.png = input PNG file
+   out.png = input PNG file
+   intensity = intensity level to slice (optional, 0-1, default 0.5)
+   distances = show distances (optional, 0/1, default 1)
+
+command line: png_offset in.png out.png [intensity [distance]]
+   in.png = input PNG file
+   out.png = input PNG file
+   intensity = intensity level to slice (optional, 0-1, default 0.5)
+   distance = distance to offset (optional, mm, default 0)
+
+command line: png_grb in.png out.grb
+   in.png = input PNG file
+   out.grb = output Gerber (RS-274X) file
+
+command line: png_drl in.png out.drl
+   in.png = input PNG file
+   out.drl = output Excellon file
+
+command line: png_path in.png out.path [error [offset_diameter [offset_number [offset_overlap [intensity_top [intensity_bottom [z_top [z_bottom [z_thickness [xz [yz [xy [type [clearance_length clearance_diameter]]]]]]]]]]]]]]
+   in.png = input PNG file
+   out.path = output path file
+   error = allowable vector fit deviation (optional, pixels, default 1.1)
+   offset_diameter = diameter to offset (optional, mm, default 0)
+   offset_number = number of contours to offset (optional, -1 to fill all, default 1)
+   offset_overlap = tool offset overlap fraction (optional, 0 (no overlap) - 1 (complete overlap, default 0.5))
+   intensity_top = top slice intensity (optional, 0-1, default 0.5)
+   intensity_bottom = bottom slice intensity (optional, 0-1, default intensity_top)
+   z_top = top slice z value (optional, mm, default 0)
+   z_bottom = bottom slice z value (optional, mm, default z_top)
+   z_thickness = slice z thickness (optional, mm, default z_top-z_bottom)
+   xz = xz finish (optional, 1=yes, default 0
+   yz = yz finish (optional, 1=yes, default 0
+   xy = xy path (optional, 1=yes, default 1
+   type = finish tool type (optional, f=flat end, b=ball end, default f
+   clearance_length = finish tool clearance length (optional, mm, 0 = no limit, default 0
+   clearance_diameter = finish tool clearance diameter (optional, mm, default offset_diameter
+
+command line: png_halftone in.png out.path [threshold [points [size [spacing [offset [invert]]]]]]
+   in.png = input PNG file
+   out.path = output path file
+   threshold = minimum spot radius (optional, pixels default 1)
+   points = points per spot (optional, default 8)
+   size = maximum spot size (optional, mm, default 1)
+   spacing = spot spacing (optional, 1 = size, default 1)
+   offset = row offset (optional, 1 = size, default 0.5)
+   offset = row offset (optional, 1 = size, default 0.5)
+   invert = invert image (0 = no (default), 1 = yes)
+
+command line: svg_path in.svg out.path [scale [points [resolution [zmin [zmax]]]]]
+   in.svg = input binary SVG file
+   out.path = output path file
+   scale = scale factor (optional, default 1.0)
+   points = points per curve segment (optional, default 25)
+   resolution = path x resolution (optional, default 10000)
+   zmin = path min intensity z (optional, mm, default 0)
+   zmax = path max intensity z (optional, mm, default zmin)
+
+command line: path_eps in.path out.eps [view]
+   in.path = input path file
+   out.eps= output PostScript file
+   view = view projection(s) (optional, z|3, default z)
+
+command line: path_dxf in.path out.dxf
+   in.path = input path file
+   out.dxf = output DXF file
+
+command line: path_png in.path out.png
+   in.path = input path file
+   out.png = output PNG file
+
+command line: path_rml in.path out.rml [speed [direction [jog [xmin ymin [zmin]]]]]
+   in.path = input path file
+   out.rml = output Roland Modela file
+   speed = cutting speed (optional, mm/s, default 4)
+   direction = machining direction (optional, 0 conventional/1 climb, default 1)
+   jog = jog height (optional, mm, default 1)
+   xmin = left position (optional, mm, default path value)
+   ymin = front position (optional, mm, default path value)
+   zmin = bottom position (optional, -mm, default path value)
+
+command line: path_sbp in.path out.sbp [direction [spindle_speed [xy_speed z_speed [xy_jog_speed z_jog_speed z_jog [units]]]]]]
+   in.path = input path file
+   out.sbp = output ShopBot file
+   direction = machining direction (optional, 0 conventional/1 climb, default 0)
+   spindle_speed = spindle speed (optional, if control installed, RPM, default 12000)
+   xy_speed = xy cutting speed (optional, mm/s, default 30)
+   z_speed = z cutting speed (optional, mm/s, default 30)
+   xy_jog_speed = xy jog speed (optional, mm/s, default 150)
+   z_jog_speed = z jog speed (optional, mm/s, default 150)
+   z_jog = z jog height (optional, mm, default 25)
+   units = mm per file unit (optional, default 25.4)
+
+command line: path_g in.path out.g [direction [z_jog [feed [z_feed [spindle [tool [coolant]]]]]]
+   in.path = input path file
+   out.g = output G-code file
+   direction = machining direction (optional, 0 conventional/1 climb, default 0)
+   z_jog = z jog height (optional, mm, default 25)
+   feed = feed rate (optional, mm/s, default 100)
+   z_feed = z plunge rate (optional, mm/s, default xy feed rate)
+   spindle = spindle speed (optional, RPM, default 5000)
+   tool = tool number (optional, default 1)
+   coolant = coolant on/off (optional, 0=off/1=on, default 1)
+
+command line: path_camm in.path out.camm [force [velocity [x y [location]]]]
+   in.path = input path file
+   out.camm = output Roland vinylcutter file
+   force = cutting force (optional, grams, default 45)
+   velocity = cutting speed (optional, cm/s, default 2)
+   x = origin x (optional, mm, default 0)
+   y = origin y (optional, mm, default 0)
+   location = origin location (optional, bottom left:l, bottom right:r, top left:L, top right:R, default l)
+
+command line: path_epi in.path out.epi [power [speed [focus [x y [ location [rate [max_power]]]]]]]
+   in.path = input path file
+   out.epi= output Epilog lasercutter file
+   power = percent power, for minimum z value (optional, 0-100, default 50)
+   speed = percent speed (optional, 0-100, default 50)
+   focus = autofocus (optional, 0=off | 1=on, default on)
+   x = origin x (optional, mm, default 0 = left side of bed)
+   y = origin y (optional, mm, default 0 = back side of bed, front positive)
+   location = origin location (optional, bottom left:l, bottom right:r, top left:L, top right:R, default l)
+   rate = pulse rate (optional, frequency, default 2500)
+   max_power = percent power, for maximum z value (optional, 0-100, default power)
+
+command line: path_uni in.path out.uni [power [speed [xmin ymin [rate [max_power]]]]]
+   in.path = input path file
+   out.uni= output Universal lasercutter file
+   power = percent power (optional, 0-100, default 100)
+   speed = percent speed (optional, 0-100, default 100)
+   xmin = left position (optional, mm, default path, 0 = left side of bed)
+   ymin = front position (optional, mm, default path, 0 = back, front positive)
+   rate = pulse rate (optional, frequency, default 500)
+   max_power = maximum power for maximum z value (optional, 0-100, default 100)
+
+command line: path_oms in.path out.oms [velocity [acceleration [period]]]
+   in.path = input path file
+   out.oms = output Resonetics excimer micromachining center file
+   velocity (default 0.1)
+   acceleration (default 5.0)
+   period (usec, default 10000)
+
+command line: path_ord in.path out.ord [lead [quality [xstart ystart]]]
+   in.path = input path file
+   out.ord = output Omax waterjet file
+   lead = lead in/out (optional, mm, default 2)
+   quality = cut quality (optional, default -3)
+   xstart,ystart = start position (optional, mm, default path start)
+
+command line: path_join in1.path in2.path out.path [dx [dy]]
+   in1.path = first input path file
+   in2.path = second input path file
+   out.path = joined output path file
+   dx = in1 horizontal offset (optional, mm, default 0)
+   dy = in1 vertical offset (optional, mm, default dx)
+
+command line: path_array in.path out.path nx ny [dx [dy]]
+   in.path = input path file
+   out.path = output path file
+   nx = number of horizonal array elements
+   ny = number of vertical array elements
+   dx = array element horizontal spacing (optional, mm, default 0)
+   dy = array element vertical spacing (optional, mm, default dx)
+
+command line: path_info in.path
+   in.path = input path file
+
+command line: path_time in.path move_speed [jog_height [jog_speed [plunge_speed]]]
+   in.path = input path file
+   move_speed = speed of path segments (mm/s)
+   jog_height = height between path segments (mm, optional, default 0)
+   jog_speed = speed between path segments (mm/s, optional, default move_speed)
+   plunge_speed = speed from jog to move  (mm/s, optional, default move_speed)
+
+command line: math_png in.math out.png [resolution [slices]]
+   in.math = input math string file
+   out.png = output PNG image
+   resolution = pixels per mm (optional, default 10)
+   slices = number of z slices (optional, default full)
+
+command line: math_dot in.math out.dot
+   in.math = input math string file
+   out.dot = output dot file
+
+command line: math_stl in.math out.stl [resolution [quality]]
+   in.math = input math string file
+   out.png = output PNG image
+   resolution = voxels per mm (optional, default 10)
+   quality = voxel interpolation level (default 8)
+
+command line: math_svg in.math out.svg [resolution [slices [error [quality]]]]
+   in.math = input math string file
+   out.png = output PNG image
+   resolution = voxels per mm (default: 10)
+   slices = z slices (defaults: 1 for 2D models, 10 for 3D models)
+   error = maximum decimation error (in mm^2)
+   quality = voxel interpolation level (default: 8)
+Note: output svgs are at 72 dpi.
+
+command line: cad_png in.cad [args]
+   in.cad = input .cad file
+   args = math_png arguments (optional)
+
+command line: cad_view in.cad [args]
+   in.cad = input .cad file
+   args = math_png arguments (optional)
+   image viewer =  eog
+
+command line: path_view in.path [view [viewer]]
+   in.path = input path file
+   view = view projection(s) (optional, z|3, default z)
+   viewer = PostScript viewer [default evince]
+
+command line: rml_move x y
+   x,y, = position to move to (mm)
+
+command line: fab_send [file]
+   file = file to send
+   file type commands:
+       {'.eps': 'inkscape "$file"', '.drl': 'gerbv "$file"', '.camm': 'printer=vinyl; lpr -P$printer "$file"', '.uni': 'port=/dev/lp0; cat "$file" > $port', '.epi': 'printer=laser; lprm -P$printer -; lpr -P$printer "$file"', '.sbp': 'gedit "$file"', '.rml': 'port=/dev/ttyUSB0; rml_send_gui "$file" $port', '.g': 'gedit "$file"', '.oms': 'gedit "$file"', '.dxf': 'gedit "$file"', '.stl': 'meshlab "$file"', '.plt': 'gedit "$file"', '.ord': 'gedit "$file"', '.grb': 'gerbv "$file"'}
+
+command line: fab_update [check|install]
+   check will inform you if a newer version of the fab modules is available.
+   install will install a newer version of the fab modules, if applicable.
+
+command line: cad_math in.cad out.math [args]
+   in.cad = input design file
+   out.math = output math string file
+   args = arguments to cad script
+          (delivered in sys.argv)
+
+command line: math_png_py in.math out.png [resolution [number [view [rx ry rx]]]]
+   in.math = input math string file
+   out.png = output PNG image
+   resolution = pixels per mm (optional, default 10)
+   number = number of z slices to evaluate (optional, default 1)
+   view = view projection(s) (optional, z|3, default z)
+   rx ry rz = 3D view angle (optional, degrees, default 70 0 20)
+[This command is deprecated; use math_png instead.]
+
+command line: math_stl in.math out.stl [resolution]
+   in.math = input math string file
+   out.stl = output STL image
+   resolution = pixels per mm (optional, default 1)
+
+command line: png_tile rows cols file1.png file2.png ...
+   rows = number of horizontal copies
+   cols = number of vertical copies
+   file1.png to fileN.png = files to tile
+
+command line: eagle_png [options] target.brd
+   target.brd = EAGLE brd file to render
+   The board outline should be a solid polygon on the 'milling' layer
+   Internal cutouts should be solid shapes on the 'holes' layer
+   
+   Valid options:
+       --resolution NUM : sets output image resolution
+       --doublesided : forces double-sided mode
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..391c70a
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.6)
+project(fabmod)
+
+set(CMAKE_BUILD_TYPE Release)
+
+add_subdirectory(core)
+add_subdirectory(solver)
+add_subdirectory(scripts)
+add_subdirectory(guis)
+add_subdirectory(py)
diff --git a/src/apps/README b/src/apps/README
new file mode 100644
index 0000000..05cf54f
--- /dev/null
+++ b/src/apps/README
@@ -0,0 +1,15 @@
+kokopelli:
+    This is a bundled version of kokopelli, an unusual CAD package.
+    It should be considered alpha software.  Use at your own risk.
+    
+Online:
+    kokopelli is usually distributed as part of the fab modules,
+    found online at http://kokompe.cba.mit.edu
+
+License:
+    kokopelli is freely available for for experimental and personal use;
+    license for commercial sale is available from MIT.
+
+Contact:
+    Matt Keeter
+    matt.keeter@cba.mit.edu
\ No newline at end of file
diff --git a/src/apps/bundle.py b/src/apps/bundle.py
new file mode 100755
index 0000000..630136f
--- /dev/null
+++ b/src/apps/bundle.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+"""
+This is a setup.py script generated by py2applet
+
+Usage:
+    python setup.py py2app
+"""
+
+from setuptools import setup
+import shutil
+import os
+import stat
+import subprocess
+import glob
+
+# Trick to make this run properly
+import sys
+sys.argv += ['py2app']
+
+subprocess.call(['make','fab'], cwd='../..')
+
+# Delete old build stuff
+try:    shutil.rmtree('build')
+except OSError: pass
+
+try:    shutil.rmtree('koko')
+except OSError: pass
+
+try:    os.remove('kokopelli.py')
+except OSError: pass
+
+# This is the pythons script that we're bundling into an application.
+shutil.copy('../../bin/kokopelli','kokopelli.py')
+shutil.copytree('../../bin/koko','koko')
+
+APP = ['kokopelli.py']
+DATA_FILES = glob.glob('../bin/koko/lib/*.py') + ['cba_icon.png']
+
+OPTIONS = {'argv_emulation': True,
+           'iconfile':'cba.icns'}
+
+# Run py2app to bundle everything.
+setup(
+    app=APP,
+    data_files=DATA_FILES,
+    options={'py2app': OPTIONS},
+    setup_requires=['py2app'],
+)
+
+# Copy libtree
+os.mkdir('dist/kokopelli.app/Contents/lib')
+shutil.copy('../../lib/libfab.dylib', 
+            'dist/kokopelli.app/Contents/lib/libfab.dylib')
+
+# Copy the readme and examples into the distribution directory, then zip it up
+shutil.copy('README','dist')
+shutil.copy('../../../../Web/examples.zip', 'dist/examples.zip')
+os.system('cd dist; unzip examples.zip; rm -rf __MACOSX;'+
+          'zip -r kokopelli.zip kokopelli.app README examples')
+shutil.rmtree('build')
+shutil.rmtree('koko')
+shutil.os.remove('kokopelli.py')
\ No newline at end of file
diff --git a/src/apps/cba.icns b/src/apps/cba.icns
new file mode 100644
index 0000000000000000000000000000000000000000..79d6dcb5ccaf8b92aa46fd752db9c4e9eb1cd38f
GIT binary patch
literal 115172
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

ovLPV#dwzU!&$2h57o>c^y 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 literal 0 HcmV?d00001 diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000..b67dadf --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 2.6) + +set(PROGRAMS vol_gif vol_stl gif_info gif_png gif_stl stl_info stl_png stl_path + png_size png_scale png_distances png_offset png_grb png_drl + png_path png_halftone svg_path + path_eps path_dxf path_png path_rml path_sbp path_g path_camm + path_epi path_uni path_oms path_ord + path_join path_array path_info path_time + CACHE STRING "Core program list") + +find_package(PNG REQUIRED) +find_package(GIF REQUIRED) +include_directories(${PNG_INCLUDE_DIR}) +include_directories(${GIF_INCLUDE_DIR}) + +#set(CMAKE_C_FLAGS "-Wall -g") +set(CMAKE_C_FLAGS "-Wall -O3") + +add_library(fabcore STATIC fab.c) + +foreach(program ${PROGRAMS}) + add_executable(${program} ${program}.c) + target_link_libraries(${program} fabcore ${PNG_LIBRARY} ${GIF_LIBRARY} m) +endforeach(program) + +if( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + install(TARGETS ${PROGRAMS} DESTINATION ${PROJECT_SOURCE_DIR}/../bin) +endif( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) diff --git a/src/core/array_direction.c b/src/core/array_direction.c new file mode 100644 index 0000000..65aeb76 --- /dev/null +++ b/src/core/array_direction.c @@ -0,0 +1,52 @@ +// +// array_direction.c +// find array edge directions +// array_direction in.array out.array threshold +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // variables + // + struct fab_vars v; + init_vars(&v); + int threshold; + // + // command line args + // + if (argc != 4) { + printf("command line: array_direction in.array out.array threshold\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // threshold + // + sscanf(argv[3],"%d",&threshold); + fab_threshold(&v,threshold); + // + // set directions + // + fab_directions(&v); + // + // write array + // + fab_write_array(&v,argv[2]); + } + diff --git a/src/core/array_distances.c b/src/core/array_distances.c new file mode 100644 index 0000000..ad65d2b --- /dev/null +++ b/src/core/array_distances.c @@ -0,0 +1,71 @@ +// +// array_distances.c +// find distances from edges +// array_distances in.array out.array threshold +// +// Neil Gershenfeld +// CBA MIT 8/5/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,threshold; + float distance; + // + // command line args + // + if (argc != 4) { + printf("command line: array_distances in.array out.array threshold\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // threshold + // + sscanf(argv[3],"%d",&threshold); + fab_threshold(&v,threshold); + // + // find edges + // + fab_edges(&v); + // + // find edge distances + // + fab_distances(&v); + // + // put distances into array + // + for (y = 0; y < v.ny; ++y) { + for (x = 0; x < v.nx; ++x) { + if (v.xptr[y][x] != -1) { + distance = sqrt((v.xptr[y][x]-x)*(v.xptr[y][x]-x) + + (v.yptr[y][x]-y)*(v.yptr[y][x]-y)); + v.array[y][x] = (int) distance; + } + else + v.array[y][x] = 128; + } + } + // + // write array + // + fab_write_array(&v,argv[2]); + } + diff --git a/src/core/array_edges.c b/src/core/array_edges.c new file mode 100644 index 0000000..8080a28 --- /dev/null +++ b/src/core/array_edges.c @@ -0,0 +1,52 @@ +// +// array_edges.c +// find edges in array +// array_edges in.array out.array threshold +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // variables + // + struct fab_vars v; + init_vars(&v); + int threshold; + // + // command line args + // + if (argc != 4) { + printf("command line: array_edges in.array out.array threshold\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // threshold + // + sscanf(argv[3],"%d",&threshold); + fab_threshold(&v,threshold); + // + // find edges + // + fab_edges(&v); + // + // write array + // + fab_write_array(&v,argv[2]); + } + diff --git a/src/core/array_info.c b/src/core/array_info.c new file mode 100644 index 0000000..7a242e3 --- /dev/null +++ b/src/core/array_info.c @@ -0,0 +1,39 @@ +// +// array_info.c +// read and print array info +// +// Neil Gershenfeld +// CBA MIT 8/5/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,threshold; + float distance; + // + // command line args + // + if (argc != 2) { + printf("command line: array_info in.array\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + } + diff --git a/src/core/array_offset.c b/src/core/array_offset.c new file mode 100644 index 0000000..299ce1d --- /dev/null +++ b/src/core/array_offset.c @@ -0,0 +1,67 @@ +// +// array_offset.c +// offset array +// array_offset in.array out.array threshold distance +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,threshold,count; + float distance; + // + // command line args + // + if (argc != 5) { + printf("command line: array_offset in.array out.array threshold distance\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // threshold + // + sscanf(argv[3],"%d",&threshold); + fab_threshold(&v,threshold); + // + // find edges + // + fab_edges(&v); + // + // find edge distances + // + fab_distances(&v); + // + // offset + // + distance = atof(argv[4]); + count = fab_offset(&v,distance); + printf("%d points remain\n",count); + // + // set edge directions + // + fab_directions(&v); + // + // write array + // + fab_write_array(&v,argv[2]); + } + diff --git a/src/core/array_png.c b/src/core/array_png.c new file mode 100644 index 0000000..3d8f8bf --- /dev/null +++ b/src/core/array_png.c @@ -0,0 +1,43 @@ +// +// array_png.c +// converted array to a PNG image +// array_png.c in.array out.png +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// z layers +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // variables + // + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (argc != 3) { + printf("command line: array_png.c in.array out.png\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // write PNG + // + fab_write_png(&v,argv[2]); + } + diff --git a/src/core/array_slice.c b/src/core/array_slice.c new file mode 100644 index 0000000..100a1c7 --- /dev/null +++ b/src/core/array_slice.c @@ -0,0 +1,48 @@ +// +// array_slice.c +// slice array +// array_slice in.array out.array threshold +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // variables + // + struct fab_vars v; + init_vars(&v); + int threshold; + // + // command line args + // + if (argc != 4) { + printf("command line: array_slice in.array out.array threshold\n"); + exit(-1); + } + // + // read lattice + // + fab_read_array(&v,argv[1]); + // + // threshold + // + sscanf(argv[3],"%d",&threshold); + fab_threshold(&v,threshold); + // + // write state slice + // + fab_write_array(&v,argv[2]); + } + diff --git a/src/core/array_states_png.c b/src/core/array_states_png.c new file mode 100644 index 0000000..22e6f69 --- /dev/null +++ b/src/core/array_states_png.c @@ -0,0 +1,47 @@ +// +// array_states_png.c +// converted array states to a PNG image +// array_states png.c in.array out.png +// +// Neil Gershenfeld +// CBA MIT 7/30/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// z layers +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // variables + // + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (argc != 3) { + printf("command line: array_states_png.c in.array out.png\n"); + exit(-1); + } + // + // read array + // + fab_read_array(&v,argv[1]); + // + // shade states + // + fab_shade_states(&v); + // + // write PNG + // + fab_write_png(&v,argv[2]); + } + diff --git a/src/core/fab.c b/src/core/fab.c new file mode 100644 index 0000000..043ed09 --- /dev/null +++ b/src/core/fab.c @@ -0,0 +1,2376 @@ +// +// fab.c +// fab modules routines +// +// Neil Gershenfeld 9/8/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +// +// initialization +// + +void init_vars(struct fab_vars *v) { + // + // fab_vars initialization + // + v->empty = 0; + v->interior = 1; + v->edge = (1 << 1); + v->north = (1 << 2); + v->west = (2 << 2); + v->east = (3 << 2); + v->south = (4 << 2); + v->stop = (5 << 2); + v->corner = (6 << 2); + v->corner2 = (7 << 2); + v->direction = (7 << 2); + v->g = 0; + v->h = 0; + v->dx = 0; + v->dy = 0; + v->dz = 0; + v->xmin = 0; + v->ymin = 0; + v->zmin = 0; + v->distances = 0; + v->starts= 0; + v->minimums= 0; + } + +void fab_limits(struct fab_vars *v, float *vertex) { + // + // update limits for vertex + // + int i; + for (i = 0; i < 3; ++i) { + if (vertex[i] > v->mesh->max[i]) + v->mesh->max[i] = vertex[i]; + if (vertex[i] < v->mesh->min[i]) + v->mesh->min[i] = vertex[i]; + } +} + +// +// input +// + +void fab_read_stl(struct fab_vars *v, char *input_file_name) { + // + // read STL into triangle mesh + // + FILE *input_file; + char buf[80],*ptr; + uint32_t i,size,ret; + // + // read file + // + input_file = fopen(input_file_name, "rb"); + if (input_file == 0) { + printf("fab.c: oops -- can't open %s\n",input_file_name); + exit(-1); + } + ret = fread(buf,80,1,input_file); + ptr = strstr(buf,"facet"); + if (ptr != NULL) { + printf("fab.c: oops -- must be binary STL file\n"); + exit(-1); + } + ret = fread(&size,4,1,input_file); + v->mesh = malloc(sizeof(struct fab_mesh_type)); + v->mesh->triangle = malloc(sizeof(struct fab_mesh_triangle_type)); + v->mesh->first = v->mesh->triangle; + v->mesh->last = v->mesh->triangle; + v->mesh->triangle->previous = v->mesh->triangle->next = 0; + ret = fread(&(v->mesh->triangle->normal),4,3,input_file); + ret = fread(&(v->mesh->triangle->v0),4,3,input_file); + ret = fread(&(v->mesh->triangle->v1),4,3,input_file); + ret = fread(&(v->mesh->triangle->v2),4,3,input_file); + ret = fread(&(v->mesh->triangle->attribute),2,1,input_file); + for (i = 1; i < size; ++i) { + v->mesh->last = malloc(sizeof(struct fab_mesh_triangle_type)); + v->mesh->last->previous = v->mesh->triangle; + v->mesh->triangle->next = v->mesh->last; + v->mesh->triangle = v->mesh->last; + v->mesh->triangle->previous = v->mesh->triangle->next = 0; + ret = fread(&(v->mesh->triangle->normal),4,3,input_file); + ret = fread(&(v->mesh->triangle->v0),4,3,input_file); + ret = fread(&(v->mesh->triangle->v1),4,3,input_file); + ret = fread(&(v->mesh->triangle->v2),4,3,input_file); + ret = fread(&(v->mesh->triangle->attribute),2,1,input_file); + } + fclose(input_file); + // + // check read + // + if (ret == 0) { + printf("fab.c: oops -- file read failed\n"); + exit(-1); + } + v->mesh->min[0] = fab_big; + v->mesh->min[1] = fab_big; + v->mesh->min[2] = fab_big; + v->mesh->max[0] = -fab_big; + v->mesh->max[1] = -fab_big; + v->mesh->max[2] = -fab_big; + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle != 0) { + fab_limits(v, v->mesh->triangle->v0); + fab_limits(v, v->mesh->triangle->v1); + fab_limits(v, v->mesh->triangle->v2); + v->mesh->triangle = v->mesh->triangle->next; + } + // + // report and return + // + v->mesh->number = size; + printf("read %s\n",input_file_name); + printf(" number of triangles: %d\n",v->mesh->number); + printf(" xmin, xmax: %f %f\n",v->mesh->min[0],v->mesh->max[0]); + printf(" ymin, ymax: %f %f\n",v->mesh->min[1],v->mesh->max[1]); + printf(" zmin, zmax: %f %f\n",v->mesh->min[2],v->mesh->max[2]); + } + +void fab_read_png(struct fab_vars *v, char *input_file_name) { + // + // read PNG into fab_vars + // + FILE *input_file; + int y; + png_uint_32 res_x,res_y; + int unit_type; + // + // read PNG file + // + input_file = fopen(input_file_name, "rb"); + if (input_file == 0) { + printf("fab.c: oops -- can't open %s\n",input_file_name); + exit(-1); + } + v->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + v->info_ptr = png_create_info_struct(v->png_ptr); + png_init_io(v->png_ptr, input_file); + png_read_info(v->png_ptr, v->info_ptr); + // + // get size + // + v->nx = png_get_image_width(v->png_ptr, v->info_ptr); + v->ny = png_get_image_height(v->png_ptr, v->info_ptr); + v->bit_depth = png_get_bit_depth(v->png_ptr, v->info_ptr); + // + // get units + // + png_get_pHYs(v->png_ptr, v->info_ptr, &res_x, &res_y, &unit_type); + if (unit_type == PNG_RESOLUTION_METER) { + v->dx = 1000 * v->nx / ((float) res_x); + v->dy = 1000 * v->ny / ((float) res_y); + } + else { + printf("fab.c: don't recognize PNG units, assuming 72/inch\n"); + res_x = (72*1000.0)/(25.4); + res_y = (72*1000.0)/(25.4); + v->dx = 1000 * v->nx / ((float) res_x); + v->dy = 1000 * v->ny / ((float) res_y); + } + // + // get texts + // + png_textp text_ptr; + int num_text; + png_get_text(v->png_ptr, v->info_ptr, &text_ptr, &num_text); + int t; + float xmin=0,ymin=0,zmin=0,zmax=0; + for (t = 0; t < num_text; ++t) { + if (0 == strcmp(text_ptr[t].key, "zmax")) + sscanf(text_ptr[t].text, "%g", &zmax); + else if (0 == strcmp(text_ptr[t].key, "zmin")) + sscanf(text_ptr[t].text, "%g", &zmin); + else if (0 == strcmp(text_ptr[t].key, "ymin")) + sscanf(text_ptr[t].text, "%g", &ymin); + else if (0 == strcmp(text_ptr[t].key, "xmin")) + sscanf(text_ptr[t].text, "%g", &xmin); + } + // + // set pixels + // + v->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * v->ny); + for (y = 0; y < v->ny; ++y) + v->row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(v->png_ptr, + v->info_ptr)); + png_read_image(v->png_ptr, v->row_pointers); + // + // set variables + // + v->nz = 1; + if (zmax != zmin) + v->dz = zmax - zmin; + else + v->dz = 0; + v->xmin = xmin; + v->ymin = ymin; + v->zmin = zmin; + // + // allocate array + // + v->array = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->array[y] = malloc(v->nx*sizeof(uint32_t)); + // + // copy image to array + // + fab_png_array(v); + // + // close and return + // + fclose(input_file); + printf("read %s\n",input_file_name); + printf(" bit depth: %d\n",v->bit_depth); + printf(" x pixels: %d, y pixels: %d\n",v->nx,v->ny); + printf(" x pixels/m: %d, y pixels/m: %d\n",(int) res_x,(int) res_y); + if (v->dz != 0) { + printf(" dx: %f mm, dy: %f mm, dz: %f mm\n",v->dx,v->dy,v->dz); + } + else { + printf(" dx: %f mm, dy: %f mm\n",v->dx,v->dy); + } + } + +void fab_read_array(struct fab_vars *v, char *input_file_name) { + // + // read array + // + FILE *input_file; + int x,y,ret; + input_file = fopen(input_file_name,"rb"); + // + // read vars + // + ret = fread(&v->nx,4,1,input_file); + ret = fread(&v->ny,4,1,input_file); + ret = fread(&v->nz,4,1,input_file); + ret = fread(&v->dx,4,1,input_file); + ret = fread(&v->dy,4,1,input_file); + ret = fread(&v->dz,4,1,input_file); + ret = fread(&v->xmin,4,1,input_file); + ret = fread(&v->ymin,4,1,input_file); + ret = fread(&v->zmin,4,1,input_file); + // + // allocate array + // + v->array = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->array[y] = malloc(v->nx*sizeof(uint32_t)); + // + // read array + // + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) + ret = fread(&v->array[y][x],1,1,input_file); + // + // check read + // + if (ret == 0) { + printf("fab.c: oops -- file read failed\n"); + exit(-1); + } + // + // print, close, and return + // + printf("read %s\n",input_file_name); + printf(" nx: %d, ny: %d, nz: %d\n",v->nx,v->ny,v->nz); + printf(" dx: %f, dy: %f, dz: %f\n",v->dx,v->dy,v->dz); + printf(" xmin: %f, ymin: %f, zmin: %f\n",v->xmin,v->ymin,v->zmin); + fclose(input_file); + } + +void fab_read_path(struct fab_vars *v, char *input_file_name) { + // + // read path from file + // + FILE *input_file; + int x,y,z,dof,nsegs=0,npts=0; + char line[255]; + input_file = fopen(input_file_name,"r"); + if (input_file == 0) { + printf("fab.c: oops -- can't open %s\n",input_file_name); + exit(-1); + } + printf("read %s\n",input_file_name); + // + // scan file + // + while (fgets(line,sizeof line,input_file) != NULL) { + if (0 == strncmp(line,"dof:",4)) { + sscanf(line,"dof: %d",&dof); + printf(" degrees of freedom: %d\n",dof); + fab_path_start(v,dof); + } + else if (0 == strncmp(line,"units:",6)) { + printf(" %s",line); // todo: parse and use units + } + else if (0 == strncmp(line,"nx ny:",6)) { + sscanf(line,"nx ny: %d %d",&v->nx,&v->ny); + printf(" nx: %d, ny: %d\n",v->nx,v->ny); + } + else if (0 == strncmp(line,"nx ny nz:",9)) { + sscanf(line,"nx ny nz: %d %d %d",&v->nx,&v->ny,&v->nz); + printf(" nx: %d, ny: %d, nz: %d\n",v->nx,v->ny,v->nz); + } + else if (0 == strncmp(line,"dx dy:",6)) { + sscanf(line,"dx dy: %lf %lf",&v->dx,&v->dy); + printf(" dx: %f, dy: %f\n",v->dx,v->dy); + } + else if (0 == strncmp(line,"dx dy dz:",9)) { + sscanf(line,"dx dy dz: %lf %lf %lf",&v->dx,&v->dy,&v->dz); + printf(" dx: %f, dy: %f, dz: %f\n",v->dx,v->dy,v->dz); + } + else if (0 == strncmp(line,"xmin ymin:",10)) { + sscanf(line,"xmin ymin: %lf %lf",&v->xmin,&v->ymin); + printf(" xmin: %f, ymin: %f\n",v->xmin,v->ymin); + } + else if (0 == strncmp(line,"xmin ymin zmin:",15)) { + sscanf(line,"xmin ymin zmin: %lf %lf %lf",&v->xmin,&v->ymin,&v->zmin); + printf(" xmin: %f, ymin: %f, zmin: %f\n",v->xmin,v->ymin,v->zmin); + } + else if (0 == strncmp(line,"path start:",11)) { + printf(" path start:\n"); + } + else if (0 == strncmp(line,"segment start:",14)) { + fab_path_segment(v); + nsegs += 1; + while (fgets(line,sizeof line,input_file) != NULL) { + if (0 == strncmp(line,"segment end:",12)) { + break; + } + else { + fab_path_point(v); + npts += 1; + if (dof == 3) { + sscanf(line,"%d %d %d",&x,&y,&z); + fab_path_axis(v,x); + fab_path_axis(v,y); + fab_path_axis(v,z); + } + else if (dof == 2) { + sscanf(line,"%d %d",&x,&y); + fab_path_axis(v,x); + fab_path_axis(v,y); + } + else { + printf("fab.c: oops -- can't handle %d dof\n",dof); + exit(-1); + } + } + } + } + else if (0 == strncmp(line,"path end:",9)) { + printf(" segments: %d, points: %d\n",nsegs,npts); + break; + } + else { + printf("fab.c: oops -- can't parse %s\n",line); + exit(-1); + } + } + fclose(input_file); + // + // create array + // + v->array = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->array[y] = malloc(v->nx*sizeof(uint32_t)); + // + // return + // + return; + } + +// +// output +// + +void fab_write_png_K(struct fab_vars *v, char *output_file_name) { + // + // write grayscale PNG from fab_vars + // + FILE *output_file; + int x,y; + int num_text=0; + char xmins[100],ymins[100],zmins[100],zmaxs[100]; + png_text text_ptr[4]; + png_uint_32 res_x,res_y; + png_byte color_type; + png_byte bit_depth; + png_byte *ptr; + // + // open PNG file + // + output_file = fopen(output_file_name, "wb"); + v->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + v->info_ptr = png_create_info_struct(v->png_ptr); + png_init_io(v->png_ptr, output_file); + // + // set vars + // + bit_depth = v->bit_depth; + color_type = PNG_COLOR_TYPE_GRAY; + png_set_IHDR(v->png_ptr, v->info_ptr, v->nx, v->ny, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + res_x = 1000 * v->nx / v->dx; + res_y = 1000 * v->ny / v->dy; + png_set_pHYs(v->png_ptr, v->info_ptr, res_x, res_y, PNG_RESOLUTION_METER); + text_ptr[0].key = "xmin"; + sprintf(xmins,"%f",v->xmin); + text_ptr[0].text = xmins; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + num_text += 1; + text_ptr[1].key = "ymin"; + sprintf(ymins,"%f",v->ymin); + text_ptr[1].text = ymins; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + num_text += 1; + if (v->dz != 0) { + text_ptr[2].key = "zmin"; + sprintf(zmins,"%f",v->zmin); + text_ptr[2].text = zmins; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE; + num_text += 1; + text_ptr[3].key = "zmax"; + sprintf(zmaxs,"%f",(v->zmin + v->dz)); + text_ptr[3].text = zmaxs; + text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE; + num_text += 1; + } + png_set_text(v->png_ptr, v->info_ptr, text_ptr, num_text); + png_write_info(v->png_ptr, v->info_ptr); + // + // allocate pixels + // + v->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * v->ny); + for (y = 0; y < v->ny; ++y) + v->row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(v->png_ptr, + v->info_ptr)); + // + // set pixels + // + if (bit_depth == 8) { + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x]); + ptr[0] = v->array[y][x]; + } + } + else if (bit_depth == 16) { + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*2]); + ptr[0] = (v->array[y][x] >> 8) & 255; + ptr[1] = v->array[y][x] & 255; + } + } + else { + printf("fab.c: oops -- don't recognize bit depth %d\n",v->bit_depth); + exit(-1); + } + // + // write, close, and return + // + png_write_image(v->png_ptr, v->row_pointers); + png_write_end(v->png_ptr, NULL); + fclose(output_file); + printf("write %s\n",output_file_name); + printf(" x pixels: %d, y pixels: %d\n",v->nx,v->ny); + printf(" x pixels/m: %d, y pixels/m: %d\n",(int) res_x,(int) res_y); + if (v->dz != 0) { + printf(" dx: %f mm, dy: %f mm, dz: %f mm\n",v->dx,v->dy,v->dz); + } + else { + printf(" dx: %f mm, dy: %f mm\n",v->dx,v->dy); + } + } + +void fab_write_array(struct fab_vars *v, char *output_file_name) { + // + // write array + // + FILE *output_file; + int x,y; + output_file = fopen(output_file_name,"wb"); + fwrite(&v->nx,4,1,output_file); + fwrite(&v->ny,4,1,output_file); + fwrite(&v->nz,4,1,output_file); + fwrite(&v->dx,4,1,output_file); + fwrite(&v->dy,4,1,output_file); + fwrite(&v->dz,4,1,output_file); + fwrite(&v->xmin,4,1,output_file); + fwrite(&v->ymin,4,1,output_file); + fwrite(&v->zmin,4,1,output_file); + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) + fwrite(&v->array[y][x],1,1,output_file); + fclose(output_file); + printf("write %s\n",output_file_name); + printf(" nx: %d, ny: %d, nz: %d\n",v->nx,v->ny,v->nz); + printf(" dx: %f, dy: %f, dz: %f\n",v->dx,v->dy,v->dz); + printf(" xmin: %f, ymin: %f, zmin: %f\n",v->xmin,v->ymin,v->zmin); + } + +void fab_write_path(struct fab_vars *v, char *output_file_name) { + // + // write path to file + // + FILE *output_file; + int i,nsegs=0,npts=0; + output_file = fopen(output_file_name,"w"); + v->path->segment = v->path->first; + fprintf(output_file,"dof: %d\n",v->path->dof); + fprintf(output_file,"units: "); + for (i = 0; i < v->path->dof; ++i) + fprintf(output_file,"mm "); + fprintf(output_file,"\n"); + if (v->path->dof == 2) { + fprintf(output_file,"nx ny: %d %d\n",v->nx,v->ny); + fprintf(output_file,"dx dy: %f %f\n",v->dx,v->dy); + fprintf(output_file,"xmin ymin: %f %f\n",v->xmin,v->ymin); + } + else if (v->path->dof > 2) { + fprintf(output_file,"nx ny nz: %d %d %d\n",v->nx,v->ny,v->nz); + fprintf(output_file,"dx dy dz: %f %f %f\n",v->dx,v->dy,v->dz); + fprintf(output_file,"xmin ymin zmin: %f %f %f\n",v->xmin,v->ymin,v->zmin); + } + fprintf(output_file,"path start:\n"); + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + fprintf(output_file,"segment start:\n"); + nsegs += 1; + while (1) { + // + // follow points + // + v->path->segment->point->axis = v->path->segment->point->first; + while (1) { + // + // follow axes + // + fprintf(output_file,"%d ",v->path->segment->point->axis->value); + if (v->path->segment->point->axis->next == 0) + break; + v->path->segment->point->axis = v->path->segment->point->axis->next; + } + fprintf(output_file,"\n"); + npts += 1; + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + } + fprintf(output_file,"segment end:\n"); + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + fprintf(output_file,"path end:\n"); + fclose(output_file); + printf("write %s\n",output_file_name); + printf(" degrees of freedom: %d\n",v->path->dof); + printf(" units: "); + for (i = 0; i < v->path->dof; ++i) { + printf("mm "); + } + printf("\n"); + printf(" segments: %d, points: %d\n",nsegs,npts); + if (v->path->dof == 2) { + printf(" nx: %d, ny: %d\n",v->nx,v->ny); + printf(" dx: %f, dy: %f\n",v->dx,v->dy); + printf(" xmin: %f, ymin: %f\n",v->xmin,v->ymin); + } + else if (v->path->dof > 2) { + printf(" nx: %d, ny: %d, nz: %d\n",v->nx,v->ny,v->nz); + printf(" dx: %f, dy: %f, dz: %f\n",v->dx,v->dy,v->dz); + printf(" xmin: %f, ymin: %f, zmin: %f\n",v->xmin,v->ymin,v->zmin); + } + } + +// +// shading +// + +void fab_shade_states(struct fab_vars *v) { + // + // shade array states + // + int x,y; + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + if ((v->array[y][x] & v->direction) == v->north) + v->array[y][x] = 200; + else if ((v->array[y][x] & v->direction) == v->east) + v->array[y][x] = 150; + else if ((v->array[y][x] & v->direction) == v->south) + v->array[y][x] = 100; + else if ((v->array[y][x] & v->direction) == v->west) + v->array[y][x] = 50; + else if ((v->array[y][x] & v->direction) == v->stop) + v->array[y][x] = 25; + else if (v->array[y][x] == v->empty) + v->array[y][x] = 0; + else if (v->array[y][x] & v->edge) + v->array[y][x] = 128; + else if (v->array[y][x] & v->interior) + v->array[y][x] = 255; + } + } + +void fab_shade_line(struct fab_vars *v, int x0, int y0, int x1, int y1, int intensity) { + // + // shade line into array + // + int x,y,dx,dy,step; + float slope; + dx = x1 - x0; + dy = y1 - y0; + x = x0; + y = y0; + if ((dx == 0) && (dy == 0)) { + if ((x0 > 0) && (x0 < v->nx) && (y0 > 0) && (y0 < v->ny)) + v->array[y0][x0] = intensity; + } + else if (abs(dx) == 0) { + if (dy > 0) + step = 1; + else + step = -1; + do { + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + y += step; + } while (y != y1); + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + } + else if (abs(dy) == 0) { + if (dx > 0) + step = 1; + else + step = -1; + do { + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + x += step; + } while (x != x1); + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + } + else { + slope = ((float) dy)/((float) dx); + if (dx > 0) + step = 1; + else + step = -1; + do { + y = y0 + slope*(x-x0); + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + x += step; + } while (x != x1); + y = y0 + slope*(x-x0); + if ((x > 0) && (x < v->nx) && (y > 0) && (y < v->ny)) + v->array[y][x] = intensity; + } + } + +void fab_shade_path(struct fab_vars *v) { + // + // shade path into array + // + int x,y,x0,y0,x1,y1,intensity; + // + // set up and clear array + // + v->bit_depth = 8; + intensity = pow(2,8) - 1; + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) + v->array[y][x] = 0; + v->path->segment = v->path->first; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + x0 = v->path->segment->point->first->value; + y0 = v->path->segment->point->first->next->value; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x1 = v->path->segment->point->first->value; + y1 = v->path->segment->point->first->next->value; + fab_shade_line(v,x0,y0,x1,y1,intensity); + x0 = x1; + y0 = y1; + } + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + } + +void fab_shade_path_displace(struct fab_vars *v) { + // + // shade path into array with z displacement + // + int x,y,x0,y0,z0,x1,y1,z1,nz,intensity; + float scale; + // + // check for thickness + // + if (v->dz == 0) { + // + // no, draw 2D + // + fab_shade_path(v); + return; + } + // + // yes, enlarge and clear array for displacements + // + nz = v->nx * v->dz / v->dx; + scale = ((float) nz) / v->nz; + v->nx += nz; + v->ny += nz; + v->dx += v->dz; + v->dy += v->dz; + v->bit_depth = 8; + v->array = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->array[y] = malloc(v->nx*sizeof(uint32_t)); + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) + v->array[y][x] = 0; + // + // follow path + // + v->path->segment = v->path->first; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + z0 = nz - scale * v->path->segment->point->first->next->next->value; + y0 = z0 + v->path->segment->point->first->next->value; + x0 = z0 + v->path->segment->point->first->value; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + z1 = nz - scale * v->path->segment->point->first->next->next->value; + y1 = z1 + v->path->segment->point->first->next->value; + x1 = z1 + v->path->segment->point->first->value; + intensity = (z0 + z1)/2; + fab_shade_line(v,x0,y0,x1,y1,intensity); + x0 = x1; + y0 = y1; + z0 = z1; + } + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + } + +int fab_row(struct fab_vars *v, float units, int Y, float value) { + // + // return array row + // + value = 0.5f + (v->ny - 1) * units * (value - v->mesh->min[Y]) / v->dy; + return (value); +} +int fab_col(struct fab_vars *v, float units, int X, float value) { + // + // return array col + // + value = 0.5f + (v->nx - 1) * units * (value - v->mesh->min[X]) / v->dx; + return value; +} + +int fab_height(struct fab_vars *v, int S, int Z, float value) { + // + // return array height + // + value = ((1-S)/2) * 65535 + S * 65535 * (value - v->mesh->min[Z]) / (v->mesh->max[Z] - v->mesh->min[Z]); + return value; +} + +void fab_shade_triangle(struct fab_vars *v, float units, int S, int X, int Y, int Z) { + // + // shade triangle intro array + // + float slope; + int xmin,ymin,zmin,x1,y1,z1,x2,y2,z2; + int x20,z20,x21,z21,x10,z10,z; + int i,j; + int dir; + int temp; + #define fab_swap(a,b) temp=a; a=b; b=temp; + // + // find coords + // + xmin = fab_col(v, units, X, v->mesh->triangle->v0[X]); + ymin = fab_row(v, units, Y, v->mesh->triangle->v0[Y]); + zmin = fab_height(v, S, Z, v->mesh->triangle->v0[Z]); + x1 = fab_col(v, units, X, v->mesh->triangle->v1[X]); + y1 = fab_row(v, units, Y, v->mesh->triangle->v1[Y]); + z1 = fab_height(v, S, Z, v->mesh->triangle->v1[Z]); + x2 = fab_col(v, units, X, v->mesh->triangle->v2[X]); + y2 = fab_row(v, units, Y, v->mesh->triangle->v2[Y]); + z2 = fab_height(v, S, Z, v->mesh->triangle->v2[Z]); + // + // check normal if needs to be drawn + // + if ((S*((x1-xmin)*(y1-y2)-(x1-x2)*(y1-ymin))) >= 0) + return; + // + // sort heights + // + if (y1 > y2) { + fab_swap(x1,x2); + fab_swap(y1,y2); + fab_swap(z1,z2); + } + if (ymin > y1) { + fab_swap(xmin,x1); + fab_swap(ymin,y1); + fab_swap(zmin,z1); + } + if (y1 > y2) { + fab_swap(x1,x2); + fab_swap(y1,y2); + fab_swap(z1,z2); + } + // + // check orientation + // + if (x1 < (xmin+((x2-xmin)*(y1-ymin))/(y2-ymin))) + dir = 1; + else + dir = -1; + // + // draw + // + if (y2 != y1) { + for (i = y2; i >= y1; --i) { + x21 = x1 + ((x2-x1)*(i-y1))/(y2-y1); + z21 = z1 + ((z2-z1)*(i-y1))/(y2-y1); + x20 = xmin + ((x2-xmin)*(i-ymin))/(y2-ymin); + z20 = zmin + ((z2-zmin)*(i-ymin))/(y2-ymin); + if (x21 != x20) + slope = (z20-z21)/((float) (x20-x21)); + else + slope = 0; + j = x21 - dir; + while (j != x20) { + j += dir; + z = z21 + slope*(j-x21); + if (z > v->array[v->ny-1-i][j]) + v->array[v->ny-1-i][j] = z; + } + } + } + if (y1 != ymin) { + for (i = y1; i >= ymin; --i) { + x10 = xmin + ((x1-xmin)*(i-ymin))/(y1-ymin); + z10 = zmin + ((z1-zmin)*(i-ymin))/(y1-ymin); + x20 = xmin + ((x2-xmin)*(i-ymin))/(y2-ymin); + z20 = zmin + ((z2-zmin)*(i-ymin))/(y2-ymin); + if (x10 != x20) + slope = (z20-z10)/((float) (x20-x10)); + else + slope = 0; + j = x10 - dir; + while (j != x20) { + j += dir; + z = z10 + slope*(j-x10); + if (z > v->array[v->ny-1-i][j]) + v->array[v->ny-1-i][j] = z; + } + } + } +} + +void fab_shade_mesh(struct fab_vars *v, float units, float resolution, char axis) { + // + // shade triangle mesh into 16-bit array + // + int X,Y,Z,S; + int i; + // + // allocate array + // + if (axis == 'x') { + X = 1; Y = 2; Z = 0; S = 1; + } + else if (axis == 'X') { + X = 1; Y = 2; Z = 0; S = -1; + } + if (axis == 'y') { + X = 2; Y = 0; Z = 1; S = 1; + } + else if (axis == 'Y') { + X = 2; Y = 0; Z = 1; S = -1; + } + if (axis == 'z') { + X = 0; Y = 1; Z = 2; S = 1; + } + else if (axis == 'Z') { + X = 0; Y = 1; Z = 2; S = -1; + } + v->dx = units * (v->mesh->max[X]-v->mesh->min[X]); + v->dy = units * (v->mesh->max[Y]-v->mesh->min[Y]); + v->dz = units * (v->mesh->max[Z]-v->mesh->min[Z]); + v->nx = resolution * v->dx; + v->ny = resolution * v->dy; + v->nz = 1; + v->xmin = units * v->mesh->min[X]; + v->ymin = units * v->mesh->min[Y]; + v->zmin = units * v->mesh->min[Z]; + v->bit_depth = 16; + // + // alloc and init + // + v->array = malloc(v->ny*sizeof(uint32_t *)); + for (i = 0; i < v->ny; ++i) { + v->array[i] = malloc(v->nx*sizeof(uint32_t)); + memset(v->array[i],'\0',v->nx*sizeof(uint32_t)); + } + // + // draw triangles into array + // + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle != 0) { + fab_shade_triangle(v, units, S, X, Y, Z); + v->mesh->triangle = v->mesh->triangle->next; + } + } + +// +// array operations +// + +void fab_png_array(struct fab_vars *v) { + // + // copy PNG image to array + // + int intensity,value,x,y; + int bit, byte; + png_byte *ptr; + png_colorp palette; + png_color color; + //png_uint_32 num_palette; + int num_palette; + + if (png_get_bit_depth(v->png_ptr, v->info_ptr) == 1) { + if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_PALETTE) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + byte = x / 8; + bit = 7 - x % 8; + ptr = &(v->row_pointers[y][byte]); + value = (ptr[0] >> bit) & 1; + png_get_PLTE(v->png_ptr, v->info_ptr, &palette, &num_palette); + color = palette[value]; + intensity = (color.red + color.green + color.blue)/3.0; + v->array[y][x] = intensity; + } + else if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_GRAY) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + byte = x / 8; + bit = 7 - x % 8; + ptr = &(v->row_pointers[y][byte]); + value = (ptr[0] >> bit) & 1; + v->array[y][x] = value; + } + else { + printf("fab.c: oops 3 -- image type not supported\n"); + exit(-1); + } + } + else if (png_get_bit_depth(v->png_ptr, v->info_ptr) == 8) { + if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_GRAY) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*1]); + v->array[y][x] = ptr[0]; + } + else if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*2]); + v->array[y][x] = (int) ((1.0-ptr[1]/255.0)*255 + (0.0+(ptr[1]/255.0))*ptr[0]); + } + else if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_RGB) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*3]); + v->array[y][x] = (int) ((ptr[0] + ptr[1] + ptr[2])/3.0); + } + else if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_RGB_ALPHA) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*4]); + v->array[y][x] = (int) ((1.0-ptr[3]/255.0)*255 + (0.0+(ptr[3]/255.0))*((ptr[0] + ptr[1] + ptr[2])/3.0)); + } + else if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_PALETTE) { + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + value = v->row_pointers[y][x]; + png_get_PLTE(v->png_ptr, v->info_ptr, &palette, &num_palette); + color = palette[value]; + intensity = (color.red + color.green + color.blue)/3.0; + v->array[y][x] = intensity; + } + } + else { + printf("fab.c: oops -- image type not supported\n"); + exit(-1); + } + } + else if (png_get_bit_depth(v->png_ptr, v->info_ptr) == 16) { + if (png_get_color_type(v->png_ptr, v->info_ptr) == PNG_COLOR_TYPE_GRAY) + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*2]); + v->array[y][x] = (ptr[0] << 8) + ptr[1]; + } + else { + printf("fab.c: oops -- image type not supported\n"); + exit(-1); + } + } + else { + printf("fab.c: oops -- image type not supported\n"); + exit(-1); + } + } + +void fab_rescale(struct fab_vars *v, float min, float max) { + // + // rescale array intensity + // + int x,y,top; + float low,high; + // + // find limits + // + top = pow(2,v->bit_depth) - 1; + low = top; + high = 0; + for (y = 0; y < v->ny; ++y) { + for (x = 0; x < v->nx; ++x) { + if (v->array[y][x] > high) + high = v->array[y][x]; + if (v->array[y][x] < low) + low = v->array[y][x]; + } + } + // + // rescale + // + for (y = 0; y < v->ny; ++y) { + for (x = 0; x < v->nx; ++x) { + v->array[y][x] = top*min + top*(max-min) * (v->array[y][x] - low) / (high - low); + } + } + } + +void add_edge(struct fab_vars *v, int* count, int y, int x) { + // + // set cell to interior edge + // + v->array[y][x] = v->interior | v->edge; + ++(*count); +} + +int fab_edges(struct fab_vars *v) { + // + // find edges of thresholded array + // + int x,y,sum,count; + + count = 0; + for (x = 1; x < (v->nx-1); ++x) + if (v->array[0][x] & v->interior) { + sum = (v->array[0][x-1] & v->interior) + + (v->array[0][x+1] & v->interior) + + (v->array[1][x] & v->interior); + if (sum < 3) + add_edge(v, &count, 0,x); + } + else if (v->array[v->ny-1][x] & v->interior) { + sum = (v->array[v->ny-1][x-1] & v->interior) + + (v->array[v->ny-1][x+1] & v->interior) + + (v->array[v->ny-2][x] & v->interior); + if (sum < 3) + add_edge(v, &count, v->ny-1,x); + } + for (y = 1; y < (v->ny-1); ++y) { + if (v->array[y][0] & v->interior) { + sum = (v->array[y-1][0] & v->interior) + + (v->array[y+1][0] & v->interior) + + (v->array[y][1] & v->interior); + if (sum < 3) + add_edge(v, &count, y,0); + } + if (v->array[y][v->nx-1] & v->interior) { + sum = (v->array[y-1][v->nx-1] & v->interior) + + (v->array[y+1][v->nx-1] & v->interior) + + (v->array[y][v->nx-2] & v->interior); + if (sum < 3) + add_edge(v, &count, y,v->nx-1); + } + for (x = 1; x < (v->nx-1); ++x) { + if (v->array[y][x] & v->interior) { + sum = (v->array[y-1][x] & v->interior) + + (v->array[y+1][x] & v->interior) + + (v->array[y][x-1] & v->interior) + + (v->array[y][x+1] & v->interior); + if (sum < 4) + add_edge(v, &count, y,x); + } + } + } + return count; + } + +void fab_threshold(struct fab_vars *v, float intensity) { + // + // threshold array + // + int x,y; + float threshold; + threshold = (pow(2,v->bit_depth) - 1.0) * intensity; + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) + if (v->array[y][x] >= threshold) + v->array[y][x] = v->interior; + else + v->array[y][x] = v->empty; + } + +int fab_distances_distance(struct fab_vars *v, int x, int y, int i) { + return ((y-i)*(y-i) + (v->g[i][x])*(v->g[i][x])); + } + +int fab_distances_intersection(struct fab_vars *v, int x, int y0, int y1) { + return ((0.0+(v->g[y0][x])*(v->g[y0][x])-(v->g[y1][x])*(v->g[y1][x])+y0*y0-y1*y1)/(2.0*(y0-y1))); + } + +void fab_distances(struct fab_vars *v) { + // + // find Euclidean distance to interior in a thresholded array + // + int x,y,closest,segment,newstart; + double d; + // + // allocate arrays if needed + // + if (v->g == 0) { + v->g = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->g[y] = malloc(v->nx*sizeof(uint32_t)); + } + if (v->h == 0) { + v->h = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->h[y] = malloc(v->nx*sizeof(uint32_t)); + } + if (v->distances == 0) { + v->distances = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->distances[y] = malloc(v->nx*sizeof(uint32_t)); + } + if (v->starts == 0) + v->starts = malloc(v->ny*sizeof(uint32_t *)); + if (v->minimums == 0) + v->minimums = malloc(v->ny*sizeof(uint32_t *)); + // + // column scan + // + for (y = 0; y < v->ny; ++y) { + // + // right pass + // + closest = -(v->nx); + for (x = 0; x < v->nx; ++x) { + if (v->array[y][x] == v->interior) { + v->g[y][x] = 0; + closest = x; + } + else + v->g[y][x] = (x-closest); + } + // + // left pass + // + closest = 2*(v->nx); + for (x = (v->nx - 1); x >= 0; --x) { + if (v->array[y][x] == v->interior) + closest = x; + else { + d = (closest-x); + if (d < v->g[y][x]) + v->g[y][x] = d; + } + } + } + // + // row scan + // + for (x = 0; x < v->nx; ++x) { + printf("\b\b\b\b\b\b\b\b %d",x); + segment = 0; + v->starts[0] = 0; + v->minimums[0] = 0; + // + // down + // + for (y = 1; y < v->ny; ++y) { + while ((segment >= 0) && + (fab_distances_distance(v, x, v->starts[segment],v->minimums[segment]) + > fab_distances_distance(v, x, v->starts[segment],y))) + segment -= 1; + if (segment < 0) { + segment = 0; + v->minimums[0] = y; + } + else { + newstart = 1 + fab_distances_intersection(v, x, v->minimums[segment],y); + if (newstart < v->ny) { + segment += 1; + v->minimums[segment] = y; + v->starts[segment] = newstart; + } + } + } + // + // up + // + for (y = (v->ny - 1); y >= 0; --y) { + v->distances[y][x] = sqrt(fab_distances_distance(v, x, y, v->minimums[segment])); + if (y == v->starts[segment]) + segment -= 1; + } + } + printf("\n"); + } + +void test_fab_distances(struct fab_vars *v) { + // + // find Euclidean distance to interior in a thresholded array + // + int x,y; + // + // allocate arrays if needed + // + if (v->ddx == 0) { + v->ddx = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->ddx[y] = malloc(v->nx*sizeof(uint32_t)); + } + if (v->ddy == 0) { + v->ddy = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->ddy[y] = malloc(v->nx*sizeof(uint32_t)); + } + if (v->distances == 0) { + v->distances = malloc(v->ny*sizeof(uint32_t *)); + for (y = 0; y < v->ny; ++y) + v->distances[y] = malloc(v->nx*sizeof(uint32_t)); + } + // + // column scan + // + for (y = 0; y < v->ny; ++y) { + printf("\b\b\b\b\b\b\b\b\b\b y %d",y); + // + // right pass + // + v->ddx[y][0] = -1; + v->ddy[y][0] = 0; + for (x = 1; x < v->nx; ++x) { + v->ddy[y][x] = 0; + if (v->array[y][x] == v->interior) + v->ddx[y][x] = 0; + else + v->ddx[y][x] = v->ddx[y][x-1] - 1; + } + // + // left pass + // + v->ddx[y][v->nx-1] = 1; + for (x = (v->nx - 2); x >= 0; --x) { + if (abs(v->ddx[y][x]) > (abs(v->ddx[y][x+1])) + 1) + v->ddx[y][x] = v->ddx[y][x+1] + 1; + //v->distances[y][x] = sqrt(v->ddx[y][x]*v->ddx[y][x]+v->ddy[y][x]*v->ddy[y][x]); + } + } + printf("\n"); + // + // row scan + // + for (x = 0; x < v->nx; ++x) { + printf("\b\b\b\b\b\b\b\b\b\b x %d",x); + // + // down + // + v->ddx[0][x] = 0; + v->ddy[0][x] = -1; + for (y = 1; y < v->ny; ++y) { + if ((v->ddx[y][x]*v->ddx[y][x]) > (v->ddx[y-1][x]*v->ddx[y-1][x] + (v->ddy[y-1][x]-1)*(v->ddy[y-1][x]-1))) { + v->ddx[y][x] = v->ddx[y-1][x]; + v->ddy[y][x] = v->ddy[y-1][x]-1; + } + v->distances[y][x] = sqrt(v->ddx[y][x]*v->ddx[y][x]+v->ddy[y][x]*v->ddy[y][x]); + } + // + // up + // + /* + v->ddx[v->ny-1][x] = 0; + v->ddy[v->ny-1][x] = 1; + for (y = (v->ny - 2); y >= 0; --y) { + if ((v->ddx[y][x]*v->ddx[y][x]+v->ddy[y][x]*v->ddy[y][x]) > (v->ddx[y+1][x]*v->ddx[y+1][x] + (abs(v->ddy[y+1][x])+1)*(abs(v->ddy[y+1][x])+1))) { + v->ddx[y][x] = v->ddx[y+1][x]; + v->ddy[y][x] = v->ddy[y+1][x]+1; + } + //v->distances[y][x] = sqrt(v->ddx[y][x]*v->ddx[y][x]+v->ddy[y][x]*v->ddy[y][x]); + } + */ + } + printf("\n"); + } + +int fab_offset(struct fab_vars *v, float distance) { + // + // use distances to offset array + // real units, assumes square pixels + // returns remaining points + // + int x,y,remaining_count; + float image_distance; + image_distance = distance * v->nx/v->dx; + // + // loop over array + // + remaining_count = 0; + for (y = 0; y < v->ny; ++y) { + for (x = 0; x < v->nx; ++x) { + if (v->distances[y][x] <= image_distance) + v->array[y][x] = v->interior; + else { + v->array[y][x] = v->empty; + remaining_count += 1; + } + } + } + return remaining_count; + } + + +int state(struct fab_vars *v, int y, int x) { + int nw, nn, ne, ww, cc, ee, sw, ss, se, state; + // + // assemble state string + // 0 = empty + // 1 = interior + // 2 = boundary + // + if ((y == 0) | (x == 0)) + nw = 2; + else + nw = v->array[y-1][x-1] & 1; + if (y == 0) + nn = 2; + else + nn = v->array[y-1][x] & 1; + if ((y == 0) | (x == (v->nx-1))) + ne = 2; + else + ne = v->array[y-1][x+1] & 1; + if (x == 0) + ww = 2; + else + ww = v->array[y][x-1] & 1; + cc = v->array[y][x] & 1; + if (x == (v->nx-1)) + ee = 2; + else + ee = v->array[y][x+1] & 1; + if ((y == (v->ny-1)) | (x == 0)) + sw = 2; + else + sw = v->array[y+1][x-1] & 1; + if (y == (v->ny-1)) + ss = 2; + else + ss = v->array[y+1][x] & 1; + if ((y == (v->ny-1)) | (x == (v->nx-1))) + se = 2; + else + se = v->array[y+1][x+1] & 1; + state = + (nw << 0) + (nn << 2) + (ne << 4) + + (ww << 6) + (cc << 8) + (ee << 10) + + (sw << 12) + (ss << 14) + (se << 16); + return state; +} + +void add_rule(struct fab_vars *v, int *table, int nw, int nn, int ne, + int ww, int cc, int ee,int sw,int ss, int se, int rule) { + // + // add a CA rule, with rotations + // + int state; + // + // add the rule + // + state = + (nw << 0) + (nn << 2) + (ne << 4) + + (ww << 6) + (cc << 8) + (ee << 10) + + (sw << 12) + (ss << 14) + (se << 16); + table[state] = rule; + // + // rotate 90 degrees + // + state = + (sw << 0) + (ww << 2) + (nw << 4) + + (ss << 6) + (cc << 8) + (nn << 10) + + (se << 12) + (ee << 14) + (ne << 16); + if (rule == v->east) + table[state] = v->south; + else if (rule == v->south) + table[state] = v->west; + else if (rule == v->west) + table[state] = v->north; + else if (rule == v->north) + table[state] = v->east; + else if (rule == v->corner) + table[state] = v->corner; + else if (rule == v->stop) + table[state] = v->stop; + // + // rotate 180 degrees + // + state = + (se << 0) + (ss << 2) + (sw << 4) + + (ee << 6) + (cc << 8) + (ww << 10) + + (ne << 12) + (nn << 14) + (nw << 16); + if (rule == v->east) + table[state] = v->west; + else if (rule == v->south) + table[state] = v->north; + else if (rule == v->west) + table[state] = v->east; + else if (rule == v->north) + table[state] = v->south; + else if (rule == v->corner) + table[state] = v->corner; + else if (rule == v->stop) + table[state] = v->stop; + // + // rotate 270 degrees + // + state = + (ne << 0) + (ee << 2) + (se << 4) + + (nn << 6) + (cc << 8) + (ss << 10) + + (nw << 12) + (ww << 14) + (sw << 16); + if (rule == v->east) + table[state] = v->north; + else if (rule == v->south) + table[state] = v->east; + else if (rule == v->west) + table[state] = v->south; + else if (rule == v->north) + table[state] = v->west; + else if (rule == v->corner) + table[state] = v->corner; + else if (rule == v->stop) + table[state] = v->stop; +} + +void fab_directions(struct fab_vars *v) { + // + // find directions around interior edges (right-hand rule) + // + int x,y,rule,dir,*table; + table = calloc((pow(2,18)), sizeof(int)); + + // + // build rule table + // + // 0 = empty + // 1 = interior + // 2 = boundary + // + // 1 0: + // + // 011 + // 111 + // 111 + add_rule(v, table,0,1,1,1,1,1,1,1,1,v->north); + // 101 + // 111 + // 111 + add_rule(v, table,1,0,1,1,1,1,1,1,1,v->east); + // + // 2 0's: + // + // 001 + // 111 + // 111 + add_rule(v, table,0,0,1,1,1,1,1,1,1,v->east); + // 100 + // 111 + // 111 + add_rule(v, table,1,0,0,1,1,1,1,1,1,v->east); + // 010 + // 111 + // 111 + add_rule(v, table,0,1,0,1,1,1,1,1,1,v->east); + // 011 + // 110 + // 111 + add_rule(v, table,0,1,1,1,1,0,1,1,1,v->south); + // 110 + // 011 + // 111 + add_rule(v, table,1,1,0,0,1,1,1,1,1,v->east); + // 101 + // 011 + // 111 + add_rule(v, table,1,0,1,0,1,1,1,1,1,v->east); + // 101 + // 110 + // 111 + add_rule(v, table,1,0,1,1,1,0,1,1,1,v->south); + // 011 + // 111 + // 110 + add_rule(v, table,0,1,1,1,1,1,1,1,0,v->corner); + // 011 + // 111 + // 101 + add_rule(v, table,0,1,1,1,1,1,1,0,1,v->north); + // 110 + // 111 + // 101 + add_rule(v, table,1,1,0,1,1,1,1,0,1,v->west); + // 101 + // 111 + // 110 + add_rule(v, table,1,0,1,1,1,1,1,1,0,v->south); + // 101 + // 111 + // 011 + add_rule(v, table,1,0,1,1,1,1,0,1,1,v->east); + // + // 3 0's: + // + // 001 + // 011 + // 111 + add_rule(v, table,0,0,1,0,1,1,1,1,1,v->east); + // 010 + // 011 + // 111 + add_rule(v, table,0,1,0,0,1,1,1,1,1,v->east); + // 010 + // 110 + // 111 + add_rule(v, table,0,1,0,1,1,0,1,1,1,v->south); + // 010 + // 111 + // 011 + add_rule(v, table,0,1,0,1,1,1,0,1,1,v->east); + // 010 + // 111 + // 110 + add_rule(v, table,0,1,0,1,1,1,1,1,0,v->south); + // 110 + // 011 + // 011 + add_rule(v, table,1,1,0,0,1,1,0,1,1,v->east); + // 011 + // 110 + // 110 + add_rule(v, table,0,1,1,1,1,0,1,1,0,v->south); + // 101 + // 011 + // 011 + add_rule(v, table,1,0,1,0,1,1,0,1,1,v->east); + // 101 + // 110 + // 110 + add_rule(v, table,1,0,1,1,1,0,1,1,0,v->south); + // 011 + // 011 + // 011; + add_rule(v, table,0,1,1,0,1,1,0,1,1,v->north); + // + // 4 0's: + // + // 001 + // 011 + // 011 + add_rule(v, table,0,0,1,0,1,1,0,1,1,v->east); + // 100 + // 110 + // 110 + add_rule(v, table,1,0,0,1,1,0,1,1,0,v->south); + // 010 + // 011 + // 011 + add_rule(v, table,0,1,0,0,1,1,0,1,1,v->east); + // 010 + // 110 + // 110 + add_rule(v, table,0,1,0,1,1,0,1,1,0,v->south); + // 001 + // 110 + // 110 + add_rule(v, table,0,0,1,1,1,0,1,1,0,v->south); + // 100 + // 011 + // 011 + add_rule(v, table,1,0,0,0,1,1,0,1,1,v->east); + // + // 5 0's: + // + // 000 + // 011 + // 011 + add_rule(v, table,0,0,0,0,1,1,0,1,1,v->east); + // + // boundary states + // + // 200 + // 211 + // 211 + add_rule(v, table,2,0,0,2,1,1,2,1,1,v->east); + // 201 + // 211 + // 211 + add_rule(v, table,2,0,1,2,1,1,2,1,1,v->east); + // 210 + // 211 + // 211 + add_rule(v, table,2,1,0,2,1,1,2,1,1,v->east); + // 002 + // 112 + // 112 + add_rule(v, table,0,0,2,1,1,2,1,1,2,v->stop); + // 102 + // 112 + // 112 + add_rule(v, table,1,0,2,1,1,2,1,1,2,v->stop); + // 002 + // 112 + // 102 + add_rule(v, table,0,0,2,1,1,2,1,0,2,v->stop); + // 012 + // 112 + // 112 + add_rule(v, table,0,1,2,1,1,2,1,1,2,v->stop); + // 012 + // 112 + // 102 + add_rule(v, table,0,1,2,1,1,2,1,0,2,v->stop); + for (y = 0; y < v->ny; ++y) { + for (x = 0; x < v->nx; ++x) { + if (v->array[y][x] & v->interior) { + v->array[y][x] = v->interior; + rule = state(v,y,x); + dir = table[rule]; + v->array[y][x] |= dir; + } + } + } + + free(table); + } + +// +// mesh operations +// + +void fab_mesh_path(struct fab_vars *v, float units, float resolution) { + // + // convert mesh to path + // + + // + // set up path + // + fab_path_start(v,3); + v->dx = units * (v->mesh->max[0]-v->mesh->min[0]); + v->dy = units * (v->mesh->max[1]-v->mesh->min[1]); + v->dz = units * (v->mesh->max[2]-v->mesh->min[2]); + v->nx = resolution * v->dx; + v->ny = resolution * v->dy; + v->nz = resolution * v->dz; + v->xmin = units * v->mesh->min[0]; + v->ymin = units * v->mesh->min[1]; + v->zmin = units * v->mesh->min[2]; + v->bit_depth = 16; + // + // loop over mesh + // + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle != 0) { + fab_path_segment(v); + fab_path_point(v); + fab_path_axis(v,(v->nx)*(v->mesh->triangle->v0[0] - v->mesh->min[0])/(v->dx)); + fab_path_axis(v,(v->ny)*(v->mesh->max[1] - v->mesh->triangle->v0[1])/(v->dy)); + fab_path_axis(v,(v->nz)*(v->mesh->triangle->v0[2] - v->mesh->min[2])/(v->dz)); + fab_path_point(v); + fab_path_axis(v,(v->nx)*(v->mesh->triangle->v1[0] - v->mesh->min[0])/(v->dx)); + fab_path_axis(v,(v->ny)*(v->mesh->max[1] - v->mesh->triangle->v1[1])/(v->dy)); + fab_path_axis(v,(v->nz)*(v->mesh->triangle->v1[2] - v->mesh->min[2])/(v->dz)); + fab_path_point(v); + fab_path_axis(v,(v->nx)*(v->mesh->triangle->v2[0] - v->mesh->min[0])/(v->dx)); + fab_path_axis(v,(v->ny)*(v->mesh->max[1] - v->mesh->triangle->v2[1])/(v->dy)); + fab_path_axis(v,(v->nz)*(v->mesh->triangle->v2[2] - v->mesh->min[2])/(v->dz)); + fab_path_point(v); + fab_path_axis(v,(v->nx)*(v->mesh->triangle->v0[0] - v->mesh->min[0])/(v->dx)); + fab_path_axis(v,(v->ny)*(v->mesh->max[1] - v->mesh->triangle->v0[1])/(v->dy)); + fab_path_axis(v,(v->nz)*(v->mesh->triangle->v0[2] - v->mesh->min[2])/(v->dz)); + v->mesh->triangle = v->mesh->triangle->next; + } + } + +// +// path operations +// + +void fab_path_start(struct fab_vars *v, int dof) { + // + // start a new path + // + v->path = malloc(sizeof(struct fab_path_type)); + v->path->first = 0; + v->path->dof = dof; + } + +void fab_path_segment(struct fab_vars *v) { + // + // add a segment to the current path + // + v->path->last = malloc(sizeof(struct fab_path_segment_type)); + v->path->last->previous = 0; + v->path->last->next = 0; + v->path->last->first = 0; + if (v->path->first == 0) { + // + // first segment + // + v->path->first = v->path->last; + v->path->segment = v->path->last; + } + else { + // + // not first segment + // + v->path->last->previous = v->path->segment; + v->path->segment->next = v->path->last; + v->path->segment = v->path->last; + } + } + +void fab_path_point(struct fab_vars *v) { + // + // add a point to the current path segment + // + v->path->segment->last = + malloc(sizeof(struct fab_path_point_type)); + v->path->segment->last->previous = 0; + v->path->segment->last->next = 0; + v->path->segment->last->first = 0; + if (v->path->segment->first == 0) { + // + // first point + // + v->path->segment->first = v->path->segment->last; + v->path->segment->point = v->path->segment->last; + } + else { + // + // not first point + // + v->path->segment->last->previous = v->path->segment->point; + v->path->segment->point->next = v->path->segment->last; + v->path->segment->point = v->path->segment->last; + } + } + +void fab_path_axis(struct fab_vars *v, int value) { + // + // add an axis to the current path segment point + // + v->path->segment->point->last = + malloc(sizeof(struct fab_path_axis_type)); + v->path->segment->point->last->previous = 0; + v->path->segment->point->last->next = 0; + v->path->segment->point->last->value = value; + if (v->path->segment->point->first == 0) { + // + // first axis + // + v->path->segment->point->first = v->path->segment->point->last; + v->path->segment->point->axis = v->path->segment->point->last; + } + else { + // + // not first axis + // + v->path->segment->point->last->previous = v->path->segment->point->axis; + v->path->segment->point->axis->next = v->path->segment->point->last; + v->path->segment->point->axis = v->path->segment->point->last; + } + } + +void fab_path_join(struct fab_vars *vin1, struct fab_vars *vin2, struct fab_vars *vout, float dx, float dy) { + // + // join paths, checking limits + // + float xf,yf,zf; + int xi,yi,zi; + float xmin,ymin,zmin,xmax,ymax,zmax,dpmm; + xmin = ((dx + vin1->xmin) < vin2->xmin) ? (dx + vin1->xmin) : vin2->xmin; + ymin = ((-dy + vin1->ymin) < vin2->ymin) ? (-dy + vin1->ymin) : vin2->ymin; + zmin = (vin1->zmin < vin2->zmin) ? vin1->zmin : vin2->zmin; + xmax = ((dx + vin1->xmin + vin1->dx) > (vin2->xmin + vin2->dx)) ? (dx + vin1->xmin + vin1->dx) : (vin2->xmin + vin2->dx); + ymax = ((-dy + vin1->ymin + vin1->dy) > (vin2->ymin + vin2->dy)) ? (-dy + vin1->ymin + vin1->dy) : (vin2->ymin + vin2->dy); + zmax = ((vin1->zmin + vin1->dz) > (vin2->zmin + vin2->dz)) ? (vin1->zmin + vin1->dz) : (vin2->zmin + vin2->dz); + dpmm = ((vin1->nx/vin1->dx) > (vin2->nx/vin2->dx)) ? (vin1->nx/vin1->dx) : (vin2->nx/vin2->dx); + vout->xmin = xmin; + vout->ymin = ymin; + vout->zmin = zmin; + vout->dx = (xmax-xmin); + vout->dy = (ymax-ymin); + vout->dz = (zmax-zmin); + vout->nx = dpmm * vout->dx; + vout->ny = dpmm * vout->dy; + vout->nz = dpmm * vout->dz; + fab_path_start(vout,vin1->path->dof); + // + // copy first path + // + vin1->path->segment = vin1->path->first; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin1->path->segment->point = vin1->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + xf = dx + vin1->xmin + vin1->dx * vin1->path->segment->point->first->value / (vin1->nx - 1.0); + xi = (vout->nx - 1) * (xf - vout->xmin) / vout->dx; + fab_path_axis(vout,xi); + yf = -dy + vin1->ymin + vin1->dy * vin1->path->segment->point->first->next->value / (vin1->ny - 1.0); + yi = (vout->ny - 1) * (yf - vout->ymin) / vout->dy; + fab_path_axis(vout,yi); + if (vin1->path->dof == 3) { + if (vin1->nz == 1) + zi = 0; + else { + zf = vin1->zmin + vin1->dz * vin1->path->segment->point->first->next->next->value / (vin1->nz - 1.0); + zi = (vout->nz - 1) * (zf - vout->zmin) / vout->dz; + } + fab_path_axis(vout,zi); + } + if (vin1->path->segment->point->next == 0) + break; + vin1->path->segment->point = vin1->path->segment->point->next; + } + if (vin1->path->segment->next == 0) + break; + vin1->path->segment = vin1->path->segment->next; + } + // + // copy second path + // + vin2->path->segment = vin2->path->first; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin2->path->segment->point = vin2->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + xf = vin2->xmin + vin2->dx * vin2->path->segment->point->first->value / (vin2->nx - 1.0); + xi = (vout->nx - 1) * (xf - vout->xmin) / vout->dx; + fab_path_axis(vout,xi); + yf = vin2->ymin + vin2->dy * vin2->path->segment->point->first->next->value / (vin2->ny - 1.0); + yi = (vout->ny - 1) * (yf - vout->ymin) / vout->dy; + fab_path_axis(vout,yi); + if (vin2->path->dof == 3) { + if (vin2->nz == 1) + zi = 0; + else { + zf = vin2->zmin + vin2->dz * vin2->path->segment->point->first->next->next->value / (vin2->nz - 1.0); + zi = (vout->nz - 1) * (zf - vout->zmin) / vout->dz; + } + fab_path_axis(vout,zi); + } + if (vin2->path->segment->point->next == 0) + break; + vin2->path->segment->point = vin2->path->segment->point->next; + } + if (vin2->path->segment->next == 0) + break; + vin2->path->segment = vin2->path->segment->next; + } + } + +void fab_path_cat(struct fab_vars *vin1, struct fab_vars *vin2, struct fab_vars *vout) { + // + // concatenate paths, copying limits + // + vout->xmin = vin1->xmin; + vout->ymin = vin1->ymin; + vout->zmin = vin1->zmin; + vout->dx = vin1->dx; + vout->dy = vin1->dy; + vout->dz = vin1->dz; + vout->nx = vin1->nx; + vout->ny = vin1->ny; + vout->nz = vin1->nz; + fab_path_start(vout,vin1->path->dof); + // + // copy first path + // + vin1->path->segment = vin1->path->first; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin1->path->segment->point = vin1->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + fab_path_axis(vout,vin1->path->segment->point->first->value); + fab_path_axis(vout,vin1->path->segment->point->first->next->value); + if (vin1->path->dof > 2) + fab_path_axis(vout,vin1->path->segment->point->first->next->next->value); + if (vin1->path->segment->point->next == 0) + break; + vin1->path->segment->point = vin1->path->segment->point->next; + } + if (vin1->path->segment->next == 0) + break; + vin1->path->segment = vin1->path->segment->next; + } + // + // copy second path + // + vin2->path->segment = vin2->path->first; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin2->path->segment->point = vin2->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + fab_path_axis(vout,vin2->path->segment->point->first->value); + fab_path_axis(vout,vin2->path->segment->point->first->next->value); + if (vin2->path->dof > 2) + fab_path_axis(vout,vin2->path->segment->point->first->next->next->value); + if (vin2->path->segment->point->next == 0) + break; + vin2->path->segment->point = vin2->path->segment->point->next; + } + if (vin2->path->segment->next == 0) + break; + vin2->path->segment = vin2->path->segment->next; + } + } + +void fab_path_append(struct fab_vars *vin, struct fab_vars *vout) { + // + // append vin to vout, copying limits + // + vin->path->segment = vin->path->first; + vout->path->segment = vout->path->last; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin->path->segment->point = vin->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + fab_path_axis(vout,vin->path->segment->point->first->value); + fab_path_axis(vout,vin->path->segment->point->first->next->value); + if (vin->path->dof > 2) + fab_path_axis(vout,vin->path->segment->point->first->next->next->value); + if (vin->path->segment->point->next == 0) + break; + vin->path->segment->point = vin->path->segment->point->next; + } + if (vin->path->segment->next == 0) + break; + vin->path->segment = vin->path->segment->next; + } + } + +void fab_path_array(struct fab_vars *vin, struct fab_vars *vout, int nx, int ny, float dx, float dy) { + // + // array path + // + int i,j,x,y,z,dnx,dny; + dnx = dx * vin->nx / vin->dx; + dny = dy * vin->ny / vin->dy; + vout->dx = nx * vin->dx + (nx-1) * dx; + vout->dy = ny * vin->dy + (ny-1) * dy; + vout->dz = vin->dz; + vout->nx = nx * vin->nx + (nx-1) * dnx; + vout->ny = ny * vin->ny + (ny-1) * dny; + vout->nz = vin->nz; + vout->xmin = vin->xmin; + vout->ymin = vin->ymin; + vout->zmin = vin->zmin; + fab_path_start(vout,vin->path->dof); + for (i = 0; i < nx; ++i) { + for (j = 0; j < ny; ++j) { + vin->path->segment = vin->path->first; + while (1) { + // + // follow segments + // + fab_path_segment(vout); + vin->path->segment->point = vin->path->segment->first; + while (1) { + // + // follow points + // + fab_path_point(vout); + x = i*(vin->nx + dnx) + vin->path->segment->point->first->value; + fab_path_axis(vout,x); + y = j*(vin->ny + dny) + vin->path->segment->point->first->next->value; + fab_path_axis(vout,y); + if (vin->path->dof == 3) { + z = vin->path->segment->point->first->next->next->value; + fab_path_axis(vout,z); + } + if (vin->path->segment->point->next == 0) + break; + vin->path->segment->point = vin->path->segment->point->next; + } + if (vin->path->segment->next == 0) + break; + vin->path->segment = vin->path->segment->next; + } + } + } + } + +void fab_follow(struct fab_vars *v, float error, int y, int x, int z) { + // + // create path by following edge directions at x,y + // error is allowable deviation before stroking (in pixel units) + // z is layer height (ignored for 2D paths) + // + int xnew=0,ynew=0; + float xmean,ymean; + float dx,dy,nx,ny,d; + int xcur,ycur,xstart,ystart,xseg,yseg,xsum,ysum,nsum; + char last_direction; + // + // don't start on a corner state + // + if (((v->array[y][x] & v->direction) == v->corner) + || ((v->array[y][x] & v->direction) == v->corner2)) + return; + // + // otherwise start segment + // + xstart = x; + ystart = y; + xcur = x; + ycur = y; + xseg = x; + yseg = y; + xsum = 0; + ysum = 0; + nsum = 0; + last_direction = '?'; + fab_path_segment(v); + // + // add first point + // + fab_path_point(v); + fab_path_axis(v,xstart); + fab_path_axis(v,ystart); + if (v->path->dof > 2) + fab_path_axis(v,z); + while (1) { + // + // accumulate current point + // + xsum += xcur; + ysum += ycur; + nsum += 1; + xmean = xsum / ((float) nsum); + ymean = ysum / ((float) nsum); + dx = (xmean - xseg); + dy = (ymean - yseg); + d = sqrt(dx*dx + dy*dy); + nx = dy/d; + ny = -dx/d; + // + // follow current direction + // + if ((v->array[ycur][xcur] & v->direction) == v->north) { + xnew = xcur; + ynew = ycur - 1; + last_direction = 'n'; // remember direction + v->array[ycur][xcur] &= ~v->direction; // clear direction + } + else if ((v->array[ycur][xcur] & v->direction) == v->south) { + xnew = xcur; + ynew = ycur + 1; + last_direction = 's'; // remember direction + v->array[ycur][xcur] &= ~v->direction; // clear direction + } + else if ((v->array[ycur][xcur] & v->direction) == v->east) { + xnew = xcur + 1; + ynew = ycur; + last_direction = 'e'; // remember direction + v->array[ycur][xcur] &= ~v->direction; // clear direction + } + else if ((v->array[ycur][xcur] & v->direction) == v->west) { + xnew = xcur - 1; + ynew = ycur; + last_direction = 'w'; // remember direction + v->array[ycur][xcur] &= ~v->direction; // clear direction + } + else if ((v->array[ycur][xcur] & v->direction) == v->corner) { + if (last_direction == 'n') { + xnew = xcur - 1; + ynew = ycur; + last_direction = 'w'; + } + else if (last_direction == 'e') { + xnew = xcur; + ynew = ycur - 1; + last_direction = 'n'; + } + else if (last_direction == 's') { + xnew = xcur + 1; + ynew = ycur; + last_direction = 'e'; + } + else if (last_direction == 'w') { + xnew = xcur; + ynew = ycur + 1; + last_direction = 's'; + } + v->array[ycur][xcur] &= ~v->direction; // set direction to corner2 + v->array[ycur][xcur] |= v->corner2; + } + else if ((v->array[ycur][xcur] & v->direction) == v->corner2) { + if (last_direction == 'n') { + xnew = xcur - 1; + ynew = ycur; + last_direction = 'w'; + } + else if (last_direction == 'e') { + xnew = xcur; + ynew = ycur - 1; + last_direction = 'n'; + } + else if (last_direction == 's') { + xnew = xcur + 1; + ynew = ycur; + last_direction = 'e'; + } + else if (last_direction == 'w') { + xnew = xcur; + ynew = ycur + 1; + last_direction = 's'; + } + v->array[ycur][xcur] &= ~v->direction; // clear direction + } + else if ((v->array[ycur][xcur] & v->direction) == 0) { + printf("fab.c: oops -- no direction\n"); + exit(-1); + } + else { + printf("fab.c: oops -- unknown direction = %d\n", + v->array[ycur][xcur] & v->direction); + exit(-1); + } + // + // finish segment and return if back to start, or stop reached + // + if (((xnew == xstart) && (ynew == ystart)) || + ((v->array[ynew][xnew] & v->direction) == v->stop)) { + fab_path_point(v); + fab_path_axis(v,xnew); + fab_path_axis(v,ynew); + if (v->path->dof > 2) + fab_path_axis(v,z); + break; + } + // + // check segment at new point + // + d = fabs(nx*(xnew-xseg) + ny*(ynew-yseg)); + if (d >= error) { + // + // exceeds error, add current point to path + // + fab_path_point(v); + fab_path_axis(v,xcur); + fab_path_axis(v,ycur); + if (v->path->dof > 2) + fab_path_axis(v,z); + xsum = 0; + ysum = 0; + nsum = 0; + xseg = xcur; + yseg = ycur; + } + // + // move to new point + // + xcur = xnew; + ycur = ynew; + } +} + +void fab_vectorize(struct fab_vars *v, float error, int z) { + // + // vectorize xy edge directions + // error is transverse distance from segment mean + // in lattice units + // z is layer height (ignored for 2D paths) + // + int x, y; + // + // find edge starts + // + for (x = 0; x < v->nx; ++x) + if ((v->array[0][x] & v->direction) == v->south) + fab_follow(v, error, 0,x, z); + for (y = 0; y < v->ny; ++y) + if ((v->array[y][v->nx-1] & v->direction) == v->west) + fab_follow(v, error, y,v->nx-1, z); + for (x = (v->nx - 1); x >= 0 ; --x) + if ((v->array[v->ny-1][x] & v->direction) == v->north) + fab_follow(v, error, v->ny-1,x, z); + for (y = (v->ny - 1); y >= 0; --y) + if ((v->array[y][0] & v->direction) == v->east) + fab_follow(v, error, y,0, z); + // + // find remaining interior paths + // + for (y = 1; y < (v->ny - 1); ++y) { + if ((y % 2) == 1) { + for (x = 1; x < (v->nx - 1); ++x) { + if (v->array[y][x] & v->direction) { + fab_follow(v,error,y,x,z); + } + } + } + else { + for (x = (v->nx - 2); x > 0; --x) { + if (v->array[y][x] & v->direction) { + fab_follow(v,error,y,x,z); + } + } + } + } + } + +void fab_halftone(struct fab_vars *v, float threshold, int points, float size, float spacing, float offset, int invert) { + // + // halftone array to path + // + int xmin,ymin,x,y,n,i,space,shift,top; + float pi,angle,r; + top = pow(2,v->bit_depth) - 1; + // + // start 2D path + // + fab_path_start(v,2); + // + // loop over spots + // + pi = 4.0*atan(1.0); + angle = 2.0*pi/(points-1.0); + n = v->nx * (0.5*size/v->dx); + space = spacing*2*n; + shift = 0; + for (ymin = n; ymin < (v->ny - n); ymin += space) { + for (xmin = n; xmin < (v->nx - n); xmin += space) { + r = n * (invert*top + (1-2*invert)* v->array[ymin][xmin]) / ((float) top); + // + // if spot radius larger than threshold, add to path + // + if (r >= threshold) { + fab_path_segment(v); + for (i = 0; i < points; ++i) { + x = shift + 0.5 + xmin + r*cos(i*angle); + y = 0.5 + ymin + r*sin(i*angle); + fab_path_point(v); + fab_path_axis(v,x); + fab_path_axis(v,y); + } + } + } + shift += offset * space; + if (shift >= space) + shift -= space; + } + } + diff --git a/src/core/fab.h b/src/core/fab.h new file mode 100644 index 0000000..36dbf5e --- /dev/null +++ b/src/core/fab.h @@ -0,0 +1,150 @@ +// +// fab.h +// fab modules header +// +// Neil Gershenfeld 7/4/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#define fab_big 1e10 + +// +// data structures +// + +struct fab_vars { + unsigned char empty; + unsigned char interior; + unsigned char edge; + unsigned char north; + unsigned char south; + unsigned char east; + unsigned char west; + unsigned char stop; + unsigned char corner; + unsigned char corner2; + unsigned char direction; + unsigned int nx,ny,nz; + unsigned int bit_depth; + unsigned int word_size; + double dx,dy,dz; + double xmin,ymin,zmin; + uint32_t **array; + uint32_t **distances,**g,**h; // for distance transform + uint32_t *starts,*minimums; // " + uint32_t **ddx,**ddy; // testing + struct fab_path_type *path; + struct fab_mesh_type *mesh; + png_bytep *row_pointers; + png_structp png_ptr; + png_infop info_ptr; + }; + +struct fab_path_type { + struct fab_path_segment_type *first,*segment,*last; + int dof; + }; + +struct fab_path_segment_type { + struct fab_path_segment_type *previous,*next; + struct fab_path_point_type *first,*point,*last; + }; + +struct fab_path_point_type { + struct fab_path_point_type *previous,*next; + struct fab_path_axis_type *first,*axis,*last; + }; + +struct fab_path_axis_type { + struct fab_path_axis_type *previous,*next; + int value; + }; + +struct fab_mesh_type { + struct fab_mesh_triangle_type *first,*triangle,*last; + float min[3]; + float max[3]; + int number; + }; + +struct fab_mesh_triangle_type { + struct fab_mesh_triangle_type *previous,*next; + float normal[3],v0[3],v1[3],v2[3]; + int attribute; + }; + +// +// function prototypes +// + +// +// initialization +// +void init_vars(struct fab_vars *v); +// +// input +// +void fab_read_stl(struct fab_vars *v, char *input_file_name); +//void fab_read_svg(struct fab_vars *v, char *input_file_name); +void fab_read_png(struct fab_vars *v, char *input_file_name); +void fab_read_array(struct fab_vars *v, char *input_file_name); +void fab_read_path(struct fab_vars *v, char *input_file_name); +// +// output +// +void fab_write_png_K(struct fab_vars *v, char *output_file_name); +void fab_write_array(struct fab_vars *v, char *output_file_name); +void fab_write_path(struct fab_vars *v, char *output_file_name); +// +// shading +// +void fab_shade_states(struct fab_vars *v); +void fab_shade_line(struct fab_vars *v, int x0, int y0, int x1, int y1, int intensity); +void fab_shade_path(struct fab_vars *v); +void fab_shade_path_displace(struct fab_vars *v); +void fab_shade_mesh(struct fab_vars *v, float units, float resolution, char axis); +void fab_shade_triangle(struct fab_vars *v, float units, int S, int X, int Y, int Z); +// +// array operations +// +void fab_png_array(struct fab_vars *v); +void fab_rescale(struct fab_vars *v, float min, float max); +int fab_edges(struct fab_vars *v); +void fab_threshold(struct fab_vars *v, float threshold); +void fab_distances(struct fab_vars *v); +int fab_offset(struct fab_vars *v, float distance); +void fab_directions(struct fab_vars *v); +// +// mesh operations +// +void fab_mesh_path(struct fab_vars *v, float units, float resolution); +// +// path operations +// +void fab_follow(struct fab_vars *v, float error, int y, int x, int z); +void fab_path_start(struct fab_vars *v, int dof); +void fab_path_segment(struct fab_vars *v); +void fab_path_point(struct fab_vars *v); +void fab_path_axis(struct fab_vars *v, int value); +void fab_path_join(struct fab_vars *vin1, struct fab_vars *vin2, struct fab_vars *vout, float dx, float dy); +void fab_path_cat(struct fab_vars *vin1, struct fab_vars *vin2, struct fab_vars *vout); +void fab_path_append(struct fab_vars *vin1, struct fab_vars *vin2); +void fab_path_array(struct fab_vars *vin, struct fab_vars *vout, int nx, int ny, float dx, float dy); +void fab_vectorize(struct fab_vars *v, float error, int z); +void fab_halftone(struct fab_vars *v, float threshold, int points, float size, float spacing, float offset, int invert); diff --git a/src/core/gif_info.c b/src/core/gif_info.c new file mode 100644 index 0000000..a7efaae --- /dev/null +++ b/src/core/gif_info.c @@ -0,0 +1,120 @@ +// +// gif_info.c +// report .gif info +// +// Neil Gershenfeld 3/24/14 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#define MAX_LINE 10000 + +#include "fab.h" + +int main(int argc, char **argv) { + // + // local vars + // + GifFileType *GIFfile; + GifRecordType GIFtype; + GifByteType *GIFextension; + GifPixelType *GIFline; + int x,y,i,n,imin,imax; + int image_width,image_height,image_count,color_resolution,GIFcode,ret; + float voxel_size; + char comment[256]; + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (!(argc == 2)) { + printf("command line: gif_info in.gif\n"); + printf(" in.gif = input GIF file\n"); + exit(-1); + } + voxel_size = -1; + image_width = -1; + image_height = -1; + image_count = -1; + // + // scan the file + // + printf("read %s\n",argv[1]); + color_resolution = -1; + GIFfile = DGifOpenFileName(argv[1]); + if (GIFfile == NULL) { + printf("gif_info: oops -- can not open %s\n",argv[1]); + exit(-1); + } + GIFline = malloc(MAX_LINE*sizeof(GifPixelType)); + imin = 256; + imax = 0; + do { + DGifGetRecordType(GIFfile,&GIFtype); + switch (GIFtype) { + case IMAGE_DESC_RECORD_TYPE: + DGifGetImageDesc(GIFfile); + image_width = GIFfile->SWidth; + image_height = GIFfile->SHeight; + image_count = GIFfile->ImageCount; + color_resolution = GIFfile->SColorResolution; + for (y = 0; y < GIFfile->SHeight; ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_info: oops -- error reading line\n"); + exit(-1); + } + for (x = 0; x < GIFfile->SWidth; ++x) { + if (GIFline[x] < imin) imin = GIFline[x]; + if (GIFline[x] > imax) imax = GIFline[x]; + } + } + break; + case EXTENSION_RECORD_TYPE: + DGifGetExtension(GIFfile,&GIFcode,&GIFextension); + if (GIFcode == COMMENT_EXT_FUNC_CODE) { + n = GIFextension[0]; + for (i = 1; i <= n; ++i) + comment[i-1] = GIFextension[i]; + comment[n] = 0; + if (voxel_size == -1) + sscanf(comment,"mm per pixel: %f;",&voxel_size); + } + while (GIFextension != NULL) + DGifGetExtensionNext(GIFfile,&GIFextension); + break; + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(GIFfile); + break; + case TERMINATE_RECORD_TYPE: + break; + case UNDEFINED_RECORD_TYPE: + printf("gif_info: oops -- undefined GIF record type\n"); + exit(-1); + break; + } + } while (GIFtype != TERMINATE_RECORD_TYPE); + if (GIFfile == NULL) { + printf("gif_info: oops -- can not open %s\n",argv[1]); + exit(-1); + } + if (voxel_size == -1) { + voxel_size = 1.0; + printf(" no pixel size found, assuming 1 mm\n"); + } + printf(" voxel size (mm): %f, color resolution (bits): %d\n",voxel_size,color_resolution); + printf(" intensity min: %d max: %d\n",imin,imax); + printf(" number of images: %d, image width %d, image height %d\n",image_count,image_width,image_height); + // + // exit + // + DGifCloseFile(GIFfile); + exit(0); + } diff --git a/src/core/gif_png.c b/src/core/gif_png.c new file mode 100644 index 0000000..e915c58 --- /dev/null +++ b/src/core/gif_png.c @@ -0,0 +1,346 @@ +// +// gif_png.c +// .gif to .png +// +// Neil Gershenfeld 9/20/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#define MAX_LINE 10000 +#define BIG 1e10 + +#include "fab.h" + +int main(int argc, char **argv) { + // + // local vars + // + GifFileType *GIFfile; + GifRecordType GIFtype; + GifByteType *GIFextension; + GifPixelType *GIFline; + uint32_t **lower_array,**upper_array; + double **image_array; + double f,fmin,fmax; + int x,y,z,h,i,j,k,n,p; + int imin,imax,image_width,image_height,image_count,color_resolution,GIFcode,ret; + float pixel_size,arg,threshold,rx,ry,rz; + char type,comment[256]; + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 7) || (argc == 10))) { + printf("command line: gif_png in.gif out.png [type [arg [points [size [rx ry rz]]]]]\n"); + printf(" in.gif = input gif file\n"); + printf(" out.png = output PNG file\n"); + printf(" type = 'z' of density, 'h' for height (default z)\n"); + printf(" arg = type argument\n"); + printf(" 'z': gamma (default 1)\n"); + printf(" 'h': threshold (0 = min, 1 = max, default 0.5)\n"); + printf(" points = points to interpolate per point (linear, default 0)\n"); + printf(" size = voxel size (mm, default from file))\n"); + printf(" to be implemented: rx,ry,rz = x,y,z rotation angles (degrees; default 0)\n"); + exit(-1); + } + type = 'z'; + p = 0; + rx = ry = rz = 0; + pixel_size = -1; + image_width = -1; + image_height = -1; + if (argc >= 4) { + sscanf(argv[3],"%c",&type); + if (!((type == 'z') || (type == 'h'))) { + printf("gif_png: oops -- type must be 'z' or 'h'\n"); + exit(-1); + } + } + if (type == 'z') arg = 1.0; + else if (type == 'h') arg = 0.5; + if (argc >= 5) + sscanf(argv[4],"%f",&arg); + if (argc >= 6) + sscanf(argv[5],"%d",&p); + if (argc >= 7) + sscanf(argv[6],"%f",&pixel_size); + if (argc >= 10) { + sscanf(argv[7],"%f",&rx); + sscanf(argv[8],"%f",&ry); + sscanf(argv[9],"%f",&rz); + } + // + // scan the file + // + printf("read %s\n",argv[1]); + imin = 256; + imax = 0; + color_resolution = -1; + GIFfile = DGifOpenFileName(argv[1]); + if (GIFfile == NULL) { + printf("gif_png: oops -- can not open %s\n",argv[1]); + exit(-1); + } + GIFline = malloc(MAX_LINE*sizeof(GifPixelType)); + do { + DGifGetRecordType(GIFfile,&GIFtype); + switch (GIFtype) { + case IMAGE_DESC_RECORD_TYPE: + DGifGetImageDesc(GIFfile); + image_width = GIFfile->SWidth; + image_height = GIFfile->SHeight; + image_count = GIFfile->ImageCount; + color_resolution = GIFfile->SColorResolution; + for (y = 0; y < GIFfile->SHeight; ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_png: oops -- error reading line\n"); + exit(-1); + } + for (x = 0; x < GIFfile->SWidth; ++x) { + if (GIFline[x] < imin) imin = GIFline[x]; + if (GIFline[x] > imax) imax = GIFline[x]; + } + } + break; + case EXTENSION_RECORD_TYPE: + DGifGetExtension(GIFfile,&GIFcode,&GIFextension); + if (GIFcode == COMMENT_EXT_FUNC_CODE) { + n = GIFextension[0]; + for (i = 1; i <= n; ++i) + comment[i-1] = GIFextension[i]; + comment[n] = 0; + if (pixel_size == -1) + sscanf(comment,"mm per pixel: %f;",&pixel_size); + } + while (GIFextension != NULL) + DGifGetExtensionNext(GIFfile,&GIFextension); + break; + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(GIFfile); + break; + case TERMINATE_RECORD_TYPE: + break; + case UNDEFINED_RECORD_TYPE: + printf("gif_png: oops -- undefined GIF record type\n"); + exit(-1); + break; + } + } while (GIFtype != TERMINATE_RECORD_TYPE); + if (GIFfile == NULL) { + printf("gif_png: oops -- can not open %s\n",argv[1]); + exit(-1); + } + if (pixel_size == -1) { + pixel_size = 1.0; + printf(" no pixel size found, assuming 1 mm\n"); + } + printf(" pixel size (mm): %f, color resolution (bits): %d\n",pixel_size,color_resolution); + printf(" intensity min: %d max: %d\n",imin,imax); + printf(" number of images: %d, image width %d, image height %d\n",image_count,image_width,image_height); + // + // set threshold + // + if (type == 'h') + threshold = imin + arg*(imax-imin); + // + // check and set limits + // + v.nx = image_width + (image_width-1)*p; + v.ny = image_height + (image_height-1)*p; + v.nz = image_count + (image_count-1)*p; + v.dx = v.nx*pixel_size; + v.dy = v.ny*pixel_size; + v.dz = v.nz*pixel_size; + v.xmin = 0; + v.ymin = 0; + v.zmin = 0; + // + // allocate arrays + // + lower_array = malloc(image_height*sizeof(uint32_t *)); + for (y = 0; y < image_height; ++y) { + lower_array[y] = malloc(image_width*sizeof(uint32_t)); + for (x = 0; x < image_width; ++x) + lower_array[y][x] = 0; + } + upper_array = malloc(image_height*sizeof(uint32_t *)); + for (y = 0; y < image_height; ++y) { + upper_array[y] = malloc(image_width*sizeof(uint32_t)); + for (x = 0; x < image_width; ++x) + upper_array[y][x] = 0; + } + image_array = malloc(v.ny*sizeof(double *)); + for (y = 0; y < v.ny; ++y) { + image_array[y] = malloc(v.nx*sizeof(double)); + for (x = 0; x < v.nx; ++x) + image_array[y][x] = 0; + } + v.array = malloc(v.ny*sizeof(uint32_t *)); + for (y = 0; y < v.ny; ++y) { + v.array[y] = malloc(v.nx*sizeof(uint32_t)); + for (x = 0; x < v.nx; ++x) + v.array[y][x] = 0; + } + // + // read the file + // + DGifCloseFile(GIFfile); + GIFfile = DGifOpenFileName(argv[1]); + if (GIFfile == NULL) { + printf("gif_png: oops -- can not open %s\n",argv[1]); + exit(-1); + } + z = 0; + do { + DGifGetRecordType(GIFfile,&GIFtype); + switch (GIFtype) { + case IMAGE_DESC_RECORD_TYPE: + // + // read image + // + DGifGetImageDesc(GIFfile); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z); + if (z == 0) { + // + // read first layer + // + for (y = 0; y < image_height; ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_png: oops -- error reading first line\n"); + exit(-1); + } + for (x = 0; x < image_width; ++x) + upper_array[y][x] = GIFline[x]; + } + } + else { + // + // read next layer + // + for (y = 0; y < image_height; ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_png: oops -- error reading line\n"); + exit(-1); + } + for (x = 0; x < image_width; ++x) { + lower_array[y][x] = upper_array[y][x]; + upper_array[y][x] = GIFline[x]; + } + } + if (p == 0) { + // + // no interpolation, loop over layer voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + if (type == 'z') { + image_array[y][x] += lower_array[y][x]; + } + else if (type == 'h') { + if ((lower_array[y][x] >= threshold) && (upper_array[y][x] < threshold)) + image_array[y][x] = z + (lower_array[y][x]-threshold)/(lower_array[y][x]-upper_array[y][x]); + } + } + } + } + else { + // + // yes interpolation, loop over layer sub-voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + for (i = 0; i <= p; ++i) { + for (j = 0; j <= p; ++j) { + for (k = 0; k <= p; ++k) { + f = lower_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + upper_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0)); + if (type == 'z') { + image_array[(1+p)*y+j][(1+p)*x+i] += f; + } + else if (type == 'h') { + h = (1+p)*z+k; + if ((f > threshold) && (h > image_array[(1+p)*y+j][(1+p)*x+i])) + image_array[(1+p)*y+j][(1+p)*x+i] = h; + } + } + } + } + } + } + } + } + z += 1; + break; + case EXTENSION_RECORD_TYPE: + DGifGetExtension(GIFfile,&GIFcode,&GIFextension); + while (GIFextension != NULL) + DGifGetExtensionNext(GIFfile,&GIFextension); + break; + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(GIFfile); + break; + case TERMINATE_RECORD_TYPE: + break; + case UNDEFINED_RECORD_TYPE: + printf("gif_png: oops -- undefined GIF record type\n"); + exit(-1); + break; + } + } while (GIFtype != TERMINATE_RECORD_TYPE); + printf("\n"); + // + // scale image and copy to PNG array + // + if (type == 'z') { + fmin = BIG; + fmax = 0; + for (x = 0; x < v.nx; ++x) { + for (y = 0; y < v.ny; ++y) { + if (image_array[y][x] > fmax) fmax = image_array[y][x]; + if (image_array[y][x] < fmin) fmin = image_array[y][x]; + } + } + if (arg == 1) { + for (x = 0; x < v.nx; ++x) + for (y = 0; y < v.ny; ++y) + v.array[y][x] = 65536*(image_array[y][x]-fmin)/(fmax-fmin); + } + else { + for (x = 0; x < v.nx; ++x) + for (y = 0; y < v.ny; ++y) + v.array[y][x] = 65536*pow((image_array[y][x]-fmin)/(fmax-fmin),arg); + } + } + else if (type == 'h') { + for (x = 0; x < v.nx; ++x) + for (y = 0; y < v.ny; ++y) + v.array[y][x] = 65536*image_array[y][x]/(v.nz-1.0); + } + // + // write PNG + // + v.bit_depth = 16; + fab_write_png_K(&v,argv[2]); + // + // exit + // + DGifCloseFile(GIFfile); + exit(0); + } diff --git a/src/core/gif_stl.c b/src/core/gif_stl.c new file mode 100644 index 0000000..d3795c8 --- /dev/null +++ b/src/core/gif_stl.c @@ -0,0 +1,717 @@ +// +// gif_stl.c +// .gif to .stl +// +// Neil Gershenfeld 12/11/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#define MAX_LINE 10000 + +#include "fab.h" + +/* +vertices: + --- + 6 7 + 4 5 + --- + 2 3 + 0 1 + --- +edges: + --- + k + l j + i + --- + h g + e f + --- + c + d b + a + --- +*/ + +// +// rotate_x +// rotate rule around x and add +// +void rotate_x(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[4] << 0) + +(b[5] << 1) + +(b[0] << 2) + +(b[1] << 3) + +(b[6] << 4) + +(b[7] << 5) + +(b[2] << 6) + +(b[3] << 7); + for (i + = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'c'; break; + case 'b': rules[*index][i] = 'g'; break; + case 'c': rules[*index][i] = 'k'; break; + case 'd': rules[*index][i] = 'h'; break; + case 'e': rules[*index][i] = 'd'; break; + case 'f': rules[*index][i] = 'b'; break; + case 'g': rules[*index][i] = 'j'; break; + case 'h': rules[*index][i] = 'l'; break; + case 'i': rules[*index][i] = 'a'; break; + case 'j': rules[*index][i] = 'f'; break; + case 'k': rules[*index][i] = 'i'; break; + case 'l': rules[*index][i] = 'e'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// rotate_y +// rotate rule around y and add +// +void rotate_y(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[1] << 0) + +(b[5] << 1) + +(b[3] << 2) + +(b[7] << 3) + +(b[0] << 4) + +(b[4] << 5) + +(b[2] << 6) + +(b[6] << 7); + for (i = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'e'; break; + case 'b': rules[*index][i] = 'd'; break; + case 'c': rules[*index][i] = 'h'; break; + case 'd': rules[*index][i] = 'l'; break; + case 'e': rules[*index][i] = 'i'; break; + case 'f': rules[*index][i] = 'a'; break; + case 'g': rules[*index][i] = 'c'; break; + case 'h': rules[*index][i] = 'k'; break; + case 'i': rules[*index][i] = 'f'; break; + case 'j': rules[*index][i] = 'b'; break; + case 'k': rules[*index][i] = 'g'; break; + case 'l': rules[*index][i] = 'j'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// rotate_z +// rotate rule around z and add +// +void rotate_z(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[2] << 0) + +(b[0] << 1) + +(b[3] << 2) + +(b[1] << 3) + +(b[6] << 4) + +(b[4] << 5) + +(b[7] << 6) + +(b[5] << 7); + for (i = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'b'; break; + case 'b': rules[*index][i] = 'c'; break; + case 'c': rules[*index][i] = 'd'; break; + case 'd': rules[*index][i] = 'a'; break; + case 'e': rules[*index][i] = 'f'; break; + case 'f': rules[*index][i] = 'g'; break; + case 'g': rules[*index][i] = 'h'; break; + case 'h': rules[*index][i] = 'e'; break; + case 'i': rules[*index][i] = 'j'; break; + case 'j': rules[*index][i] = 'k'; break; + case 'k': rules[*index][i] = 'l'; break; + case 'l': rules[*index][i] = 'i'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// print_rules +// print the rule table +// +void print_rules(char rules[255][20]) { + int i,b; + printf("76543210\n"); + for (i = 0; i < 256; ++i) { + for (b = 7; b >= 0; --b) { + printf("%d",(i & (1 << b)) >> b); + } + printf(" %d %s\n",i,rules[i]); + } + } +// add_rules +// add a rule and its variants to the table +// +void add_rules(char rules[255][20], int index, char *edges) { + int i,j,k,l; + strcpy(rules[index],edges); + for (i=0; i<4; ++i) { + for (j=0; j<4; ++j) { + for (k=0; k<4; ++k) { + rotate_x(rules,&index); + } + rotate_y(rules,&index); + } + rotate_z(rules,&index); + } + } +// +// init_rules +// create the rule table +// +void init_rules(char rules[255][20]) { + int i,j; + for (i = 0; i < 256; ++i) + for (j = 0; j < 20; ++j) + rules[i][j] = 0; + add_rules(rules,0b00000000,""); // 0 + add_rules(rules,0b11111111,""); // ~0 + add_rules(rules,0b00000001,"eda"); // 1 + add_rules(rules,0b11111110,"ade"); // ~1 + add_rules(rules,0b00000011,"fed dbf"); // 2 + add_rules(rules,0b11111100,"def fbd"); // ~2 + add_rules(rules,0b00100001,"eda jif"); // 3 + add_rules(rules,0b11011110,"ade fij"); // ~3 + add_rules(rules,0b10000001,"eda gkj"); // 4 + add_rules(rules,0b01111110,"ade jkg"); // ~4 + add_rules(rules,0b00001110,"fhg fdh fad"); // 5 + add_rules(rules,0b11110001,"ghf hdf daf"); // ~5 + add_rules(rules,0b10000011,"fed fdb gkj"); // 6 + add_rules(rules,0b01111100,"def bdf jkg"); // ~6 + add_rules(rules,0b10010010,"bfa ile gkj"); // 7 + add_rules(rules,0b01101101,"afb eli jkg"); // ~7 + add_rules(rules,0b00001111,"ehg feg"); // 8 + add_rules(rules,0b11110000,"ghe gef"); // ~8 + add_rules(rules,0b01001101,"elk eka akg agb"); // 9 + add_rules(rules,0b10110010,"kle ake gka bga"); // ~9 + add_rules(rules,0b10011001,"ild ida ckj cjb"); // 10 + add_rules(rules,0b01100110,"dli adi jkc bjc"); // ~10 + add_rules(rules,0b10001101,"hkj hja hae ajb"); // 11 + add_rules(rules,0b01110010,"jkh ajh eah bja"); // ~11 + add_rules(rules,0b00011110,"ile hgf hfd dfa"); // 12 + add_rules(rules,0b11100001,"eli fgh dfh afd"); // ~12 + add_rules(rules,0b01101001,"eda bcg lkh jif"); // 13 + add_rules(rules,0b10010110,"ade gcb hkl fij"); // ~13 + add_rules(rules,0b01001110,"lkg lga lad agf"); // 14 + add_rules(rules,0b10110001,"gkl agl dal fga"); // ~14 + } +// +// vertex +// add a triangle vertex +// +void vertex(char c, int x, int y, int z, float voxel_size, float t, uint32_t *w, float *array) { + switch(c) { + case 'a': + array[0] = x+(w[0]-t)/(w[0]-((float) w[1])); + array[1] = y; + array[2] = z; + break; + case 'b': + array[0] = x+1; + array[1] = y+(w[1]-t)/(w[1]-((float) w[3])); + array[2] = z; + break; + case 'c': + array[0] = x+(w[2]-t)/(w[2]-((float) w[3])); + array[1] = y+1; + array[2] = z; + break; + case 'd': + array[0] = x; + array[1] = y+(w[0]-t)/(w[0]-((float) w[2])); + array[2] = z; + break; + case 'e': + array[0] = x; + array[1] = y; + array[2] = z+(w[0]-t)/(w[0]-((float) w[4])); + break; + case 'f': + array[0] = x+1; + array[1] = y; + array[2] = z+(w[1]-t)/(w[1]-((float) w[5])); + break; + case 'g': + array[0] = x+1; + array[1] = y+1; + array[2] = z+(w[3]-t)/(w[3]-((float) w[7])); + break; + case 'h': + array[0] = x; + array[1] = y+1; + array[2] = z+(w[2]-t)/(w[2]-((float) w[6])); + break; + case 'i': + array[0] = x+(w[4]-t)/(w[4]-((float) w[5])); + array[1] = y; + array[2] = z+1; + break; + case 'j': + array[0] = x+1; + array[1] = y+(w[5]-t)/(w[5]-((float) w[7])); + array[2] = z+1; + break; + case 'k': + array[0] = x+(w[6]-t)/(w[6]-((float) w[7])); + array[1] = y+1; + array[2] = z+1; + break; + case 'l': + array[0] = x; + array[1] = y+(w[4]-t)/(w[4]-((float) w[6])); + array[2] = z+1; + break; + } + array[0] = voxel_size*array[0]; + array[1] = voxel_size*array[1]; + array[2] = voxel_size*array[2]; + } +// +// triangulate +// triangulate voxel at lattice site x,y,z with vertex weights w +// +void triangulate(int x, int y, int z, float voxel_size, float t, uint32_t *w, char rules[255][20], struct fab_vars *v) { + int i,index; + char c; + // + // set index code + // + index = ((w[0] >= t) ? 0 : 1) + + ((w[1] >= t) ? 0 : 2) + + ((w[2] >= t) ? 0 : 4) + + ((w[3] >= t) ? 0 : 8) + + ((w[4] >= t) ? 0 : 16) + + ((w[5] >= t) ? 0 : 32) + + ((w[6] >= t) ? 0 : 64) + + ((w[7] >= t) ? 0 : 128); + // + // add triangles for rule + // + i = 0; + while (1) { + // + // loop over rule chars + // + c = rules[index][i]; + if (c == 0) + // + // end of rule + // + break; + else if (c == ' ') { + // + // space between rules + // + i += 1; + continue; + } + else { + // + // create triangle for rule + // + v->mesh->last = malloc(sizeof(struct fab_mesh_triangle_type)); + v->mesh->last->previous = v->mesh->triangle; + v->mesh->triangle->next = v->mesh->last; + v->mesh->triangle = v->mesh->last; + v->mesh->triangle->next = 0; + v->mesh->triangle->attribute = 0; + v->mesh->triangle->normal[0] = v->mesh->triangle->normal[1] = v->mesh->triangle->normal[2] = 0; + // + // add vertices for rule + // + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v0); + i += 1; + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v1); + i += 1; + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v2); + i += 1; + } + } + } + +void fab_write_stl(struct fab_vars *v, char *output_file_name) { + // + // write mesh as STL + // + FILE *output_file; + char buf[80]; + uint32_t count; + // + // open output file + // + output_file = fopen(output_file_name, "wb"); + if (output_file == 0) { + printf("fab.c: oops -- can't open %s\n",output_file_name); + exit(-1); + } + // + // write header + // + fwrite(buf,80,1,output_file); + // + // write count + // + count = 0; + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle->next != 0) { + v->mesh->triangle = v->mesh->triangle->next; + count += 1; + } + fwrite(&count,4,1,output_file); + // + // write triangles + // + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle->next != 0) { + v->mesh->triangle = v->mesh->triangle->next; + fwrite(v->mesh->triangle->normal,4,3,output_file); + fwrite(v->mesh->triangle->v0,4,3,output_file); + fwrite(v->mesh->triangle->v1,4,3,output_file); + fwrite(v->mesh->triangle->v2,4,3,output_file); + fwrite(&(v->mesh->triangle->attribute),2,1,output_file); + } + // + // return + // + printf("wrote %d triangles to %s\n",count,output_file_name); + fclose(output_file); + } + +float interp(int x,int y,int i,int j,int k,uint32_t **lower_array,uint32_t **upper_array,int p) { + // + // trilinear interpolation within a voxel + // + return (lower_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + upper_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0))); + } + +int main(int argc, char **argv) { + // + // local vars + // + GifFileType *GIFfile; + GifRecordType GIFtype; + GifByteType *GIFextension; + GifPixelType *GIFline; + uint32_t w[8],**lower_array,**upper_array; + int x,y,z,i,j,k,n,p,imin,imax; + int image_width,image_height,image_count,color_resolution,GIFcode,ret; + float threshold,voxel_size; + char comment[256],rules[255][20]; + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6))) { + printf("command line: gif_stl in.gif out.stl [threshold [size [points [angle]]]]\n"); + printf(" in.gif = input GIF section file\n"); + printf(" out.stl = output STL file\n"); + printf(" threshold: surface intensity threshold (0 = min, 1 = max, default 0.5))\n"); + printf(" size = voxel size (mm, default from file))\n"); + printf(" points = points to interpolate per point (default 0)\n"); + printf(" to be implemented: angle = minimum relative face angle to decimate vertices (default 0)\n"); + exit(-1); + } + p = 0; + threshold = 0.5; + voxel_size = -1; + image_width = -1; + image_height = -1; + image_count = -1; + if (argc >= 4) + sscanf(argv[3],"%f",&threshold); + if (argc >= 5) + sscanf(argv[4],"%f",&voxel_size); + if (argc >= 6) + sscanf(argv[5],"%d",&p); + // + // initialize the rule table + // + init_rules(rules); + // + // scan the file + // + printf("read %s\n",argv[1]); + color_resolution = -1; + GIFfile = DGifOpenFileName(argv[1]); + if (GIFfile == NULL) { + printf("gif_stl: oops -- can not open %s\n",argv[1]); + exit(-1); + } + GIFline = malloc(MAX_LINE*sizeof(GifPixelType)); + imin = 256; + imax = 0; + do { + DGifGetRecordType(GIFfile,&GIFtype); + switch (GIFtype) { + case IMAGE_DESC_RECORD_TYPE: + DGifGetImageDesc(GIFfile); + image_width = GIFfile->SWidth; + image_height = GIFfile->SHeight; + image_count = GIFfile->ImageCount; + color_resolution = GIFfile->SColorResolution; + for (y = 0; y < GIFfile->SHeight; ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_stl: oops -- error reading line\n"); + exit(-1); + } + for (x = 0; x < GIFfile->SWidth; ++x) { + if (GIFline[x] < imin) imin = GIFline[x]; + if (GIFline[x] > imax) imax = GIFline[x]; + } + } + break; + case EXTENSION_RECORD_TYPE: + DGifGetExtension(GIFfile,&GIFcode,&GIFextension); + if (GIFcode == COMMENT_EXT_FUNC_CODE) { + n = GIFextension[0]; + for (i = 1; i <= n; ++i) + comment[i-1] = GIFextension[i]; + comment[n] = 0; + if (voxel_size == -1) + sscanf(comment,"mm per pixel: %f;",&voxel_size); + } + while (GIFextension != NULL) + DGifGetExtensionNext(GIFfile,&GIFextension); + break; + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(GIFfile); + break; + case TERMINATE_RECORD_TYPE: + break; + case UNDEFINED_RECORD_TYPE: + printf("gif_stl: oops -- undefined GIF record type\n"); + exit(-1); + break; + } + } while (GIFtype != TERMINATE_RECORD_TYPE); + if (GIFfile == NULL) { + printf("gif_stl: oops -- can not open %s\n",argv[1]); + exit(-1); + } + if (voxel_size == -1) { + voxel_size = 1.0; + printf(" no pixel size found, assuming 1 mm\n"); + } + printf(" voxel size (mm): %f, color resolution (bits): %d\n",voxel_size,color_resolution); + printf(" intensity min: %d max: %d\n",imin,imax); + printf(" number of images: %d, image width %d, image height %d\n",image_count,image_width,image_height); + // + // set threshold + // + threshold = imin + threshold*(imax-imin); + // + // add empty border + // + image_width += 2; + image_height += 2; + image_count += 2; + // + // allocate arrays + // + lower_array = malloc(image_height*sizeof(uint32_t *)); + for (y = 0; y < image_height; ++y) { + lower_array[y] = malloc(image_width*sizeof(uint32_t)); + for (x = 0; x < image_width; ++x) + lower_array[y][x] = 0; + } + upper_array = malloc(image_height*sizeof(uint32_t *)); + for (y = 0; y < image_height; ++y) { + upper_array[y] = malloc(image_width*sizeof(uint32_t)); + for (x = 0; x < image_width; ++x) + upper_array[y][x] = 0; + } + // + // read the file + // + DGifCloseFile(GIFfile); + GIFfile = DGifOpenFileName(argv[1]); + if (GIFfile == NULL) { + printf("gif_stl: oops -- can not open %s\n",argv[1]); + exit(-1); + } + z = 0; + v.mesh = malloc(sizeof(struct fab_mesh_type)); + v.mesh->triangle = malloc(sizeof(struct fab_mesh_triangle_type)); + v.mesh->first = v.mesh->triangle; + v.mesh->last = v.mesh->triangle; + v.mesh->triangle->previous = v.mesh->triangle->next = 0; + do { + DGifGetRecordType(GIFfile,&GIFtype); + switch (GIFtype) { + case IMAGE_DESC_RECORD_TYPE: + // + // read image + // + DGifGetImageDesc(GIFfile); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z); + // + // read layer + // + for (y = 0; y < (image_height-2); ++y) { + ret = DGifGetLine(GIFfile,GIFline,GIFfile->SWidth); + if (ret != GIF_OK) { + printf("gif_stl: oops -- error reading line\n"); + exit(-1); + } + for (x = 0; x < (image_width-2); ++x) { + lower_array[y+1][x+1] = upper_array[y+1][x+1]; + upper_array[y+1][x+1] = GIFline[x]; + } + } + if (p == 0) { + // + // no interpolation, loop over layer voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + w[0] = lower_array[y][x]; + w[1] = lower_array[y][x+1]; + w[2] = lower_array[y+1][x]; + w[3] = lower_array[y+1][x+1]; + w[4] = upper_array[y][x]; + w[5] = upper_array[y][x+1]; + w[6] = upper_array[y+1][x]; + w[7] = upper_array[y+1][x+1]; + triangulate(x,y,z,voxel_size,threshold,w,rules,&v); + } + } + } + else { + // + // yes interpolation, loop over layer sub-voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + for (i = 0; i <= p; ++i) { + for (j = 0; j <= p; ++j) { + for (k = 0; k <= p; ++k) { + w[0] = interp(x,y,i,j,k,lower_array,upper_array,p); + w[1] = interp(x,y,i+1,j,k,lower_array,upper_array,p); + w[2] = interp(x,y,i,j+1,k,lower_array,upper_array,p); + w[3] = interp(x,y,i+1,j+1,k,lower_array,upper_array,p); + w[4] = interp(x,y,i,j,k+1,lower_array,upper_array,p); + w[5] = interp(x,y,i+1,j,k+1,lower_array,upper_array,p); + w[6] = interp(x,y,i,j+1,k+1,lower_array,upper_array,p); + w[7] = interp(x,y,i+1,j+1,k+1,lower_array,upper_array,p); + triangulate((1+p)*x+i,(1+p)*y+j,(1+p)*z+k,voxel_size,threshold,w,rules,&v); + } + } + } + } + } + } + z += 1; + break; + case EXTENSION_RECORD_TYPE: + DGifGetExtension(GIFfile,&GIFcode,&GIFextension); + while (GIFextension != NULL) + DGifGetExtensionNext(GIFfile,&GIFextension); + break; + case SCREEN_DESC_RECORD_TYPE: + DGifGetScreenDesc(GIFfile); + break; + case TERMINATE_RECORD_TYPE: + break; + case UNDEFINED_RECORD_TYPE: + printf("gif_stl: oops -- undefined GIF record type\n"); + exit(-1); + break; + } + } while (GIFtype != TERMINATE_RECORD_TYPE); + // + // add empty top layer + // + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z); + for (y = 0; y < (image_height-2); ++y) { + for (x = 0; x < (image_width-2); ++x) { + lower_array[y+1][x+1] = upper_array[y+1][x+1]; + upper_array[y+1][x+1] = 0; + } + } + if (p == 0) { + // + // no interpolation, loop over layer voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + w[0] = lower_array[y][x]; + w[1] = lower_array[y][x+1]; + w[2] = lower_array[y+1][x]; + w[3] = lower_array[y+1][x+1]; + w[4] = upper_array[y][x]; + w[5] = upper_array[y][x+1]; + w[6] = upper_array[y+1][x]; + w[7] = upper_array[y+1][x+1]; + triangulate(x,y,z,voxel_size,threshold,w,rules,&v); + } + } + } + else { + // + // yes interpolation, loop over layer sub-voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + for (i = 0; i <= p; ++i) { + for (j = 0; j <= p; ++j) { + for (k = 0; k <= p; ++k) { + w[0] = interp(x,y,i,j,k,lower_array,upper_array,p); + w[1] = interp(x,y,i+1,j,k,lower_array,upper_array,p); + w[2] = interp(x,y,i,j+1,k,lower_array,upper_array,p); + w[3] = interp(x,y,i+1,j+1,k,lower_array,upper_array,p); + w[4] = interp(x,y,i,j,k+1,lower_array,upper_array,p); + w[5] = interp(x,y,i+1,j,k+1,lower_array,upper_array,p); + w[6] = interp(x,y,i,j+1,k+1,lower_array,upper_array,p); + w[7] = interp(x,y,i+1,j+1,k+1,lower_array,upper_array,p); + triangulate((1+p)*x+i,(1+p)*y+j,(1+p)*z+k,voxel_size,threshold,w,rules,&v); + } + } + } + } + } + } + printf("\n"); + // + // write STL + // + fab_write_stl(&v,argv[2]); + // + // exit + // + DGifCloseFile(GIFfile); + exit(0); + } diff --git a/src/core/path_array.c b/src/core/path_array.c new file mode 100644 index 0000000..4463400 --- /dev/null +++ b/src/core/path_array.c @@ -0,0 +1,69 @@ +// +// path_array.c +// array path +// +// Neil Gershenfeld +// CBA MIT 10/6/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars vin; + init_vars(&vin); + struct fab_vars vout; + init_vars(&vout); + int nx,ny; + float dx,dy; + // + // command line args + // + if (!((argc == 5) || (argc == 6) || (argc == 7))) { + printf("command line: path_array in.path out.path nx ny [dx [dy]]\n"); + printf(" in.path = input path file\n"); + printf(" out.path = output path file\n"); + printf(" nx = number of horizonal array elements\n"); + printf(" ny = number of vertical array elements\n"); + printf(" dx = array element horizontal spacing (optional, mm, default 0)\n"); + printf(" dy = array element vertical spacing (optional, mm, default dx)\n"); + exit(-1); + } + if (argc == 5) { + sscanf(argv[3],"%d",&nx); + sscanf(argv[4],"%d",&ny); + dx = 0; + dy = dx; + } + if (argc == 6) { + sscanf(argv[3],"%d",&nx); + sscanf(argv[4],"%d",&ny); + sscanf(argv[5],"%f",&dx); + dy = dx; + } + else if (argc == 7) { + sscanf(argv[3],"%d",&nx); + sscanf(argv[4],"%d",&ny); + sscanf(argv[5],"%f",&dx); + sscanf(argv[6],"%f",&dy); + } + // + // read path + // + fab_read_path(&vin,argv[1]); + // + // array path + // + fab_path_array(&vin,&vout,nx,ny,dx,dy); + // + // write path + // + fab_write_path(&vout,argv[2]); + } + diff --git a/src/core/path_camm.c b/src/core/path_camm.c new file mode 100644 index 0000000..2da75fa --- /dev/null +++ b/src/core/path_camm.c @@ -0,0 +1,128 @@ +// +// path_camm.c +// convert path to Roland vinylcutter .camm +// +// Neil Gershenfeld +// CBA MIT 9/1/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_camm(struct fab_vars *v, char *output_file_name, float force, float velocity, float ox, float oy, char loc) { + // + // write path to Roland vinylcutter file + // + FILE *output_file; + int x,y,nsegs=0,npts=0; + float scale,xoffset,yoffset; + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"PA;PA;!ST1;!FS%f;VS%f;\n",force,velocity); + scale = 40.0*v->dx/(v->nx-1.0); // 40/mm + if (loc == 'l') { + xoffset = 40.0*(ox); + yoffset = 40.0*(oy); + } + else if (loc == 'r') { + xoffset = 40.0*(ox - v->dx); + yoffset = 40.0*(oy); + } + else if (loc == 'L') { + xoffset = 40.0*(ox); + yoffset = 40.0*(oy - v->dy); + } + else if (loc == 'R') { + xoffset = 40.0*(ox - v->dx); + yoffset = 40.0*(oy - v->dy); + } + v->path->segment = v->path->last; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + fprintf(output_file,"PU%d,%d;\n",x,y); // move up to start point + fprintf(output_file,"PU%d,%d;\n",x,y); // hack: repeat in case comm dropped + fprintf(output_file,"PD%d,%d;\n",x,y); // move down + fprintf(output_file,"PD%d,%d;\n",x,y); // hack: repeat in case comm dropped + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + fprintf(output_file,"PD%d,%d;\n",x,y); // move down + fprintf(output_file,"PD%d,%d;\n",x,y); // hack: repeat in case comm dropped + npts += 1; + } + //fprintf(output_file,"\n",x,y); + if (v->path->segment->previous == 0) + break; + v->path->segment = v->path->segment->previous; + } + fprintf(output_file,"PU0,0;\n"); // pen up to origin + fprintf(output_file,"PU0,0;\n"); // hack: repeat in case comm dropped + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float ox,oy,force,velocity; + char loc; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 7) || (argc == 8))) { + printf("command line: path_camm in.path out.camm [force [velocity [x y [location]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.camm = output Roland vinylcutter file\n"); + printf(" force = cutting force (optional, grams, default 45)\n"); + printf(" velocity = cutting speed (optional, cm/s, default 2)\n"); + printf(" x = origin x (optional, mm, default 0)\n"); + printf(" y = origin y (optional, mm, default 0)\n"); + printf(" location = origin location (optional, bottom left:l, bottom right:r, top left:L, top right:R, default l)\n"); + exit(-1); + } + force = 45; + velocity = 2; + ox = 0; + oy = 0; + loc = 'l'; + if (argc >= 4) { + sscanf(argv[3],"%f",&force); + } + if (argc >= 5) { + sscanf(argv[4],"%f",&velocity); + } + if (argc >= 7) { + sscanf(argv[5],"%f",&ox); + sscanf(argv[6],"%f",&oy); + } + if (argc >= 8) { + sscanf(argv[7],"%c",&loc); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write .epi + // + fab_write_camm(&v,argv[2],force,velocity,ox,oy,loc); + } + diff --git a/src/core/path_dxf.c b/src/core/path_dxf.c new file mode 100644 index 0000000..5635fa7 --- /dev/null +++ b/src/core/path_dxf.c @@ -0,0 +1,149 @@ +// +// path_dxf.c +// convert path to DXF +// todo: 3D paths +// +// Neil Gershenfeld +// CBA MIT 8/25/12 +// +// (c) Massachusetts Institute of Technology 2012 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_dxf(struct fab_vars *v, char *output_file_name) { + // + // write path to DXF file + // + int x,y,z; + float x0,y0,z0,x1,y1,z1; + FILE *output_file; + int nsegs=0, npts=0; + float scale,units; + units = 1/25.4; + scale = v->dx/(v->nx-1.0); + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"999\nDXF written by fab modules path_dxf\n"); + fprintf(output_file,"0\nSECTION\n"); + fprintf(output_file,"2\nHEADER\n"); + fprintf(output_file,"9\n$ACADVER\n1\nAC1009\n"); + fprintf(output_file,"9\n$EXTMIN\n"); + fprintf(output_file,"10\n%f\n",units*v->xmin); + fprintf(output_file,"20\n%f\n",units*v->ymin); + if (v->path->dof == 3) + fprintf(output_file,"30\n%f\n",units*(v->zmin)); + fprintf(output_file,"9\n$EXTMAX\n"); + fprintf(output_file,"10\n%f\n",units*(v->xmin+v->dx)); + fprintf(output_file,"20\n%f\n",units*(v->ymin+v->dy)); + if (v->path->dof == 3) + fprintf(output_file,"30\n%f\n",units*(v->zmin+v->dz)); + fprintf(output_file,"0\nENDSEC\n"); + /* + fprintf(output_file,"0\nSECTION\n"); + fprintf(output_file,"2\nTABLES\n"); + fprintf(output_file,"0\nTABLE\n"); + fprintf(output_file,"2\nLTYPE\n70\n1\n"); + fprintf(output_file,"0\nLTYPE\n"); + fprintf(output_file,"2\nCONTINUOUS\n"); + fprintf(output_file,"70\n64\n3\n"); + fprintf(output_file,"Solid line\n"); + fprintf(output_file,"72\n65\n73\n0\n40\n0.000000\n"); + fprintf(output_file,"0\nENDTAB\n"); + fprintf(output_file,"0\nTABLE\n2\nLAYER\n70\n1\n"); + fprintf(output_file,"0\nLAYER\n2\ndefault\n70\n64\n62\n7\n6\n"); + fprintf(output_file,"CONTINUOUS\n0\nENDTAB\n"); + fprintf(output_file,"0\nENDSEC\n"); + fprintf(output_file,"0\nSECTION\n"); + fprintf(output_file,"2\nBLOCKS\n"); + fprintf(output_file,"0\nENDSEC\n"); + */ + fprintf(output_file,"0\nSECTION\n"); + fprintf(output_file,"2\nENTITIES\n"); + v->path->segment = v->path->first; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + if (v->path->dof == 3) + z = v->path->segment->point->first->next->next->value; + x0 = units*(v->xmin+scale*x); + y0 = units*(v->ymin+scale*y); + if (v->path->dof == 3) + z0 = units*(v->zmin+scale*z); + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + if (v->path->dof == 3) + z = v->path->segment->point->first->next->next->value; + x1 = units*(v->xmin+scale*x); + y1 = units*(v->ymin+scale*y); + if (v->path->dof == 3) + z1 = units*(v->zmin+scale*z); + fprintf(output_file,"0\nLINE\n"); + fprintf(output_file,"10\n%f\n",x0); + fprintf(output_file,"20\n%f\n",y0); + if (v->path->dof == 3) + fprintf(output_file,"30\n%f\n",z0); + fprintf(output_file,"11\n%f\n",x1); + fprintf(output_file,"21\n%f\n",y1); + if (v->path->dof == 3) + fprintf(output_file,"31\n%f\n",z1); + x0 = x1; + y0 = y1; + if (v->path->dof == 3) + z0 = z1; + npts += 1; + } + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + fprintf(output_file,"0\nENDSEC\n"); + fprintf(output_file,"0\nEOF\n"); + fclose(output_file); + printf("write %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + struct fab_vars vnew; + init_vars(&vnew); + char view; + int x,y,z,nz,dz; + float scale; + // + // command line args + // + if (!(argc == 3)) { + printf("command line: path_dxf in.path out.dxf\n"); + printf(" in.path = input path file\n"); + printf(" out.dxf = output DXF file\n"); + exit(-1); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write dxf + // + fab_write_dxf(&v,argv[2]); + } + diff --git a/src/core/path_epi.c b/src/core/path_epi.c new file mode 100644 index 0000000..5775678 --- /dev/null +++ b/src/core/path_epi.c @@ -0,0 +1,182 @@ +// +// path_epi.c +// convert path to Epilog lasercutter .epi +// +// Neil Gershenfeld 8/18/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +void fab_write_epi(struct fab_vars *v, char *output_file_name, int power, int speed, int focus, float ox, float oy, char loc, int rate, int max_power) { + // + // write path to Epilog lasercutter file + // + FILE *output_file; + int i,x,y,z,current_z,layer_power,nsegs=0,npts=0; + float scale,xoffset,yoffset; + output_file = fopen(output_file_name,"w"); + scale = 600.0*v->dx/(25.4*(v->nx-1.0)); // 600 DPI + if (loc == 'l') { + xoffset = 600.0*(ox)/25.4; + yoffset = 600.0*(oy - v->dy)/25.4; + } + else if (loc == 'r') { + xoffset = 600.0*(ox - v->dx)/25.4; + yoffset = 600.0*(oy - v->dy)/25.4; + } + else if (loc == 'L') { + xoffset = 600.0*(ox)/25.4; + yoffset = 600.0*(oy)/25.4; + } + else if (loc == 'R') { + xoffset = 600.0*(ox - v->dx)/25.4; + yoffset = 600.0*(oy)/25.4; + } + if (focus == 0) + // + // init with autofocus off + // + fprintf(output_file,"%%-12345X@PJL JOB NAME=%s\r\nE@PJL ENTER LANGUAGE=PCL\r\n&y0A&l0U&l0Z&u600D*p0X*p0Y*t600R*r0F&y50P&z50S*r6600T*r5100S*r1A*rC%%1BIN;XR%d;YP%d;ZS%d;\n",output_file_name,rate,power,speed); + else + // + // init with autofocus on + // + fprintf(output_file,"%%-12345X@PJL JOB NAME=%s\r\nE@PJL ENTER LANGUAGE=PCL\r\n&y1A&l0U&l0Z&u600D*p0X*p0Y*t600R*r0F&y50P&z50S*r6600T*r5100S*r1A*rC%%1BIN;XR%d;YP%d;ZS%d;\n",output_file_name,rate,power,speed); + current_z = 0; + fprintf(output_file,"YP%d;\n",power); + v->path->segment = v->path->last; + while (1) { + // + // follow segments in reverse order + // + v->path->segment->point = v->path->segment->first; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * v->path->segment->point->first->next->value; + if (v->path->dof >= 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + layer_power = power + (max_power-power) * z / (v->nz - 1.0); + fprintf(output_file,"YP%d;\n",layer_power); + current_z = z; + } + } + if (x < 0) x = 0; + if (y < 0) y = 0; + fprintf(output_file,"PU%d,%d;",x,y); + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * v->path->segment->point->first->next->value; + if (v->path->dof >= 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + layer_power = power + (max_power-power) * z / (v->nz - 1.0); + fprintf(output_file,"YP%d;\n",layer_power); + current_z = z; + } + } + if (x < 0) x = 0; + if (y < 0) y = 0; + fprintf(output_file,"PD%d,%d;",x,y); + npts += 1; + } + fprintf(output_file,"\n"); + if (v->path->segment == v->path->first) + break; + v->path->segment = v->path->segment->previous; + } + fprintf(output_file,"%%0B%%1BPUE%%-12345X@PJL EOJ \r\n"); + // + // end-of-file padding hack from Epilog print driver + // + for (i = 0; i < 10000; ++i) + fprintf(output_file," "); + // fprintf(output_file,"%c",26); // ^z + // + // close and return + // + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int power,max_power,speed,focus,rate; + float ox,oy; + char loc; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 8) || (argc == 9) || (argc == 10) || (argc == 11))) { + printf("command line: path_epi in.path out.epi [power [speed [focus [x y [ location [rate [max_power]]]]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.epi= output Epilog lasercutter file\n"); + printf(" power = percent power, for minimum z value (optional, 0-100, default 50)\n"); + printf(" speed = percent speed (optional, 0-100, default 50)\n"); + printf(" focus = autofocus (optional, 0=off | 1=on, default on)\n"); + printf(" x = origin x (optional, mm, default 0 = left side of bed)\n"); + printf(" y = origin y (optional, mm, default 0 = back side of bed, front positive)\n"); + printf(" location = origin location (optional, bottom left:l, bottom right:r, top left:L, top right:R, default l)\n"); + printf(" rate = pulse rate (optional, frequency, default 2500)\n"); + printf(" max_power = percent power, for maximum z value (optional, 0-100, default power)\n"); + exit(-1); + } + power = 50; + speed = 50; + focus = 1; + ox = 0; + oy = 0; + loc = 'l'; + rate = 2500; + max_power = power; + if (argc >= 4) { + sscanf(argv[3],"%d",&power); + } + if (argc >= 5) { + sscanf(argv[4],"%d",&speed); + } + if (argc >= 6) { + sscanf(argv[5],"%d",&focus); + } + if (argc >= 8) { + sscanf(argv[6],"%f",&ox); + sscanf(argv[7],"%f",&oy); + } + if (argc >= 9) { + sscanf(argv[8],"%c",&loc); + } + if (argc >= 10) { + sscanf(argv[9],"%d",&rate); + } + if (argc >= 11) { + sscanf(argv[10],"%d",&max_power); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write .epi + // + fab_write_epi(&v,argv[2],power,speed,focus,ox,oy,loc,rate,max_power); + } + diff --git a/src/core/path_eps.c b/src/core/path_eps.c new file mode 100644 index 0000000..11f421d --- /dev/null +++ b/src/core/path_eps.c @@ -0,0 +1,182 @@ +// +// path_eps.c +// convert .path to .eps +// +// Neil Gershenfeld 7/4/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +void fab_write_eps(struct fab_vars *v, char *output_file_name) { + // + // write path to PostScript file + // + int x,y,z,current_z; + float margin = 0.5; // lower left margin, in inches + float gray; + FILE *output_file; + int nsegs=0, npts=0; + float scale; + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"%%! path_eps output\n"); + fprintf(output_file,"%%%%BoundingBox: %f %f %f %f\n",72.0*margin,72.0*margin, + 72.0*(margin+v->dx/25.4),72.0*(margin+v->dy/25.4)); + fprintf(output_file,"/m {moveto} def\n"); + fprintf(output_file,"/l {lineto} def\n"); + fprintf(output_file,"/g {setgray} def\n"); + fprintf(output_file,"/s {stroke} def\n"); + fprintf(output_file,"72 72 scale\n"); + fprintf(output_file,"%f %f translate\n",margin,margin); + fprintf(output_file,"1 setlinewidth\n"); + scale = v->dx/(25.4*(v->nx-1.0)); + fprintf(output_file,"%f %f scale\n",scale,scale); + current_z = 0; + fprintf(output_file,"0 g\n"); + v->path->segment = v->path->first; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + if (v->path->dof == 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + gray = 0.9 * z / (v->nz - 1.0); + fprintf(output_file,"%.3f g\n",gray); + current_z = z; + } + } + fprintf(output_file,"%d %d m\n",x,y); + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + fprintf(output_file,"%d %d l\n",x,y); + if (v->path->dof == 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + gray = 0.9 * 0.5 * (z + current_z) / (v->nz - 1.0); + fprintf(output_file,"s %.3f g %d %d m\n",gray,x,y); + current_z = z; + } + } + npts += 1; + } + fprintf(output_file,"s\n"); + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + //fprintf(output_file,"showpage\n"); + fclose(output_file); + printf("write %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + struct fab_vars vnew; + init_vars(&vnew); + char view; + int x,y,z,nz,dz; + float scale; + // + // command line args + // + if (!((argc == 3) || (argc == 4))) { + printf("command line: path_eps in.path out.eps [view]\n"); + printf(" in.path = input path file\n"); + printf(" out.eps= output PostScript file\n"); + printf(" view = view projection(s) (optional, z|3, default z)\n"); + exit(-1); + } + view = 'z'; + if (argc == 4) + view = argv[3][0]; + // + // read path + // + fab_read_path(&v,argv[1]); + // + // check view + // + if (view == 'z') { + // + // write eps + // + fab_write_eps(&v,argv[2]); + } + else if (view == '3') { + if (v.path->dof < 3) { + printf("path_eps: oops -- path not 3D\n"); + exit(-1); + } + nz = v.nx * v.dz / v.dx; + scale = ((float) nz) / v.nz; + vnew.nx = v.nx + nz; + vnew.ny = v.ny + nz; + vnew.nz = v.nz; + vnew.dx = v.dx + v.dz; + vnew.dy = v.dy + v.dz; + vnew.dz = v.dz; + vnew.xmin = v.xmin; + vnew.ymin = v.ymin; + vnew.zmin = v.zmin; + fab_path_start(&vnew,v.path->dof); + // + // follow path + // + v.path->segment = v.path->first; + while (1) { + // + // follow segments + // + v.path->segment->point = v.path->segment->first; + fab_path_segment(&vnew); + while (1) { + // + // follow points + // + fab_path_point(&vnew); + z = v.path->segment->point->first->next->next->value; + dz = nz - scale*z; + y = dz + v.path->segment->point->first->next->value; + x = dz + v.path->segment->point->first->value; + fab_path_axis(&vnew,x); + fab_path_axis(&vnew,y); + fab_path_axis(&vnew,z); + if (v.path->segment->point->next == 0) + break; + v.path->segment->point = v.path->segment->point->next; + } + if (v.path->segment->next == 0) + break; + v.path->segment = v.path->segment->next; + } + // + // write eps + // + fab_write_eps(&vnew,argv[2]); + } + } + diff --git a/src/core/path_g.c b/src/core/path_g.c new file mode 100644 index 0000000..631e8e9 --- /dev/null +++ b/src/core/path_g.c @@ -0,0 +1,273 @@ +// +// path_g.c +// convert path to G codes +// +// Neil Gershenfeld, David Carr +// CBA MIT 8/10/11 +// +// (c) Massachusetts Institute of Technology 2011 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_g(struct fab_vars *v, char *output_file_name, int direction, float z_jog, float feed_rate, float z_feed_rate, float spindle_speed, int tool, int coolant) { + // + // write path to G-code file + // + FILE *output_file; + int i,nsegs=0,npts=0; + float units,xscale,yscale,zscale,x,y,z,xoffset,yoffset,zoffset; + output_file = fopen(output_file_name,"w"); + units = 1.0/25.4; // inches + xscale = units*v->dx/(v->nx-1.0); + yscale = units*v->dy/(v->ny-1.0); + if (v->nz > 1) + zscale = units*v->dz/v->nz; + else + zscale = 0; + xoffset = units*v->xmin; + yoffset = units*v->ymin; + zoffset = units*v->zmin; + z_jog = units*z_jog; + feed_rate = 60*units*feed_rate; // feed rate in inches per minute + z_feed_rate = 60*units*z_feed_rate; + // + // Write G code header + // + //fprintf(output_file, "; G-Code generated by MIT CBA fab modules\n"); + fprintf(output_file, "%%\n"); // tape start + //fprintf(output_file, "; http://kokompe.cba.mit.edu/dist\n\n"); + // Clear all state: XY plane, inch mode, cancel diameter compensation, cancel length offset + // coordinate system 1, cancel motion, non-incremental motion, feed/minute mode + fprintf(output_file,"G17\n"); + fprintf(output_file,"G20\n"); + fprintf(output_file,"G40\n"); + fprintf(output_file,"G49\n"); + fprintf(output_file,"G54\n"); + fprintf(output_file,"G80\n"); + fprintf(output_file,"G90\n"); + fprintf(output_file,"G94\n"); + fprintf(output_file,"T%dM06\n",tool); // tool selection, tool change + fprintf(output_file,"F%0.4f\n",feed_rate); // feed rate + fprintf(output_file,"S%0.4f\n",spindle_speed); // spindle speed + if (coolant == 1) + fprintf(output_file,"M08\n"); // coolant on + fprintf(output_file,"G00Z%0.4f\n",z_jog); // move up before starting spindle + fprintf(output_file,"M03\n"); // spindle on clockwise + fprintf(output_file,"G04 P1\n"); // give spindle 1 second to spin up + // + // follow segments in reverse order (mill boundaries last) + // + v->path->segment = v->path->last; + while (1) { + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->last; + else + // + // climb + // + v->path->segment->point = v->path->segment->first; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + // + // move to first point + // + fprintf(output_file,"G00X%0.4fY%0.4fZ%0.4f\n",x,y,z_jog); + // + // move down + // + if (v->path->dof == 2) { + fprintf(output_file,"G01Z%0.4f F%0.4f\n",zoffset,z_feed_rate); + fprintf(output_file,"F%0.4f\n",feed_rate); //restore XY feed rate + } + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"G01Z%0.4f F%0.4f\n",z,z_feed_rate); + fprintf(output_file,"F%0.4f\n",feed_rate); + } + else { + printf("path_g: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + nsegs += 1; + while (1) { + // + // check if last point + // + if (direction == 0) { + // + // conventional + // + if (v->path->segment->point->previous == 0) { + fprintf(output_file,"Z%0.4f\n",z_jog); + break; + } + } + else { + // + // climb + // + if (v->path->segment->point->next == 0) { + fprintf(output_file,"Z%0.4f\n",z_jog); + break; + } + } + // + // move to next point + // + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->point->previous; + else + // + // climb + // + v->path->segment->point = v->path->segment->point->next; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 2) + fprintf(output_file,"X%0.4fY%0.4f\n",x,y); + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"X%0.4fY%0.4fZ%0.4f\n",x,y,z); + } + else { + printf("path_g: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + npts += 1; + } + // + // check for previous segment + // + if (v->path->segment->previous == 0) + break; + v->path->segment = v->path->segment->previous; + } + // + // close and return + // + fprintf(output_file,"G00Z%0.4f\n",z_jog); // move up before stopping spindle + fprintf(output_file,"M05\n"); // spindle stop + if (coolant == 1) + fprintf(output_file,"M09\n"); // coolant off + fprintf(output_file,"M30\n"); // program end and reset + fprintf(output_file, "%%\n"); // tape end + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float z_jog,feed_rate,z_feed_rate,spindle_speed; + int direction,tool,coolant; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 7) || (argc == 8) || (argc == 9) || (argc == 10))) { + printf("command line: path_g in.path out.g [direction [z_jog [feed [z_feed [spindle [tool [coolant]]]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.g = output G-code file\n"); + printf(" direction = machining direction (optional, 0 conventional/1 climb, default 0)\n"); + printf(" z_jog = z jog height (optional, mm, default 25)\n"); + printf(" feed = feed rate (optional, mm/s, default 100)\n"); + printf(" z_feed = z plunge rate (optional, mm/s, default xy feed rate)\n"); + printf(" spindle = spindle speed (optional, RPM, default 5000)\n"); + printf(" tool = tool number (optional, default 1)\n"); + printf(" coolant = coolant on/off (optional, 0=off/1=on, default 1)\n"); + exit(-1); + } + if (argc == 3) { + direction = 0; + z_jog = 25.0; + feed_rate = 5.0; + z_feed_rate = feed_rate; + spindle_speed = 5000.0; + tool = 1; + coolant = 1; + } + else if (argc == 4) { + sscanf(argv[3],"%d",&direction); + z_jog = 25.0; + feed_rate = 5.0; + z_feed_rate = feed_rate; + spindle_speed = 5000.0; + tool = 1; + coolant = 1; + } + else if (argc == 5) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + feed_rate = 5.0; + z_feed_rate = feed_rate; + spindle_speed = 5000.0; + tool = 1; + coolant = 1; + } + else if (argc == 6) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + sscanf(argv[5],"%f",&feed_rate); + z_feed_rate = feed_rate; + spindle_speed = 5000.0; + tool = 1; + coolant = 1; + } + else if (argc == 7) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + sscanf(argv[5],"%f",&feed_rate); + sscanf(argv[6],"%f",&z_feed_rate); + spindle_speed = 5000.0; + tool = 1; + coolant = 1; + } + else if (argc == 8) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + sscanf(argv[5],"%f",&feed_rate); + sscanf(argv[6],"%f",&z_feed_rate); + sscanf(argv[7],"%f",&spindle_speed); + tool = 1; + coolant = 1; + } + else if (argc == 9) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + sscanf(argv[5],"%f",&feed_rate); + sscanf(argv[6],"%f",&z_feed_rate); + sscanf(argv[7],"%f",&spindle_speed); + sscanf(argv[8],"%d",&tool); + coolant = 1; + } + else if (argc == 10) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%f",&z_jog); + sscanf(argv[5],"%f",&feed_rate); + sscanf(argv[6],"%f",&z_feed_rate); + sscanf(argv[7],"%f",&spindle_speed); + sscanf(argv[8],"%d",&tool); + sscanf(argv[9],"%d",&coolant); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write G codes + // + fab_write_g(&v,argv[2],direction,z_jog,feed_rate,z_feed_rate,spindle_speed,tool,coolant); + } + diff --git a/src/core/path_info.c b/src/core/path_info.c new file mode 100644 index 0000000..35679b5 --- /dev/null +++ b/src/core/path_info.c @@ -0,0 +1,41 @@ +// +// path_info.c +// report .path info +// +// Neil Gershenfeld 10/3/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// +// todo +// gradient intensity +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float units,resolution; + char axis; + // + // command line args + // + if (argc != 2) { + printf("command line: path_info in.path\n"); + printf(" in.path = input path file\n"); + exit(-1); + } + // + // read path + // + fab_read_path(&v,argv[1]); + } diff --git a/src/core/path_join.c b/src/core/path_join.c new file mode 100644 index 0000000..d519dbf --- /dev/null +++ b/src/core/path_join.c @@ -0,0 +1,64 @@ +// +// path_join.c +// join paths +// +// Neil Gershenfeld +// CBA MIT 11/6/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars vin1; + init_vars(&vin1); + struct fab_vars vin2; + init_vars(&vin2); + struct fab_vars vout; + init_vars(&vout); + float dx,dy; + // + // command line args + // + if (!((argc == 4) || (argc == 5) || (argc == 6))) { + printf("command line: path_join in1.path in2.path out.path [dx [dy]]\n"); + printf(" in1.path = first input path file\n"); + printf(" in2.path = second input path file\n"); + printf(" out.path = joined output path file\n"); + printf(" dx = in1 horizontal offset (optional, mm, default 0)\n"); + printf(" dy = in1 vertical offset (optional, mm, default dx)\n"); + exit(-1); + } + if (argc == 4) { + dx = 0; + dy = dx; + } + if (argc == 5) { + sscanf(argv[4],"%f",&dx); + dy = dx; + } + else if (argc == 6) { + sscanf(argv[4],"%f",&dx); + sscanf(argv[5],"%f",&dy); + } + // + // read paths + // + fab_read_path(&vin1,argv[1]); + fab_read_path(&vin2,argv[2]); + // + // append path + // + fab_path_join(&vin1,&vin2,&vout,dx,dy); + // + // write path + // + fab_write_path(&vout,argv[3]); + } + diff --git a/src/core/path_oms.c b/src/core/path_oms.c new file mode 100644 index 0000000..5dce2fb --- /dev/null +++ b/src/core/path_oms.c @@ -0,0 +1,120 @@ +// +// path_oms.c +// convert path to Resonetics excimer micromachining center .oms +// +// Neil Gershenfeld +// CBA MIT 6/4/13 +// +// (c) Massachusetts Institute of Technology 2013 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_oms(struct fab_vars *v, char *output_file_name, float velocity, float acceleration, int period) { + // + // write path to Epilog lasercutter file + // + FILE *output_file; + float x,y,scale,xoffset,yoffset; + float slew_velocity = 1.0; + float slew_acceleration = 5.0; + int npts=0,nsegs=0; + int settle = 100; + scale = v->dx/(v->nx-1.0); // mm + xoffset = v->xmin; + yoffset = v->ymin; + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"AA LP0,0,0,0,0\n"); // set origin + fprintf(output_file,"PP%d\n",period); // set pulse period (in us) + v->path->segment = v->path->first; + while (1) { + // + // follow segments + // + v->path->segment->point = v->path->segment->first; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + //fprintf(output_file,"VL%.1f,%.1f\n",slew_velocity,slew_velocity); + // redundantly include pulses/s in VL + fprintf(output_file,"VL%.1f,%.1f,,%.0f\n",slew_velocity,slew_velocity,1.0e6/period); + fprintf(output_file,"AC%.1f,%.1f\n",slew_acceleration,slew_acceleration); + fprintf(output_file,"MA%f,%f\n",x,y); + //fprintf(output_file,"VL%.1f,%.1f\n",velocity,velocity); + // redundantly include pulses/s in VL + fprintf(output_file,"VL%.1f,%.1f,,%.0f\n",velocity,velocity,1.0e6/period); + fprintf(output_file,"AC%.1f,%.1f\n",acceleration,acceleration); + fprintf(output_file,"WT%d\n",settle); + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + fprintf(output_file,"CutAbs %f,%f\n",x,y); + npts += 1; + } + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + } + fprintf(output_file,"END\n"); + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float velocity, acceleration; + int period; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6))) { + printf("command line: path_oms in.path out.oms [velocity [acceleration [period]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.oms = output Resonetics excimer micromachining center file\n"); + printf(" velocity (default 0.1)\n"); + printf(" acceleration (default 5.0)\n"); + printf(" period (usec, default 10000)\n"); + exit(-1); + } + if (argc == 3) { + velocity = 0.1; + acceleration = 5.0; + period = 10000; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&velocity); + acceleration = 5.0; + period = 10000; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&velocity); + sscanf(argv[4],"%f",&acceleration); + period = 10000; + } + else if (argc == 6) { + sscanf(argv[3],"%f",&velocity); + sscanf(argv[4],"%f",&acceleration); + sscanf(argv[5],"%d",&period); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write .oms + // + fab_write_oms(&v,argv[2],velocity,acceleration,period); + } diff --git a/src/core/path_ord.c b/src/core/path_ord.c new file mode 100644 index 0000000..840b629 --- /dev/null +++ b/src/core/path_ord.c @@ -0,0 +1,164 @@ +// +// path_ord.c +// convert path to Omax waterjet .ord +// +// Neil Gershenfeld +// CBA MIT 10/5/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" +#define nostart -10000 + +void fab_write_ord(struct fab_vars *v, char *output_file_name, float lead, int quality, float xstart, float ystart) { + // + // write path to ShopBot file + // + FILE *output_file; + int i,nsegs=0,npts=0; + float units,xscale,yscale,x,y,xmin,ymin,x0,y0,x1,y1,xoffset,yoffset,xlead,ylead,dx,dy,norm_x,norm_y,norm; + output_file = fopen(output_file_name,"w"); + units = 1.0/25.4; // inches + xscale = units*v->dx/(v->nx-1.0); + yscale = units*v->dy/(v->ny-1.0); + xoffset = units*v->xmin; + yoffset = units*v->ymin; + lead = units*lead; + // + // write start if supplied + // + if (xstart != nostart) { + xstart = units*xstart; + ystart = units*ystart; + fprintf(output_file,"%f, %f, 0, 0\n",xstart,ystart); // rapid traverse from lead-out + } + // + // follow segments in reverse order + // + v->path->segment = v->path->last; + while (1) { + // + // follow points in forward order + // + v->path->segment->point = v->path->segment->first; + // + // calculate and write lead-in perpendicular to segment start + // + x0 = xoffset + xscale * v->path->segment->point->first->value; + y0 = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + x1 = xoffset + xscale * v->path->segment->point->next->first->value; + y1 = yoffset + yscale * (v->ny - v->path->segment->point->next->first->next->value); + dx = x1 - x0; + dy = y1 - y0; + norm_x = -dy; + norm_y = dx; + norm = sqrt(norm_x*norm_x + norm_y*norm_y); + norm_x = norm_x/norm; + norm_y = norm_y/norm; + xlead = x0 + norm_x*lead; + ylead = y0 + norm_y*lead; + fprintf(output_file,"%f, %f, 0, -9\n",xlead,ylead); // lead-in + fprintf(output_file,"%f, %f, 0, %d\n",x0,y0,quality); // first point + nsegs += 1; + while (1) { + if (v->path->segment->point->next == 0) { + // + // no next point in segment, write lead-out + // + x0 = xoffset + xscale * v->path->segment->point->previous->first->value; + y0 = yoffset + yscale * (v->ny - v->path->segment->point->previous->first->next->value); + x1 = xoffset + xscale * v->path->segment->point->first->value; + y1 = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + dx = x1 - x0; + dy = y1 - y0; + norm_x = -dy; + norm_y = dx; + norm = sqrt(norm_x*norm_x + norm_y*norm_y); + norm_x = norm_x/norm; + norm_y = norm_y/norm; + xlead = x1 + norm_x*lead; + ylead = y1 + norm_y*lead; + fprintf(output_file,"%f, %f, 0, 0\n",xlead,ylead); // rapid traverse from lead-out + break; + } + v->path->segment->point = v->path->segment->point->next; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->segment->point->next != 0) + fprintf(output_file,"%f, %f, 0, %d\n",x,y,quality); + else + fprintf(output_file,"%f, %f, 0, -9\n",x,y); // lead-out next + npts += 1; + } + // + // check for previous segment + // + if (v->path->segment->previous == 0) + break; + v->path->segment = v->path->segment->previous; + } + // + // close and return + // + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float lead,xstart,ystart; + int quality; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 7))) { + printf("command line: path_ord in.path out.ord [lead [quality [xstart ystart]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.ord = output Omax waterjet file\n"); + printf(" lead = lead in/out (optional, mm, default 2)\n"); + printf(" quality = cut quality (optional, default -3)\n"); + printf(" xstart,ystart = start position (optional, mm, default path start)\n"); + exit(-1); + } + if (argc == 3) { + lead = 2.0; + quality = -3; + xstart = nostart; + ystart = nostart; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&lead); + quality = -3; + xstart = nostart; + ystart = nostart; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&lead); + sscanf(argv[4],"%d",&quality); + xstart = nostart; + ystart = nostart; + } + else if (argc == 7) { + sscanf(argv[3],"%f",&lead); + sscanf(argv[4],"%d",&quality); + sscanf(argv[5],"%f",&xstart); + sscanf(argv[6],"%f",&ystart); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write .ord + // + fab_write_ord(&v,argv[2],lead,quality,xstart,ystart); + } + diff --git a/src/core/path_png.c b/src/core/path_png.c new file mode 100644 index 0000000..8071ab9 --- /dev/null +++ b/src/core/path_png.c @@ -0,0 +1,45 @@ +// +// path_png.c +// convert path to PNG +// +// Neil Gershenfeld +// CBA MIT 2/26/11 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,intensity,number,n,count,count_sum; + float distance,error,z; + // + // command line args + // + if (argc != 3) { + printf("command line: path_png in.path out.png\n"); + printf(" in.path = input path file\n"); + printf(" out.png = output PNG file\n"); + exit(-1); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // shade path with z displacement + // + fab_shade_path_displace(&v); + // + // write PNG + // + fab_write_png_K(&v,argv[2]); + } + diff --git a/src/core/path_rml.c b/src/core/path_rml.c new file mode 100644 index 0000000..f479455 --- /dev/null +++ b/src/core/path_rml.c @@ -0,0 +1,196 @@ +// +// path_rml.c +// convert path to Roland Modela .rml +// +// Neil Gershenfeld +// CBA MIT 9/6/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_rml(struct fab_vars *v, char *output_file_name, float speed, int direction, float z_up) { + // + // write path to Roland Modela file + // + FILE *output_file; + int i,x,y,z,iz_down,iz_up,nsegs=0,npts=0; + float xscale,yscale,zscale,xoffset,yoffset,zoffset; + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"PA;PA;"); // plot absolute + fprintf(output_file,"VS%.1f;!VZ%.1f;",speed,speed); + xscale = 40.0*v->dx/(v->nx-1.0); // 40/mm + yscale = 40.0*v->dy/(v->ny-1.0); // 40/mm + if (v->nz > 1) + zscale = 40.0*v->dz/v->nz; // 40/mm + else + zscale = 0; + xoffset = 40.0*v->xmin; + yoffset = 40.0*v->ymin; + zoffset = 40.0*v->zmin; + iz_up = 40.0*z_up; + iz_down = zoffset; + fprintf(output_file,"!PZ%d,%d;",iz_down,iz_up); // set z down, jog + fprintf(output_file,"!MC1;\n"); // turn motor on + // + // follow segments in reverse order (mill boundaries last) + // + v->path->segment = v->path->last; + while (1) { + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->last; + else + // + // climb + // + v->path->segment->point = v->path->segment->first; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + // + // move up to first point + // + fprintf(output_file,"PU%d,%d;\n",x,y); + // + // move down + // + if (v->path->dof == 2) { + fprintf(output_file,"PD%d,%d;\n",x,y); + } + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"Z%d,%d,%d;\n",x,y,z); + } + else { + printf("path_rml: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + nsegs += 1; + while (1) { + // + // check if last point + // + if (direction == 0) { + // + // conventional + // + if (v->path->segment->point->previous == 0) { + fprintf(output_file,"PU%d,%d;\n",x,y); + break; + } + } + else { + // + // climb + // + if (v->path->segment->point->next == 0) { + fprintf(output_file,"PU%d,%d;\n",x,y); + break; + } + } + // + // move to next point + // + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->point->previous; + else + // + // climb + // + v->path->segment->point = v->path->segment->point->next; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 2) { + fprintf(output_file,"PD%d,%d;\n",x,y); + } + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"Z%d,%d,%d;\n",x,y,z); + } + else { + printf("path_rml: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + npts += 1; + } + // + // check for previous segment + // + //fprintf(output_file,"\n",x,y); + if (v->path->segment->previous == 0) + break; + v->path->segment = v->path->segment->previous; + } + // + // pad end of file with motor off commands for Modela buffering bug + // + for (i = 0; i < 1000; ++i) + fprintf(output_file,"!MC0;"); + // + // return to home + // + fprintf(output_file,"\nH;\n"); + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float speed,z_up; + int direction; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 7) || (argc == 8) || (argc == 9))) { + printf("command line: path_rml in.path out.rml [speed [direction [jog [xmin ymin [zmin]]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.rml = output Roland Modela file\n"); + printf(" speed = cutting speed (optional, mm/s, default 4)\n"); + printf(" direction = machining direction (optional, 0 conventional/1 climb, default 1)\n"); + printf(" jog = jog height (optional, mm, default 1)\n"); + printf(" xmin = left position (optional, mm, default path value)\n"); + printf(" ymin = front position (optional, mm, default path value)\n"); + printf(" zmin = bottom position (optional, -mm, default path value)\n"); + exit(-1); + } + speed = 4; + direction = 1; + z_up = 1; + if (argc >= 4) + sscanf(argv[3],"%f",&speed); + if (argc >= 5) + sscanf(argv[4],"%d",&direction); + if (argc >= 6) + sscanf(argv[5],"%f",&z_up); + // + // read path + // + fab_read_path(&v,argv[1]); + // + // check origin + // + if (argc >= 7) + sscanf(argv[6],"%lf",&v.xmin); + if (argc >= 8) + sscanf(argv[7],"%lf",&v.ymin); + if (argc >= 9) + sscanf(argv[8],"%lf",&v.zmin); + // + // write .rml + // + fab_write_rml(&v,argv[2],speed,direction,z_up); + } + diff --git a/src/core/path_sbp.c b/src/core/path_sbp.c new file mode 100644 index 0000000..1d9e8ac --- /dev/null +++ b/src/core/path_sbp.c @@ -0,0 +1,238 @@ +// +// path_sbp.c +// convert path to ShopBot .sbp +// +// Neil Gershenfeld +// CBA MIT 10/1/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_sbp(struct fab_vars *v, char *output_file_name, int direction, int spindle_speed, float xy_speed, float z_speed, float xy_jog_speed, float z_jog_speed, float z_jog, float units) { + // + // write path to ShopBot file + // + FILE *output_file; + int i,nsegs=0,npts=0; + float xscale,yscale,zscale,x,y,z,xoffset,yoffset,zoffset; + output_file = fopen(output_file_name,"w"); + fprintf(output_file,"SA\r\n"); // set to absolute distances + fprintf(output_file,"TR,%d,1\r\n",spindle_speed); // set spindle speed + fprintf(output_file,"SO,1,1\r\n"); // set output number 1 to on + fprintf(output_file,"pause,2\r\n"); // let spindle come up to speed + xscale = v->dx/(v->nx-1.0)/units; + yscale = v->dy/(v->ny-1.0)/units; + if (v->nz > 1) + zscale = v->dz/(units*v->nz); + else + zscale = 0; + xoffset = v->xmin/units; + yoffset = v->ymin/units; + zoffset = v->zmin/units; + xy_speed = xy_speed/units; + z_speed = z_speed/units; + xy_jog_speed = xy_jog_speed/units; + z_jog_speed = z_jog_speed/units; + z_jog = z_jog/units; + fprintf(output_file,"MS,%f,%f\r\n",xy_speed,z_speed); // set xy,z speed + fprintf(output_file,"JS,%f,%f\r\n",xy_jog_speed,z_jog_speed); // set jog xy,z speed + fprintf(output_file,"JZ,%f\r\n",z_jog); // move up + // + // follow segments in reverse order (mill boundaries last) + // + v->path->segment = v->path->last; + while (1) { + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->last; + else + // + // climb + // + v->path->segment->point = v->path->segment->first; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + // + // move to first point + // + fprintf(output_file,"J2,%f,%f\r\n",x,y); + // + // move down + // + if (v->path->dof == 2) + fprintf(output_file,"MZ,%f\r\n",zoffset); + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"M3,%f,%f,%f\r\n",x,y,z); + } + else { + printf("path_sbp: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + nsegs += 1; + while (1) { + // + // check if last point + // + if (direction == 0) { + // + // conventional + // + if (v->path->segment->point->previous == 0) { + fprintf(output_file,"MZ,%f\r\n",z_jog); + break; + } + } + else { + // + // climb + // + if (v->path->segment->point->next == 0) { + fprintf(output_file,"MZ,%f\r\n",z_jog); + break; + } + } + // + // move to next point + // + if (direction == 0) + // + // conventional + // + v->path->segment->point = v->path->segment->point->previous; + else + // + // climb + // + v->path->segment->point = v->path->segment->point->next; + x = xoffset + xscale * v->path->segment->point->first->value; + y = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 2) + fprintf(output_file,"M2,%f,%f\r\n",x,y); + else if (v->path->dof == 3) { + z = zoffset + zscale * v->path->segment->point->first->next->next->value; + fprintf(output_file,"M3,%f,%f,%f\r\n",x,y,z); + } + else { + printf("path_sbp: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + npts += 1; + } + // + // check for previous segment + // + if (v->path->segment->previous == 0) + break; + v->path->segment = v->path->segment->previous; + } + // + // close and return + // + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float xy_speed, z_speed, xy_jog_speed, z_jog_speed, z_jog, units; + int direction,spindle_speed; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 7) || (argc == 10) || (argc == 11))) { + printf("command line: path_sbp in.path out.sbp [direction [spindle_speed [xy_speed z_speed [xy_jog_speed z_jog_speed z_jog [units]]]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.sbp = output ShopBot file\n"); + printf(" direction = machining direction (optional, 0 conventional/1 climb, default 0)\n"); + printf(" spindle_speed = spindle speed (optional, if control installed, RPM, default 12000)\n"); + printf(" xy_speed = xy cutting speed (optional, mm/s, default 30)\n"); + printf(" z_speed = z cutting speed (optional, mm/s, default 30)\n"); + printf(" xy_jog_speed = xy jog speed (optional, mm/s, default 150)\n"); + printf(" z_jog_speed = z jog speed (optional, mm/s, default 150)\n"); + printf(" z_jog = z jog height (optional, mm, default 25)\n"); + printf(" units = mm per file unit (optional, default 25.4)\n"); + exit(-1); + } + if (argc == 3) { + direction = 0; + spindle_speed = 12000; + xy_speed = 30; + z_speed = 30; + xy_jog_speed = 150; + z_jog_speed = 150; + z_jog = 25; + units = 25.4; + } + else if (argc == 4) { + sscanf(argv[3],"%d",&direction); + spindle_speed = 12000; + xy_speed = 30; + z_speed = 30; + xy_jog_speed = 150; + z_jog_speed = 150; + z_jog = 25; + units = 25.4; + } + else if (argc == 5) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%d",&spindle_speed); + xy_speed = 30; + z_speed = 30; + xy_jog_speed = 150; + z_jog_speed = 150; + z_jog = 25; + units = 25.4; + } + else if (argc == 7) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%d",&spindle_speed); + sscanf(argv[5],"%f",&xy_speed); + sscanf(argv[6],"%f",&z_speed); + xy_jog_speed = 150; + z_jog_speed = 150; + z_jog = 25; + units = 25.4; + } + else if (argc == 10) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%d",&spindle_speed); + sscanf(argv[5],"%f",&xy_speed); + sscanf(argv[6],"%f",&z_speed); + sscanf(argv[7],"%f",&xy_jog_speed); + sscanf(argv[8],"%f",&z_jog_speed); + sscanf(argv[9],"%f",&z_jog); + units = 25.4; + } + else if (argc == 11) { + sscanf(argv[3],"%d",&direction); + sscanf(argv[4],"%d",&spindle_speed); + sscanf(argv[5],"%f",&xy_speed); + sscanf(argv[6],"%f",&z_speed); + sscanf(argv[7],"%f",&xy_jog_speed); + sscanf(argv[8],"%f",&z_jog_speed); + sscanf(argv[9],"%f",&z_jog); + sscanf(argv[10],"%f",&units); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // write .sbp + // + fab_write_sbp(&v,argv[2],direction,spindle_speed,xy_speed,z_speed,xy_jog_speed,z_jog_speed,z_jog,units); + return 0; + } + diff --git a/src/core/path_time.c b/src/core/path_time.c new file mode 100644 index 0000000..cb8d7a6 --- /dev/null +++ b/src/core/path_time.c @@ -0,0 +1,174 @@ +// +// path_time.c +// estimate path time +// +// Neil Gershenfeld 10/29/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +void fab_find_time(struct fab_vars *v, float units, float move, float height, float jog, float plunge, float *time, int *segments, int *points) { + float xscale, yscale, zscale; + float xoffset, yoffset, zoffset; + float xold, yold, zold, xnew, ynew, znew; + if ((v->path->dof < 2) || (v->path->dof > 3)) { + printf("path_time: path degrees of freedom must be 2 or 3\n"); + exit(-1); + } + xoffset = v->xmin/units; + yoffset = v->ymin/units; + xscale = v->dx/(v->nx-1.0)/units; + yscale = v->dy/(v->ny-1.0)/units; + if (v->path->dof == 3) { + zoffset = v->zmin/units; + if (v->nz > 1) + zscale = v->dz/(units*v->nz); + else + zscale = 0; + } + // + // start at origin + // + xold = 0; + yold = 0; + zold = 0; + *time = 0; + *segments = 0; + *points = 0; + // + // follow segments + // + v->path->segment = v->path->first; + while (1) { + *segments += 1; + // + // follow segment points + // + v->path->segment->point = v->path->segment->first; + *points += 1; + xnew = xoffset + xscale * v->path->segment->point->first->value; + ynew = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + znew = height; + // + // jog to first point + // + *time += sqrt((xnew-xold)*(xnew-xold)+(ynew-yold)*(ynew-yold))/jog; + xold = xnew; + yold = ynew; + // + // plunge to first point + // + if (v->path->dof == 3) { + znew = zoffset + zscale * v->path->segment->point->first->next->next->value; + *time += sqrt((znew-zold)*(znew-zold))/plunge; + zold = znew; + } + while (1) { + // + // check if last point + // + if (v->path->segment->point->next == 0) { + znew = height; + *time += sqrt((znew-zold)*(znew-zold))/plunge; + zold = znew; + break; + } + // + // move to next point + // + v->path->segment->point = v->path->segment->point->next; + *points += 1; + xnew = xoffset + xscale * v->path->segment->point->first->value; + ynew = yoffset + yscale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 2) { + *time += sqrt((xnew-xold)*(xnew-xold)+(ynew-yold)*(ynew-yold))/move; + xold = xnew; + yold = ynew; + } + else if (v->path->dof == 3) { + znew = zoffset + zscale * v->path->segment->point->first->next->next->value; + *time += sqrt((xnew-xold)*(xnew-xold)+(ynew-yold)*(ynew-yold)+(znew-zold)*(znew-zold))/move; + xold = xnew; + yold = ynew; + zold = znew; + } + } + // + // check for next segment + // + if (v->path->segment->next == 0) + break; + v->path->segment = v->path->segment->next; + *segments += 1; + } + // + // return + // + return; + } + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float units, move, height, jog, plunge, time; + int segments, points; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6))) { + printf("command line: path_time in.path move_speed [jog_height [jog_speed [plunge_speed]]]\n"); + printf(" in.path = input path file\n"); + printf(" move_speed = speed of path segments (mm/s)\n"); + printf(" jog_height = height between path segments (mm, optional, default 0)\n"); + printf(" jog_speed = speed between path segments (mm/s, optional, default move_speed)\n"); + printf(" plunge_speed = speed from jog to move (mm/s, optional, default move_speed)\n"); + exit(-1); + } + if (argc == 3) { + sscanf(argv[2],"%f",&move); + height = 0; + jog = move; + plunge = move; + } + else if (argc == 4) { + sscanf(argv[2],"%f",&move); + sscanf(argv[3],"%f",&height); + jog = move; + plunge = move; + } + else if (argc == 5) { + sscanf(argv[2],"%f",&move); + sscanf(argv[3],"%f",&height); + sscanf(argv[4],"%f",&jog); + plunge = move; + } + else if (argc == 6) { + sscanf(argv[2],"%f",&move); + sscanf(argv[3],"%f",&height); + sscanf(argv[4],"%f",&jog); + sscanf(argv[5],"%f",&plunge); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // calculate time + // + fab_find_time(&v,1.0,move,height,jog,plunge,&time,&segments,&points); + // + // report and return + // + printf("path time: %.0f seconds, %.1f minutes, %.2f hours\n",time,time/60.0,time/(60.0*60.0)); + } diff --git a/src/core/path_uni.c b/src/core/path_uni.c new file mode 100644 index 0000000..a7329b6 --- /dev/null +++ b/src/core/path_uni.c @@ -0,0 +1,166 @@ +// +// path_uni.c +// convert path to Universal lasercutter .uni +// +// Neil Gershenfeld +// CBA MIT 9/21/11 +// +// (c) Massachusetts Institute of Technology 2011 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_uni(struct fab_vars *v, char *output_file_name, int power, int max_power, int speed, int rate) { + // + // write path to Universal lasercutter file + // + FILE *output_file; + int x,y,z,current_z,layer_power,nsegs=0,npts=0; + unsigned char ppi,speed_hi,speed_lo,power_hi,power_lo; + float scale,xoffset,yoffset; + // + output_file = fopen(output_file_name,"w"); + scale = 1000.0*v->dx/(25.4*(v->nx-1.0)); // 1000 DPI + xoffset = 1000.0*v->xmin/25.4; + yoffset = 1000.0*v->ymin/25.4; + fprintf(output_file,"Z"); // initialize + fprintf(output_file,"t%s~;",output_file_name); // title + fprintf(output_file,"IN;DF;PS0;DT~"); // initialize + ppi = rate/10; + fprintf(output_file,"s%c",ppi); // PPI + speed_hi = (648*speed)/256; + speed_lo = (648*speed)%256; + fprintf(output_file,"v%c%c",speed_hi,speed_lo); // speed + power_hi = (320*power)/256; + power_lo = (320*power)%256; + fprintf(output_file,"p%c%c",power_hi,power_lo); // power + fprintf(output_file,"a%c",2); // air assist on high + current_z = 0; + v->path->segment = v->path->last; + while (1) { + // + // follow segments in reverse order + // + v->path->segment->point = v->path->segment->first; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + layer_power = power + (max_power-power) * z / (v->nz - 1.0); + power_hi = (320*layer_power)/256; + power_lo = (320*layer_power)%256; + fprintf(output_file,"p%c%c",power_hi,power_lo); // power + current_z = z; + } + } + fprintf(output_file,"PU;PA%d,%d;PD;",x,y); + nsegs += 1; + while (1) { + // + // follow points + // + if (v->path->segment->point->next == 0) + break; + v->path->segment->point = v->path->segment->point->next; + x = xoffset + scale * v->path->segment->point->first->value; + y = yoffset + scale * (v->ny - v->path->segment->point->first->next->value); + if (v->path->dof == 3) { + z = v->path->segment->point->first->next->next->value; + if (z != current_z) { + layer_power = power + (max_power-power) * z / (v->nz - 1.0); + fprintf(output_file,"YP%d;\n",layer_power); + current_z = z; + } + } + fprintf(output_file,"PA%d,%d;",x,y); + npts += 1; + } + fprintf(output_file,"\n",x,y); + if (v->path->segment == v->path->first) + break; + v->path->segment = v->path->segment->previous; + } + fprintf(output_file,"e"); // end of file + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" segments: %d, points: %d\n",nsegs,npts); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int power,max_power,speed,focus,rate; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 7) || (argc == 8) || (argc == 9))) { + printf("command line: path_uni in.path out.uni [power [speed [xmin ymin [rate [max_power]]]]]\n"); + printf(" in.path = input path file\n"); + printf(" out.uni= output Universal lasercutter file\n"); + printf(" power = percent power (optional, 0-100, default 100)\n"); + printf(" speed = percent speed (optional, 0-100, default 100)\n"); + printf(" xmin = left position (optional, mm, default path, 0 = left side of bed)\n"); + printf(" ymin = front position (optional, mm, default path, 0 = back, front positive)\n"); + printf(" rate = pulse rate (optional, frequency, default 500)\n"); + printf(" max_power = maximum power for maximum z value (optional, 0-100, default 100)\n"); + exit(-1); + } + if (argc == 3) { + power = 100; + speed = 100; + rate = 500; + max_power = 100; + } + else if (argc == 4) { + sscanf(argv[3],"%d",&power); + speed = 100; + rate = 500; + max_power = 100; + } + else if (argc == 5) { + sscanf(argv[3],"%d",&power); + sscanf(argv[4],"%d",&speed); + rate = 500; + max_power = 100; + } + else if (argc == 7) { + sscanf(argv[3],"%d",&power); + sscanf(argv[4],"%d",&speed); + rate = 500; + max_power = 100; + } + else if (argc == 8) { + sscanf(argv[3],"%d",&power); + sscanf(argv[4],"%d",&speed); + sscanf(argv[7],"%d",&rate); + max_power = 100; + } + else if (argc == 9) { + sscanf(argv[3],"%d",&power); + sscanf(argv[4],"%d",&speed); + sscanf(argv[7],"%d",&rate); + sscanf(argv[8],"%d",&max_power); + } + // + // read path + // + fab_read_path(&v,argv[1]); + // + // origin + // + if ((argc == 7) || (argc == 8) || (argc == 9)) { + sscanf(argv[5],"%lf",&v.xmin); + sscanf(argv[6],"%lf",&v.ymin); + } + // + // write .epi + // + fab_write_uni(&v,argv[2],power,max_power,speed,rate); + } + diff --git a/src/core/png_distances.c b/src/core/png_distances.c new file mode 100644 index 0000000..882e437 --- /dev/null +++ b/src/core/png_distances.c @@ -0,0 +1,77 @@ +// +// png_distances.c +// find distances from edges in PNG +// +// Neil Gershenfeld +// CBA MIT 7/24/11 +// +// (c) Massachusetts Institute of Technology 2011 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,distances; + float intensity,distance; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5))) { + printf("command line: png_distances in.png out.png [intensity [distances]]\n"); + printf(" in.png = input PNG file\n"); + printf(" out.png = input PNG file\n"); + printf(" intensity = intensity level to slice (optional, 0-1, default 0.5)\n"); + printf(" distances = show distances (optional, 0/1, default 1)\n"); + exit(-1); + } + if (argc == 3) { + intensity = 0.5; + distances = 1; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&intensity); + distances = 1; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&intensity); + sscanf(argv[4],"%d",&distances); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // threshold + // + fab_threshold(&v,intensity); + // + // find distances + // + if (distances == 1) { + printf(" find distances\n"); + fab_distances(&v); + // + // copy distances to image array + // + for (y = 0; y < v.ny; ++y) + for (x = 0; x < v.nx; ++x) + v.array[y][x] = v.distances[y][x]; + } + // + // scale + // + v.bit_depth = 16; + fab_rescale(&v,0,1); + // + // write PNG + // + fab_write_png_K(&v,argv[2]); + } + diff --git a/src/core/png_drl.c b/src/core/png_drl.c new file mode 100644 index 0000000..9796a55 --- /dev/null +++ b/src/core/png_drl.c @@ -0,0 +1,267 @@ +/* +% Rewind and Stop +X#Y# Move and Drill +T# Tool Selection +M30 End of Program +M00 End of Program +R#X#Y# Repeat Hole +G05, G81 Select Drill Mode +G90 Absolute Mode +G91 Incremental Mode +G92 X#Y# Set Zero +G93 X#Y# Set Zero +M48 Program Header to first "%" +M72 English-Imperial Mode +*/ +/* +% Rewind and Stop +X#Y# Move and Drill +T# Tool Selection +M30 End of Program +M00 End of Program +M25 Beginning of Pattern +M31 Beginning of Pattern +M01 End of Pattern +M02 X#Y# Repeat Pattern +R#M02X#Y# Multiple Repeat Pattern +M02 X#Y# M70 Swap Axis +M02 X#Y# M80 Mirror Image X Axis +M02 X#Y# M90 Mirror Image Y Axis +M08 End of Step and Repeat +N# Block Sequence Number +/ Block Delete +R#X#Y# Repeat Hole +G05, G81 Select Drill Mode +G04 X# Variable Dwell (ignored) +G90 Absolute Mode +G91 Incremental Mode +G92 X#Y# Set Zero +G93 X#Y# Set Zero +M48 Program Header to first "%" +M47 Operator Message CRT Display +M71 Metric Mode +M72 English-Imperial Mode +Snn Spindle Speed (RPM) +Fnn Z axis feed speed (IPM) +*/ +/* +M48 Program Header +M72, LZ English measurement Leading 0's +T03C0.038 T03 .0380" +T04C0.125 T04 .1250" +T06C0.046 T06 .0460" +T12C0.063 T12 .0630" +T16C0.250 T16 .2500" +% Rewind and Stop (start of drill data) +T03 Drill COMMAND GET TOOL 3 +X00581Y0122 Drill location with TOOL 3 +T06 Drill COMMAND GET TOOL 6 +X01657Y03295 Drill location with TOOL 6 +T12 Drill COMMAND GET TOOL 12 +X00585Y03311 Drill location with TOOL 12 +T04 Drill COMMAND GET TOOL 4 +X00873Y02691 Drill location with TOOL 4 +T16 Drill COMMAND GET TOOL 16 +X00625Y02191 Drill location with TOOL 16 +T00 Drill COMMAND UNLOAD TOOL +M30 End of Program +*/ +// +// png_drl.c +// PNG to Excellon +// +// Neil Gershenfeld +// CBA MIT 11/22/12 +// +// (c) Massachusetts Institute of Technology 2012 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +#define MAX_HOLES 100000 +#define TOLERANCE 0.01 // hole drill match percent tolerance + +void fab_write_drl(struct fab_vars *v, char *output_file_name) { + FILE *output_file; + int x,y,edges,points,hole,holes,drill,drills,index[MAX_HOLES]; + float units,scale; + float x0[MAX_HOLES],y0[MAX_HOLES],r[MAX_HOLES],d[MAX_HOLES]; + output_file = fopen(output_file_name,"w"); + // + // threshold array + // + fab_threshold(v,0.5); + // + // find edges + // + edges = fab_edges(v); + if (edges == 0) { + printf("png_drl: oops -- no edges\n"); + exit(-1); + } + // + // set edge directions + // + fab_directions(v); + // + // follow edges + // + fab_path_start(v,2); + fab_vectorize(v,1,0); + // + // + // + units = 1.0/25.4; // inches + scale = units*v->dx/(v->nx-1.0); + // + // follow segments to find holes + // + v->path->segment = v->path->first; + hole = 0; + while (1) { + // + // find hole centers + // + v->path->segment->point = v->path->segment->first; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + x0[hole] = x; + y0[hole] = y; + points = 1; + while (1) { + if (v->path->segment->point->next == 0) { + x0[hole] = x0[hole] / points; + y0[hole] = y0[hole] / points; + break; + } + v->path->segment->point = v->path->segment->point->next; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + x0[hole] += x; + y0[hole] += y; + points += 1; + } + // + // find hole radii + // + v->path->segment->point = v->path->segment->first; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + r[hole] = sqrt((x-x0[hole])*(x-x0[hole])+(y-y0[hole])*(y-y0[hole])); + points = 1; + while (1) { + if (v->path->segment->point->next == 0) { + x0[hole] = scale * x0[hole]; + y0[hole] = scale * y0[hole]; + r[hole] = scale * r[hole] / points; + break; + } + v->path->segment->point = v->path->segment->point->next; + x = v->path->segment->point->first->value; + y = v->ny - v->path->segment->point->first->next->value; + r[hole] += sqrt((x-x0[hole])*(x-x0[hole])+(y-y0[hole])*(y-y0[hole])); + points += 1; + } + hole += 1; + if (v->path->segment->next == 0) { + break; + } + v->path->segment = v->path->segment->next; + } + holes = hole; + // + // find unique drills + // + drills = 0; + for (hole = 0; hole < holes; ++hole) { + drill = 0; + while (1) { + if (drill == drills) { + drills += 1; + d[drill] = 2*r[hole]; + index[hole] = drill; + break; + } + if ((fabs(d[drill] - 2*r[hole])/d[drill]) < TOLERANCE) { + index[hole] = drill; + break; + } + drill += 1; + } + } + // + // write header + // + fprintf(output_file,"M48\n"); // program header + fprintf(output_file,"M72, LZ\n"); // inches, leading zeros + // + // write drills + // + for (drill = 0; drill < drills; ++drill) { + fprintf(output_file,"T%.2dC%.3f\n",(1+drill),d[drill]); + } + // + // write holes + // + fprintf(output_file,"%%\n"); // rewind and stop (start hole data) + for (hole = 0; hole < holes; ++hole) { + fprintf(output_file,"T%.2d\n",(1+index[hole])); // tool + x = 10000*x0[hole]; + y = 10000*y0[hole]; + fprintf(output_file,"X%.6dY%.6d\n",x,y); // location + } + /* + T06 Drill COMMAND GET TOOL 6 + X01657Y03295 Drill location with TOOL 6 + T12 Drill COMMAND GET TOOL 12 + X00585Y03311 Drill location with TOOL 12 + T04 Drill COMMAND GET TOOL 4 + X00873Y02691 Drill location with TOOL 4 + T16 Drill COMMAND GET TOOL 16 + X00625Y02191 Drill location with TOOL 16 + T00 Drill COMMAND UNLOAD TOOL + */ + // + // close file + // + fprintf(output_file,"M30\n"); // end of program + fclose(output_file); + printf("wrote %s\n",output_file_name); + printf(" holes: %d, drills: %d\n",holes,drills); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if ((argc < 3) || (argc > 3)) { + printf("command line: png_drl in.png out.drl\n"); + printf(" in.png = input PNG file\n"); + printf(" out.drl = output Excellon file\n"); + exit(-1); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // copy image to array + // + fab_png_array(&v); + // + // write array to Excellon + // + fab_write_drl(&v,argv[2]); + // + // exit + // + exit(0); + } + diff --git a/src/core/png_ex.c b/src/core/png_ex.c new file mode 100644 index 0000000..880dd4e --- /dev/null +++ b/src/core/png_ex.c @@ -0,0 +1,66 @@ +#include +#include +#include + +int x, y; +int width, height; +png_byte color_type; +png_byte bit_depth; +png_structp png_ptr; +png_infop info_ptr; +png_bytep * row_pointers; + +void read_png_file(char* file_name) { + FILE *fp = fopen(file_name, "rb"); + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL,NULL,NULL); + info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, fp); + png_read_info(png_ptr, info_ptr); + width = info_ptr->width; + height = info_ptr->height; + color_type = info_ptr->color_type; + bit_depth = info_ptr->bit_depth; + printf("width %d height %d color %d bit %d\n", + width,height,color_type,bit_depth); + row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); + for (y=0; yrowbytes); + png_read_image(png_ptr, row_pointers); + fclose(fp); + } + +void write_png_file(char* file_name) { + FILE *fp = fopen(file_name, "wb"); + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL,NULL,NULL); + info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, fp); + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, NULL); + fclose(fp); + } + +void process_file(void) { + png_byte *ptr; + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) { + ptr = &(row_pointers[y][x*3]); + ptr[0] = 255; + ptr[1] = ptr[2]; + } + } + +int main(int argc, char **argv) { + if (argc != 3) { + printf("Usage: program_name \n"); + exit(0); + } + read_png_file(argv[1]); + process_file(); + write_png_file(argv[2]); + } diff --git a/src/core/png_grb.c b/src/core/png_grb.c new file mode 100644 index 0000000..60312fc --- /dev/null +++ b/src/core/png_grb.c @@ -0,0 +1,125 @@ +// +// png_grb.c +// PNG to Gerber (RS-274X) +// +// Neil Gershenfeld +// CBA MIT 11/22/12 +// +// (c) Massachusetts Institute of Technology 2012 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +void fab_write_grb(struct fab_vars *v, char *output_file_name) { + FILE *output_file; + int i,j,k,x,y,width,height; + float units,dx,dy,xmin,ymin; + output_file = fopen(output_file_name,"w"); + // + // write header + // + fprintf(output_file,"%%FSLAX24Y24*%%\n"); // leading zeros omitted, absolute coordinates, 2.4 + fprintf(output_file,"%%MOIN*%%\n"); // inches units + fprintf(output_file,"%%OFA0B0*%%\n"); // no offset + // + // write apertures + // + units = 1.0/25.4; // inches + dx = units*v->dx/(v->nx-1.0); + dy = units*v->dy/(v->ny-1.0); + xmin = units*v->xmin; + ymin = units*v->ymin; + for (i = 1; i <= 10; ++i) { + for (j = 1; j <= 10; ++j) { + fprintf(output_file,"%%ADD%dR,%.4fX%.4f*%%\n",i*10+j,j*dx,i*dy); + } + } + // + // write flashes + // + for (i = (v->ny-1); i >= 0; --i) { + for (j = 0; j < v->nx; ++j) { + // + // find next starting pixel + // + if (v->array[i][j] > 0) { + // + // find width + // + v->array[i][j] = 0; + width = 1; + while ((width < 10) && ((j+width) < v->nx)){ + if (v->array[i][j+width] != 0) { + v->array[i][j+width] = 0; + width += 1; + } + else + break; + } + // + // find height + // + height = 1; + while ((height < 10) && ((i-height) >= 0)){ + for (k = 0; k < width; ++k) { + if (v->array[i-height][j+k] == 0) + goto height_continue; + } + for (k = 0; k < width; ++k) + v->array[i-height][j+k] = 0; + height += 1; + } + height_continue: + // + // flash it + // + x = 10000*(xmin+dx*(j+width/2.0)); + y = 10000*(ymin+dy*(v->ny-1-i+height/2.0)); + fprintf(output_file,"D%d*\n",height*10+width); + fprintf(output_file,"X%dY%dD03*\n",x,y); + } + } + } + // + // close file + // + fprintf(output_file,"M02*\n"); // end of file + fclose(output_file); + printf("wrote %s\n",output_file_name); + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if ((argc < 3) || (argc > 3)) { + printf("command line: png_grb in.png out.grb\n"); + printf(" in.png = input PNG file\n"); + printf(" out.grb = output Gerber (RS-274X) file\n"); + exit(-1); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // copy image to array + // + fab_png_array(&v); + // + // write array to Gerber + // + fab_write_grb(&v,argv[2]); + // + // exit + // + exit(0); + } + diff --git a/src/core/png_halftone.c b/src/core/png_halftone.c new file mode 100644 index 0000000..17b8b71 --- /dev/null +++ b/src/core/png_halftone.c @@ -0,0 +1,108 @@ +// +// png_halftone.c +// halftone PNG to path +// +// Neil Gershenfeld +// CBA MIT 9/9/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int points, invert; + float threshold, size, spacing, offset; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6) || (argc == 7) || (argc == 8) || (argc == 9))) { + printf("command line: png_halftone in.png out.path [threshold [points [size [spacing [offset [invert]]]]]]\n"); + printf(" in.png = input PNG file\n"); + printf(" out.path = output path file\n"); + printf(" threshold = minimum spot radius (optional, pixels default 1)\n"); + printf(" points = points per spot (optional, default 8)\n"); + printf(" size = maximum spot size (optional, mm, default 1)\n"); + printf(" spacing = spot spacing (optional, 1 = size, default 1)\n"); + printf(" offset = row offset (optional, 1 = size, default 0.5)\n"); + printf(" offset = row offset (optional, 1 = size, default 0.5)\n"); + printf(" invert = invert image (0 = no (default), 1 = yes)\n"); + exit(-1); + } + if (argc == 3) { + threshold = 1.0; + points = 8; + size = 1.0; + spacing = 1.0; + offset = 0.5; + invert = 0; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&threshold); + points = 8; + size = 1.0; + spacing = 1.0; + offset = 0.5; + invert = 0; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&threshold); + sscanf(argv[4],"%d",&points); + size = 1.0; + spacing = 1.0; + offset = 0.5; + invert = 0; + } + else if (argc == 6) { + sscanf(argv[3],"%f",&threshold); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%f",&size); + spacing = 1.0; + offset = 0.5; + invert = 0; + } + else if (argc == 7) { + sscanf(argv[3],"%f",&threshold); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%f",&size); + sscanf(argv[6],"%f",&spacing); + offset = 0.5; + invert = 0; + } + else if (argc == 8) { + sscanf(argv[3],"%f",&threshold); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%f",&size); + sscanf(argv[6],"%f",&spacing); + sscanf(argv[7],"%f",&offset); + invert = 0; + } + else if (argc == 9) { + sscanf(argv[3],"%f",&threshold); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%f",&size); + sscanf(argv[6],"%f",&spacing); + sscanf(argv[7],"%f",&offset); + sscanf(argv[8],"%d",&invert); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // halftone + // + fab_halftone(&v,threshold,points,size,spacing,offset,invert); + // + // write path + // + fab_write_path(&v,argv[2]); + } + diff --git a/src/core/png_offset.c b/src/core/png_offset.c new file mode 100644 index 0000000..4dc78b7 --- /dev/null +++ b/src/core/png_offset.c @@ -0,0 +1,85 @@ +// +// png_offset.c +// offset PNG +// png_offset in.png out.png threshold distance +// +// Neil Gershenfeld +// CBA MIT 9/11/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int x,y,count; + float intensity,distance; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5))) { + printf("command line: png_offset in.png out.png [intensity [distance]]\n"); + printf(" in.png = input PNG file\n"); + printf(" out.png = input PNG file\n"); + printf(" intensity = intensity level to slice (optional, 0-1, default 0.5)\n"); + printf(" distance = distance to offset (optional, mm, default 0)\n"); + exit(-1); + } + if (argc == 3) { + intensity = 0.5; + distance = 0; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&intensity); + distance = 0; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&intensity); + sscanf(argv[4],"%f",&distance); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // threshold + // + fab_threshold(&v,intensity); + // + // find edges + // + fab_edges(&v); + // + // find edge distances + // + fab_distances(&v); + // + // offset + // + count = fab_offset(&v,distance); + printf("png_offset: %d points remain\n",count); + // + // set edge directions + // + fab_directions(&v); + // + // shade states + // + fab_shade_states(&v); + // + // write PNG + // + fab_write_png_K(&v,argv[2]); + } + diff --git a/src/core/png_path.c b/src/core/png_path.c new file mode 100644 index 0000000..4bfaca5 --- /dev/null +++ b/src/core/png_path.c @@ -0,0 +1,671 @@ +// +// png_path.c +// slice, offset, and vectorize PNG to path +// +// Neil Gershenfeld 10/14/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// +// todo: + +#include "fab.h" + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + struct fab_vars vxz; + init_vars(&vxz); + struct fab_vars vyz; + init_vars(&vyz); + int offset_number,offset_count, + layer,layer_number,nz,xz,yz,xy, + ix,ixmin,ixmax,idx, + iy,iymin,iymax,idy, + iz,ithreshold, + *tool_dx,*tool_dy,*tool_iz,tool_pt,tool_n,tool_ir,tool_id, + *clearance_dx,*clearance_dy,*clearance_iz,clearance_pt,clearance_n,clearance_ir,clearance_id, + remaining_count,remaining_count_sum,tool_collision; + float error,offset_diameter,offset_overlap,clearance_length,clearance_diameter, + intensity_top,intensity_bottom,intensity_layer, + z_top,z_bottom,z_thickness,z_layer,*z_list,distance; + char tool_type; + // + // command line args + // + if ((argc < 3) || (argc > 18)) { + printf("command line: png_path in.png out.path [error [offset_diameter [offset_number [offset_overlap [intensity_top [intensity_bottom [z_top [z_bottom [z_thickness [xz [yz [xy [type [clearance_length clearance_diameter]]]]]]]]]]]]]]\n"); + printf(" in.png = input PNG file\n"); + printf(" out.path = output path file\n"); + printf(" error = allowable vector fit deviation (optional, pixels, default 1.1)\n"); + printf(" offset_diameter = diameter to offset (optional, mm, default 0)\n"); + printf(" offset_number = number of contours to offset (optional, -1 to fill all, default 1)\n"); + printf(" offset_overlap = tool offset overlap fraction (optional, 0 (no overlap) - 1 (complete overlap, default 0.5))\n"); + printf(" intensity_top = top slice intensity (optional, 0-1, default 0.5)\n"); + printf(" intensity_bottom = bottom slice intensity (optional, 0-1, default intensity_top)\n"); + printf(" z_top = top slice z value (optional, mm, default 0)\n"); + printf(" z_bottom = bottom slice z value (optional, mm, default z_top)\n"); + printf(" z_thickness = slice z thickness (optional, mm, default z_top-z_bottom)\n"); + printf(" xz = xz finish (optional, 1=yes, default 0\n"); + printf(" yz = yz finish (optional, 1=yes, default 0\n"); + printf(" xy = xy path (optional, 1=yes, default 1\n"); + printf(" type = finish tool type (optional, f=flat end, b=ball end, default f\n"); + printf(" clearance_length = finish tool clearance length (optional, mm, 0 = no limit, default 0\n"); + printf(" clearance_diameter = finish tool clearance diameter (optional, mm, default offset_diameter\n"); + exit(-1); + } + error = 1.1; + offset_diameter = 0; + offset_number = 1; + offset_overlap = 0.5; + intensity_top = 0.5; + intensity_bottom = intensity_top; + z_top = 0; + z_bottom = 0; + z_thickness = 0; + xz = 0; + yz = 0; + xy = 1; + tool_type = 'f'; + if (argc >= 4) { + sscanf(argv[3],"%f",&error); + } + if (argc >= 5) { + sscanf(argv[4],"%f",&offset_diameter); + } + if (argc >= 6) { + sscanf(argv[5],"%d",&offset_number); + } + if (argc >= 7) { + sscanf(argv[6],"%f",&offset_overlap); + } + if (argc >= 8) { + sscanf(argv[7],"%f",&intensity_top); + intensity_bottom = intensity_top; + } + if (argc >= 9) { + sscanf(argv[8],"%f",&intensity_bottom); + } + if (argc >= 10) { + sscanf(argv[9],"%f",&z_top); + z_bottom = z_top; + } + if (argc >= 11) { + sscanf(argv[10],"%f",&z_bottom); + z_thickness = z_top - z_bottom; + } + if (argc >= 12) { + sscanf(argv[11],"%f",&z_thickness); + } + if (argc >= 13) { + sscanf(argv[12],"%d",&xz); + } + if (argc >= 14) { + sscanf(argv[13],"%d",&yz); + } + if (argc >= 15) { + sscanf(argv[14],"%d",&xy); + } + if (argc >= 16) { + sscanf(argv[15],"%c",&tool_type); + } + clearance_length = z_top - z_bottom; + clearance_diameter = offset_diameter; + if (argc >= 17) { + sscanf(argv[16],"%f",&clearance_length); + if (clearance_length == 0) + clearance_length = z_top - z_bottom; + } + if (argc >= 18) { + sscanf(argv[17],"%f",&clearance_diameter); + } + tool_collision = 0; + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // 2D path? + // + if (argc < 9) { + // + // start path + // + fab_path_start(&v,2); + printf("png_path: intensity %f\n",intensity_top); + // + // copy image to array + // + fab_png_array(&v); + // + // threshold array + // + printf(" threshold\n"); + fab_threshold(&v,intensity_top); + // + // find edges + // + printf(" find edges\n"); + remaining_count = fab_edges(&v); + if (remaining_count != 0) { + // + // find edge distances + // + printf(" find distances\n"); + //test_fab_distances(&v); + fab_distances(&v); + // + // loop over contours + // + printf(" offset:\n"); + offset_count = 0; + remaining_count_sum = 0; + do { + // + // offset + // + distance = offset_diameter/2.0 + offset_diameter*(1-offset_overlap)*offset_count; + remaining_count = fab_offset(&v,distance); + remaining_count_sum += remaining_count; + printf(" distance %f, %d exterior points remain\n", + distance,remaining_count); + if (remaining_count != 0) { + // + // set edge directions + // + fab_directions(&v); + // + // vectorize edge directions + // + fab_vectorize(&v,error,0); + } + ++offset_count; + } while ((offset_count != offset_number) && (remaining_count != 0)); + } + else { + printf("path.c: oops -- no layer edges\n"); + exit(-1); + } + if (remaining_count_sum == 0) { + printf("png_path: no offset edges\n"); + exit(1); + } + } + // + // 3D path + // + else { + // + // start path + // + fab_path_start(&v,3); + // + // set path z bounds + // + v.zmin = z_bottom; + v.dz = (z_top - z_bottom); + if (v.dz == 0) + v.nz = 1; + else + v.nz = v.dz * v.nx / v.dx; + // + // find z layer values + // + if (xy == 1) { + if (v.dz == 0) + nz = 1; + else { + nz = 2 + (z_top-z_bottom)/z_thickness; + z_list = (float*) malloc(nz*sizeof(float)); + z_layer = z_top; + nz = 0; + while (1) { + z_list[nz] = z_layer; + nz += 1; + if (z_layer == z_bottom) + break; + z_layer -= z_thickness; + if (z_layer < z_bottom) + z_layer = z_bottom; + } + } + } + // + // copy image to array for finish cuts + // + fab_png_array(&v); + // + // create tool shape offset list + // + tool_ir = v.nx*offset_diameter/(2*v.dx); + tool_id = 2*tool_ir; + tool_dx = (int*) malloc(tool_id*tool_id*sizeof(int)); + tool_dy = (int*) malloc(tool_id*tool_id*sizeof(int)); + tool_iz = (int*) malloc(tool_id*tool_id*sizeof(int)); + tool_pt = 0; + tool_n = 0; + for (ix = 0; ix < tool_id; ++ix) + for (iy = 0; iy < tool_id; ++iy) + if (sqrt((ix-tool_ir)*(ix-tool_ir)+(iy-tool_ir)*(iy-tool_ir)) < tool_ir) { + tool_dx[tool_pt] = ix-tool_ir; + tool_dy[tool_pt] = iy-tool_ir; + if (tool_type == 'f') + tool_iz[tool_pt] = 0; + else if (tool_type == 'b') { + tool_iz[tool_pt] = pow(2,v.bit_depth)*(tool_ir - sqrt(tool_ir*tool_ir + - ((ix-tool_ir)*(ix-tool_ir) + (iy-tool_ir)*(iy-tool_ir))))/v.nz; + } + else { + printf("path.c: oops -- unsupported tool type\n"); + exit(-1); + } + tool_pt += 1; + tool_n = tool_pt; + } + // + // create tool clearance offset list + // + clearance_ir = v.nx*clearance_diameter/(2*v.dx); + clearance_id = 2*clearance_ir; + clearance_dx = (int*) malloc(clearance_id*clearance_id*sizeof(int)); + clearance_dy = (int*) malloc(clearance_id*clearance_id*sizeof(int)); + clearance_iz = (int*) malloc(clearance_id*clearance_id*sizeof(int)); + clearance_pt = 0; + clearance_n = 0; + for (ix = 0; ix < clearance_id; ++ix) + for (iy = 0; iy < clearance_id; ++iy) + if (((sqrt((ix-clearance_ir)*(ix-clearance_ir)+(iy-clearance_ir)*(iy-clearance_ir))) >= tool_ir) + && ((sqrt((ix-clearance_ir)*(ix-clearance_ir)+(iy-clearance_ir)*(iy-clearance_ir))) < clearance_ir)) { + clearance_dx[clearance_pt] = ix-clearance_ir; + clearance_dy[clearance_pt] = iy-clearance_ir; + clearance_iz[clearance_pt] = (pow(2,v.bit_depth)-1)*clearance_length/v.dz; + clearance_pt += 1; + clearance_n = clearance_pt; + } + // + // check for xz cut + // + if (xz == 1) { + // + // allocate xz finish cut array + // + vxz.nx = v.nx; + vxz.ny = v.nz; + vxz.nz = 1; + vxz.dx = v.dx; + vxz.dy = v.dz; + vxz.dz = 0; + vxz.xmin = v.xmin; + vxz.ymin = v.zmin; + vxz.zmin = 0; + vxz.array = malloc(v.nz*sizeof(uint32_t *)); + for (iz = 0; iz < v.nz; ++iz) + vxz.array[iz] = malloc(v.nx*sizeof(uint32_t)); + // + // start xz path + // + fab_path_start(&vxz,3); + // + // y loop + // + iymin = v.ny*clearance_diameter/(2.0*v.dy); + iymax = (v.ny-1) - v.ny*clearance_diameter/(2.0*v.dy); + idy = v.ny*offset_diameter*(1-offset_overlap)/v.dy; + printf(" xz finish:\n"); + for (iy = iymin; iy <= iymax; (iy += idy)) { + printf(" y=%d/%d\n",iy,iymax); + // + // x loop + // + for (ix = 0; ix < vxz.nx; ++ix) { + // + // set z threshold + // + if ((ix <= clearance_ir) | (ix >= (vxz.nx-clearance_ir))) + // + // too close to edge, set max + // + ithreshold = pow(2,v.bit_depth); + else { + // + // offset for tool shape + // + ithreshold = 0; + for (tool_pt = 0; tool_pt < tool_n; ++tool_pt) { + if (v.array[iy+tool_dy[tool_pt]][ix+tool_dx[tool_pt]] > (ithreshold+tool_iz[tool_pt])) + ithreshold = v.array[iy+tool_dy[tool_pt]][ix+tool_dx[tool_pt]] - tool_iz[tool_pt]; + } + // + // check clearance + // + for (clearance_pt = 0; clearance_pt < clearance_n; ++clearance_pt) { + if (v.array[iy+clearance_dy[clearance_pt]][ix+clearance_dx[clearance_pt]] > (ithreshold+clearance_iz[clearance_pt])) { + ithreshold = v.array[iy+clearance_dy[clearance_pt]][ix+clearance_dx[clearance_pt]] - clearance_iz[clearance_pt]; + tool_collision = 1; + } + } + } + // + // convert from image to lattice units + // + ithreshold = 1+(v.nz-2.0)*ithreshold/(pow(2,v.bit_depth)-1.0); // +1 for bottom edge + // + // z (array y) loop + // + for (iz = 0; iz < vxz.ny; ++iz) { + if (iz <= ithreshold) + vxz.array[iz][ix] = v.interior; + else + vxz.array[iz][ix] = v.empty; + } + } + // + // set edge directions + // + fab_directions(&vxz); + // + // vectorize edge directions + // + fab_vectorize(&vxz,error,iy); + } + // + // copy xz path + // + vxz.path->segment = vxz.path->first; + while (1) { + // + // follow segment forward + // + vxz.path->segment->point = vxz.path->segment->first; + fab_path_segment(&v); + while (1) { + // + // follow points + // + fab_path_point(&v); + vxz.path->segment->point->axis = vxz.path->segment->point->first; + ix = vxz.path->segment->point->axis->value; + vxz.path->segment->point->axis = vxz.path->segment->point->axis->next; + iy = vxz.path->segment->point->axis->value; + vxz.path->segment->point->axis = vxz.path->segment->point->axis->next; + iz = vxz.path->segment->point->axis->value; + fab_path_axis(&v,ix); + fab_path_axis(&v,iz); + fab_path_axis(&v,iy); + if (vxz.path->segment->point->next == 0) + break; + vxz.path->segment->point = vxz.path->segment->point->next; + } + if (vxz.path->segment->next == 0) + break; + vxz.path->segment = vxz.path->segment->next; + // + // follow segment backwards + // + vxz.path->segment->point = vxz.path->segment->last; + fab_path_segment(&v); + while (1) { + // + // follow points + // + fab_path_point(&v); + vxz.path->segment->point->axis = vxz.path->segment->point->first; + ix = vxz.path->segment->point->axis->value; + vxz.path->segment->point->axis = vxz.path->segment->point->axis->next; + iy = vxz.path->segment->point->axis->value; + vxz.path->segment->point->axis = vxz.path->segment->point->axis->next; + iz = vxz.path->segment->point->axis->value; + fab_path_axis(&v,ix); + fab_path_axis(&v,iz); + fab_path_axis(&v,iy); + if (vxz.path->segment->point->previous == 0) + break; + vxz.path->segment->point = vxz.path->segment->point->previous; + } + if (vxz.path->segment->next == 0) + break; + vxz.path->segment = vxz.path->segment->next; + } + } + // + // check for yz cut + // + if (yz == 1) { + // + // allocate yz finish cut array + // + vyz.nx = v.ny; + vyz.ny = v.nz; + vyz.nz = 1; + vyz.dx = v.dy; + vyz.dy = v.dz; + vyz.dz = 0; + vyz.xmin = v.ymin; + vyz.ymin = v.zmin; + vyz.zmin = 0; + vyz.array = malloc(v.nz*sizeof(uint32_t *)); + for (iz = 0; iz < v.nz; ++iz) + vyz.array[iz] = malloc(v.ny*sizeof(uint32_t)); + // + // start yz path + // + fab_path_start(&vyz,3); + // + // x loop + // + ixmin = v.nx*clearance_diameter/(2.0*v.dx); + ixmax = (v.nx-1) - v.nx*clearance_diameter/(2.0*v.dx); + idx = v.nx*offset_diameter*(1-offset_overlap)/v.dx; + printf(" yz finish:\n"); + for (ix = ixmax; ix >= ixmin; (ix -= idx)) { + printf(" x=%d/%d\n",ix,ixmax); + // + // y (array x) loop + // + for (iy = 0; iy < vyz.nx; ++iy) { + // + // set z threshold + // + if ((iy <= clearance_ir) | (iy >= (vyz.nx-clearance_ir))) + // + // too close to edge, set max + // + ithreshold = pow(2,v.bit_depth); + else { + // + // offset for tool shape + // + ithreshold = 0; + for (tool_pt = 0; tool_pt < tool_n; ++tool_pt) { + if (v.array[iy+tool_dy[tool_pt]][ix+tool_dx[tool_pt]] > (ithreshold+tool_iz[tool_pt])) + ithreshold = v.array[iy+tool_dy[tool_pt]][ix+tool_dx[tool_pt]] - tool_iz[tool_pt]; + } + // + // check clearance + // + for (clearance_pt = 0; clearance_pt < clearance_n; ++clearance_pt) { + if (v.array[iy+clearance_dy[clearance_pt]][ix+clearance_dx[clearance_pt]] > (ithreshold+clearance_iz[clearance_pt])) { + ithreshold = v.array[iy+clearance_dy[clearance_pt]][ix+clearance_dx[clearance_pt]] - clearance_iz[clearance_pt]; + tool_collision = 1; + } + } + } + // + // convert from image to lattice units + // + ithreshold = 1+(v.nz-2.0)*ithreshold/(pow(2,v.bit_depth)-1.0); // +1 for bottom edge + // + // z (array y) loop + // + for (iz = 0; iz < vyz.ny; ++iz) { + if (iz <= ithreshold) + vyz.array[iz][iy] = v.interior; + else + vyz.array[iz][iy] = v.empty; + } + } + // + // set edge directions + // + fab_directions(&vyz); + // + // vectorize edge directions + // + fab_vectorize(&vyz,error,ix); + } + // + // copy yz path + // + vyz.path->segment = vyz.path->first; + while (1) { + // + // follow segment forwards + // + vyz.path->segment->point = vyz.path->segment->first; + fab_path_segment(&v); + while (1) { + // + // follow points + // + fab_path_point(&v); + vyz.path->segment->point->axis = vyz.path->segment->point->first; + ix = vyz.path->segment->point->axis->value; + vyz.path->segment->point->axis = vyz.path->segment->point->axis->next; + iy = vyz.path->segment->point->axis->value; + vyz.path->segment->point->axis = vyz.path->segment->point->axis->next; + iz = vyz.path->segment->point->axis->value; + fab_path_axis(&v,iz); + fab_path_axis(&v,ix); + fab_path_axis(&v,iy); + if (vyz.path->segment->point->next == 0) + break; + vyz.path->segment->point = vyz.path->segment->point->next; + } + if (vyz.path->segment->next == 0) + break; + vyz.path->segment = vyz.path->segment->next; + // + // follow segment backwards + // + vyz.path->segment->point = vyz.path->segment->last; + fab_path_segment(&v); + while (1) { + // + // follow points + // + fab_path_point(&v); + vyz.path->segment->point->axis = vyz.path->segment->point->first; + ix = vyz.path->segment->point->axis->value; + vyz.path->segment->point->axis = vyz.path->segment->point->axis->next; + iy = vyz.path->segment->point->axis->value; + vyz.path->segment->point->axis = vyz.path->segment->point->axis->next; + iz = vyz.path->segment->point->axis->value; + fab_path_axis(&v,iz); + fab_path_axis(&v,ix); + fab_path_axis(&v,iy); + if (vyz.path->segment->point->previous == 0) + break; + vyz.path->segment->point = vyz.path->segment->point->previous; + } + if (vyz.path->segment->next == 0) + break; + vyz.path->segment = vyz.path->segment->next; + } + } + // + // check for xy cut + // + if (xy == 1) { + // + // z loop + // + for (layer = (nz-1); layer >= 0; --layer) { + if (v.dz == 0) { + z_layer = z_top; + intensity_layer = intensity_top; + layer_number = 0; + } + else { + z_layer = z_list[layer]; + intensity_layer = intensity_bottom + (intensity_top-intensity_bottom)*(z_layer-z_bottom)/(z_top-z_bottom); + layer_number = v.nz*(z_layer-z_bottom)/(z_top-z_bottom); + } + printf("png_path: intensity %f, z %f\n",intensity_layer,z_layer); + // + // copy image to array + // + fab_png_array(&v); + // + // threshold array + // + printf(" threshold\n"); + fab_threshold(&v,intensity_layer); + // + // find edges + // + printf(" find edges\n"); + remaining_count = fab_edges(&v); + if (remaining_count == 0) { + printf(" no layer edges\n"); + continue; + } + // + // find edge distances + // + printf(" find distances\n"); + //test_fab_distances(&v); + fab_distances(&v); + // + // loop over contours + // + printf(" offset:\n"); + offset_count = 0; + remaining_count_sum = 0; + do { + // + // offset + // + distance = offset_diameter/2.0 + offset_diameter*(1-offset_overlap)*offset_count; + remaining_count = fab_offset(&v,distance); + remaining_count_sum += remaining_count; + printf(" distance %f, %d exterior points remain\n", + distance,remaining_count); + if (remaining_count != 0) { + // + // set edge directions + // + fab_directions(&v); + // + // vectorize edge directions + // + fab_vectorize(&v,error,layer_number); + } + ++offset_count; + } while ((offset_count != offset_number) && (remaining_count != 0)); + } + if (remaining_count_sum == 0) { + printf("png_path: no offset edges\n"); + exit(1); + } + } + } + if (tool_collision == 1) + printf(" tool collisions\n"); + // + // write path + // + fab_write_path(&v,argv[2]); + // + // exit + // + exit(0); + } + diff --git a/src/core/png_scale.c b/src/core/png_scale.c new file mode 100644 index 0000000..fde1d99 --- /dev/null +++ b/src/core/png_scale.c @@ -0,0 +1,48 @@ +// +// png_scale.c +// rescale PNG intensity +// +// Neil Gershenfeld +// CBA MIT 1/22/11 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float min,max; + // + // command line args + // + if (argc != 5) { + printf("command line: png_scale in.png out.png low high\n"); + printf(" in.png = input PNG file\n"); + printf(" out.png = output PNG file\n"); + printf(" low = rescaled intensity minimum (0-1)\n"); + printf(" high = rescaled intensity maximum (0-1)\n"); + exit(-1); + } + // + // read PNG + // + fab_read_png(&v,argv[1]); + // + // rescale + // + sscanf(argv[3],"%f",&min); + sscanf(argv[4],"%f",&max); + fab_rescale(&v,min,max); + // + // write PNG + // + fab_write_png_K(&v,argv[2]); + } + diff --git a/src/core/png_size.c b/src/core/png_size.c new file mode 100644 index 0000000..c441b60 --- /dev/null +++ b/src/core/png_size.c @@ -0,0 +1,59 @@ +// +// png_size.c +// display and edit PNG size +// +// Neil Gershenfeld +// CBA MIT 8/28/10 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// +// todo +// variable units +// pipe I/O +// variable bit depth +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float dx,dy; + // + // command line args + // + if (!((argc == 2) || (argc == 3) || (argc == 4))) { + printf("command line: png_size in.png [dx [dy]]\n"); + printf(" in.png = input PNG file\n"); + printf(" dx = set width (optional, mm)\n"); + printf(" dy = set height (optional, mm)\n"); + exit(-1); + } + // + // read image + // + fab_read_png(&v,argv[1]); + // + // rescale if size given + // + if (argc == 3) { + sscanf(argv[2],"%f",&dx); + dy = v.dy * dx / ((float) v.dx); + v.dx = dx; + v.dy = dy; + fab_write_png_K(&v,argv[1]); + } + else if (argc == 4) { + sscanf(argv[2],"%f",&dx); + sscanf(argv[3],"%f",&dy); + v.dx = dx; + v.dy = dy; + fab_write_png_K(&v,argv[1]); + } + } + diff --git a/src/core/stl_info.c b/src/core/stl_info.c new file mode 100644 index 0000000..af7dbf8 --- /dev/null +++ b/src/core/stl_info.c @@ -0,0 +1,35 @@ +// +// stl_info.c +// report .stl info +// +// Neil Gershenfeld +// CBA MIT 3/6/11 +// +// (c) Massachusetts Institute of Technology 2011 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float units,resolution; + char axis; + // + // command line args + // + if (argc != 2) { + printf("command line: stl_info in.stl\n"); + printf(" in.stl = input binary STL file\n"); + exit(-1); + } + // + // read .stl + // + fab_read_stl(&v,argv[1]); + } diff --git a/src/core/stl_path.c b/src/core/stl_path.c new file mode 100644 index 0000000..061d092 --- /dev/null +++ b/src/core/stl_path.c @@ -0,0 +1,64 @@ +// +// stl_path.c +// convert .stl to .path +// +// Neil Gershenfeld 10/4/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float units,resolution; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5))) { + printf("command line: stl_path in.stl out.path [units [resolution]]]\n"); + printf(" in.stl = input binary STL file\n"); + printf(" out.png = output PNG file\n"); + printf(" units = file units (optional, mm/unit, default 1)\n"); + printf(" resolution = image resolution (optional, pixels/mm, default 10)\n"); + exit(-1); + } + if (argc == 3) { + units = 1; + resolution = 10; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&units); + resolution = 10; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&units); + sscanf(argv[4],"%f",&resolution); + } + // + // read .stl + // + fab_read_stl(&v,argv[1]); + // + // convert mesh to path + // + fab_mesh_path(&v,units,resolution); + // + // write .path + // + fab_write_path(&v,argv[2]); + // + // return + // + return(0); + } diff --git a/src/core/stl_png.c b/src/core/stl_png.c new file mode 100644 index 0000000..8b8c9cb --- /dev/null +++ b/src/core/stl_png.c @@ -0,0 +1,76 @@ +// +// stl_png.c +// convert STL to PNG +// +// Neil Gershenfeld 10/4/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#include "fab.h" + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + float units,resolution; + char axis; + // + // command line args + // + if (!((argc == 3) || (argc == 4) || (argc == 5) || (argc == 6))) { + printf("command line: stl_png in.stl out.png [units [resolution [axis]]]\n"); + printf(" in.stl = input binary STL file\n"); + printf(" out.png = output PNG file\n"); + printf(" units = file units (optional, mm/unit, default 1)\n"); + printf(" resolution = image resolution (optional, pixels/mm, default 10)\n"); + printf(" axis = projection axis (optional, top or bottom, x|X|y|Y|z|Z, default z)\n"); + exit(-1); + } + if (argc == 3) { + units = 1; + resolution = 10; + axis = 'z'; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&units); + resolution = 10; + axis = 'z'; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&units); + sscanf(argv[4],"%f",&resolution); + axis = 'z'; + } + else if (argc == 6) { + sscanf(argv[3],"%f",&units); + sscanf(argv[4],"%f",&resolution); + sscanf(argv[5],"%c",&axis); + } + // + // read STL + // + fab_read_stl(&v,argv[1]); + // + // draw mesh into array + // + fab_shade_mesh(&v,units,resolution,axis); + // + // move origin to corner + // + v.xmin = 0; + v.ymin = 0; + v.zmin = 0; + // + // write PNG + // + fab_write_png_K(&v,argv[2]); + } diff --git a/src/core/svg_path.c b/src/core/svg_path.c new file mode 100644 index 0000000..886a001 --- /dev/null +++ b/src/core/svg_path.c @@ -0,0 +1,1255 @@ +// +// svg_path.c +// convert SVG to path +// +// Neil Gershenfeld 9/21/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// +// todo +// gradient intensity +// + +#include "fab.h" + +#define SVG_MAX_FILE 1000000 +#define SVG_MAX_TRANSFORM 100 + +double angle(double ux, double uy, double vx, double vy) { + double sign = (((ux*vy-uy*vx) > 0) ? 1 : -1); + return (sign*acos((ux*vx+uy*vy)/(sqrt(ux*ux+uy*uy)*sqrt(vx*vx+vy*vy)))); + } + +void parse_number_units(char *ptr, double *number, double *unit_scale, char *units) { + // + // parse quoted number and units + // return scale in mm/unit + // + char *start,*end; + start = strstr(ptr,"\""); + end = strstr(start+1,"\""); + char c1,c2; + c1 = *(end-1); + c2 = *(end-2); + if ((((c2 >= '0') && (c2 <= '9')) || (c2 == '.')) + && (((c1 >= '0') && (c1 <= '9')) || (c1 == '.'))) { + *number = strtod(start+1,NULL); + strcpy(units,"px"); + } + else { + units[0] = *(end-2); + units[1] = *(end-1); + units[2] = 0; + *(end-2) = ' '; + *(end-1) = ' '; + *number = strtod(start+1,NULL); + } + if (0 == strncmp(units,"px",2)) + *unit_scale = 25.4*1.0/90.0; // Inkscape px default 90/inch + else if (0 == strncmp(units,"pt",2)) + *unit_scale = 25.4*1.0/72.0; + else if (0 == strncmp(units,"in",2)) + *unit_scale = 25.4; + else if (0 == strncmp(units,"mm",2)) + *unit_scale = 1.0; + else if (0 == strncmp(units,"cm",2)) + *unit_scale = 10.0; + else { + printf("svg_path: oops -- don't recognize unit %s\n",units); + exit(-1); + } + } + +void next_number(char **ptr, double *number) { + // + // return next number after pointer + // + char haystack[] = "0123456789.-+"; + char *end; + // + // find start + // + while (1) { + if (strchr(haystack,**ptr) != NULL) + break; + *ptr += 1; + } + // + // find end + // + end = *ptr; + while (1) { + if (strchr(haystack,*end) == NULL) + break; + end += 1; + } + // + // move pointer to end and return number + // + *number = strtod(*ptr,&end); + *ptr = end; + } + +char next_element(char **ptr, char current_element) { + // + // return next path element after pointer + // + char number_haystack[] = "0123456789.-+"; + char element_haystack[] = "mMlLhHvVcCsSaAzZ\""; + while (1) { + if (strchr(element_haystack,**ptr) != NULL) + return(**ptr); + else if (strchr(number_haystack,**ptr) != NULL) + return(current_element); + else + *ptr += 1; + } + } + +void clear_transform(int *transform) { + // + // pop current transform from stack + // + *transform -= 1; + } + +int hex_int(char chr) { + // + // return hex for char + // + if (chr == '0') return 0; + else if (chr == '1') return 1; + else if (chr == '2') return 2; + else if (chr == '3') return 3; + else if (chr == '4') return 4; + else if (chr == '5') return 5; + else if (chr == '6') return 6; + else if (chr == '7') return 7; + else if (chr == '8') return 8; + else if (chr == '9') return 9; + else if ((chr == 'a') || (chr == 'A')) return 10; + else if ((chr == 'b') || (chr == 'B')) return 11; + else if ((chr == 'c') || (chr == 'C')) return 12; + else if ((chr == 'd') || (chr == 'D')) return 13; + else if ((chr == 'e') || (chr == 'e')) return 14; + else if ((chr == 'f') || (chr == 'F')) return 15; + printf("svg_path: oops -- non-hex char\n"); + exit(-1); + } + +void set_intensity(char *start, int *zn, struct fab_vars *v, int zsign) { + char *end,*ptr; + int r,g,b; + float i; + // + // set zn from element intensity + // + end = strstr(start+1,">"); + ptr = strstr(start,"stroke:"); + if ((ptr != NULL) && (ptr < end)) { + // + // stroke found, check for hex encoding + // + ptr = strstr(ptr,"#"); + if ((ptr != NULL) && (ptr < end)) { + // + // hex encoding found, set intensity + // + r = 16*hex_int(ptr[1]) + hex_int(ptr[2]); + g = 16*hex_int(ptr[3]) + hex_int(ptr[4]); + b = 16*hex_int(ptr[5]) + hex_int(ptr[6]); + if (zsign == 1) + i = (r+g+b)/(255.0+255.0+255.0); + else + i = 1.0 - (r+g+b)/(255.0+255.0+255.0); + *zn = i * (v->nz - 1); + } + else { + // + // hex encoding not found, set to bottom + // + *zn = 0; + } + } + else { + // + // stroke not found, set to bottom + // + *zn = 0; + } + } + +void set_transform(char *start, int *transform, double transforms[SVG_MAX_TRANSFORM][6]) { + double a,b,c,d,e,f; + double pi = 4*atan(1.0); + char *end,*next,*ptr; + // + // push transform for current element onto stack + // + end = strstr(start+1,">"); + next = strstr(start+1,"<"); + if ((next != NULL) && (next < end)) + end = next; + // + // check for transform + // + ptr = strstr(start,"transform"); + if ((ptr != NULL) && (ptr < end)) { + // + // found, check for matrix + // + ptr = strstr(start,"matrix("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: matrix\n"); + next_number(&ptr,&a); + next_number(&ptr,&b); + next_number(&ptr,&c); + next_number(&ptr,&d); + next_number(&ptr,&e); + next_number(&ptr,&f); + transforms[*transform][0] = a; + transforms[*transform][1] = b; + transforms[*transform][2] = c; + transforms[*transform][3] = d; + transforms[*transform][4] = e; + transforms[*transform][5] = f; + *transform += 1; + return; + } + // + // check for translate + // + ptr = strstr(start,"translate("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: translate\n"); + next_number(&ptr,&e); + next_number(&ptr,&f); + transforms[*transform][0] = 1; + transforms[*transform][1] = 0; + transforms[*transform][2] = 0; + transforms[*transform][3] = 1; + transforms[*transform][4] = e; + transforms[*transform][5] = f; + *transform += 1; + return; + } + // + // check for scale + // + ptr = strstr(start,"scale("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: scale\n"); + next_number(&ptr,&a); + transforms[*transform][0] = a; + transforms[*transform][1] = 0; + transforms[*transform][2] = 0; + transforms[*transform][3] = a; + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + // + // check for rotate + // + ptr = strstr(start,"rotate("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: rotate\n"); + next_number(&ptr,&a); + transforms[*transform][0] = cos(a*pi/180.0); + transforms[*transform][1] = sin(a*pi/180.0); + transforms[*transform][2] = -sin(a*pi/180.0); + transforms[*transform][3] = cos(a*pi/180.0); + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + // + // check for skewX + // + ptr = strstr(start,"skewX("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: skewX\n"); + next_number(&ptr,&a); + transforms[*transform][0] = 1; + transforms[*transform][1] = 0; + transforms[*transform][2] = tan(a*pi/180.0); + transforms[*transform][3] = 1; + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + // + // check for skewY + // + ptr = strstr(start,"skewY("); + if ((ptr != NULL) && (ptr < end)) { + //printf("trans: skewY\n"); + next_number(&ptr,&a); + transforms[*transform][0] = 1; + transforms[*transform][1] = tan(a*pi/180.0); + transforms[*transform][2] = 0; + transforms[*transform][3] = 1; + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + // + // didn't find transform + // + printf("svg_path: oops -- didn't find transform\n"); + transforms[*transform][0] = 1; + transforms[*transform][1] = 0; + transforms[*transform][2] = 0; + transforms[*transform][3] = 1; + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + else { + // + // transform not found, set unit transform + // + transforms[*transform][0] = 1; + transforms[*transform][1] = 0; + transforms[*transform][2] = 0; + transforms[*transform][3] = 1; + transforms[*transform][4] = 0; + transforms[*transform][5] = 0; + *transform += 1; + return; + } + } + +void path_point(int *xn, int *yn, double x, double y, int transform, double transforms[SVG_MAX_TRANSFORM][6], + double xnscale, double ynscale, double xnmid, double vxmid, double ynmid, double vymid) { + double xt,yt,xtemp,ytemp; + int t; + // + // return path point + // + xt = x; + yt = y; + for (t = (transform-1); t >= 0; --t) { + xtemp = transforms[t][0]*xt + transforms[t][2]*yt + transforms[t][4]; + ytemp = transforms[t][1]*xt + transforms[t][3]*yt + transforms[t][5]; + xt = xtemp; + yt = ytemp; + } + *xn = xnmid + xnscale*(xt - vxmid); + *yn = ynmid + ynscale*(yt - vymid); + } + +void fab_read_svg(struct fab_vars *v, char *input_file_name, float scale, int points, int resolution, float zmin, float zmax) { + // + // read SVG into fab_vars + // + FILE *input_file; + char buf[SVG_MAX_FILE]; + char units[3]; + char current_element,last_element; + int point,ret; + char *ptr,*start,*stop,*endptr; + int transform; + double transforms[SVG_MAX_TRANSFORM][6]; + double unit_scale; + double xnscale,ynscale,xnmid,ynmid; + double vxmin,vymin,vxmid,vymid,vwidth,vheight,vaspect; + double width,height,aspect; + double x,y,z,x0,y0,x1,y1,x2,y2; + double rx,ry,theta,theta_0,theta_1,theta_diff,rotation,large_arc,sweep; + double phi,x1p,y1p,sign,cxp,cyp; + double ax,bx,cx,ay,by,cy,xt,yt,t,r; + double pi; + int xn,yn,zn; + int zsign; + int count; + pi = 4*atan(1.0); + // + // read SVG file + // + input_file = fopen(input_file_name, "rb"); + if (input_file == 0) { + printf("svg_path.c: oops -- can't open %s\n",input_file_name); + exit(-1); + } + ret = fread(buf,1,SVG_MAX_FILE,input_file); + if (ret >= SVG_MAX_FILE) { + printf("svg_path: oops -- exceeded SVG buffer size\n"); + exit(-1); + } + endptr = buf + ret; + fclose(input_file); + printf("read %d bytes from %s\n",ret,input_file_name); + // + // find SVG element + // + ptr = strstr(buf,""); + // + // check for width and height + // + start = strstr(ptr,"width="); + if ((start == NULL) || (start > stop)) { + printf("svg_path: oops -- no width\n"); + exit(-1); + } + parse_number_units(start,&width,&unit_scale,units); + printf(" width %f %s\n",width,units); + start = strstr(ptr,"height="); + if ((start == NULL) || (start > stop)) { + printf("svg_path: oops -- no height\n"); + exit(-1); + } + parse_number_units(start,&height,&unit_scale,units); + printf(" height %f %s\n",height,units); + // + // check for viewBox + // + start = strstr(ptr,"viewBox="); + if ((start != NULL) && (start < stop)) { + next_number(&start,&vxmin); + next_number(&start,&vymin); + next_number(&start,&vwidth); + next_number(&start,&vheight); + printf(" view x min %f\n",vxmin); + printf(" view y min %f\n",vymin); + printf(" view width %f\n",vwidth); + printf(" view height %f\n",vheight); + aspect = height/width; + vaspect = vheight/vwidth; + vxmid = vxmin + vwidth/2.0; + vymid = vymin + vheight/2.0; + // assume xMidYMid meet scaling + if (vaspect > aspect) { + ynscale = resolution*aspect/vheight; + xnscale = ynscale; + } + else { + xnscale = resolution/vwidth; + ynscale = xnscale; + } + xnmid = resolution/2.0; + ynmid = aspect*xnmid; + } + else { + vxmid = width/2.0; + vymid = height/2.0; + xnscale = resolution/width; + ynscale = xnscale; + xnmid = xnscale*width/2.0; + ynmid = ynscale*height/2.0; + } + // + // start path + // + v->nx = 2*xnmid; + v->ny = 2*ynmid; + v->dx = scale*width*unit_scale; + v->dy = scale*height*unit_scale; + v->xmin = 0; + v->ymin = 0; + zsign = 1; + if (v->path->dof > 2) { + if (zmin > zmax) { + z = zmin; + zmin = zmax; + zmax = z; + zsign = -1; + } + v->nz = 1+xnscale*(zmax-zmin); + v->dz = zmax-zmin; + v->zmin = zmin; + } + // + // find graphic elements + // + ptr = buf; + transform = 0; + do { + ptr += 1; + if (strncmp(ptr,"",2) == 0) { + // + // closing g, clear transform + // + clear_transform(&transform); + } + else if (strncmp(ptr,"",2) == 0) + // + // self-closing + // + break; + else if (strncmp(ptr,">",1) == 0) { + // + // not self-closing + // + while (1) { + ptr += 1; + if (strncmp(ptr,"",7) == 0) + break; + } + break; + } + } + printf(" svg_path: defs not yet implemented\n"); + } + else if (strncmp(ptr,"",2) == 0) + // + // self-closing + // + break; + else if (strncmp(ptr,">",1) == 0) { + // + // not self-closing + // + while (1) { + ptr += 1; + if (strncmp(ptr,"",8) == 0) + break; + } + break; + } + } + printf(" svg_path: image not yet implemented\n"); + } + else if (strncmp(ptr,"path->dof > 2) + fab_path_axis(v,zn); + } + else if (current_element == 'M') { + // + // absolute moveto + // + next_number(&ptr,&x0); + next_number(&ptr,&y0); + //printf(" path M: %f %f\n",x0,y0); + current_element = 'L'; + fab_path_segment(v); + fab_path_point(v); + path_point(&xn,&yn,x0,y0,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + else if (current_element == 'l') { + // + // relative lineto + // + next_number(&ptr,&x); + next_number(&ptr,&y); + //printf(" path l: %f %f\n",x,y); + current_element = 'l'; + fab_path_point(v); + path_point(&xn,&yn,x0+x,y0+y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + x0 = x0+x; + y0 = y0+y; + } + else if (current_element == 'L') { + // + // absolute lineto + // + next_number(&ptr,&x); + next_number(&ptr,&y); + //printf(" path L: %f %f\n",x,y); + current_element = 'L'; + fab_path_point(v); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + x0 = x; + y0 = y; + } + else if (current_element == 'h') { + // + // relative horizontal + // + next_number(&ptr,&x); + //printf(" path h: %f\n",x); + current_element = 'j'; + fab_path_point(v); + path_point(&xn,&yn,x0+x,y0,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + x0 = x0+x; + } + else if (current_element == 'H') { + // + // absolute horizontal + // + next_number(&ptr,&x); + //printf(" path H: %f\n",x); + current_element = 'H'; + fab_path_point(v); + path_point(&xn,&yn,x,y0,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + x0 = x; + } + else if (current_element == 'v') { + // + // relative vertical + // + next_number(&ptr,&y); + //printf(" path v: %f\n",y); + current_element = 'v'; + fab_path_point(v); + path_point(&xn,&yn,x0,y0+y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + y0 = y0+y; + } + else if (current_element == 'V') { + // + // absolute vertical + // + next_number(&ptr,&y); + //printf(" path V: %f\n",y); + current_element = 'V'; + fab_path_point(v); + path_point(&xn,&yn,x0,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + y0 = y; + } + else if (current_element == 'c') { + // + // relative curveto + // + next_number(&ptr,&x1); + x1 += x0; + next_number(&ptr,&y1); + y1 += y0; + next_number(&ptr,&x2); + x2 += x0; + next_number(&ptr,&y2); + y2 += y0; + next_number(&ptr,&x); + x += x0; + next_number(&ptr,&y); + y += y0; + //printf(" path c: %f %f %f %f %f %f\n",x1,y1,x2,y2,x,y); + current_element = 'c'; + cx = 3 * (x1 - x0); + bx = 3 * (x2 - x1) - cx; + ax = x - x0 - cx - bx; + cy = 3 * (y1 - y0); + by = 3 * (y2 - y1) - cy; + ay = y - y0 - cy - by; + for (point = 0; point < points; ++point) { + t = point / (points - 1.0); + xt = ax*t*t*t + bx*t*t + cx*t + x0; + yt = ay*t*t*t + by*t*t + cy*t + y0; + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if (current_element == 'C') { + // + // absolute curveto + // + next_number(&ptr,&x1); + next_number(&ptr,&y1); + next_number(&ptr,&x2); + next_number(&ptr,&y2); + next_number(&ptr,&x); + next_number(&ptr,&y); + //printf(" path C: %f %f %f %f %f %f\n",x1,y1,x2,y2,x,y); + current_element = 'C'; + cx = 3 * (x1 - x0); + bx = 3 * (x2 - x1) - cx; + ax = x - x0 - cx - bx; + cy = 3 * (y1 - y0); + by = 3 * (y2 - y1) - cy; + ay = y - y0 - cy - by; + for (point = 0; point < points; ++point) { + t = point / (points - 1.0); + xt = ax*t*t*t + bx*t*t + cx*t + x0; + yt = ay*t*t*t + by*t*t + cy*t + y0; + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if (current_element == 's') { + // + // relative smooth curveto + // + if ((last_element == 'c') || (last_element == 'C') || (last_element == 's') || (last_element == 'S')) { + x1 = x0 + (x0-x2); + y1 = y0 + (y0-y2); + } + else { + x1 = x0; + y1 = y0; + } + next_number(&ptr,&x2); + x2 += x0; + next_number(&ptr,&y2); + y2 += y0; + next_number(&ptr,&x); + x += x0; + next_number(&ptr,&y); + y += y0; + //printf(" path s: %f %f %f %f\n",x2,y2,x,y); + current_element = 'c'; + cx = 3 * (x1 - x0); + bx = 3 * (x2 - x1) - cx; + ax = x - x0 - cx - bx; + cy = 3 * (y1 - y0); + by = 3 * (y2 - y1) - cy; + ay = y - y0 - cy - by; + for (point = 0; point < points; ++point) { + t = point / (points - 1.0); + xt = ax*t*t*t + bx*t*t + cx*t + x0; + yt = ay*t*t*t + by*t*t + cy*t + y0; + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if (current_element == 'S') { + // + // absolute smooth curveto + // + if ((last_element == 'c') || (last_element == 'C') || (last_element == 's') || (last_element == 'S')) { + x1 = x0 + (x0-x2); + y1 = y0 + (y0-y2); + } + else { + x1 = x0; + y1 = y0; + } + next_number(&ptr,&x2); + next_number(&ptr,&y2); + next_number(&ptr,&x); + next_number(&ptr,&y); + //printf(" path S: %f %f %f %f\n",x2,y2,x,y); + current_element = 'C'; + cx = 3 * (x1 - x0); + bx = 3 * (x2 - x1) - cx; + ax = x - x0 - cx - bx; + cy = 3 * (y1 - y0); + by = 3 * (y2 - y1) - cy; + ay = y - y0 - cy - by; + for (point = 0; point < points; ++point) { + t = point / (points - 1.0); + xt = ax*t*t*t + bx*t*t + cx*t + x0; + yt = ay*t*t*t + by*t*t + cy*t + y0; + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if (current_element == 'a') { + // + // relative arc + // + next_number(&ptr,&rx); + next_number(&ptr,&ry); + next_number(&ptr,&rotation); + next_number(&ptr,&large_arc); + next_number(&ptr,&sweep); + next_number(&ptr,&x); + x += x0; + next_number(&ptr,&y); + y += y0; + //printf(" path a: %f %f %f %f %f %f %f\n",rx,ry,rotation,large_arc,sweep,x,y); + current_element = 'a'; + phi = rotation*pi/180.0; + x1 = x0; + x2 = x; + y1 = y0; + y2 = y; + x1p = cos(phi)*(x1-x2)/2.0 + sin(phi)*(y1-y2)/2.0; + y1p = -sin(phi)*(x1-x2)/2.0 + cos(phi)*(y1-y2)/2.0; + sign = ((large_arc == sweep) ? -1 : 1); + if ((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p) < 0) { + cxp = 0; + cyp = 0; + } + else { + cxp = sign * sqrt((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p)/(rx*rx*y1p*y1p + ry*ry*x1p*x1p)) * rx*y1p/ry; + cyp = -1 * sign * sqrt((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p)/(rx*rx*y1p*y1p + ry*ry*x1p*x1p)) * ry*x1p/rx; + } + cx = cos(phi)*cxp - sin(phi)*cyp + (x1+x2)/2.0; + cy = sin(phi)*cxp + cos(phi)*cyp + (y1+y2)/2.0; + theta_0 = angle(1,0,(x1p-cxp)/rx,(y1p-cyp)/ry); + theta_diff = angle ((x1p-cxp)/rx,(y1p-cyp)/ry,(-x1p-cxp)/rx,(-y1p-cyp)/ry); + theta_1 = theta_0 + theta_diff; + if (large_arc == 1) { + if (sweep == 0) + theta_1 -= 2*pi; + else + theta_1 += 2*pi; + } + for (point = 0; point < points; ++point) { + theta = theta_0 + (theta_1-theta_0) * point / (points - 1.0); + xt = cx + rx*cos(theta); + yt = cy + ry*sin(theta); + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if (current_element == 'A') { + // + // absolute arc + // + next_number(&ptr,&rx); + next_number(&ptr,&ry); + next_number(&ptr,&rotation); + next_number(&ptr,&large_arc); + next_number(&ptr,&sweep); + next_number(&ptr,&x); + next_number(&ptr,&y); + //printf(" path A: %f %f %f %f %f %f %f\n",rx,ry,rotation,large_arc,sweep,x,y); + current_element = 'A'; + phi = rotation*pi/180.0; + x1 = x0; + x2 = x; + y1 = y0; + y2 = y; + x1p = cos(phi)*(x1-x2)/2.0 + sin(phi)*(y1-y2)/2.0; + y1p = -sin(phi)*(x1-x2)/2.0 + cos(phi)*(y1-y2)/2.0; + sign = ((large_arc == sweep) ? -1 : 1); + if ((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p) < 0) { + cxp = 0; + cyp = 0; + } + else { + cxp = sign * sqrt((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p)/(rx*rx*y1p*y1p + ry*ry*x1p*x1p)) * rx*y1p/ry; + cyp = -1 * sign * sqrt((rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p)/(rx*rx*y1p*y1p + ry*ry*x1p*x1p)) * ry*x1p/rx; + } + cx = cos(phi)*cxp - sin(phi)*cyp + (x1+x2)/2.0; + cy = sin(phi)*cxp + cos(phi)*cyp + (y1+y2)/2.0; + theta_0 = angle(1,0,(x1p-cxp)/rx,(y1p-cyp)/ry); + theta_diff = angle ((x1p-cxp)/rx,(y1p-cyp)/ry,(-x1p-cxp)/rx,(-y1p-cyp)/ry); + theta_1 = theta_0 + theta_diff; + if (large_arc == 1) { + if (sweep == 0) + theta_1 -= 2*pi; + else + theta_1 += 2*pi; + } + for (point = 0; point < points; ++point) { + theta = theta_0 + (theta_1-theta_0) * point / (points - 1.0); + xt = cx + rx*cos(theta); + yt = cy + ry*sin(theta); + fab_path_point(v); + path_point(&xn,&yn,xt,yt,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + x0 = x; + y0 = y; + } + else if ((current_element == 'z') || (current_element == 'Z')) { + // + // closepath + // + //printf(" path zZ\n"); + fab_path_point(v); + fab_path_axis(v,v->path->segment->first->first->value); + fab_path_axis(v,v->path->segment->first->first->next->value); + if (v->path->dof > 2) + fab_path_axis(v,zn); + current_element = 0; + ptr += 1; + } + } while (*ptr != '\"'); + clear_transform(&transform); + } + else if (strncmp(ptr,"",2) != 0) ptr += 1; // read to end of element + //printf(" rect: %f %f %f %f\n",width,height,x,y); + fab_path_segment(v); + fab_path_point(v); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + fab_path_point(v); + path_point(&xn,&yn,x,y+height,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + fab_path_point(v); + path_point(&xn,&yn,x+width,y+height,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + fab_path_point(v); + path_point(&xn,&yn,x+width,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + fab_path_point(v); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + clear_transform(&transform); + } + else if (strncmp(ptr,"",2) != 0) ptr += 1; // read to end of element + //printf(" circle: %f %f %f\n",cx,cy,r); + fab_path_segment(v); + for (point = 0; point < points; ++point) { + fab_path_point(v); + x = cx + r*cos(point*2*pi/(points-1.0)); + y = cy + r*sin(point*2*pi/(points-1.0)); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + } + clear_transform(&transform); + } + else if (strncmp(ptr,"",2) != 0) ptr += 1; // read to end of element + printf(" svg_path: ellipse not yet implemented\n"); + } + else if (strncmp(ptr,"",2) != 0) ptr += 1; // read to end of element + //printf(" line: %f %f %f %f\n",x1,y1,x2,y2); + fab_path_segment(v); + fab_path_point(v); + path_point(&xn,&yn,x1,y1,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + fab_path_point(v); + path_point(&xn,&yn,x2,y2,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + clear_transform(&transform); + } + else if (strncmp(ptr,"path->dof > 2) + fab_path_axis(v,zn); + while (1) { + // + // loop over remaining points + // + next_number(&ptr,&x); + next_number(&ptr,&y); + fab_path_point(v); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + while ((*ptr == ' ') || (*ptr == '"') || (*ptr == 13) || (*ptr == 10)) ptr += 1; // skip space + if (strncmp(ptr,"/>",2) == 0) break; // check for end + } + clear_transform(&transform); + } + else if (strncmp(ptr,"path->dof > 2) + fab_path_axis(v,zn); + while (1) { + // + // loop over remaining points + // + next_number(&ptr,&x); + next_number(&ptr,&y); + fab_path_point(v); + path_point(&xn,&yn,x,y,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + while ((*ptr == ' ') || (*ptr == '"') || (*ptr == 13) || (*ptr == 10)) ptr += 1; // skip space + if (strncmp(ptr,"/>",2) == 0) break; // check for end + } + fab_path_point(v); + path_point(&xn,&yn,x0,y0,transform,transforms,xnscale,ynscale,xnmid,vxmid,ynmid,vymid); + fab_path_axis(v,xn); + fab_path_axis(v,yn); + if (v->path->dof > 2) + fab_path_axis(v,zn); + clear_transform(&transform); + } + else if (strncmp(ptr,"",6) != 0) ptr += 1; // read to end of element + printf(" svg_path: text not implemented\n"); + } + } while ((endptr-ptr) > 1); + } + +int main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v; + init_vars(&v); + int points,resolution; + float scale,zmin,zmax; + // + // command line args + // Largo al Factotum Canadian Brass + // + if ((argc != 3) && (argc != 4) && (argc != 5) && (argc != 6) && (argc != 7) && (argc != 8)) { + printf("command line: svg_path in.svg out.path [scale [points [resolution [zmin [zmax]]]]]\n"); + printf(" in.svg = input binary SVG file\n"); + printf(" out.path = output path file\n"); + printf(" scale = scale factor (optional, default 1.0)\n"); + printf(" points = points per curve segment (optional, default 25)\n"); + printf(" resolution = path x resolution (optional, default 10000)\n"); + printf(" zmin = path min intensity z (optional, mm, default 0)\n"); + printf(" zmax = path max intensity z (optional, mm, default zmin)\n"); + exit(-1); + } + if (argc == 3) { + scale = 1.0; + points = 25; + resolution = 10000; + zmin = 0; + zmax = 0; + } + else if (argc == 4) { + sscanf(argv[3],"%f",&scale); + points = 25; + resolution = 10000; + zmin = 0; + zmax = 0; + } + else if (argc == 5) { + sscanf(argv[3],"%f",&scale); + sscanf(argv[4],"%d",&points); + resolution = 10000; + zmin = 0; + zmax = 0; + } + else if (argc == 6) { + sscanf(argv[3],"%f",&scale); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%d",&resolution); + zmin = 0; + zmax = 0; + } + else if (argc == 7) { + sscanf(argv[3],"%f",&scale); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%d",&resolution); + sscanf(argv[6],"%f",&zmin); + zmax = zmin; + } + else if (argc == 8) { + sscanf(argv[3],"%f",&scale); + sscanf(argv[4],"%d",&points); + sscanf(argv[5],"%d",&resolution); + sscanf(argv[6],"%f",&zmin); + sscanf(argv[7],"%f",&zmax); + } + // + // read SVG + // + if (argc <= 6) + fab_path_start(&v,2); + else + fab_path_start(&v,3); + fab_read_svg(&v,argv[1],scale,points,resolution,zmin,zmax); + // + // write path + // + fab_write_path(&v,argv[2]); + // + // return + // + return(0); + } diff --git a/src/core/test.c b/src/core/test.c new file mode 100644 index 0000000..5de547f --- /dev/null +++ b/src/core/test.c @@ -0,0 +1,18 @@ +#include +#include + +main() { + float X,Y,Z; + int val; + int True=1, False=0; + int i,j; + X = 0; + Y = 0; + Z = 0; + for (i = 0; i < 10000; ++ i) { + for (j = 0; j < 10000; ++j) { +val = ((3296100*((False | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(0.15)) >= (-0.015)) & (((Y-(1.59))-(0.15)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.155))*((X-(1.47))-(-0.155)) + ((Y-(1.59))-(0.15))*((Y-(1.59))-(0.15)) <= 0.015*0.015) & ((Z-(-0.005)) >= (0)) & ((Z-(-0.005)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(0.1)) >= (-0.015)) & (((Y-(1.59))-(0.1)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(0.05)) >= (-0.015)) & (((Y-(1.59))-(0.05)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(0)) >= (-0.015)) & (((Y-(1.59))-(0)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(-0.05)) >= (-0.015)) & (((Y-(1.59))-(-0.05)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(-0.1)) >= (-0.015)) & (((Y-(1.59))-(-0.1)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(-0.12)) >= (-0.035)) & (((X-(1.47))-(-0.12)) <= (0.035)) & (((Y-(1.59))-(-0.15)) >= (-0.015)) & (((Y-(1.59))-(-0.15)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(-0.15)) >= (-0.015)) & (((Y-(1.59))-(-0.15)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(-0.1)) >= (-0.015)) & (((Y-(1.59))-(-0.1)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(-0.05)) >= (-0.015)) & (((Y-(1.59))-(-0.05)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(0)) >= (-0.015)) & (((Y-(1.59))-(0)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(0.05)) >= (-0.015)) & (((Y-(1.59))-(0.05)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(0.1)) >= (-0.015)) & (((Y-(1.59))-(0.1)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.47))-(0.12)) >= (-0.035)) & (((X-(1.47))-(0.12)) <= (0.035)) & (((Y-(1.59))-(0.15)) >= (-0.015)) & (((Y-(1.59))-(0.15)) <= (0.015)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(0.107)) <= (0.05)) & (((-(X-(1.52)))-(-0.1)) >= (-0.025)) & (((-(X-(1.52)))-(-0.1)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(0.157))*((-(-(Y-(1.22))))-(0.157)) + ((-(X-(1.52)))-(-0.1))*((-(X-(1.52)))-(-0.1)) <= 0.025*0.025) & ((Z-(-0.005)) >= (0)) & ((Z-(-0.005)) <= (0))) | ((((-(-(Y-(1.22))))-(-0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(-0.107)) <= (0.05)) & (((-(X-(1.52)))-(-0.1)) >= (-0.025)) & (((-(X-(1.52)))-(-0.1)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(0.107)) <= (0.05)) & (((-(X-(1.52)))-(0)) >= (-0.025)) & (((-(X-(1.52)))-(0)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(-0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(-0.107)) <= (0.05)) & (((-(X-(1.52)))-(0)) >= (-0.025)) & (((-(X-(1.52)))-(0)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(0.107)) <= (0.05)) & (((-(X-(1.52)))-(0.1)) >= (-0.025)) & (((-(X-(1.52)))-(0.1)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(-(Y-(1.22))))-(-0.107)) >= (-0.05)) & (((-(-(Y-(1.22))))-(-0.107)) <= (0.05)) & (((-(X-(1.52)))-(0.1)) >= (-0.025)) & (((-(X-(1.52)))-(0.1)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((X >= (1.582)) & (X <= (1.628)) & (Y >= (1.432)) & (Y <= (1.448)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.612)) & (X <= (1.628)) & (Y >= (1.319)) & (Y <= (1.448)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.512)) & (X <= (1.598)) & (Y >= (1.482)) & (Y <= (1.498)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.512)) & (X <= (1.528)) & (Y >= (1.319)) & (Y <= (1.498)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.342)) & (X <= (1.368)) & (Y >= (1.432)) & (Y <= (1.448)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.352)) & (X <= (1.368)) & (Y >= (1.192)) & (Y <= (1.448)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.352)) & (X <= (1.528)) & (Y >= (1.192)) & (Y <= (1.208)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.512)) & (X <= (1.528)) & (Y >= (1.105)) & (Y <= (1.208)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.342)) & (X <= (1.428)) & (Y >= (1.582)) & (Y <= (1.598)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.412)) & (X <= (1.428)) & (Y >= (1.319)) & (Y <= (1.598)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.462)) & (X <= (1.598)) & (Y >= (1.732)) & (Y <= (1.748)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.462)) & (X <= (1.478)) & (Y >= (1.232)) & (Y <= (1.748)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.462)) & (X <= (1.578)) & (Y >= (1.232)) & (Y <= (1.248)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.562)) & (X <= (1.578)) & (Y >= (1.025)) & (Y <= (1.248)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.412)) & (X <= (1.578)) & (Y >= (1.025)) & (Y <= (1.041)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.412)) & (X <= (1.428)) & (Y >= (1.025)) & (Y <= (1.121)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(0.25)) >= (-0.025)) & (((Y-(1.59))-(0.25)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.78))-(-0.05))*((X-(1.78))-(-0.05)) + ((Y-(1.59))-(0.25))*((Y-(1.59))-(0.25)) <= 0.025*0.025) & ((Z-(-0.005)) >= (0)) & ((Z-(-0.005)) <= (0))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(0.15)) >= (-0.025)) & (((Y-(1.59))-(0.15)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(0.05)) >= (-0.025)) & (((Y-(1.59))-(0.05)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(-0.05)) >= (-0.025)) & (((Y-(1.59))-(-0.05)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(-0.15)) >= (-0.025)) & (((Y-(1.59))-(-0.15)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.78))-(0)) >= (-0.05)) & (((X-(1.78))-(0)) <= (0.05)) & (((Y-(1.59))-(-0.25)) >= (-0.025)) & (((Y-(1.59))-(-0.25)) <= (0.025)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((X >= (1.612)) & (X <= (1.868)) & (Y >= (1.105)) & (Y <= (1.121)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.852)) & (X <= (1.868)) & (Y >= (1.105)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.772)) & (X <= (1.868)) & (Y >= (1.632)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.582)) & (X <= (1.698)) & (Y >= (1.682)) & (Y <= (1.698)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.682)) & (X <= (1.698)) & (Y >= (1.532)) & (Y <= (1.698)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.682)) & (X <= (1.788)) & (Y >= (1.532)) & (Y <= (1.548)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.582)) & (X <= (1.668)) & (Y >= (1.632)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.652)) & (X <= (1.668)) & (Y >= (1.432)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.652)) & (X <= (1.788)) & (Y >= (1.432)) & (Y <= (1.448)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((((-(Y-(1.698)))-(-0.053)) >= (-0.016)) & (((-(Y-(1.698)))-(-0.053)) <= (0.016)) & (((X-(1.15))-(0)) >= (-0.085)) & (((X-(1.15))-(0)) <= (0.085)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(Y-(1.698)))-(0)) >= (-0.016)) & (((-(Y-(1.698)))-(0)) <= (0.016)) & (((X-(1.15))-(0)) >= (-0.085)) & (((X-(1.15))-(0)) <= (0.085)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((-(Y-(1.698)))-(0.053)) >= (-0.016)) & (((-(Y-(1.698)))-(0.053)) <= (0.016)) & (((X-(1.15))-(0)) >= (-0.085)) & (((X-(1.15))-(0)) <= (0.085)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((X >= (1.262)) & (X <= (1.358)) & (Y >= (1.682)) & (Y <= (1.698)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.262)) & (X <= (1.278)) & (Y >= (1.682)) & (Y <= (1.759)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.142)) & (X <= (1.278)) & (Y >= (1.743)) & (Y <= (1.759)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.412)) & (X <= (1.428)) & (Y >= (1.025)) & (Y <= (1.121)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.022)) & (X <= (1.428)) & (Y >= (1.025)) & (Y <= (1.041)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.022)) & (X <= (1.038)) & (Y >= (1.025)) & (Y <= (1.706)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.022)) & (X <= (1.158)) & (Y >= (1.69)) & (Y <= (1.706)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.142)) & (X <= (1.358)) & (Y >= (1.632)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.142)) & (X <= (1.158)) & (Y >= (1.632)) & (Y <= (1.653)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((((X-(1.35))-(-0.06)) >= (-0.032)) & (((X-(1.35))-(-0.06)) <= (0.032)) & (((Y-(1.84))-(0)) >= (-0.034)) & (((Y-(1.84))-(0)) <= (0.034)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.35))-(0.06)) >= (-0.032)) & (((X-(1.35))-(0.06)) <= (0.032)) & (((Y-(1.84))-(0)) >= (-0.034)) & (((Y-(1.84))-(0)) <= (0.034)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((X >= (1.282)) & (X <= (1.358)) & (Y >= (1.832)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.342)) & (X <= (1.358)) & (Y >= (1.732)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.772)) & (X <= (1.868)) & (Y >= (1.632)) & (Y <= (1.648)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.852)) & (X <= (1.868)) & (Y >= (1.632)) & (Y <= (1.908)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.282)) & (X <= (1.868)) & (Y >= (1.892)) & (Y <= (1.908)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.282)) & (X <= (1.298)) & (Y >= (1.832)) & (Y <= (1.908)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.402)) & (X <= (1.428)) & (Y >= (1.832)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.412)) & (X <= (1.428)) & (Y >= (1.319)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((((X-(1.59))-(-0.06)) >= (-0.032)) & (((X-(1.59))-(-0.06)) <= (0.032)) & (((Y-(1.84))-(0)) >= (-0.034)) & (((Y-(1.84))-(0)) <= (0.034)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((((X-(1.59))-(0.06)) >= (-0.032)) & (((X-(1.59))-(0.06)) <= (0.032)) & (((Y-(1.84))-(0)) >= (-0.034)) & (((Y-(1.84))-(0)) <= (0.034)) & (((Z-(-0.005))-(0)) >= (0)) & (((Z-(-0.005))-(0)) <= (0))) | ((X >= (1.582)) & (X <= (1.658)) & (Y >= (1.732)) & (Y <= (1.748)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.642)) & (X <= (1.658)) & (Y >= (1.732)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.522)) & (X <= (1.538)) & (Y >= (1.832)) & (Y <= (1.908)) & (Z >= (-0.005)) & (Z <= (-0.005))) | ((X >= (1.642)) & (X <= (1.788)) & (Y >= (1.832)) & (Y <= (1.848)) & (Z >= (-0.005)) & (Z <= (-0.005))))!=0)) | False | (65280*((False | False | ((((((X-(1.47))-(0))-(-0.0455))-(0)) >= (0.0105)) & (((((X-(1.47))-(0))-(-0.0455))-(0)) <= (0.0175)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.47))-(0))-(-0.0455))-(0)) >= (0.0056)) & (((((X-(1.47))-(0))-(-0.0455))-(0)) <= (0.0224)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) <= (0.007))) | ((((((X-(1.47))-(0))-(-0.0455))-(0)) >= (0.0056)) & (((((X-(1.47))-(0))-(-0.0455))-(0)) <= (0.0224)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) >= (0.035)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.014*0.014) | (((((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.014*0.014) | ((((((X-(1.47))-(0))-(-0.0455))-(0.0315)) >= (0)) & (((((X-(1.47))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) >= (0.01225)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) <= (0.02975)))) & ~((((((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.007*0.007))) & ~((((((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.47))-(0))-(-0.0455))-(0.0315)) >= (0.007)) & (((((X-(1.47))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.042)) <= (0.028)))) | ((((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375)) >= (0.0105)) & ((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375)) <= (0.0175)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0)) >= (0)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042))) | (((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375)) >= (0)) & ((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375)) <= (0.014)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0)) >= (0.0245)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042)))) & ~(((((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375))-(0))*((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375))-(0)) + ((((((Y-(1.59))-(0.0525))-(0))-(-0.042))-(0))-(0.042))*((((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.004375))-(0))) <= 0.0105*0.0105)) | False | (((((((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0))*((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0)) + ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0))-(0.0105))*((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0))) <= 0.0105*0.0105)) & ~(((((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0))*((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0)) + ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0))-(0.0105))*((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021))-(0))) <= 0.0035*0.0035))) & ~((((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021)) >= (-0.028)) & ((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021)) <= (0.028)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0)) >= (0.0105)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042))))) & ~((((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021)) >= (0)) & ((((((X-(1.47))-(0))-(-0.0455))-(0))-(0.021)) <= (0.028)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0)) >= (-0.042)) & ((((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042)))) | ((((((X-(1.47))-(0))-(-0.0455))-(0)) >= (0.0105)) & (((((X-(1.47))-(0))-(-0.0455))-(0)) <= (0.0175)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) >= (0.007)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) <= (0.0315))) | ((((((X-(1.47))-(0))-(-0.0455))-(0)) >= (0.0056)) & (((((X-(1.47))-(0))-(-0.0455))-(0)) <= (0.0224)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) >= (0.0175)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) <= (0.0245))) | (((((((X-(1.47))-(0))-(-0.0455))-(0.0315)) >= (0.021)) & (((((X-(1.47))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) <= (0.042))) | (((((0.042)-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0))-((0.021)-(0))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.014))) >= 0) & ((((0.014)-(0.042))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.021))-((0.021)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.042))) >= 0) & ((((0.014)-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.021))-((0)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.014))) >= 0))) & ~((((((0.0315)-(0.021))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.01225))-((0.021)-(0.01225))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.021))) >= 0) & ((((0.021)-(0.0315))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.021))-((0.021)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.0315))) >= 0) & ((((0.021)-(0.021))*(((((X-(1.47))-(0))-(-0.0455))-(0.0315))-(0.021))-((0.01225)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.021))) >= 0))) | (((((((X-(1.47))-(0))-(-0.0455))-(0.063)) >= (0.021)) & (((((X-(1.47))-(0))-(-0.0455))-(0.063)) <= (0.028)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.59))-(0.0525))-(0))-(-0.105)) <= (0.042))) | (((((0.042)-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0))-((0.021)-(0))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.014))) >= 0) & ((((0.014)-(0.042))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.021))-((0.021)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.042))) >= 0) & ((((0.014)-(0.014))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.021))-((0)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.014))) >= 0))) & ~((((((0.0315)-(0.021))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.01225))-((0.021)-(0.01225))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.021))) >= 0) & ((((0.021)-(0.0315))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.021))-((0.021)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.0315))) >= 0) & ((((0.021)-(0.021))*(((((X-(1.47))-(0))-(-0.0455))-(0.063))-(0.021))-((0.01225)-(0.021))*(((((Y-(1.59))-(0.0525))-(0))-(-0.105))-(0.021))) >= 0))))!=0)) | (255*((False | False | ((((((0.0315)-(0.0315))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0))-((0.021)-(0))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0.0315))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.021))-((0.0105)-(0.021))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.0315)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))-((0)-(0.0105))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.04725)-(0.04725))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0))-((0.021)-(0))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.01575)-(0.04725))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.021))-((0.0105)-(0.021))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.04725)-(0.01575))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))-((0)-(0.0105))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.021)))))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.007875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.023625))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875)) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.018375)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.02625))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.0223125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.013125))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.0091875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375)) | ((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))/(1.5))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))/(1.5))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525)))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.007875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.023625))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875)) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.018375)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.02625))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0223125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.013125))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0091875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375)) | ((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125)) >= (0.007875)) & ((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125)) <= (0.013125)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) >= (0)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125)) >= (0)) & ((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125)) <= (0.0105)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) >= (0.018375)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) <= (0.0315)))) & ~(((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0)) + ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0))-(0.0315))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0))) <= 0.007875*0.007875)))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.007875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.023625))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875)) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.018375)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.02625))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.0223125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.013125))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.0091875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375)) | (((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0))/(0.875))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0))/(0.875))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525)) | (((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105)) + (((0) + ((((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.013125))-(0))/(0.875))-(0.0105))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))) <= 0.0105*0.0105)) & ~(((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105)) + (((0) + ((((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.013125))-(0))/(0.875))-(0.0105))*((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.007875)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.023625)))))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.007875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875) | (((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.023625))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.013125))) <= 0.007875*0.007875)) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.018375)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.02625))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.0223125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.013125))))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.0091875))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0039375*0.0039375)) | (((((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((0.021)-(0.00525))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-((0)-(0))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0) & ((((0.021)-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-((0.01575)-(0))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((0.00525)-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0)-(0.01575))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0)))) & ~((((((0.018375)-(0.00525))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.007875))-((0.021)-(0.007875))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0) & ((((0.00525)-(0.018375))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.021)-(0.021))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((0.00525)-(0.00525))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.007875)-(0.021))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0))))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | ((((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((0.02625)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-((0)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0.02625)-(0.02625))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0))-((0.01575)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.02625))) >= 0) & ((((0)-(0.02625))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0)-(0.01575))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.02625))) >= 0)))) & ~((((((0.02625)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.00525))-((0.021)-(0.00525))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.02625))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.021)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.02625))) >= 0) & ((((0)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.00525)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))))!=0)) | (255*((False | False | ((((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.35))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.35))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | (((((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.021))))) & ~((((((0.01575)-(0.0315))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.021)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.01575)-(0.01575))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.0105)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0) & ((((0.0315)-(0.01575))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0))) | (((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.35))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525)) | ((((((X-(1.35))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.35))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.021))))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | (((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.021))) | ((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | (((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0.01575)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.49))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((0.0315)-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-((0.01575)-(0))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.0105))) >= 0) & ((((0.0105)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0.01575)-(0.01575))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.0105)-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0)-(0.01575))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.0105))) >= 0))) & ~((((((0.023625)-(0.01575))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0091875))-((0.01575)-(0.0091875))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0) & ((((0.01575)-(0.023625))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0.01575)-(0.01575))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.023625))) >= 0) & ((((0.01575)-(0.01575))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0.0091875)-(0.01575))*(((((Y-(1.49))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0))))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | (((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0))/(0.875))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0))/(0.875))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525)) | (((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105)) + (((0) + ((((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.013125))-(0))/(0.875))-(0.0105))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))) <= 0.0105*0.0105)) & ~(((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105)) + (((0) + ((((((Y-(1.54))-(0.01575))-(0))-(-0.0315))-(0.013125))-(0))/(0.875))-(0.0105))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.007875)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.023625)))))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | (((((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.0105)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.59))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((0.021)-(0.00525))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-((0)-(0))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0) & ((((0.021)-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0))-((0.01575)-(0))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((0.00525)-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.01575))-((0)-(0.01575))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0)))) & ~((((((0.018375)-(0.00525))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.007875))-((0.021)-(0.007875))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0) & ((((0.00525)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.021)-(0.021))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((0.00525)-(0.00525))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.007875)-(0.021))*(((((Y-(1.59))-(0.01575))-(0))-(-0.0315))-(0.00525))) >= 0))))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | ((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125)) >= (0.007875)) & ((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125)) <= (0.013125)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) >= (0)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125)) >= (0)) & ((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125)) <= (0.0105)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) >= (0.018375)) & ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0)) <= (0.0315)))) & ~(((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0)) + ((((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0))-(0.0315))*((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00328125))-(0))) <= 0.007875*0.007875)))!=0)) | (255*((False | False | ((((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | ((((((0.0315)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~(((((((0.018375)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0))-((0.0105)-(0))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0) & ((((-0.013125)-(0.018375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.0105))-((0.021)-(0.0105))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0) & ((((-0.013125)-(-0.013125))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.021))-((0)-(0.021))*(((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(-0.013125))) >= 0))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) >= (0.00525)) & (((((Y-(1.69))-(0.01575))-(0))-(-0.0315)) <= (0.0105))))) | ((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))/(1.5))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((0) + (((((Y-(1.69))-(0.01575))-(0))-(-0.0315))-(0))/(1.5))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525)))!=0)) | (255*((False | False | ((((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.59))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.59))-(0))-(-0.034125))-(0)) >= (0.0105)) & (((((X-(1.59))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.01575))) | ((((((((X-(1.59))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((0.039375)-(0.039375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.01575)-(0.00525))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.039375))) >= 0) & ((((0.007875)-(0.039375))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.01575)-(0.01575))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.039375))) >= 0) & ((((0.039375)-(0.007875))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.00525)-(0.01575))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.007875))) >= 0)))) & ~((((((0.023625)-(-0.007875))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(-0.007875))) >= 0) & ((((-0.007875)-(0.023625))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.01575)-(0.00525))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.023625))) >= 0) & ((((-0.007875)-(-0.007875))*(((((X-(1.59))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.00525)-(0.01575))*(((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(-0.007875))) >= 0))) | (((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525)) + (((0) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0))/(1.0))-(0.01575))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525))) <= 0.01575*0.01575)) & ~((((((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525)) + (((0) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0))/(1.0))-(0.01575))*(((((X-(1.59))-(0))-(-0.034125))-(0.04725))-(0.00525))) <= 0.0105*0.0105))) & ~(((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (-0.021)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((0) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0))/(1.0)) >= (0)) & (((0) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0))/(1.0)) <= (0.0315)))) | ((((((X-(1.59))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.59))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (65280*((False | False | (((((((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.52))-(0))-(-0.02975))-(0))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.52))-(0))-(-0.02975))-(0)) >= (0)) & (((((X-(1.52))-(0))-(-0.02975))-(0)) <= (0.028)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.042)) <= (0.042)))) | ((((((X-(1.52))-(0))-(-0.02975))-(0)) >= (0.021)) & (((((X-(1.52))-(0))-(-0.02975))-(0)) <= (0.028)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0.0105)) & ((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.0175)) & ((((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0)) >= (0)) & ((((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042))) | (((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0)) & ((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.014)) & ((((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0)) >= (0.0245)) & ((((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042)))) & ~(((((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))*((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0)) + ((((((Y-(1.22))-(0.0525))-(0))-(-0.042))-(0))-(0.042))*((((((X-(1.52))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))) <= 0.0105*0.0105)) | False | ((((((X-(1.52))-(0))-(-0.0455))-(0)) >= (0.0105)) & (((((X-(1.52))-(0))-(-0.0455))-(0)) <= (0.0175)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.52))-(0))-(-0.0455))-(0)) >= (0.0056)) & (((((X-(1.52))-(0))-(-0.0455))-(0)) <= (0.0224)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.007))) | ((((((X-(1.52))-(0))-(-0.0455))-(0)) >= (0.0056)) & (((((X-(1.52))-(0))-(-0.0455))-(0)) <= (0.0224)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0.035)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.52))-(0))-(-0.0455))-(0.0315)) >= (0)) & (((((X-(1.52))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((((X-(1.52))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.52))-(0))-(-0.0455))-(0.063)) <= (0.007)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.042))) | (((((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014))*(((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014)) + (((((Y-(1.22))-(0.0525))-(0))-(-0.105))-(0.028))*(((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014))) <= 0.014*0.014) | ((((((X-(1.52))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.52))-(0))-(-0.0455))-(0.063)) <= (0.014)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0.014)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.042)))) & ~((((((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014))*(((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014)) + (((((Y-(1.22))-(0.0525))-(0))-(-0.105))-(0.028))*(((((X-(1.52))-(0))-(-0.0455))-(0.063))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.52))-(0))-(-0.0455))-(0.063)) >= (0.007)) & (((((X-(1.52))-(0))-(-0.0455))-(0.063)) <= (0.014)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) >= (0.021)) & (((((Y-(1.22))-(0.0525))-(0))-(-0.105)) <= (0.035)))))!=0)) | (255*((False | False | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) >= (0.007875)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) <= (0.013125)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) >= (0.0042)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) <= (0.0168)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.00525))) | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) >= (0.0042)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.023625)) <= (0.0168)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.04725)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.04725)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))) <= 0.0105*0.0105) | (((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))) <= 0.0105*0.0105) | ((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875)) >= (0.00525)) & (((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.0459375))-(0.070875)) <= (0.01575)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))))!=0)) | (255*((False | False | ((((((0.0315)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0))-((0.021)-(0))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0.021))-((0.0105)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.0315)-(0))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0.0105))-((0)-(0.0105))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.04725)-(0.04725))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0))-((0.021)-(0))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.01575)-(0.04725))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0.021))-((0.0105)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.04725)-(0.01575))*(((((cos(-1.57079632679)*(X-(1.62))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0105))-(0))-(0.0105))-((0)-(0.0105))*(((((-sin(-1.57079632679)*(X-(1.62))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0))))!=0)) | (255*((False | False | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | (((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | (((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((0.0315)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.00525))-((0.015225)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.018375)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.015225))-((0.00525)-(0.015225))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.0315)-(0.018375))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.00525))-((0.00525)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.018375))) >= 0)))) & ~((((((0.01575)-(0))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.00945)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0.0315)-(0.01575))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.00945))-((0.021)-(0.00945))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0) & ((((0)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.021))-((0.021)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0)))) & ~((((((0.013125)-(0))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.00525))-((0.00525)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.013125))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.00525))-((0.015225)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.013125))) >= 0) & ((((0)-(0))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725))-(0.015225))-((0.00525)-(0.015225))*(((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))))!=0)) | (255*((False | False | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | (((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625)) >= (0.00525)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.023625)) <= (0.01575)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.04725)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.04725)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) >= (0.007875)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) <= (0.013125)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) >= (0.0042)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) <= (0.0168)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.00525))) | ((((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) >= (0.0042)) & (((((cos(-1.57079632679)*(X-(1.52))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.0459375))-(0.070875)) <= (0.0168)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((-sin(-1.57079632679)*(X-(1.52))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | (((((((0.0315)-(0))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.021))-((0.00525)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.021)-(-0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0) & ((((-0.0105)-(0.021))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((-0.0105)-(-0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0))-(0.021))-((0.00525)-(0.021))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0)))) & ~(((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) >= (0.007875)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) <= (0.013125)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.327)))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.327)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | (((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105)) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) >= (0.0105)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.01575))) | ((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((0.039375)-(0.039375))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.01575)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.039375))) >= 0) & ((((0.007875)-(0.039375))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.01575)-(0.01575))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.039375))) >= 0) & ((((0.039375)-(0.007875))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.00525)-(0.01575))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.007875))) >= 0)))) & ~((((((0.023625)-(-0.007875))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.00525)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(-0.007875))) >= 0) & ((((-0.007875)-(0.023625))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.00525))-((0.01575)-(0.00525))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0.023625))) >= 0) & ((((-0.007875)-(-0.007875))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.023625))-(0.01575))-((0.00525)-(0.01575))*(((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(-0.007875))) >= 0))) | (((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525)) + (((0) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0))/(1.0))-(0.01575))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525))) <= 0.01575*0.01575)) & ~((((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525)) + (((0) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0))/(1.0))-(0.01575))*(((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725))-(0.00525))) <= 0.0105*0.0105))) & ~(((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725)) >= (-0.021)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((0) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0))/(1.0)) >= (0)) & (((0) + (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315))-(0))/(1.0)) <= (0.0315)))) | ((((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((cos(-1.57079632679)*(X-(1.42))+sin(-1.57079632679)*(Y-(1.113)))-(0))-(-0.034125))-(0.04725)) <= (0.00525)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((-sin(-1.57079632679)*(X-(1.42))+cos(-1.57079632679)*(Y-(1.113)))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (65280*((False | False | (((((((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014)) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014)) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.78))-(0))-(-0.1085))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0)) <= (0.028)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042)))) | ((((((X-(1.78))-(0))-(-0.1085))-(0)) >= (0.021)) & (((((X-(1.78))-(0))-(-0.1085))-(0)) <= (0.028)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | (((((((((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.028))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014)) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.028))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.78))-(0))-(-0.1085))-(0.0315)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.0315)) <= (0.014)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.028)))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.0315)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.0315)) <= (0.028)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.028)))) & ~((((((0.028)-(0.007))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0))-((0)-(0))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.007))) >= 0) & ((((0.028)-(0.028))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0))-((0.021)-(0))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.028))) >= 0) & ((((0.007)-(0.028))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.021))-((0)-(0.021))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.028))) >= 0)))) & ~((((((0.0245)-(0.007))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.0105))-((0.028)-(0.0105))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.007))) >= 0) & ((((0.007)-(0.0245))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.028))-((0.028)-(0.028))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.0245))) >= 0) & ((((0.007)-(0.007))*(((((X-(1.78))-(0))-(-0.1085))-(0.0315))-(0.028))-((0.0105)-(0.028))*(((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0.007))) >= 0))) | False | ((((((X-(1.78))-(0))-(-0.1085))-(0.0945)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.0945)) <= (0.007)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.0945)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.0945)) <= (0.028)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.035)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.0945)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.0945)) <= (0.0186666666667)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.0175)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.0245))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.126)) >= (0.0105)) & (((((X-(1.78))-(0))-(-0.1085))-(0.126)) <= (0.0175)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.126)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.126)) <= (0.028)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.035)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | (((((((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007))*(((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007)) + (((0) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0))/(1.0))-(0.021))*(((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007))) <= 0.021*0.021)) & ~((((((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007))*(((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007)) + (((0) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0))/(1.0))-(0.021))*(((((X-(1.78))-(0))-(-0.1085))-(0.1575))-(0.007))) <= 0.014*0.014))) & ~(((((((X-(1.78))-(0))-(-0.1085))-(0.1575)) >= (-0.028)) & (((((X-(1.78))-(0))-(-0.1085))-(0.1575)) <= (0.007)) & (((0) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0))/(1.0)) >= (0)) & (((0) + (((((Y-(1.59))-(0.021))-(0))-(-0.042))-(0))/(1.0)) <= (0.042)))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.1575)) >= (0)) & (((((X-(1.78))-(0))-(-0.1085))-(0.1575)) <= (0.007)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.189)) >= (0.0105)) & (((((X-(1.78))-(0))-(-0.1085))-(0.189)) <= (0.0175)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.189)) >= (0.0056)) & (((((X-(1.78))-(0))-(-0.1085))-(0.189)) <= (0.0224)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.007))) | ((((((X-(1.78))-(0))-(-0.1085))-(0.189)) >= (0.0056)) & (((((X-(1.78))-(0))-(-0.1085))-(0.189)) <= (0.0224)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) >= (0.035)) & (((((Y-(1.59))-(0.021))-(0))-(-0.042)) <= (0.042))))!=0)) | (255*((False | False | ((((((((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.081375))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) & ~((((((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.081375))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.081375))-(0)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.081375))-(0)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.78))-(0))-(-0.081375))-(0)) >= (0.0105)) & (((((X-(1.78))-(0))-(-0.081375))-(0)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.01575))) | False | ((((((X-(1.78))-(0))-(-0.081375))-(0.04725)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0.04725)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105))) <= 0.0105*0.0105)) & ~((((((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105)) + (((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0.070875))-(0.0105))) <= 0.00525*0.00525)) | ((((((X-(1.78))-(0))-(-0.081375))-(0.070875)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0.070875)) <= (0.00525)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.081375))-(0.0945)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0.0945)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((((((X-(1.78))-(0))-(-0.081375))-(0.118125)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0.118125)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~(((((((X-(1.78))-(0))-(-0.081375))-(0.118125)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.081375))-(0.118125)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))) & ~((((((0.021)-(0.021))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.00525))-((0.014175)-(0.00525))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((0.013125)-(0.021))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.014175))-((0.00525)-(0.014175))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((0.021)-(0.013125))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.013125))) >= 0)))) & ~((((((0.0105)-(0))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.021))-((0.00945)-(0.021))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0.021)-(0.0105))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.00945))-((0.021)-(0.00945))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.0105))) >= 0) & ((((0)-(0.021))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.021))-((0.021)-(0.021))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0)))) & ~((((((0.007875)-(0))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.007875))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.00525))-((0.014175)-(0.00525))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0.007875))) >= 0) & ((((0)-(0))*(((((X-(1.78))-(0))-(-0.081375))-(0.118125))-(0.014175))-((0.00525)-(0.014175))*(((((Y-(1.84))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) | ((((((X-(1.78))-(0))-(-0.081375))-(0.14175)) >= (0)) & (((((X-(1.78))-(0))-(-0.081375))-(0.14175)) <= (0.021)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.84))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.74))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0.007875)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.74))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((0.0315)-(0.0315))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0))-((0.021)-(0))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0.0315))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.021))-((0.0105)-(0.021))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0.0315)-(0))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))-((0)-(0.0105))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.04725)-(0.04725))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0))-((0.021)-(0))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.01575)-(0.04725))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.021))-((0.0105)-(0.021))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.04725))) >= 0) & ((((0.04725)-(0.01575))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))-((0)-(0.0105))*(((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.01575))) >= 0))) | ((((((((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0.023625))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.021)))) | ((((((((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105) | (((((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0091875)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.0223125)))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105)) + (((((Y-(1.64))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0.04725))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.034125))-(0.04725)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.64))-(0.01575))-(0))-(-0.0315)) <= (0.021)))))!=0)) | (255*((False | False | ((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0.007875)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.013125)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.021)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.0223125))-(0.023625)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0.023625)) <= (0.021)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.54))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.00525)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105)) + (((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | (((((((0.0315)-(0))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.021))-((0.00525)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.021)-(-0.0105))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0) & ((((-0.0105)-(0.021))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((-0.0105)-(-0.0105))*(((((X-(1.78))-(0))-(-0.0223125))-(0))-(0.021))-((0.00525)-(0.021))*(((((Y-(1.44))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0)))) & ~(((((((X-(1.78))-(0))-(-0.0223125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) | ((((((X-(1.78))-(0))-(-0.0223125))-(0.023625)) >= (0)) & (((((X-(1.78))-(0))-(-0.0223125))-(0.023625)) <= (0.021)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.44))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (255*((False | False | ((((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.00525)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | (((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.0105*0.0105) | ((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) & ~((((((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105)) + (((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.0105))) <= 0.00525*0.00525))) & ~(((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0.00525)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.0105)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0.01575)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.02625)))) | (((((((0.0315)-(0))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0))) >= 0) & ((((0)-(0.0315))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0.0315))) >= 0) & ((((0)-(0))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.021))-((0.00525)-(0.021))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0))) >= 0))) & ~((((((0.021)-(-0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.00525))-((0.00525)-(0.00525))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0) & ((((-0.0105)-(0.021))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.00525))-((0.021)-(0.00525))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(0.021))) >= 0) & ((((-0.0105)-(-0.0105))*(((((X-(1.78))-(0))-(-0.034125))-(0))-(0.021))-((0.00525)-(0.021))*(((((Y-(1.34))-(0.01575))-(0))-(-0.0315))-(-0.0105))) >= 0)))) & ~(((((((X-(1.78))-(0))-(-0.034125))-(0)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0)) <= (0.021)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0.0105)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315)))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0.007875)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.013125)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.023625)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.023625)) <= (0.021)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0.02625)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315))) | ((((((X-(1.78))-(0))-(-0.034125))-(0.04725)) >= (0)) & (((((X-(1.78))-(0))-(-0.034125))-(0.04725)) <= (0.021)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) >= (0)) & (((((Y-(1.34))-(0.01575))-(0))-(-0.0315)) <= (0.0315))))!=0)) | (65280*((False | False | ((((((((((X-(1.15))-(0))-(-0.077))-(0)) >= (0)) & (((((X-(1.15))-(0))-(-0.077))-(0)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.042)))) & ~((((((0.042)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0))-((0)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0) & ((((0.021)-(0.042))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0))-((0.0091)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0) & ((((0)-(0.021))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.0091))-((0)-(0.0091))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.021))) >= 0)))) & ~((((((0.021)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.028))-((0.0189)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0) & ((((0.042)-(0.021))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.0189))-((0.028)-(0.0189))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.021))) >= 0) & ((((0)-(0.042))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.028))-((0.028)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0)))) & ~((((((0.042)-(0.042))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.007))-((0.021)-(0.007))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0) & ((((0.0259)-(0.042))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.021))-((0.014)-(0.021))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0) & ((((0.042)-(0.0259))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.014))-((0.007)-(0.014))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.0259))) >= 0)))) & ~((((((0.0161)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.007))-((0.014)-(0.007))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0) & ((((0)-(0.0161))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.014))-((0.021)-(0.014))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.0161))) >= 0) & ((((0)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0))-(0.021))-((0.007)-(0.021))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0))) | ((((((X-(1.15))-(0))-(-0.077))-(0.0315)) >= (0.0105)) & (((((X-(1.15))-(0))-(-0.077))-(0.0315)) <= (0.0175)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.15))-(0))-(-0.077))-(0.0315)) >= (0)) & (((((X-(1.15))-(0))-(-0.077))-(0.0315)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0.035)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((0.042)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0))-((0.014)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0) & ((((0)-(0.042))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0.014))-((0.028)-(0.014))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0) & ((((0)-(0))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0.028))-((0)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))) >= 0))) & ~(((((((0.0245)-(-0.0175))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0))-((0.014)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(-0.0175))) >= 0) & ((((-0.0175)-(0.0245))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0.014))-((0.028)-(0.014))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0.0245))) >= 0) & ((((-0.0175)-(-0.0175))*(((((X-(1.15))-(0))-(-0.077))-(0.063))-(0.028))-((0)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(-0.0175))) >= 0))) & ~(((((((X-(1.15))-(0))-(-0.077))-(0.063)) >= (0)) & (((((X-(1.15))-(0))-(-0.077))-(0.063)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0.007)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.014))))) | ((((((X-(1.15))-(0))-(-0.077))-(0.0945)) >= (0)) & (((((X-(1.15))-(0))-(-0.077))-(0.0945)) <= (0.007)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.042))) | ((((((X-(1.15))-(0))-(-0.077))-(0.0945)) >= (0)) & (((((X-(1.15))-(0))-(-0.077))-(0.0945)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.042)) <= (0.007))) | ((((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375)) >= (0.0105)) & ((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375)) <= (0.0175)) & ((((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0)) >= (0)) & ((((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042))) | (((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375)) >= (0)) & ((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375)) <= (0.014)) & ((((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0)) >= (0.0245)) & ((((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042)))) & ~(((((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375))-(0))*((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375))-(0)) + ((((((Y-(1.698))-(0.0525))-(0))-(-0.042))-(0))-(0.042))*((((((X-(1.15))-(0))-(-0.077))-(0.126))-(0.004375))-(0))) <= 0.0105*0.0105)) | False | (((((((((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014)) + (((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.028))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014)) + (((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.028))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.15))-(0))-(-0.09275))-(0)) >= (0)) & (((((X-(1.15))-(0))-(-0.09275))-(0)) <= (0.014)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) <= (0.028)))) | ((((((X-(1.15))-(0))-(-0.09275))-(0)) >= (0)) & (((((X-(1.15))-(0))-(-0.09275))-(0)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) <= (0.028)))) & ~((((((0.028)-(0.007))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0))-((0)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.007))) >= 0) & ((((0.028)-(0.028))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0))-((0.021)-(0))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.028))) >= 0) & ((((0.007)-(0.028))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.021))-((0)-(0.021))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.028))) >= 0)))) & ~((((((0.0245)-(0.007))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.0105))-((0.028)-(0.0105))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.007))) >= 0) & ((((0.007)-(0.0245))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.028))-((0.028)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.0245))) >= 0) & ((((0.007)-(0.007))*(((((X-(1.15))-(0))-(-0.09275))-(0))-(0.028))-((0.0105)-(0.028))*(((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0.007))) >= 0))) | ((((((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014)) + (((0) + (((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0))/(1.5))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014)) + (((0) + (((((Y-(1.698))-(0.0525))-(0))-(-0.105))-(0))/(1.5))-(0.014))*(((((X-(1.15))-(0))-(-0.09275))-(0.0315))-(0.014))) <= 0.007*0.007)) | False | ((((((X-(1.15))-(0))-(-0.09275))-(0.0945)) >= (0)) & (((((X-(1.15))-(0))-(-0.09275))-(0.0945)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.15))-(0))-(-0.09275))-(0.126)) >= (0)) & (((((X-(1.15))-(0))-(-0.09275))-(0.126)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.15))-(0))-(-0.09275))-(0.1575)) >= (0)) & (((((X-(1.15))-(0))-(-0.09275))-(0.1575)) <= (0.028)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.698))-(0.0525))-(0))-(-0.105)) <= (0.042))))!=0)) | (65280*((False | False | ((((((((X-(1.35))-(0))-(-0.02975))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.02975))-(0)) <= (0.007)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.042))) | (((((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014))) <= 0.014*0.014) | ((((((X-(1.35))-(0))-(-0.02975))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.02975))-(0)) <= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.042)))) & ~((((((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.35))-(0))-(-0.02975))-(0)) >= (0.007)) & (((((X-(1.35))-(0))-(-0.02975))-(0)) <= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0.021)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.035)))) | (((((((0.042)-(0))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.007))-((0.007)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0))) >= 0) & ((((0)-(0.042))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.007))-((0.028)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.042))) >= 0) & ((((0)-(0))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.028))-((0.007)-(0.028))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0))) >= 0))) & ~((((((0.028)-(-0.014))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.007))-((0.007)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(-0.014))) >= 0) & ((((-0.014)-(0.028))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.007))-((0.028)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.028))) >= 0) & ((((-0.014)-(-0.014))*(((((X-(1.35))-(0))-(-0.02975))-(0))-(0.028))-((0.007)-(0.028))*(((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(-0.014))) >= 0)))) & ~(((((((X-(1.35))-(0))-(-0.02975))-(0)) >= (0)) & (((((X-(1.35))-(0))-(-0.02975))-(0)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.042)))) | ((((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0.0105)) & ((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.0175)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) >= (0)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042))) | (((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0)) & ((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.014)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) >= (0.0245)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042)))) & ~(((((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))*((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0)) + ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0))-(0.042))*((((((X-(1.35))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))) <= 0.0105*0.0105)) | False | ((((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375)) >= (0.0105)) & ((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375)) <= (0.0175)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) >= (0)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042))) | (((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375)) >= (0)) & ((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375)) <= (0.014)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) >= (0.0245)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042)))) & ~(((((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375))-(0))*((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375))-(0)) + ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))-(0.042))*((((((X-(1.35))-(0))-(-0.0455))-(0))-(0.004375))-(0))) <= 0.0105*0.0105)) | ((((((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((0) + (((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))/(1.5))-(0.014))*(((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((0) + (((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))/(1.5))-(0.014))*(((((X-(1.35))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.007*0.007)) | ((((((((((X-(1.35))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.35))-(0))-(-0.0455))-(0.063)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.042)))) & ~(((((((X-(1.35))-(0))-(-0.0455))-(0.063)) >= (0.007)) & (((((X-(1.35))-(0))-(-0.0455))-(0.063)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.042))))) & ~((((((0.028)-(0.028))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.007))-((0.0189)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.028))) >= 0) & ((((0.0175)-(0.028))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.0189))-((0.007)-(0.0189))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.028))) >= 0) & ((((0.028)-(0.0175))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.007))-((0.007)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.0175))) >= 0)))) & ~((((((0.014)-(0))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.028))-((0.0126)-(0.028))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))) >= 0) & ((((0.028)-(0.014))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.0126))-((0.028)-(0.0126))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.014))) >= 0) & ((((0)-(0.028))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.028))-((0.028)-(0.028))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.028))) >= 0)))) & ~((((((0.0105)-(0))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.007))-((0.007)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))) >= 0) & ((((0)-(0.0105))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.007))-((0.0189)-(0.007))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.0105))) >= 0) & ((((0)-(0))*(((((X-(1.35))-(0))-(-0.0455))-(0.063))-(0.0189))-((0.007)-(0.0189))*(((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))) >= 0))))!=0)) | (65280*((False | False | ((((((((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))) <= 0.014*0.014) | (((((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))) <= 0.014*0.014) | ((((((X-(1.59))-(0))-(-0.02975))-(0)) >= (0)) & (((((X-(1.59))-(0))-(-0.02975))-(0)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0.01225)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.02975)))) & ~((((((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))) <= 0.007*0.007))) & ~((((((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0.028))*(((((X-(1.59))-(0))-(-0.02975))-(0))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.59))-(0))-(-0.02975))-(0)) >= (0.007)) & (((((X-(1.59))-(0))-(-0.02975))-(0)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) >= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.042)) <= (0.028)))) | ((((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0.0105)) & ((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.0175)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) >= (0)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042))) | (((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375)) >= (0)) & ((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375)) <= (0.014)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) >= (0.0245)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0)) <= (0.042)))) & ~(((((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))*((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0)) + ((((((Y-(1.84))-(0.0525))-(0))-(-0.042))-(0))-(0.042))*((((((X-(1.59))-(0))-(-0.02975))-(0.0315))-(0.004375))-(0))) <= 0.0105*0.0105)) | False | ((((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375)) >= (0.0105)) & ((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375)) <= (0.0175)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) >= (0)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042))) | (((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375)) >= (0)) & ((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375)) <= (0.014)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) >= (0.0245)) & ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0)) <= (0.042)))) & ~(((((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375))-(0))*((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375))-(0)) + ((((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0))-(0.042))*((((((X-(1.59))-(0))-(-0.0455))-(0))-(0.004375))-(0))) <= 0.0105*0.0105)) | (((((((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.014))*(((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.014*0.014)) & ~((((((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014))*(((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014)) + (((((Y-(1.84))-(0.0525))-(0))-(-0.105))-(0.014))*(((((X-(1.59))-(0))-(-0.0455))-(0.0315))-(0.014))) <= 0.007*0.007))) & ~(((((((X-(1.59))-(0))-(-0.0455))-(0.0315)) >= (0)) & (((((X-(1.59))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.042)))) | ((((((X-(1.59))-(0))-(-0.0455))-(0.0315)) >= (0)) & (((((X-(1.59))-(0))-(-0.0455))-(0.0315)) <= (0.007)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0.014)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.028))) | ((((((X-(1.59))-(0))-(-0.0455))-(0.0315)) >= (0.021)) & (((((X-(1.59))-(0))-(-0.0455))-(0.0315)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.028))) | ((((((X-(1.59))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.59))-(0))-(-0.0455))-(0.063)) <= (0.007)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.59))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.59))-(0))-(-0.0455))-(0.063)) <= (0.028)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0.035)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.042))) | ((((((X-(1.59))-(0))-(-0.0455))-(0.063)) >= (0)) & (((((X-(1.59))-(0))-(-0.0455))-(0.063)) <= (0.0186666666667)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) >= (0.0175)) & (((((Y-(1.84))-(0.0525))-(0))-(-0.105)) <= (0.0245))))!=0)) | (16777215*(((True) & ~(((X >= (1)) & (X <= (2)) & (Y >= (1)) & (Y <= (1.93)))))!=0))); + } + } + printf("%d %d %d\n",i,j,val); + } diff --git a/src/core/vol_gif.c b/src/core/vol_gif.c new file mode 100644 index 0000000..c06ba71 --- /dev/null +++ b/src/core/vol_gif.c @@ -0,0 +1,265 @@ +// +// vol_gif.c +// .vol to .gif +// +// Neil Gershenfeld 11/29/13 +// (c) Massachusetts Institute of Technology 2013 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +/* +gcc -O3 vol_gif.c -o vol_gif -D_FILE_OFFSET_BITS=64 -Wall -lm -lgif +*/ + +#include "fab.h" + +void read_voxel_f(FILE *input_file,float *f,int x,int y,int z,int *xi,int *yi,int *zi,int ix,int iy,int iz) { + int r,match=0; + while (1) { + if ((x == *xi) && (y == *yi) && (z == *zi)) { + match = 1; + } + r = fread(f,sizeof(*f),1,input_file); + if (r == 0) { + printf("vol_gif: oops -- not enough points in file\n"); + exit(-1); + } + *xi += 1; + if (*xi == ix) { + *xi = 0; + *yi += 1; + if (*yi == iy) { + *yi = 0; + *zi += 1; + } + } + if (match == 1) + return; + } + } + +void read_voxel_i(FILE *input_file,uint16_t *i,int x,int y,int z,int *xi,int *yi,int *zi,int ix,int iy,int iz) { + int r,match=0; + while (1) { + if ((x == *xi) && (y == *yi) && (z == *zi)) { + match = 1; + } + r = fread(i,sizeof(*i),1,input_file); + if (r == 0) { + printf("vol_gif: oops -- not enough points in file\n"); + exit(-1); + } + *xi += 1; + if (*xi == ix) { + *xi = 0; + *yi += 1; + if (*yi == iy) { + *yi = 0; + *zi += 1; + } + } + if (match == 1) + return; + } + } + +int main(int argc, char **argv) { + FILE *input_file; + float arg,size,rx,ry,rz; + float f,fmin=1e10,fmax=-1e10; + uint16_t i; + uint64_t count; + int xi,yi,zi,xo,yo,zo,nx,ny,nz,dx,dy,dz,x0,y0,z0,h; + int **image; + char format,type,comment[256]; + GifFileType *GIFfile; + ColorMapObject *GIFcmap; + GifPixelType *GIFline; + // + // command line args + // + if (!((argc == 6) || (argc == 7) || (argc == 8) || (argc == 9) || (argc == 10) || (argc == 13) || (argc == 16) || (argc == 19))) { + printf("command line: vol_gif in.vol out.gif nx ny nz [format [type [arg [size [dx dy dz [x0 y0 z0 [rx ry rz]]]]]]]\n"); + printf(" in.vol = input volume file\n"); + printf(" out.gif = output GIF file\n"); + printf(" nx,ny,nz = x,y,z input voxel number\n"); + printf(" format = 'f' for float 32, 'i' for uint16_t (default 'f')\n"); + printf(" type = 's' for section, 'h' for height (default 's')\n"); + printf(" arg = gamma for 's', threshold for 'h' (default 1)\n"); + printf(" size = mm per voxel (default 1)\n"); + printf(" dx,dy,dz = x,y,z output voxel number (default all)\n"); + printf(" x0,y0,z0 = x,y,z output voxel origin (default 0)\n"); + printf(" to be implemented: rx,ry,rz = view rotation angles (degrees; default 0)\n"); + exit(-1); + } + format = 'f'; + type = 's'; + arg = 1; + size = 1.0; + rx = ry = rz = 0; + sscanf(argv[3],"%d",&nx); + sscanf(argv[4],"%d",&ny); + sscanf(argv[5],"%d",&nz); + dx = nx; dy = ny; dz = nz; + x0 = y0 = z0 = 0; + if (argc >= 7) { + sscanf(argv[6],"%c",&format); + if (!((format == 'f') || (format == 'i'))) { + printf("vol_gif: oops -- format must be 'f' or 'i'\n"); + exit(-1); + } + } + if (argc >= 8) { + sscanf(argv[7],"%c",&type); + if (!((type == 's') || (type == 'h'))) { + printf("vol_gif: oops -- type must be 's' or 'h'\n"); + exit(-1); + } + } + if (argc >= 9) { + sscanf(argv[8],"%f",&arg); + } + if (argc >= 10) { + sscanf(argv[9],"%f",&size); + } + if (argc >= 13) { + sscanf(argv[10],"%d",&x0); + sscanf(argv[11],"%d",&y0); + sscanf(argv[12],"%d",&z0); + } + if (argc >= 16) { + sscanf(argv[13],"%d",&dx); + sscanf(argv[14],"%d",&dy); + sscanf(argv[15],"%d",&dz); + } + if (argc >= 19) { + sscanf(argv[16],"%f",&rx); + sscanf(argv[17],"%f",&ry); + sscanf(argv[18],"%f",&rz); + } + // + // check and find limits + // + input_file = fopen(argv[1],"rb"); + if (input_file == NULL) { + printf("vol_gif: oops -- can not open %s\n",argv[1]); + exit(-1); + } + if (((x0 + dx) > nx) || ((y0 + dy) > ny) || ((z0 + dz) > nz)) { + printf("vol_gif: oops -- region too large\n"); + exit(-1); + } + printf("read %s\n",argv[1]); + if (format == 'f') { + count = 0; + while (fread(&f,sizeof(f),1,input_file) != 0) { + if (f > fmax) fmax = f; + if (f < fmin) fmin = f; + count += 1; + } + } + else if (format == 'i') { + count = 0; + while (fread(&i,sizeof(i),1,input_file) != 0) { + if (i > fmax) fmax = i; + if (i < fmin) fmin = i; + count += 1; + } + } + printf(" %" PRIu64 " points, min %f, max %f\n",count,fmin,fmax); + printf(" nx ny nz: %d %d %d\n",nx,ny,nz); + rewind(input_file); + // + // set up color map + // + GIFcmap = MakeMapObject(256, NULL); + for (i = 0; i < 256; i++) { + GIFcmap->Colors[i].Red = i; + GIFcmap->Colors[i].Green = i; + GIFcmap->Colors[i].Blue = i; + } + // + // open GIF file + // + printf("write %s\n",argv[2]); + GIFfile = EGifOpenFileName(argv[2], 0); + EGifPutScreenDesc(GIFfile,dx,dy,8,0,GIFcmap); + unsigned char loop_count[] = {1,0,0}; + EGifPutExtensionFirst(GIFfile, APPLICATION_EXT_FUNC_CODE, 11, "NETSCAPE2.0"); + EGifPutExtensionLast(GIFfile, APPLICATION_EXT_FUNC_CODE, 3, loop_count); + unsigned char delay_count[5] = { + 0, // no transparency + 0, // delay time + 0, // delay time + 0 // transparent index not used + }; + // + // allocate image + // + image = malloc(dy*sizeof(int *)); + for (yo = 0; yo < dy; ++yo) { + image[yo] = malloc(dx*sizeof(int)); + for (xo = 0; xo < dx; ++xo) + image[yo][xo] = 0; + } + GIFline = malloc(dx*sizeof(GifPixelType)); + // + // scan file + // + xi = yi = zi = 0; + for (zo = 0; zo < dz; ++zo) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",zo); + EGifPutExtension(GIFfile,GRAPHICS_EXT_FUNC_CODE,4,delay_count); + EGifPutImageDesc(GIFfile,0,0,dx,dy,0,NULL); + // + // read layer + // + for (yo = 0; yo < dy; ++yo) { + for (xo = 0; xo < dx; ++xo) { + if (format == 'f') { + read_voxel_f(input_file,&f,xo+x0,yo+y0,zo+z0,&xi,&yi,&zi,nx,ny,nz); + if (type == 'h') { + h = 255*zo/(nz-1.0); + if ((h > image[yo][xo]) && (f > arg)) + image[yo][xo] = h; + GIFline[xo] = image[yo][xo]*(nz-1.0)/zo; + } + else if (type == 's') { + GIFline[xo] = 255*pow((f-fmin)/(fmax-fmin),arg); + } + } + else if (format == 'i') { + read_voxel_i(input_file,&i,xo+x0,yo+y0,zo+z0,&xi,&yi,&zi,nx,ny,nz); + if (type == 'h') { + h = 255*zo/(nz-1.0); + if ((h > image[yo][xo]) && (i > arg)) + image[yo][xo] = h; + GIFline[xo] = image[yo][xo]*(nz-1.0)/zo; + } + else if (type == 's') { + GIFline[xo] = 255*pow((i-fmin)/(fmax-fmin),arg); + } + } + } + EGifPutLine(GIFfile,GIFline,dx); + } + } + printf("\n"); + // + // put mm per pixel in comment + // + sprintf(comment,"mm per pixel: %f;",size); + EGifPutComment(GIFfile,comment); + // + // exit + // + fclose(input_file); + EGifCloseFile(GIFfile); + exit(0); + } diff --git a/src/core/vol_stl.c b/src/core/vol_stl.c new file mode 100644 index 0000000..c8a7b1b --- /dev/null +++ b/src/core/vol_stl.c @@ -0,0 +1,667 @@ +// +// vol_stl.c +// .vol to .stl +// +// Neil Gershenfeld 5/21/14 +// (c) Massachusetts Institute of Technology 2014 +// +// This work may be reproduced, modified, distributed, +// performed, and displayed for any purpose, but must +// acknowledge the fab modules project. Copyright is +// retained and must be preserved. The work is provided +// as is; no warranty is provided, and users accept all +// liability. +// + +#define MAX_LINE 10000 + +#include "fab.h" + +/* +vertices: + --- + 6 7 + 4 5 + --- + 2 3 + 0 1 + --- +edges: + --- + k + l j + i + --- + h g + e f + --- + c + d b + a + --- +*/ + +// +// rotate_x +// rotate rule around x and add +// +void rotate_x(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[4] << 0) + +(b[5] << 1) + +(b[0] << 2) + +(b[1] << 3) + +(b[6] << 4) + +(b[7] << 5) + +(b[2] << 6) + +(b[3] << 7); + for (i + = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'c'; break; + case 'b': rules[*index][i] = 'g'; break; + case 'c': rules[*index][i] = 'k'; break; + case 'd': rules[*index][i] = 'h'; break; + case 'e': rules[*index][i] = 'd'; break; + case 'f': rules[*index][i] = 'b'; break; + case 'g': rules[*index][i] = 'j'; break; + case 'h': rules[*index][i] = 'l'; break; + case 'i': rules[*index][i] = 'a'; break; + case 'j': rules[*index][i] = 'f'; break; + case 'k': rules[*index][i] = 'i'; break; + case 'l': rules[*index][i] = 'e'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// rotate_y +// rotate rule around y and add +// +void rotate_y(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[1] << 0) + +(b[5] << 1) + +(b[3] << 2) + +(b[7] << 3) + +(b[0] << 4) + +(b[4] << 5) + +(b[2] << 6) + +(b[6] << 7); + for (i = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'e'; break; + case 'b': rules[*index][i] = 'd'; break; + case 'c': rules[*index][i] = 'h'; break; + case 'd': rules[*index][i] = 'l'; break; + case 'e': rules[*index][i] = 'i'; break; + case 'f': rules[*index][i] = 'a'; break; + case 'g': rules[*index][i] = 'c'; break; + case 'h': rules[*index][i] = 'k'; break; + case 'i': rules[*index][i] = 'f'; break; + case 'j': rules[*index][i] = 'b'; break; + case 'k': rules[*index][i] = 'g'; break; + case 'l': rules[*index][i] = 'j'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// rotate_z +// rotate rule around z and add +// +void rotate_z(char rules[255][20], int *index) { + int i,b[8]; + int old_index = *index; + for (i = 0; i < 8; ++i) b[i] = (*index & (1 << i)) >> i; + *index = + (b[2] << 0) + +(b[0] << 1) + +(b[3] << 2) + +(b[1] << 3) + +(b[6] << 4) + +(b[4] << 5) + +(b[7] << 6) + +(b[5] << 7); + for (i = 0; i < strlen(rules[old_index]); ++i) { + switch (rules[old_index][i]) { + case 'a': rules[*index][i] = 'b'; break; + case 'b': rules[*index][i] = 'c'; break; + case 'c': rules[*index][i] = 'd'; break; + case 'd': rules[*index][i] = 'a'; break; + case 'e': rules[*index][i] = 'f'; break; + case 'f': rules[*index][i] = 'g'; break; + case 'g': rules[*index][i] = 'h'; break; + case 'h': rules[*index][i] = 'e'; break; + case 'i': rules[*index][i] = 'j'; break; + case 'j': rules[*index][i] = 'k'; break; + case 'k': rules[*index][i] = 'l'; break; + case 'l': rules[*index][i] = 'i'; break; + case ' ': rules[*index][i] = ' '; break; + } + } + } +// +// print_rules +// print the rule table +// +void print_rules(char rules[255][20]) { + int i,b; + printf("76543210\n"); + for (i = 0; i < 256; ++i) { + for (b = 7; b >= 0; --b) { + printf("%d",(i & (1 << b)) >> b); + } + printf(" %d %s\n",i,rules[i]); + } + } +// add_rules +// add a rule and its variants to the table +// +void add_rules(char rules[255][20], int index, char *edges) { + int i,j,k,l; + strcpy(rules[index],edges); + for (i=0; i<4; ++i) { + for (j=0; j<4; ++j) { + for (k=0; k<4; ++k) { + rotate_x(rules,&index); + } + rotate_y(rules,&index); + } + rotate_z(rules,&index); + } + } +// +// init_rules +// create the rule table +// +void init_rules(char rules[255][20]) { + int i,j; + for (i = 0; i < 256; ++i) + for (j = 0; j < 20; ++j) + rules[i][j] = 0; + add_rules(rules,0b00000000,""); // 0 + add_rules(rules,0b11111111,""); // ~0 + add_rules(rules,0b00000001,"eda"); // 1 + add_rules(rules,0b11111110,"ade"); // ~1 + add_rules(rules,0b00000011,"fed dbf"); // 2 + add_rules(rules,0b11111100,"def fbd"); // ~2 + add_rules(rules,0b00100001,"eda jif"); // 3 + add_rules(rules,0b11011110,"ade fij"); // ~3 + add_rules(rules,0b10000001,"eda gkj"); // 4 + add_rules(rules,0b01111110,"ade jkg"); // ~4 + add_rules(rules,0b00001110,"fhg fdh fad"); // 5 + add_rules(rules,0b11110001,"ghf hdf daf"); // ~5 + add_rules(rules,0b10000011,"fed fdb gkj"); // 6 + add_rules(rules,0b01111100,"def bdf jkg"); // ~6 + add_rules(rules,0b10010010,"bfa ile gkj"); // 7 + add_rules(rules,0b01101101,"afb eli jkg"); // ~7 + add_rules(rules,0b00001111,"ehg feg"); // 8 + add_rules(rules,0b11110000,"ghe gef"); // ~8 + add_rules(rules,0b01001101,"elk eka akg agb"); // 9 + add_rules(rules,0b10110010,"kle ake gka bga"); // ~9 + add_rules(rules,0b10011001,"ild ida ckj cjb"); // 10 + add_rules(rules,0b01100110,"dli adi jkc bjc"); // ~10 + add_rules(rules,0b10001101,"hkj hja hae ajb"); // 11 + add_rules(rules,0b01110010,"jkh ajh eah bja"); // ~11 + add_rules(rules,0b00011110,"ile hgf hfd dfa"); // 12 + add_rules(rules,0b11100001,"eli fgh dfh afd"); // ~12 + add_rules(rules,0b01101001,"eda bcg lkh jif"); // 13 + add_rules(rules,0b10010110,"ade gcb hkl fij"); // ~13 + add_rules(rules,0b01001110,"lkg lga lad agf"); // 14 + add_rules(rules,0b10110001,"gkl agl dal fga"); // ~14 + } +// +// vertex +// add a triangle vertex +// +void vertex(char c, int x, int y, int z, float voxel_size, float t, float *w, float *array) { + switch(c) { + case 'a': + array[0] = x+(w[0]-t)/(w[0]-w[1]); + array[1] = y; + array[2] = z; + break; + case 'b': + array[0] = x+1; + array[1] = y+(w[1]-t)/(w[1]-w[3]); + array[2] = z; + break; + case 'c': + array[0] = x+(w[2]-t)/(w[2]-w[3]); + array[1] = y+1; + array[2] = z; + break; + case 'd': + array[0] = x; + array[1] = y+(w[0]-t)/(w[0]-w[2]); + array[2] = z; + break; + case 'e': + array[0] = x; + array[1] = y; + array[2] = z+(w[0]-t)/(w[0]-w[4]); + break; + case 'f': + array[0] = x+1; + array[1] = y; + array[2] = z+(w[1]-t)/(w[1]-w[5]); + break; + case 'g': + array[0] = x+1; + array[1] = y+1; + array[2] = z+(w[3]-t)/(w[3]-w[7]); + break; + case 'h': + array[0] = x; + array[1] = y+1; + array[2] = z+(w[2]-t)/(w[2]-w[6]); + break; + case 'i': + array[0] = x+(w[4]-t)/(w[4]-w[5]); + array[1] = y; + array[2] = z+1; + break; + case 'j': + array[0] = x+1; + array[1] = y+(w[5]-t)/(w[5]-w[7]); + array[2] = z+1; + break; + case 'k': + array[0] = x+(w[6]-t)/(w[6]-w[7]); + array[1] = y+1; + array[2] = z+1; + break; + case 'l': + array[0] = x; + array[1] = y+(w[4]-t)/(w[4]-w[6]); + array[2] = z+1; + break; + } + array[0] = voxel_size*array[0]; + array[1] = voxel_size*array[1]; + array[2] = voxel_size*array[2]; + } +// +// triangulate +// triangulate voxel at lattice site x,y,z with vertex weights w +// +void triangulate(int x, int y, int z, float voxel_size, float t, float *w, char rules[255][20], struct fab_vars *v) { + int i,index; + char c; + // + // set index code + // + index = ((w[0] < t) ? 0 : 1) + + ((w[1] < t) ? 0 : 2) + + ((w[2] < t) ? 0 : 4) + + ((w[3] < t) ? 0 : 8) + + ((w[4] < t) ? 0 : 16) + + ((w[5] < t) ? 0 : 32) + + ((w[6] < t) ? 0 : 64) + + ((w[7] < t) ? 0 : 128); + // + // add triangles for rule + // + i = 0; + while (1) { + // + // loop over rule chars + // + c = rules[index][i]; + if (c == 0) + // + // end of rule + // + break; + else if (c == ' ') { + // + // space between rules + // + i += 1; + continue; + } + else { + // + // create triangle for rule + // + v->mesh->last = malloc(sizeof(struct fab_mesh_triangle_type)); + v->mesh->last->previous = v->mesh->triangle; + v->mesh->triangle->next = v->mesh->last; + v->mesh->triangle = v->mesh->last; + v->mesh->triangle->next = 0; + v->mesh->triangle->attribute = 0; + v->mesh->triangle->normal[0] = v->mesh->triangle->normal[1] = v->mesh->triangle->normal[2] = 0; + // + // add vertices for rule + // + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v0); + i += 1; + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v1); + i += 1; + c = rules[index][i]; + vertex(c,x,y,z,voxel_size,t,w,v->mesh->triangle->v2); + i += 1; + } + } + } + +void fab_write_stl(struct fab_vars *v, char *output_file_name) { + // + // write mesh as STL + // + FILE *output_file; + char buf[80]; + uint32_t count; + // + // open output file + // + output_file = fopen(output_file_name, "wb"); + if (output_file == 0) { + printf("fab.c: oops -- can't open %s\n",output_file_name); + exit(-1); + } + // + // write header + // + fwrite(buf,80,1,output_file); + // + // write count + // + count = 0; + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle->next != 0) { + v->mesh->triangle = v->mesh->triangle->next; + count += 1; + } + fwrite(&count,4,1,output_file); + // + // write triangles + // + v->mesh->triangle = v->mesh->first; + while (v->mesh->triangle->next != 0) { + v->mesh->triangle = v->mesh->triangle->next; + fwrite(v->mesh->triangle->normal,4,3,output_file); + fwrite(v->mesh->triangle->v0,4,3,output_file); + fwrite(v->mesh->triangle->v1,4,3,output_file); + fwrite(v->mesh->triangle->v2,4,3,output_file); + fwrite(&(v->mesh->triangle->attribute),2,1,output_file); + } + // + // return + // + printf("wrote %d triangles to %s\n",count,output_file_name); + fclose(output_file); + } + +float interp(int x,int y,int i,int j,int k,float **lower_array,float **upper_array,int p) { + // + // trilinear interpolation within a voxel + // + return (lower_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + lower_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((p+1.0-k)/(p+1.0)) + + upper_array[y][x]*((p+1.0-i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y][x+1]*((i)/(p+1.0))*((p+1.0-j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x]*((p+1.0-i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0)) + + upper_array[y+1][x+1]*((i)/(p+1.0))*((j)/(p+1.0))*((k)/(p+1.0))); + } + +int main(int argc, char **argv) { + // + // local vars + // + FILE *input_file; + uint64_t count; + uint16_t itype; + int x,y,z,i,j,k,n,p,imin,imax,nx,ny,nz; + int image_width,image_height,color_resolution,ret; + float w[8],**lower_array,**upper_array; + float threshold,voxel_size; + float ftype,fmin=1e10,fmax=-1e10; + char format,comment[256],rules[255][20]; + struct fab_vars v; + init_vars(&v); + // + // command line args + // + if (!((argc == 6) || (argc == 7) || (argc == 8) || (argc == 9) || (argc == 10))) { + printf("command line: vol_stl in.vol out.stl nx ny nz [format [threshold [size [points [angle]]]]]\n"); + printf(" in.vol = input VOL file\n"); + printf(" out.stl = output STL file\n"); + printf(" nx,ny,nz = x,y,z input voxel number\n"); + printf(" format = 'f' for float 32, 'i' for uint16_t (default 'f')\n"); + printf(" threshold: surface intensity threshold (0 = min, 1 = max, default 0.5))\n"); + printf(" size = voxel size (mm, default from file))\n"); + printf(" points = points to interpolate per point (default 0)\n"); + printf(" to be implemented: angle = minimum relative face angle to decimate vertices (default 0)\n"); + exit(-1); + } + format = 'f'; + p = 0; + threshold = 0.5; + voxel_size = -1; + image_width = -1; + image_height = -1; + sscanf(argv[3],"%d",&nx); + sscanf(argv[4],"%d",&ny); + sscanf(argv[5],"%d",&nz); + if (argc >= 7) { + sscanf(argv[6],"%c",&format); + if (!((format == 'f') || (format == 'i'))) { + printf("vol_gif: oops -- format must be 'f' or 'i'\n"); + exit(-1); + } + } + if (argc >= 8) + sscanf(argv[7],"%f",&threshold); + if (argc >= 9) + sscanf(argv[8],"%f",&voxel_size); + if (argc >= 10) + sscanf(argv[9],"%d",&p); + // + // initialize the rule table + // + init_rules(rules); + // + // check and find limits + // + input_file = fopen(argv[1],"rb"); + if (input_file == NULL) { + printf("vol_stl: oops -- can not open %s\n",argv[1]); + exit(-1); + } + printf("read %s\n",argv[1]); + if (format == 'f') { + count = 0; + while (fread(&ftype,sizeof(ftype),1,input_file) != 0) { + if (ftype > fmax) fmax = ftype; + if (ftype < fmin) fmin = ftype; + count += 1; + } + } + else if (format == 'i') { + count = 0; + while (fread(&itype,sizeof(itype),1,input_file) != 0) { + if (itype > fmax) fmax = itype; + if (itype < fmin) fmin = itype; + count += 1; + } + } + if (nx*ny*nz != count) { + printf("vol_stl: oops -- file size doesn't match pixel number\n"); + exit(-1); + } + printf(" %" PRIu64 " points, min %f, max %f\n",count,fmin,fmax); + printf(" nx ny nz: %d %d %d\n",nx,ny,nz); + rewind(input_file); + // + // scan the file + // + printf("read %s\n",argv[1]); + // + // set threshold + // + threshold = fmin + threshold*(fmax-fmin); + // + // add empty border + // + image_width = nx+2; + image_height = ny+2; + // + // allocate arrays + // + lower_array = malloc(image_height*sizeof(float *)); + for (y = 0; y < image_height; ++y) { + lower_array[y] = malloc(image_width*sizeof(float)); + for (x = 0; x < image_width; ++x) + lower_array[y][x] = 0; + } + upper_array = malloc(image_height*sizeof(float *)); + for (y = 0; y < image_height; ++y) { + upper_array[y] = malloc(image_width*sizeof(float)); + for (x = 0; x < image_width; ++x) + upper_array[y][x] = 0; + } + // + // read the file + // + z = 0; + v.mesh = malloc(sizeof(struct fab_mesh_type)); + v.mesh->triangle = malloc(sizeof(struct fab_mesh_triangle_type)); + v.mesh->first = v.mesh->triangle; + v.mesh->last = v.mesh->triangle; + v.mesh->triangle->previous = v.mesh->triangle->next = 0; + for (z = 0; z < nz; ++z) { + // + // read layer + // + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z); + for (y = 0; y < ny; ++y) { + for (x = 0; x < nx; ++x) { + lower_array[y+1][x+1] = upper_array[y+1][x+1]; + if (format == 'f') { + fread(&ftype,sizeof(ftype),1,input_file); + upper_array[y+1][x+1] = ftype; + } + else if (format == 'i') { + fread(&itype,sizeof(itype),1,input_file); + upper_array[y+1][x+1] = itype; + } + } + } + if (p == 0) { + // + // no interpolation, loop over layer voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + w[0] = lower_array[y][x]; + w[1] = lower_array[y][x+1]; + w[2] = lower_array[y+1][x]; + w[3] = lower_array[y+1][x+1]; + w[4] = upper_array[y][x]; + w[5] = upper_array[y][x+1]; + w[6] = upper_array[y+1][x]; + w[7] = upper_array[y+1][x+1]; + triangulate(x,y,z,voxel_size,threshold,w,rules,&v); + } + } + } + else { + // + // yes interpolation, loop over layer sub-voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + for (i = 0; i <= p; ++i) { + for (j = 0; j <= p; ++j) { + for (k = 0; k <= p; ++k) { + w[0] = interp(x,y,i,j,k,lower_array,upper_array,p); + w[1] = interp(x,y,i+1,j,k,lower_array,upper_array,p); + w[2] = interp(x,y,i,j+1,k,lower_array,upper_array,p); + w[3] = interp(x,y,i+1,j+1,k,lower_array,upper_array,p); + w[4] = interp(x,y,i,j,k+1,lower_array,upper_array,p); + w[5] = interp(x,y,i+1,j,k+1,lower_array,upper_array,p); + w[6] = interp(x,y,i,j+1,k+1,lower_array,upper_array,p); + w[7] = interp(x,y,i+1,j+1,k+1,lower_array,upper_array,p); + triangulate((1+p)*x+i,(1+p)*y+j,(1+p)*z+k,voxel_size,threshold,w,rules,&v); + } + } + } + } + } + } + } + // + // add empty top layer + // + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b layer = %d",z); + for (y = 0; y < (image_height-2); ++y) { + for (x = 0; x < (image_width-2); ++x) { + lower_array[y+1][x+1] = upper_array[y+1][x+1]; + upper_array[y+1][x+1] = 0; + } + } + if (p == 0) { + // + // no interpolation, loop over layer voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + w[0] = lower_array[y][x]; + w[1] = lower_array[y][x+1]; + w[2] = lower_array[y+1][x]; + w[3] = lower_array[y+1][x+1]; + w[4] = upper_array[y][x]; + w[5] = upper_array[y][x+1]; + w[6] = upper_array[y+1][x]; + w[7] = upper_array[y+1][x+1]; + triangulate(x,y,z,voxel_size,threshold,w,rules,&v); + } + } + } + else { + // + // yes interpolation, loop over layer sub-voxels + // + for (x = 0; x < (image_width-1); ++x) { + for (y = 0; y < (image_height-1); ++y) { + for (i = 0; i <= p; ++i) { + for (j = 0; j <= p; ++j) { + for (k = 0; k <= p; ++k) { + w[0] = interp(x,y,i,j,k,lower_array,upper_array,p); + w[1] = interp(x,y,i+1,j,k,lower_array,upper_array,p); + w[2] = interp(x,y,i,j+1,k,lower_array,upper_array,p); + w[3] = interp(x,y,i+1,j+1,k,lower_array,upper_array,p); + w[4] = interp(x,y,i,j,k+1,lower_array,upper_array,p); + w[5] = interp(x,y,i+1,j,k+1,lower_array,upper_array,p); + w[6] = interp(x,y,i,j+1,k+1,lower_array,upper_array,p); + w[7] = interp(x,y,i+1,j+1,k+1,lower_array,upper_array,p); + triangulate((1+p)*x+i,(1+p)*y+j,(1+p)*z+k,voxel_size,threshold,w,rules,&v); + } + } + } + } + } + } + printf("\n"); + // + // write STL + // + fab_write_stl(&v,argv[2]); + // + // exit + // + fclose(input_file); + exit(0); + } diff --git a/src/guis/CMakeLists.txt b/src/guis/CMakeLists.txt new file mode 100644 index 0000000..f6ab3c6 --- /dev/null +++ b/src/guis/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 2.6) + +set(GUIs fab fab.html fabserver + make_cad_png make_cad_eps make_cad_stl make_cad_camm make_cad_rml + make_cad_epi make_cad_uni make_cad_sbp make_cad_g make_cad_ord + make_cad_grb make_cad_drl + make_math_camm make_math_epi make_math_g make_math_ord make_math_eps + make_math_uni make_math_rml make_math_sbp make_math_grb + make_math_drl + make_png_png make_png_eps make_png_epi make_png_uni make_png_grb + make_png_epi_halftone make_png_uni_halftone make_png_rml make_png_sbp + make_png_ord make_png_camm make_png_plt make_png_g make_png_drl + make_png_oms + make_stl_png make_stl_rml make_stl_sbp make_stl_g + make_svg_camm make_svg_epi make_svg_uni make_svg_oms + make_svg_g make_svg_rml make_svg_sbp make_svg_ord make_png_snap + make_cad_snap make_stl_snap make_svg_snap make_png_eps_halftone + make_cad_dxf make_math_dxf make_math_stl make_png_dxf + make_gif_stl + cad_ui + rml_send_gui + CACHE STRING "GUI script list") + +if( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + install(PROGRAMS ${GUIs} DESTINATION ${PROJECT_SOURCE_DIR}/../bin) +endif( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) diff --git a/src/guis/cad_ui b/src/guis/cad_ui new file mode 100755 index 0000000..1d55c8a --- /dev/null +++ b/src/guis/cad_ui @@ -0,0 +1,1406 @@ +#!/usr/bin/env python + +import wx +import wx.py +import wx.stc + +import os, sys +import subprocess +import inspect +import re + +from datetime import datetime + +SHOW_SCROLL = True + +# Special case to set up the search path if we're bundled into +# an application (Mac OS X only) +if '.app' in sys.argv[0]: + sys.path.append('') + APP_MODE = True + BUNDLED = True +else: + APP_MODE = False + BUNDLED = False + +import cad_shapes +import cad_text + +from Queue import Queue, Empty +import threading + +full_image_size = 480 +small_image_size = 2 * full_image_size / 3 + +image_size = full_image_size + +text_width = 480 +border = 3 + +VERSION = '0.25' + +DARK_THEME = { +'txt': [(wx.stc.STC_STYLE_DEFAULT, '#000000', '#000000'), + (wx.stc.STC_STYLE_LINENUMBER, '#303030', '#c8c8c8'), + (wx.stc.STC_P_CHARACTER, '#000000', '#ff73fd'), + (wx.stc.STC_P_CLASSNAME, '#000000', '#96cbfe'), + (wx.stc.STC_P_COMMENTBLOCK, '#000000', '#7f7f7f'), + (wx.stc.STC_P_COMMENTLINE, '#000000', '#a8ff60'), + (wx.stc.STC_P_DEFAULT, '#000000', '#ffffff'), + (wx.stc.STC_P_DEFNAME, '#000000', '#96cbfe'), + (wx.stc.STC_P_IDENTIFIER, '#000000', '#ffffff'), + (wx.stc.STC_P_NUMBER, '#000000', '#ffffff'), + (wx.stc.STC_P_OPERATOR, '#000000', '#ffffff'), + (wx.stc.STC_P_STRING, '#000000', '#ff73fd'), + (wx.stc.STC_P_STRINGEOL, '#000000', '#ffffff'), + (wx.stc.STC_P_TRIPLE, '#000000', '#ff6c60'), + (wx.stc.STC_P_TRIPLEDOUBLE, '#000000', '#96cbfe'), + (wx.stc.STC_P_WORD, '#000000', '#b5dcff')], +'background': '#252525', +'foreground': '#c8c8c8' +} + +LIGHT_THEME = { +'txt': [(wx.stc.STC_STYLE_DEFAULT, '#ffffff', '#ffffff'), + (wx.stc.STC_STYLE_LINENUMBER, '#c0c0c0', '#000000'), + (wx.stc.STC_P_CHARACTER, '#ffffff', '#7f007f'), + (wx.stc.STC_P_CLASSNAME, '#ffffff', '#0000ff'), + (wx.stc.STC_P_COMMENTBLOCK, '#ffffff', '#7f7f7f'), + (wx.stc.STC_P_COMMENTLINE, '#ffffff', '#007f00'), + (wx.stc.STC_P_DEFAULT, '#ffffff', '#000000'), + (wx.stc.STC_P_DEFNAME, '#ffffff', '#007f7f'), + (wx.stc.STC_P_IDENTIFIER, '#ffffff', '#000000'), + (wx.stc.STC_P_NUMBER, '#ffffff', '#000000'), + (wx.stc.STC_P_OPERATOR, '#ffffff', '#000000'), + (wx.stc.STC_P_STRING, '#ffffff', '#7f007f'), + (wx.stc.STC_P_STRINGEOL, '#ffffff', '#000000'), + (wx.stc.STC_P_TRIPLE, '#ffffff', '#7f0000'), + (wx.stc.STC_P_TRIPLEDOUBLE, '#ffffff', '#000051'), + (wx.stc.STC_P_WORD, '#ffffff', '#00007f')], +'background': '#e0e0e0', +'foreground': '#222222' +} + +def ApplyTheme(theme, txt, backgrounds, foregrounds): + for t in txt: + t.apply_theme(theme['txt']) + for b in backgrounds: + b(theme['background']) + for f in foregrounds: + f(theme['foreground']) + return theme + +class CadEditor(wx.py.editwindow.EditWindow): + def __init__(self, parent, size, style): + wx.py.editwindow.EditWindow.__init__(self, parent, + size=size, style=style) + + def apply_theme(self, theme): + for s in theme: + self.StyleSetBackground(s[0], s[1]) + self.StyleSetForeground(s[0], s[2]) + +################################################################################ +# LibraryFrame +# A simple read-only frame that displays the text from a given file. +################################################################################ +class LibraryFrame(wx.Frame): + '''A simple text frame to display the contents of a standard libraries.''' + def __init__(self, title, filename, theme): + wx.Frame.__init__(self, None, title = title) + + # Create text pane. + self.txt = CadEditor(self, size=(text_width, text_width), + style=wx.NO_BORDER) + if not SHOW_SCROLL: + self.txt.SetUseHorizontalScrollBar(False) + dummyScroll = wx.ScrollBar(self) + dummyScroll.Hide() + self.txt.SetVScrollBar(dummyScroll) + self.txt.SetCaretLineVisible(0) + + self.txt.ClearAll() + with open(filename.replace('pyc','py'), 'r') as f: + self.txt.SetText(f.read()) + self.txt.SetSelection(0, 0) + self.txt.SetReadOnly(True) + + ApplyTheme(theme, [self.txt], [self.SetBackgroundColour], []) + + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.txt, 1, wx.EXPAND | wx.RIGHT | wx.TOP | wx.BOTTOM, + border=border * 4) + self.SetSizerAndFit(self.sizer) + self.Show() + +################################################################################ +# Cadvars +# A class that represents a set of cad variables loaded from a .math file +################################################################################ +class CadVars: + # + # cad variables + # + def __init__(self): + self.xmin = 0 # minimum x value to render + self.xmax = 0 # maximum x value to render + self.ymin = 0 # minimum y value to render + self.ymax = 0 # maximum y value to render + self.zmin = 0 # minimum z value to render + self.zmax = 0 # maximum z value to render + self.layers = [] # optional number of layers to render + self.function = '' # cad function + self.labels = [] # display labels + self.mm_per_unit = 1.0 # file units + self.type = '' # math string type + +################################################################################ +# ResolutionDialog +# A simple dialog box that lets the user set the resolution at which +# a cad file will be rendered to png. +################################################################################ +class ResolutionDialog(wx.Dialog): + def __init__(self, parent, res): + wx.Dialog.__init__(self, parent = parent, title = 'Export') + self.value = wx.TextCtrl(self, -1, style=wx.TE_PROCESS_ENTER) + self.value.Bind(wx.EVT_TEXT, self.LimitToNumbers) + self.value.Bind(wx.EVT_TEXT_ENTER, self.Done) + self.value.ChangeValue(str(int(res))) + vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(self.value, flag = wx.ALL, border=10) + okButton = wx.Button(self, label='OK') + okButton.Bind(wx.EVT_BUTTON, self.Done) + hbox.Add(okButton, flag = wx.ALL, border=10) + + vbox.Add(wx.StaticText(self, -1, 'Resolution (pixels/mm):'), + flag = wx.LEFT | wx.TOP, border = 10) + vbox.Add(hbox) + + self.SetSizerAndFit(vbox) + +################################################################################ + + def LimitToNumbers(self, event): + value = self.value.GetValue() + i = self.value.GetInsertionPoint() + if value[i-1] in '0123456789.': + return + self.value.ChangeValue(value.replace(value[i-1],'')) + self.value.SetInsertionPoint(i - 1) + +################################################################################ + + def Done(self, event): + self.EndModal(wx.ID_OK) + self.result = self.value.GetValue() + self.Destroy() + +############################################################################## + +class CadUIFrame(wx.Frame): + def __init__(self, Parent, title = 'cad_ui'): + wx.Frame.__init__(self, None, title = title) + + self.parent = Parent + self.backgrounds = [self.SetBackgroundColour] + self.foregrounds = [] + + imgpanel = self.CreateImagePanel() + + self.CreateTextBox(textCallback = Parent.OnText, + isSavedCallback = Parent.IsSaved, + isUnsavedCallback = Parent.IsUnsaved) + + self.CreateMenus(newCallback = Parent.LoadTemplate, + openCallback = Parent.OnOpen, + reloadCallback = Parent.ReloadFile, + saveCallback = Parent.OnSave, + saveasCallback = Parent.OnSaveAs, + exitCallback = Parent.OnExit, + renderCallback = Parent.Render, + exportCallback = Parent.Export) + + self.ArrangeGUI(self.txt, imgpanel) + self.ApplyTheme(DARK_THEME) + + self.Bind(wx.EVT_IDLE, lambda e: Parent.monitor_threads()) + +################################################################################ + + def CreateTextBox(self, textCallback, isSavedCallback, isUnsavedCallback): + self.txt = CadEditor(self, size=(text_width, 0), style=wx.NO_BORDER) + # Set the margins on the text window: + # 2 with margin numbers + # 1 with symbols to indicate compile errors + # 3 just to add a bit of space + self.txt.SetMarginWidth(2, 16) + self.txt.SetMarginType(2,wx.stc.STC_MARGIN_NUMBER) + + self.txt.SetMarginWidth(1, 16) + self.txt.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) + self.txt.MarkerDefine(0, wx.stc.STC_MARK_SHORTARROW, 'black','red') + + self.txt.SetMarginWidth(3, 4) + + self.txt.SetEOLMode(wx.stc.STC_EOL_LF) +# self.txt.SetViewEOL(True) + + # Hide the scroll bars for visual cleanliness + if not SHOW_SCROLL: + self.txt.SetUseHorizontalScrollBar(False) + dummyScroll = wx.ScrollBar(self) + dummyScroll.Hide() + self.txt.SetVScrollBar(dummyScroll) + + # Make the caret grey so that it works with both themes. + self.txt.SetCaretForeground('#888888') + + # Bind callbacks to text events + self.txt.Bind(wx.stc.EVT_STC_CHANGE, textCallback) + self.txt.SetModEventMask(wx.stc.STC_MODEVENTMASKALL & + ~wx.stc.STC_MOD_CHANGEMARKER & + ~wx.stc.STC_MOD_CHANGESTYLE) + self.txt.Bind(wx.stc.EVT_STC_SAVEPOINTLEFT, isUnsavedCallback) + self.txt.Bind(wx.stc.EVT_STC_SAVEPOINTREACHED, isSavedCallback) + + self.txt.Bind(wx.EVT_KEY_DOWN, self.HandleKey) + self.Bind(wx.EVT_KEY_DOWN, self.HandleKey) + self.txt.Bind(wx.EVT_KEY_UP, self.HandleKey) + self.txt.Bind(wx.EVT_KEY_UP, self.HandleKey) + +################################################################################ + + def CreateImagePanel(self): + # Create a nested panel to contain the image and a colorful border + centeringPanel = wx.Panel(self) + imgpanel = wx.Panel(centeringPanel) + + empty = wx.EmptyImage(image_size, image_size) + image = wx.StaticBitmap(imgpanel, -1, wx.BitmapFromImage(empty)) + + imgsizer = wx.BoxSizer() + imgsizer.Add(image, 0, wx.ALL, + border=border) + imgpanel.SetSizer(imgsizer) + + self.SetBorder = lambda color: [imgpanel.SetBackgroundColour(color), + imgpanel.Refresh()] + + self.SetImage = lambda bitmap: [image.SetBitmap(bitmap), + self.Layout()] + + # Create text pane. + self.outputTxt = CadEditor(centeringPanel, size=(image_size + border * 12, + image_size/4), + style=wx.NO_BORDER) + if not SHOW_SCROLL: + self.outputTxt.SetUseHorizontalScrollBar(False) + dummyScroll = wx.ScrollBar(self) + dummyScroll.Hide() + self.outputTxt.SetVScrollBar(dummyScroll) + self.outputTxt.SetReadOnly(True) + self.outputTxt.SetCaretLineVisible(0) + self.outputTxt.Hide() + + # Create nested horizontal and vertical centering sizers + vcenter = wx.BoxSizer(wx.VERTICAL) + vcenter.Add((0,0), 1) + vcenter.Add(imgpanel, 0, wx.LEFT | wx.RIGHT | wx.CENTER, border = 5 * border) + statusText = wx.StaticText(centeringPanel) + vcenter.Add(statusText, 0, wx.LEFT, border = 5 * border) + vcenter.Add((0,0), 1) + vcenter.Add(self.outputTxt, 25, wx.TOP | wx.EXPAND, border = 5 * border) + + hcenter = wx.BoxSizer(wx.HORIZONTAL) + hcenter.Add((0,0), 1) + hcenter.Add(vcenter, 0, wx.CENTER | wx.EXPAND), + hcenter.Add((0,0), 1) + centeringPanel.SetSizer(hcenter) + + self.SetStatus = lambda h: statusText.SetLabel(h) + + self.backgrounds += [imgpanel.SetBackgroundColour, + centeringPanel.SetBackgroundColour] + self.foregrounds += [statusText.SetForegroundColour] + + return centeringPanel + +################################################################################ + + def CreateMenus(self, newCallback = None, + openCallback = None, reloadCallback = None, + saveCallback = None, saveasCallback = None, + exitCallback = None, renderCallback = None, + exportCallback = None): + + menu = wx.Menu() + + new = menu.Append(wx.ID_NEW, 'New\tCtrl+N', 'Start a new cad file') + self.Bind(wx.EVT_MENU, newCallback, new) + + about = menu.Append(wx.ID_ABOUT, 'About', + 'Display information about cad_ui') + self.Bind(wx.EVT_MENU, self.AboutBox, about) + + open = menu.Append(wx.ID_OPEN, 'Open\tCtrl+O', "Open a cad file") + self.Bind(wx.EVT_MENU, openCallback, open) + + reload = menu.Append(-1, 'Reload\tCtrl+R','Reload the current file') + self.Bind(wx.EVT_MENU, reloadCallback, reload) + + save = menu.Append(wx.ID_SAVE, 'Save\tCtrl+S', "Save the current file") + self.Bind(wx.EVT_MENU, saveCallback, save) + + saveas = menu.Append(wx.ID_SAVEAS, 'Save As\tCtrl+Shift+S', "Save the current file") + self.Bind(wx.EVT_MENU, saveasCallback, saveas) + + exit = menu.Append(wx.ID_EXIT,'Exit\tCtrl+Q',"Terminate the program") + self.Bind(wx.EVT_MENU, exitCallback, exit) + self.Bind(wx.EVT_CLOSE, exitCallback) + + settingsMenu = wx.Menu() + self.Bind(wx.EVT_MENU, renderCallback, + settingsMenu.Append(-1, 'Render\tCtrl+Enter', + "Render the current .cad file to the preview pane") + ) + self.auto = settingsMenu.AppendCheckItem(-1, 'Auto-render', + "Re-render whenever the cad file changes") + self.Bind(wx.EVT_MENU, renderCallback, self.auto) + self.auto.Check(True) + + # Menu to change view options + viewMenu = wx.Menu() + self.fullScreen = viewMenu.AppendCheckItem(-1, 'Full screen\tCtrl+Shift+F', + 'Expand window and activate full screen mode.') + self.Bind(wx.EVT_MENU, lambda e: self.ShowFullScreen(e.Checked()), + self.fullScreen) + output = viewMenu.AppendCheckItem(-1, 'Show errors\tCtrl+E', + 'Show errors messages in a separate pane.') + self.Bind(wx.EVT_MENU, self.ShowOutput, output) + + themeMenu = wx.Menu() + viewMenu.AppendSubMenu(themeMenu, 'Theme') + + light = themeMenu.AppendRadioItem(-1, 'Light') + self.Bind(wx.EVT_MENU, lambda e: self.ApplyTheme(LIGHT_THEME), light) + + dark = themeMenu.AppendRadioItem(-1, 'Dark') + self.Bind(wx.EVT_MENU, lambda e: self.ApplyTheme(DARK_THEME), dark) + + # Default theme is dark + dark.Check(True) + + libraryMenu = wx.Menu() + show_cad_shapes = lambda e: LibraryFrame('cad_shapes', + cad_shapes.__file__, + self.theme) + self.Bind(wx.EVT_MENU, show_cad_shapes, + libraryMenu.Append(-1, 'cad_shapes','View the standard shapes library')) + + show_cad_text = lambda e: LibraryFrame('cad_text', + cad_text.__file__, + self.theme) + self.Bind(wx.EVT_MENU, show_cad_text, + libraryMenu.Append(-1, 'cad_text','View the standard text library')) + + exportMenu = wx.Menu() + self.Bind(wx.EVT_MENU, lambda e: exportCallback('math'), + exportMenu.Append(-1, '.math','Export to .math file')) + self.Bind(wx.EVT_MENU, lambda e: exportCallback('png'), + exportMenu.Append(-1, '.png','Export to image file')) + self.Bind(wx.EVT_MENU, lambda e: exportCallback('svg'), + exportMenu.Append(-1, '.svg','Export to svg file')) + self.Bind(wx.EVT_MENU, lambda e: exportCallback('stl'), + exportMenu.Append(-1, '.stl','Export to stl file')) + self.Bind(wx.EVT_MENU, lambda e: exportCallback('dot'), + exportMenu.Append(-1, '.dot','Export to dot / Graphviz file')) + + menuBar = wx.MenuBar() + menuBar.Append(menu, 'File') + menuBar.Append(viewMenu, 'View') + menuBar.Append(settingsMenu, 'Options') + menuBar.Append(libraryMenu, 'Libraries') + menuBar.Append(exportMenu, 'Export') + + self.Bind(wx.EVT_MENU_HIGHLIGHT, self.OnMenuHighlight) + self.Bind(wx.EVT_MENU_CLOSE, self.OnMenuClose) + self.Bind(wx.EVT_MENU_OPEN, self.OnMenuOpen) + + self.SetMenuBar(menuBar) + +################################################################################ + + def ArrangeGUI(self, txt, img): + self.sizer = wx.FlexGridSizer(rows = 3, cols = 2) + self.sizer.AddGrowableCol(0, 1) + self.sizer.AddGrowableRow(1, 1) + + self.sizer.Add((0, 0)) # Add a dummy widget to the top left corner + + # Create and add version text + versionText = wx.StaticText(self, -1, 'cad_ui %s' % VERSION) + self.foregrounds += [versionText.SetForegroundColour] + + self.sizer.Add(versionText, 0, wx.ALIGN_RIGHT) + self.sizer.Add(txt, 0, wx.EXPAND) + self.sizer.Add(img, 0, wx.EXPAND) + + # Create and add syntax hint + syntaxHint = wx.StaticText(self) + self.foregrounds += [syntaxHint.SetForegroundColour] + + self.sizer.Add(syntaxHint) + self.SetHint = lambda h: syntaxHint.SetLabel(h) + + # Fit everything into the sizer + self.SetSizerAndFit(self.sizer) + +################################################################################ + + def ApplyTheme(self, theme): + self.theme = ApplyTheme(theme, [self.txt, self.outputTxt], + self.backgrounds, self.foregrounds) + +################################################################################ + + def HandleKey(self, e): + try: + control = wx.WXK_RAW_CONTROL + except: + control = wx.WXK_CONTROL + + if e.GetKeyCode() == wx.WXK_ESCAPE and \ + e.GetEventType() == wx.EVT_KEY_DOWN.typeId: + self.ShowFullScreen(False) + self.fullScreen.Check(False) + + # Highlighting is not available in the revised solver. +# elif e.GetKeyCode() == control and \ +# e.GetEventType() == wx.EVT_KEY_DOWN.typeId and\ +# self.parent.cad.type == "Boolean": +# self.parent.Render(highlight = True) +# elif e.GetKeyCode() == control and \ +# e.GetEventType() == wx.EVT_KEY_UP.typeId and\ +# self.parent.cad.type == "Highlight": +# self.parent.Render() + + else: + if e.GetEventType() == wx.EVT_KEY_DOWN: + self.SetHint('') + e.Skip() +############################################################################### + def ShowOutput(self, e): + global image_size + if type(e) is bool: + show = e + else: + show = e.Checked() + if e.Checked(): + self.outputTxt.Show() + if image_size != small_image_size: + image_size = small_image_size + empty = wx.EmptyImage(image_size, image_size) + self.SetImage(wx.BitmapFromImage(empty)) + self.parent.Render() + else: + self.outputTxt.Hide() + if image_size != full_image_size: + image_size = full_image_size + empty = wx.EmptyImage(image_size, image_size) + self.SetImage(wx.BitmapFromImage(empty)) + self.parent.Render() + + self.Layout() + +############################################################################### + + def AboutBox(self, e = None): + info = wx.AboutDialogInfo() + info.SetName("cad_ui") + if APP_MODE: + info.SetIcon(wx.Icon('cba_icon.png', wx.BITMAP_TYPE_PNG)) + info.SetVersion(VERSION) + info.SetDescription('A design tool for .cad files.') + info.SetWebSite('http://kokompe.cba.mit.edu') + info.SetCopyright('(C) 2012 Matthew Keeter') + wx.AboutBox(info) + +############################################################################### + + def OnMenuHighlight(self, event): + # Show how to get menu item info from this event handler + id = event.GetMenuId() + item = self.GetMenuBar().FindItemById(id) + if not item or not item.GetHelp(): + self.SetHint('') + else: + self.SetHint(item.GetHelp()) +# print "highlight" + + def OnMenuClose(self, event): +# print "close" + self.SetHint('') + + def OnMenuOpen(self, event): +# print "Open" + pass + +############################################################################### + + def SetText(self, text): + self.txt.ClearAll() + self.txt.SetText(text) + self.txt.SetSelection(0, 0) + + def SetOutput(self, text): + self.outputTxt.SetReadOnly(False) + self.outputTxt.ClearAll() + self.outputTxt.SetText(text) + self.outputTxt.SetSelection(0, 0) + self.outputTxt.SetReadOnly(True) + +############################################################################### + + def GetText(self): + return self.txt.GetText() + +############################################################################### + + def BindTimer(self, callback, time = 10): + self.timer = wx.Timer(self, -1) + self.Bind(wx.EVT_TIMER, callback, self.timer) + self.timer.Start(time) + +############################################################################### + + def MarkError(self, line): + self.txt.MarkerAdd(line, 0) + +############################################################################### + + def ClearError(self): + self.txt.MarkerDeleteAll(0) + +############################################################################### + + def SyntaxHelper(self): + self.SetHint('') + + c = self.txt.GetCurLine() + before = c[0][:c[1] + 1] + if not before: + return + + # Try to grab a token being typed. + i = len(before) - 1 + while i >= 0 and before[i:].replace('_','a').isalnum(): + i -= 1 + token = before[i+1:] + + matches = [] + for op in dir(cad_shapes): + if token and op.startswith(token) \ + and callable(eval("cad_shapes." + op)): + matches += [(op, 'cad_shapes.')] + for op in dir(cad_text): + if token and op.startswith(token) \ + and callable(eval("cad_text." + op)): + matches += [(op, 'cad_text.')] + + # Otherwise, try to get the name of the outermost function + if not matches: + openParens = len(before) - 1 + depth = 0 + while openParens >= 0: + if before[openParens] == '(': + if depth == 0: + break + else: + depth -= 1 + elif before[openParens] == ')': + depth += 1 + openParens -= 1 + + if openParens == -1: + return + before = before[:openParens] + + # Extract the name + i = len(before) - 1 + while i >= 0 and before[i:].replace('_','a').isalnum(): + i -= 1 + token = before[i+1:] + + for op in dir(cad_shapes): + if token and op.startswith(token) \ + and callable(eval("cad_shapes." + op)): + matches += [(op, 'cad_shapes.')] + for op in dir(cad_text): + if token and op.startswith(token) \ + and callable(eval("cad_text." + op)): + matches += [(op, 'cad_text.')] + + if not matches: + return + + # Pick the match with the largest fraction of matching characters + best_score = 0 + match = '' + print matches + for m in matches: + score = min(len(m), len(token)) / float(max(len(m), len(token))) + if score > best_score: + best_score = score + match = m + try: + args = inspect.getargspec(eval(match[1] + match[0])).args + self.SetHint(match[0] + '(' + ', '.join(args) + ')') + except TypeError: + pass + +############################################################################### +# CadUIApp +# The class that actually runs everything. +############################################################################### + +class CadUIApp(wx.App): + def OnInit(self): + self.frame = CadUIFrame(self) + self.frame.Show() + self.image = wx.EmptyImage(image_size, image_size) + + self.threads = [] + self.export = False + + self.saved = True + + # Either load a file from the first command-line argument, or open + # a template + if len(sys.argv) != 2: + self.LoadTemplate() + else: + try: + if len(sys.argv) == 2: + if os.path.isabs(sys.argv[1]): + filename = sys.argv[1] + else: + filename = os.path.join(os.getcwd(), sys.argv[1]) + print filename + self.SetFilename(os.path.split(filename)[0], + os.path.split(filename)[1]) + self.LoadFile() + except: + self.LoadTemplate() + self.SetFilename(os.path.split(filename)[0], + os.path.split(filename)[1]) + self.OnSave() + + self.cad = CadVars() + self.resolution = 0 + + return True + + def LoadTemplate(self, e = None): + if not self.WarnChanges(): + return + + self.SetFilename('','') + + self.frame.SetText('''from cad_shapes import * + +# Render boundaries +cad.xmin = -1 +cad.xmax = 1 +cad.ymin = -1 +cad.ymax = 1 +cad.mm_per_unit = 25.4 # inch units + +cad.function = circle(0, 0, 0.5)''') + self.frame.txt.SetSavePoint() + self.IsSaved() + + def IsSaved(self, e = None): + self.saved = True + self.UpdateTitle() + + def IsUnsaved(self, e = None): + self.saved = False + self.UpdateTitle() + + + def OnSave(self, e = None): + if self.cadFilePath: + with open(self.cadFilePath, 'w') as f: + f.write(self.frame.txt.GetText()) + self.IsSaved() + self.frame.txt.SetSavePoint() + else: + self.OnSaveAs() + + def OnSaveAs(self, e = None): + directory = self.cadFileDir if self.cadFileDir else os.getcwd() + dlg = wx.FileDialog(self.frame, "Choose a file", + directory, '', '*.*', wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetFilename() + # Automatically append a .cad extension to the filename + if filename[-4:] != '.cad': + filename += '.cad' + self.SetFilename(dlg.GetDirectory(), filename) + self.OnSave() + dlg.Destroy() + + def Export(self, target): + # Pick png/svg/stl resolution + if target in ['png', 'svg', 'stl']: + dlg = ResolutionDialog(self.frame, self.resolution) + result = dlg.ShowModal() + dlg.Destroy() + if result == wx.ID_OK: + resolution = dlg.result + else: + return + + # Pick new filename + directory = self.cadFileDir if self.cadFileDir else os.getcwd() + dlg = wx.FileDialog(self.frame, '', directory, + '', '*.*',wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetFilename() + directory = dlg.GetDirectory() + path = os.path.join(directory, filename) + + if target == 'math': + self.start_thread(self.export_math, (path,)) + elif target == 'dot': + self.start_thread(self.export_dot, (path,)) + elif target == 'png': + self.start_thread(self.export_png, (resolution,path)) + elif target == 'svg': + self.start_thread(self.export_svg, (resolution,path)) + elif target == 'stl': + self.start_thread(self.export_stl, (resolution,path)) + + dlg.Destroy() + + def LoadImage(self, imageName): + '''Loads an image from a file and puts it into the UI.''' + self.image = wx.Image(imageName) + self.bitmap = wx.BitmapFromImage(self.image) + + self.frame.SetImage(self.bitmap) + + + def SetFilename(self, directory, name): + '''Given a directory and filename, set internal variables that describe + our output/input targets. Also, clear state variables to mark that this + is the first time we've run this file. + ''' + self.cadFileDir = directory + self.cadFilePath = os.path.join(self.cadFileDir, name) + + self.cad = CadVars() + + def OnOpen(self, e = None): + '''Callback for the open file dialog box. Saves the name + of the opened file and generates .math and .png names.''' + + if not self.WarnChanges(): + return + + directory = self.cadFileDir if self.cadFileDir else os.getcwd() + dlg = wx.FileDialog(self.frame, "Choose a file", + directory, '', '*.*', wx.OPEN) + result = dlg.ShowModal() + dlg.Destroy() + if result != wx.ID_OK: + return + + self.SetFilename(dlg.GetDirectory(), dlg.GetFilename()) + self.LoadFile() + + def ReloadFile(self, e = None): + if self.cadFilePath == '': + return + + if not self.WarnChanges(): + return + + self.LoadFile(reset = False) + + def LoadFile(self, reset = True): + with open(self.cadFilePath, 'r') as f: + text = f.read() + + if reset: + self.frame.auto.Check(True) + + self.frame.SetText(text) + self.frame.txt.SetSavePoint() + + self.IsSaved() + + def UpdateTitle(self): + if not self.cadFilePath: + s = 'cad_ui: [Untitled]' + else: + s = 'cad_ui: ' + self.cadFilePath + + if self.saved: + self.frame.SetTitle(s) + else: + self.frame.SetTitle(s + '*') + + def OnText(self, event): + self.frame.SyntaxHelper() + + # If auto-render is enabled, then render the image + # (unless we're currently exporting something) + if self.frame.auto.IsChecked() and not self.export: + self.Render() + else: + self.frame.SetBorder((100, 100, 100)) + + def WarnChanges(self): + '''Check to see if the user is ok with abandoning unsaved changes. + Returns True if we should proceed.''' + if self.saved: + return True + + dlg = wx.MessageDialog(None, "All unsaved changes will be lost.", + "Warning:", + wx.OK | wx.CANCEL | wx.ICON_EXCLAMATION) + result = dlg.ShowModal() + dlg.Destroy() + return result == wx.ID_OK + + def OnExit(self, event = None): + if event is None: + return + if self.WarnChanges(): + self.frame.Destroy() + + def GetCadVars(self): + self.cad = CadVars() + + f = open('_cad_ui_tmp.math') + for line in f: + if 'format:' in line: + self.cad.type = line[8:] + elif 'mm per unit:' in line: + self.cad.mm_per_unit = float(line[12:]) + elif 'dx dy dz:' in line: + [dx, dy, dz] = [float(v) for v in line[10:].split(' ')] + elif 'xmin ymin zmin:' in line: + [self.cad.xmin, + self.cad.ymin, + self.cad.zmin] = [float(v) for v in line[16:].split(' ')] + + self.cad.xmax = self.cad.xmin + dx + self.cad.ymax = self.cad.ymin + dy + self.cad.zmax = self.cad.zmin + dz + f.close() + + def get_resolution(self, size = None): + '''Calculates the desired resolution based on the .math file.''' + if not size: + size = image_size + self.GetCadVars() + + dx = self.cad.xmax - self.cad.xmin + dy = self.cad.ymax - self.cad.ymin + side = max(dx, dy) + self.resolution = size / (self.cad.mm_per_unit * side) + return self.resolution + +################################################################################ + + def start_thread(self, callable, args=()): + e = threading.Event() + t = threading.Thread(target=callable, args=args, kwargs={'event':e}) + t.daemon = True + t.start() + self.threads += [(t, e)] + + def monitor_threads(self): + ''' Monitor the list of active threads, joining those that are dead. + + This function runs in the wx IDLE callback, so it is continuously + checking in the background. + ''' + dead_threads = filter(lambda (thread, event): not thread.is_alive(), + self.threads) + + for thread, event in dead_threads: + thread.join() + + self.threads = filter(lambda t: t not in dead_threads, self.threads) + + def stop_threads(self): + ''' Tells all threads to stop at their earliest convenience. + ''' + for thread, event in self.threads: + event.set() + print '' +################################################################################ + + def export_math(self, filename, event = threading.Event()): + '''Exports a .math file. + + Updates the UI in case of success. + ''' + self.export = True + + print "#### Exporting .math file ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string (.math export)") + cm = self.cad_math(filename, event) + + if cm is True: # Program succeeded + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.frame.SetStatus, + ".math export complete") + self.export = False + +################################################################################ + + def export_png(self, resolution, filename, event = threading.Event()): + '''Exports a .png file. + + Updates the UI in case of success. + ''' + self.export = True + + print "#### Exporting .png file ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string (.png export)") + + # Save math file with default filename + if not self.cad_math(event=event): + self.export = False + return + + # Call math_png + mp = self.math_png(resolution, filename, event, incremental = False) + + if mp is True: + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.frame.SetStatus, + ".png export complete") + self.export = False + +################################################################################ + + def export_stl(self, resolution, filename, event = threading.Event()): + '''Exports a .stl file. + + Updates the UI in case of success. + ''' + self.export = True + + print "#### Exporting .stl file ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string (.stl export)") + + # Save math file with default filename + if not self.cad_math(event=event): + self.export = False + return + + # Call math_stl + mp = self.math_stl(resolution, filename, event) + + if mp is True: + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.frame.SetStatus, + ".stl export complete") + + self.export = False + +################################################################################ + + def export_svg(self, resolution, filename, event = threading.Event()): + '''Exports a .svg file. + + Updates the UI in case of success. + ''' + self.export = True + + print "#### Exporting .svg file ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string (.svg export)") + + # Save math file with default filename + if not self.cad_math(event=event): + self.export = False + return + + # Call math_svg + mp = self.math_svg(resolution, filename, event) + + if mp is True: + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.frame.SetStatus, + ".svg export complete") + + self.export = False +################################################################################ + + def export_dot(self, filename, event = threading.Event()): + '''Exports a .dot file. + + Updates the UI in case of success. + ''' + self.export = True + + print "#### Exporting .dot file ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string (.dot export)") + + # Save math file with default filename + if not self.cad_math(event=event): + self.export = False + return + + # Call math_dot + mp = self.math_dot(filename, event) + + if mp is True: + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.frame.SetStatus, + ".dot export complete") + self.export = False +################################################################################ + + def render(self, event = threading.Event()): + ''' Renders an image and loads it in the display panel. + + This function should be called in an independent thread. + ''' + now = datetime.now() + print "#### Rendering image ####" + wx.CallAfter(self.frame.ClearError) + wx.CallAfter(self.frame.SetBorder, (255, 165, 0)) + wx.CallAfter(self.frame.SetOutput, "\n\tNo errors") + wx.CallAfter(self.frame.SetStatus, + "Converting to math string") + + # Save math file with default filename + if not self.cad_math(event=event): + return + + # Extract the resolution from the .math file + resolution = self.get_resolution() + + # Call math_png. If it fails, then return early. + if self.math_png(resolution, event=event) is not True: + return + + wx.CallAfter(self.frame.SetBorder, (0, 255, 0)) + wx.CallAfter(self.LoadImage, '_cad_ui_tmp.png') + wx.CallAfter(os.remove, '_cad_ui_tmp.png') + wx.CallAfter(self.frame.SetStatus, "") + print "Time taken: ", datetime.now() - now + +################################################################################ + + def cad_math(self, filename = None, event = threading.Event()): + '''Runs cad_math. This should be started in a separate thread. + + Returns None if interrupted, False if failed, True if success. + In case of failure, updates UI accordingly. + + Deletes the source .cad file on success. + + ''' + + # Dump the contents of the text box into a .cad file. + with open('_cad_ui_tmp.cad', 'w') as cad_file: + + # To maintain backwards compatibility, we need to include + # this pair of libraries + cad_file.write('from string import *\nfrom math import *\n') + + # To allow for included files, we modify the python system path + if self.cadFileDir: + cad_file.write('import sys\nsys.path.append("%s")\n' % + self.cadFileDir) + + # Check to see if we should abort before writing the file + if event.is_set(): return + + cad_file.write(self.frame.GetText()) + + # If we are exporting with a particular file name, then the filename + # field should be populated; otherwise, use the default name. + if filename is None: + filename = '_cad_ui_tmp.math' + + if BUNDLED: + command = ['../MacOS/python', 'cad_math', + '_cad_ui_tmp.cad',target] + else: + command = ['cad_math', '_cad_ui_tmp.cad', filename] + + # Last chance to abort before starting the subprocess + if event.is_set(): return + + # Start running the process + print '>> ' + ' '.join(command) + process = subprocess.Popen(command, stderr = subprocess.PIPE) + + # Wait for the process to terminate or for the stop event to be set + while process.poll() is None: + if event.is_set(): + process.terminate() + return + + # If something went wrong, try to parse the error messages + # and update the GUI accordingly + if process.returncode != 0: + + # Read the text of the error messages + errors = process.stderr.readlines() + errors = errors[0] + ''.join(errors[3:]) + + # Go through the set of errors and modify line numbers to match + # the displayed file (since we may be adding lines to the beginning) + line_offset = (4 if self.cadFileDir else 2) + for m in re.findall(r'line (\d+)', errors): + error_line = int(m) - line_offset + errors = errors.replace('line %s' % m, 'line_ %i' % error_line) + errors = errors.replace('line_','line') + + # One more chance to abort before we update the GUI + if event.is_set(): return + + # Write out the errors in the text box + wx.CallAfter(self.frame.SetOutput, errors) + + # Make the image border red + wx.CallAfter(self.frame.SetBorder, (255, 0, 0)) + + # Update the status line + try: + wx.CallAfter(self.frame.MarkError, error_line - 1) + wx.CallAfter(self.frame.SetStatus, + "cad_math failed (line %i)" % error_line) + except NameError: + wx.CallAfter(self.frame.SetStatus, "cad_math failed") + + return False + + # If everything worked, then we return delete the temporary file + # and return True + os.remove('_cad_ui_tmp.cad') + return True + +################################################################################ + + def math_xyz(self, program, filename, resolution=None, + event=threading.Event(), args = [], + monitor = None): + + ''' Generic function to run math_png, math_svg, math_stl, etc. + + ''' + + if BUNDLED: + xyz_path = './%s' % program + else: + xyz_path = program + + if monitor is None: + monitor = self.progress_bar + minotaur = "RAWR!" + + if event.is_set(): return + + command = [xyz_path] + args + ['_cad_ui_tmp.math', filename] + if resolution: command += [str(resolution)] + + print '>> ' + ' '.join(command) + process = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + monitor(process, event) + success = (process.returncode == 0) + errors = process.stderr.read() + + # One more chance to abort before updating the GUI + if event.is_set(): return + + if not success: + wx.CallAfter(self.frame.SetOutput, errors) + wx.CallAfter(self.frame.SetBorder, (255, 0, 0)) + wx.CallAfter(self.frame.SetStatus, "%s failed" % program) + return False + + # If everything worked, then we delete the temporary file + # and return True + os.remove('_cad_ui_tmp.math') + return True + +################################################################################ + + def math_png(self, resolution, filename = None, event = threading.Event(), + incremental=None): + + # If we aren't saving to a particular file, use the default + if filename is None: + filename = '_cad_ui_tmp.png' + + if incremental is None and not 'Linux' in os.uname(): + incremental = not(self.cad.zmax - self.cad.zmin > 0) + + return self.math_xyz('math_png', filename, resolution=resolution, + event=event, + args = ['--incremental'] if incremental else [], + monitor = self.incremental) + +################################################################################ + + def math_stl(self, resolution, filename, event = threading.Event()): + + return self.math_xyz('math_stl', filename, + resolution=resolution, event=event) + +################################################################################ + + def math_svg(self, resolution, filename, event = threading.Event()): + + return self.math_xyz('math_svg', filename, + resolution=resolution, event=event) + +################################################################################ + + def math_dot(self, filename, event = threading.Event()): + + return self.math_xyz('math_dot', filename, event=event) + +################################################################################ + + def progress_bar(self, process, event): + ''' Waits for a process to finish, drawing a progress bar. + + Halts when the progress finishes or the event is set. + + ''' + + line = '' + while process.poll() is None: + if event.is_set(): + process.terminate() + return + + c = process.stdout.read(1) + if c == '\n' or c == '\r': + print repr(line) + if '[|' in line: + line = line[4:] + percent = (line.count('|') * 100) / (len(line) - 2) + if percent < 100: + wx.CallAfter(self.frame.SetStatus, + "Rendering (%i%%)" % percent) + else: + wx.CallAfter(self.frame.SetStatus, + "Writing output file") + else: + print line + line = '' + else: + line = line + c + +################################################################################ + + def incremental(self, process, event): + ''' Waits for a process to finish, drawing a progress bar and + incremental render blobs. + + Halts when the progress finishes or the event is set. + + ''' + + try: + dc = wx.MemoryDC(self.bitmap) + dc.SetPen(wx.TRANSPARENT_PEN) + except: + dc = None + + Y_MAX = (self.cad.ymax - self.cad.ymin) * self.cad.mm_per_unit*self.resolution + + line = '' + + if 'Linux' in os.uname(): + regex = None + else: + regex = re.compile( + r'([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) (.)' + ) + + while process.poll() is None: + if event.is_set(): + process.terminate() + return + + c = process.stdout.read(1) + if c == '\n' or c == '\r': + if '[|' in line: + line = line[4:] + percent = (line.count('|') * 100) / (len(line) - 2) + if percent < 100: + wx.CallAfter(self.frame.SetStatus, + "Rendering (%i%%)" % percent) + else: + wx.CallAfter(self.frame.SetStatus, + "Writing output file") + elif regex and regex.match(line): + xmin, xmax, ymin, ymax, color = regex.match(line).groups() + xmin, xmax, ymin, ymax = map(int, (xmin, xmax, ymin, ymax)) + color = ord(color) + if dc: + dc.SetBrush(wx.Brush(wx.Colour(color, color, color))) + dc.DrawRectangle(xmin, Y_MAX - ymax, + xmax-xmin, ymax-ymin) + wx.CallAfter(self.frame.SetImage, self.bitmap) + else: + print line + line = '' + else: + line = line + c + +################################################################################ + + def Render(self, e = None): + '''Attempt to render the .cad file into an image.''' + + # If this is an event callback, make sure that the box is checked. + if e and not e.Checked(): + return + + # Tell all of the existing threads to stop (politely) + self.stop_threads() + + # Start up a new thread to render and load the image. + self.start_thread(self.render) + +wx.Log.EnableLogging(False) +app = CadUIApp() +app.MainLoop() diff --git a/src/guis/fab b/src/guis/fab new file mode 100755 index 0000000..6b7e8c4 --- /dev/null +++ b/src/guis/fab @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# +# fab +# GUI wrapper wrapper +# +# Neil Gershenfeld +# CBA MIT +date = "10/4/13" +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx, sys, os, os.path +from fab_mods import set_workflows +# +# defaults +# +input_file = '""' +size = '400' +# +# command line +# +print "command line: fab [input_file [size]]" +print " input_file = input file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# set up frame +# +frame = wx.Frame(None, -1, 'fab') +frame_sizer = wx.GridBagSizer(10,10) +frame.SetSizer(frame_sizer) +bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) +# +# quit routine +# +def quit(event): + sys.exit() +# +# labels +# +format_text = wx.StaticText(frame,label="from format:") +format_text.SetFont(bold_font) +frame_sizer.Add(format_text,(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) +# +process_text = wx.StaticText(frame,label="to process:") +process_text.SetFont(bold_font) +frame_sizer.Add(process_text,(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) +# +program_text = wx.StaticText(frame,label="with program:") +program_text.SetFont(bold_font) +frame_sizer.Add(program_text,(0,2),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) +# +# menu event handler +# +def handler(event): + selected_format = frame.formats.GetValue() + selected_process = frame.processes.GetValue() + if ((selected_format == "format") | (selected_process == "process")): + return + key = selected_format + ' : ' + selected_process + if workflows.has_key(key): + frame.program = workflows[key] + frame.programs.SetLabel(frame.program) + frame.Layout() + frame.Fit() + else: + frame.program = "" + frame.programs.SetLabel("not defined") + frame.Layout() + frame.Fit() +# +# program call +# +frame.program = "" +def call_program(event): + if (frame.program != ""): + command = frame.program + ' ' + input_file + ' ' + size_control.GetValue() + '&' + print command + os.system(command) +# +# menus +# +frame.formats = wx.ComboBox(frame,value='format',style=wx.CB_READONLY) +frame.formats.Bind(wx.EVT_COMBOBOX,handler) +frame_sizer.Add(frame.formats,(1,0)) +# +frame.processes = wx.ComboBox(frame,value='process',style=wx.CB_READONLY) +frame.processes.Bind(wx.EVT_COMBOBOX,handler) +frame_sizer.Add(frame.processes,(1,1)) +# +frame.programs = wx.Button(frame,label='program') +frame.programs.Bind(wx.EVT_BUTTON,call_program) +frame_sizer.Add(frame.programs,(1,2),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) +# +# set workflows +# +workflows = {} +formats = [] +set_workflows(frame,formats,workflows) +# +# controls +# +control_panel = wx.Panel(frame) +control_sizer = wx.GridBagSizer(10,10) +control_panel.SetSizer(control_sizer) +# +control_sizer.Add(wx.StaticText(control_panel,label=' GUI size (pixels):'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) +# +size_control = wx.TextCtrl(control_panel,-1,size) +control_sizer.Add(size_control,(0,1),flag=(wx.ALIGN_LEFT)) +# +control_sizer.Add(wx.StaticText(control_panel,label="fab modules version: "+date),(0,2),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) +# +d = 4 +w = 1 +l = 6*d+2*w +def logo_paint(event): + dc = wx.PaintDC(logo_panel) + dc.SetBrush(wx.Brush('white')) + dc.SetPen(wx.Pen('white', 0)) + dc.DrawRectangleRect((0, 0, l, l)) + dc.SetBrush(wx.Brush('red')) + dc.DrawCircle(d,d,d) + dc.DrawCircle(3*d+w,3*d+w,d) + dc.SetBrush(wx.Brush('blue')) + dc.DrawRectangleRect((2*d+w,0,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,0,2*d,2*d)) + dc.DrawRectangleRect((0,2*d+w,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,2*d+w,2*d,2*d)) + dc.DrawRectangleRect((0,4*d+2*w,2*d,2*d)) + dc.DrawRectangleRect((2*d+w,4*d+2*w,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,4*d+2*w,2*d,2*d)) +logo_panel = wx.Panel(control_panel,size=(l,l)) +logo_panel.Bind(wx.EVT_PAINT,logo_paint) +control_sizer.Add(logo_panel,(0,3)) +# +control_quit = wx.Button(control_panel,label='quit') +control_quit.Bind(wx.EVT_BUTTON,quit) +control_sizer.Add(control_quit,(0,4)) +# +control_sizer.Add(wx.StaticText(control_panel,label=" "),(0,5),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) +# +control_panel.Fit() +frame_sizer.Add(control_panel,(2,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# process command line +# +if (len(sys.argv) > 1): + input_file = sys.argv[1] + ext = os.path.splitext(input_file)[1] + if (formats.count(ext) != 0): + frame.formats.SetSelection(formats.index(ext)) +if (len(sys.argv) > 2): + size = sys.argv[2] +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/fab.html b/src/guis/fab.html new file mode 100644 index 0000000..ded0ac8 --- /dev/null +++ b/src/guis/fab.html @@ -0,0 +1,6539 @@ + + + + + + + + + + + + + + +
+
+ + + diff --git a/src/guis/fabserver b/src/guis/fabserver new file mode 100755 index 0000000..4832a24 --- /dev/null +++ b/src/guis/fabserver @@ -0,0 +1,369 @@ +#!/usr/bin/env python +# +# fabserver.py +# command line syntax: python fabserver.py port +# +# Neil Gershenfeld +# CBA MIT 12/6/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +from socket import * +from string import * +from select import * +from math import * +import sys +import subprocess +import os +import glob + +MAX_PACKET = 4096 +MAX_RESPONSE = 10000000 +PACKET_TIMEOUT = 0.01 + +SERVER_ADDRESS = "127.0.0.1" + +def send_image(msg): + client_socket.sendall( + 'HTTP/1.1 200 OK\n' + +'Content-Length: %d\n'%len(msg) + +'Content-Type: image/jpeg\n' + +'\n' + +msg + ) + +def send_text(text): + client_socket.sendall( + 'HTTP/1.1 200 OK\n' + +'Content-Type: text/html\n' + +'\n' + +'\n' + +text + ) + +def parse(): + global mode, units, dx, dy, dz, xmin, ymin, zmin, xrot, yrot, zrot, resolution, slices, expression + # + # parse math string + # + start = 0 + start = 1+find(response,"{",start) + end = find(response,"}",start) + mode = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + units = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + dx = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + dy = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + dz = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + xmin = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + ymin = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + zmin = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + xrot = float(response[start:end]) + start = 1+find(response,"{",end) + end = find(response,"}",start) + yrot = float(response[start:end]) + start = 1+find(response,"{",end) + end = find(response,"}",start) + zrot = float(response[start:end]) + start = 1+find(response,"{",end) + end = find(response,"}",start) + resolution = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + slices = response[start:end] + start = 1+find(response,"{",end) + end = find(response,"}",start) + expression = response[start:end] + +def render(): + # + # render math string, xy view + # + math_file = open("fab_render_xy.math","w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+dx+" "+dy+" "+dz+"\n") + math_file.write("xmin ymin zmin: "+xmin+" "+ymin+" "+zmin+"\n") + math_file.write("expression: "+expression+"\n") + math_file.close() + os.system("math_png fab_render_xy.math fab_render_xy.png "+resolution+" "+slices) + os.system("rm fab_render_xy.math") + if (float(dz) != 0): + # + # xz view + # + math_file = open("fab_render_xz.math","w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+dx+" "+dz+" "+dy+"\n") + math_file.write("xmin ymin zmin: "+xmin+" "+zmin+" "+ymin+"\n") + math_file.write("expression: "+expression+"\n") + new_expression = replace(expression,'Y','#') + new_expression = replace(new_expression,'Z','Y') + new_expression = replace(new_expression,'#','Z') + math_file.write("expression: "+new_expression+"\n") + math_file.close() + os.system("math_png fab_render_xz.math fab_render_xz.png "+resolution+" "+slices) + os.system("rm fab_render_xz.math") + # + # zy view + # + math_file = open("fab_render_zy.math","w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+dz+" "+dy+" "+dx+"\n") + math_file.write("xmin ymin zmin: "+zmin+" "+ymin+" "+xmin+"\n") + new_expression = replace(expression,'X','#') + new_expression = replace(new_expression,'Z','((%f)-X)'%(float(dz)+2*float(zmin))) + new_expression = replace(new_expression,'#','Z') + math_file.write("expression: "+new_expression+"\n") + math_file.close() + os.system("math_png fab_render_zy.math fab_render_zy.png "+resolution+" "+slices) + os.system("rm fab_render_zy.math") + # + # xyz view + # + math_file = open("fab_render_xyz.math","w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+"2"+" "+"2"+" "+"2"+"\n") + math_file.write("xmin ymin zmin: "+"-1"+" "+"-1"+" "+"-1"+"\n") + # + # view scaling + # + -1 + 1 + new_expression = replace(expression,'X','(('+xmin+')+'+dx+'*(X+1)/2)') + new_expression = replace(new_expression,'Y','(('+ymin+')+'+dy+'*(Y+1)/2)') + new_expression = replace(new_expression,'Z','(('+zmin+')+'+dz+'*(Z+1)/2)') + #new_expression = replace(expression,'X','(X+('+xmin+')+1)') + #new_expression = replace(new_expression,'Y','(Y+('+ymin+')+1)') + #new_expression = replace(new_expression,'Z','(Z+('+zmin+')+1)') + # + # z rotation + # + new_expression = replace(new_expression,'X','(('+str(cos(zrot))+')*X+('+str(-sin(zrot))+')*ytemp)') + new_expression = replace(new_expression,'Y','(('+str(sin(zrot))+')*X+('+str(cos(zrot))+')*Y)') + new_expression = replace(new_expression,'ytemp','Y') + # + # y rotation (not used in GUI) + # + # + # x rotation + # + new_expression = replace(new_expression,'Y','(('+str(cos(xrot))+')*Y+('+str(sin(xrot))+')*ztemp)') + new_expression = replace(new_expression,'Z','(('+str(-sin(xrot))+')*Y+('+str(cos(xrot))+')*Z)') + new_expression = replace(new_expression,'ztemp','Z') + # + # write and evaluate + # + math_file.write("expression: "+new_expression+"\n") + math_file.close() + os.system("math_png fab_render_xyz.math fab_render_xyz.png "+resolution+" "+slices) + os.system("rm fab_render_xyz.math") + #send_text("render") + +# +# get command line arguments +# +if (len(sys.argv) != 2): + print "command line syntax: python fabserver.py port" + sys.exit() +server_port = sys.argv[1] +# +# start listening on server port +# +try: + server_socket = socket(AF_INET, SOCK_STREAM) + server_socket.bind((SERVER_ADDRESS,int(server_port))) + server_socket.listen(5) + print "listening on port "+server_port +except: + print "error: couldn't open socket" + sys.exit() + +# +# start main loop +# +while 1: + # + # blocking select call to wait for a connection + # + [read_ready, write_ready, error_ready] = select([server_socket],[],[]) + if (read_ready != []): + # + # child process, non-blocking select call to receive packet + # + (client_socket, client_address) = server_socket.accept() + response = "" + while 1: + [read_ready, write_ready, error_ready] = select([client_socket],[],[],PACKET_TIMEOUT) + if (read_ready != []): + response += client_socket.recv(MAX_PACKET) + else: + break + # + # process response + # + #print response + if (find(response,"GET / ") == 0): + # + # root request, send fab.html + # + file = open(os.path.join(os.path.dirname(sys.argv[0]), 'fab.html'), + 'rb') + msg = file.read() + file.close() + send_text(msg) + elif (find(response,"GET /fab_render_xy.png") == 0): + try: + file = open('fab_render_xy.png','rb') + os.system("rm fab_render_xy.png") + msg = file.read() + file.close() + send_image(msg) + except IOError: + print "oops" + elif (find(response,"GET /fab_render_xz.png") == 0): + try: + file = open('fab_render_xz.png','rb') + os.system("rm fab_render_xz.png") + msg = file.read() + file.close() + send_image(msg) + except IOError: + print "oops" + elif (find(response,"GET /fab_render_zy.png") == 0): + try: + file = open('fab_render_zy.png','rb') + os.system("rm fab_render_zy.png") + msg = file.read() + file.close() + send_image(msg) + except IOError: + print "oops" + elif (find(response,"GET /fab_render_xyz.png") == 0): + try: + file = open('fab_render_xyz.png','rb') + os.system("rm fab_render_xyz.png") + msg = file.read() + file.close() + send_image(msg) + except IOError: + print "oops" + elif (find(response,"GET /fab.html") == 0): + file = open('fab.html','rb') + msg = file.read() + file.close() + send_text(msg) + elif (find(response,"GET /quit") == 0): + break + elif (find(response,"POST /list_files") == 0): + files = glob.glob('*.fab') + file_names = ','.join(files) + cwd = os.getcwd() + dirs = filter(os.path.isdir, os.listdir('.')) + dirs_names = ','.join(dirs) + send_text(file_names+';'+cwd+';'+dirs_names) + elif (find(response,"POST /cd") == 0): + start = 1+find(response,"{") + end = find(response,"}",start) + dir_name = response[start:end] + os.chdir(dir_name) + files = glob.glob('*.fab') + file_names = ','.join(files) + cwd = os.getcwd() + dirs = filter(os.path.isdir, os.listdir('.')) + dirs_names = ','.join(dirs) + send_text(file_names+';'+cwd+';'+dirs_names) + elif (find(response,"POST /delete") == 0): + start = 1+find(response,"{") + end = find(response,"}",start) + file_name = response[start:end] + os.remove(file_name) + files = glob.glob('*.fab') + file_names = ','.join(files) + cwd = os.getcwd() + dirs = filter(os.path.isdir, os.listdir('.')) + dirs_names = ','.join(dirs) + send_text(file_names+';'+cwd+';'+dirs_names) + elif (find(response,"POST /open") == 0): + start = 1+find(response,"{") + end = find(response,"}",start) + file_name = response[start:end] + print "file"+file_name+"name" + try: + file = open(file_name,'rb') + msg = file.read() + file.close() + send_text(msg) + except IOError: + print "oops" + elif (find(response,"POST /render") == 0): + # + # render + # + parse() + render() + elif (find(response,"POST /fabricate") == 0): + # + # fabricate + # + parse() + math_file = open("fab_render_xy.math","w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+dx+" "+dy+" "+dz+"\n") + math_file.write("xmin ymin zmin: "+xmin+" "+ymin+" "+zmin+"\n") + math_file.write("expression: "+expression+"\n") + math_file.close() + os.system("fab fab_render_xy.math") + os.system("rm fab_render_xy.math") + elif (find(response,"POST /save_graph") == 0): + start = 17+find(response,"POST /save_graph") + end = find(response,"/",start) + file_name = response[start:end] + file = open(file_name,"w") + start = find(response,"graph start:") + file.writelines(response[start:]) + file.close() + client_socket.send("saved "+file_name) + elif (find(response,"POST /save_math") == 0): + start = 16+find(response,"POST /save_math") + end = find(response,"/",start) + file_name = response[start:end] + parse() + math_file = open(file_name,"w") + math_file.write("format: "+mode+"\n") + math_file.write("mm per unit: "+units+"\n") + math_file.write("dx dy dz: "+dx+" "+dy+" "+dz+"\n") + math_file.write("xmin ymin zmin: "+xmin+" "+ymin+" "+zmin+"\n") + math_file.write("expression: "+expression+"\n") + math_file.close() + client_socket.send("saved "+file_name) + # + # close connection socket and exit + # + client_socket.close() +# +# close server socket and exit +# +server_socket.close() diff --git a/src/guis/make_cad_camm b/src/guis/make_cad_camm new file mode 100755 index 0000000..dd99999 --- /dev/null +++ b/src/guis/make_cad_camm @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# +# make_cad_camm +# .cad to .camm GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_camm import path_camm_panel +# +# command line +# +print "command line: make_cad_camm [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_camm",sys.argv) +frame.size = frame.size/1.25 +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.camm_panel = path_camm_panel(frame) +frame.sizer.Add(frame.camm_panel,(1,3)) +# +# defaults +# +frame.set_cad_camm() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_drl b/src/guis/make_cad_drl new file mode 100755 index 0000000..6df91f4 --- /dev/null +++ b/src/guis/make_cad_drl @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_cad_drl +# .cad to .drl GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_drl import png_drl_panel +# +# command line +# +print "command line: make_cad_drl [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_drl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.drl_panel = png_drl_panel(frame) +frame.sizer.Add(frame.drl_panel,(1,2)) +# +# defaults +# +#frame.set_cad_drl() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_dxf b/src/guis/make_cad_dxf new file mode 100755 index 0000000..8014ec9 --- /dev/null +++ b/src/guis/make_cad_dxf @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_dxf +# .cad to .dxf GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 8/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_dxf import path_dxf_panel +# +# command line +# +print "command line: make_cad_dxf [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_dxf",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.dxf_panel = path_dxf_panel(frame) +frame.sizer.Add(frame.dxf_panel,(1,3)) +# +# defaults +# +#frame.set_cad_dxf() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_epi b/src/guis/make_cad_epi new file mode 100755 index 0000000..341c566 --- /dev/null +++ b/src/guis/make_cad_epi @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_epi +# .cad to .epi GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_epi import path_epi_panel +# +# command line +# +print "command line: make_cad_epi [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_epi",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.epi_panel = path_epi_panel(frame) +frame.sizer.Add(frame.epi_panel,(1,3)) +# +# defaults +# +frame.set_cad_epi() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_eps b/src/guis/make_cad_eps new file mode 100755 index 0000000..4e4448d --- /dev/null +++ b/src/guis/make_cad_eps @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# make_cad_eps +# .cad to .eps GUI wrapper +# +# Neil Gershenfeld 7/4/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_eps import path_eps_panel +# +# command line +# +print "command line: make_cad_eps [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_eps",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.eps_panel = path_eps_panel(frame) +frame.sizer.Add(frame.eps_panel,(1,3)) +# +# defaults +# +frame.set_cad_eps() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_g b/src/guis/make_cad_g new file mode 100755 index 0000000..ee6aae3 --- /dev/null +++ b/src/guis/make_cad_g @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_g +# .cad to .g GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_g import path_g_panel +# +# command line +# +print "command line: make_cad_g [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_g",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.g_panel = path_g_panel(frame) +frame.sizer.Add(frame.g_panel,(1,3)) +# +# defaults +# +frame.set_cad_g() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_grb b/src/guis/make_cad_grb new file mode 100755 index 0000000..a22bee3 --- /dev/null +++ b/src/guis/make_cad_grb @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_cad_grb +# .cad to .grb GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_grb import png_grb_panel +# +# command line +# +print "command line: make_cad_grb [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_grb",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.grb_panel = png_grb_panel(frame) +frame.sizer.Add(frame.grb_panel,(1,2)) +# +# defaults +# +#frame.set_cad_grb() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_ord b/src/guis/make_cad_ord new file mode 100755 index 0000000..258e8ea --- /dev/null +++ b/src/guis/make_cad_ord @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_ord +# .cad to .ord GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_ord import path_ord_panel +# +# command line +# +print "command line: make_cad_ord [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_ord",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.ord_panel = path_ord_panel(frame) +frame.sizer.Add(frame.ord_panel,(1,3)) +# +# defaults +# +frame.set_cad_ord() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_png b/src/guis/make_cad_png new file mode 100755 index 0000000..53525f4 --- /dev/null +++ b/src/guis/make_cad_png @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# +# make_cad_png +# .cad to .png GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/18/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +# +# command line +# +print "command line: make_cad_png [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_png",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +# +# defaults +# +frame.defaults = {} +frame.control_panel.defaults.Append('preview') +frame.defaults["preview"] = "self.png_panel.resolution.SetValue('10')" +frame.control_panel.defaults.Append('render') +frame.defaults["render"] = "self.png_panel.resolution.SetValue('50')" +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_rml b/src/guis/make_cad_rml new file mode 100755 index 0000000..3c96c58 --- /dev/null +++ b/src/guis/make_cad_rml @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_rml +# .cad to .rml GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_rml import path_rml_panel +# +# command line +# +print "command line: make_cad_rml [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.rml_panel = path_rml_panel(frame) +frame.sizer.Add(frame.rml_panel,(1,3)) +# +# defaults +# +frame.set_cad_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_sbp b/src/guis/make_cad_sbp new file mode 100755 index 0000000..f9cc0f9 --- /dev/null +++ b/src/guis/make_cad_sbp @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_sbp +# .cad to .sbp GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_sbp import path_sbp_panel +# +# command line +# +print "command line: make_cad_sbp [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_sbp",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.cad_png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.cad_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.sbp_panel = path_sbp_panel(frame) +frame.sizer.Add(frame.sbp_panel,(1,3)) +# +# defaults +# +frame.set_cad_sbp() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_snap b/src/guis/make_cad_snap new file mode 100755 index 0000000..7ea072b --- /dev/null +++ b/src/guis/make_cad_snap @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_snap +# .cad to MTP Snap GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_snap import path_snap_panel +# +# command line +# +print "command line: make_cad_snap [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_snap",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.snap_panel = path_snap_panel(frame) +frame.sizer.Add(frame.snap_panel,(1,3)) +# +# defaults +# +#frame.set_cad_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_stl b/src/guis/make_cad_stl new file mode 100755 index 0000000..5d8ae92 --- /dev/null +++ b/src/guis/make_cad_stl @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_cad_stl +# .cad to .stl GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/22/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_stl import cad_stl_panel +# +# command line +# +print "command line: make_cad_stl [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_stl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.stl_panel = cad_stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,1)) +# +# defaults +# +frame.defaults = {} +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_cad_uni b/src/guis/make_cad_uni new file mode 100755 index 0000000..50ab51b --- /dev/null +++ b/src/guis/make_cad_uni @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_cad_uni +# .cad to .uni GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_cad import cad_panel +from panel_cad_png import cad_png_panel +from panel_png_path import png_path_panel +from panel_path_uni import path_uni_panel +# +# command line +# +print "command line: make_cad_uni [input_file [size]]" +print " input_file = input .cad file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_cad_uni",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.cad_panel = cad_panel(frame) +frame.sizer.Add(frame.cad_panel,(1,0)) +frame.png_panel = cad_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.uni_panel = path_uni_panel(frame) +frame.sizer.Add(frame.uni_panel,(1,3)) +# +# defaults +# +frame.set_cad_uni() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_gif_stl b/src/guis/make_gif_stl new file mode 100644 index 0000000..24beb9c --- /dev/null +++ b/src/guis/make_gif_stl @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_gif_stl +# .gif to .stl GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/25/14 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_gif import gif_panel +from panel_gif_stl import gif_stl_panel +# +# command line +# +print "command line: make_gif_stl [input_file [size]]" +print " input_file = input .gif file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_gif_stl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.gif_panel = gif_panel(frame) +frame.sizer.Add(frame.gif_panel,(1,0)) +frame.stl_panel = gif_stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,1)) +# +# defaults +# +frame.defaults = {} +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_camm b/src/guis/make_math_camm new file mode 100755 index 0000000..366d295 --- /dev/null +++ b/src/guis/make_math_camm @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_camm +# .math to .camm GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_camm import path_camm_panel +# +# command line +# +print "command line: make_math_camm [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_camm",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.camm_panel = path_camm_panel(frame) +frame.sizer.Add(frame.camm_panel,(1,3)) +# +# defaults +# +frame.set_math_camm() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_drl b/src/guis/make_math_drl new file mode 100755 index 0000000..7d3c0f8 --- /dev/null +++ b/src/guis/make_math_drl @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_math_drl +# .math to .drl GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_drl import png_drl_panel +# +# command line +# +print "command line: make_math_drl [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_drl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.drl_panel = png_drl_panel(frame) +frame.sizer.Add(frame.drl_panel,(1,2)) +# +# defaults +# +#frame.set_math_drl() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_dxf b/src/guis/make_math_dxf new file mode 100755 index 0000000..e4c101c --- /dev/null +++ b/src/guis/make_math_dxf @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_dxf +# .math to .dxf GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 8/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_dxf import path_dxf_panel +# +# command line +# +print "command line: make_math_dxf [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_dxf",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.dxf_panel = path_dxf_panel(frame) +frame.sizer.Add(frame.dxf_panel,(1,3)) +# +# defaults +# +#frame.set_math_dxf() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_epi b/src/guis/make_math_epi new file mode 100755 index 0000000..58543a4 --- /dev/null +++ b/src/guis/make_math_epi @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_epi +# .math to .epi GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_epi import path_epi_panel +# +# command line +# +print "command line: make_math_epi [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_epi",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.math_png_panel = math_png_panel(frame) +frame.sizer.Add(frame.math_png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.epi_panel = path_epi_panel(frame) +frame.sizer.Add(frame.epi_panel,(1,3)) +# +# defaults +# +frame.set_math_epi() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_eps b/src/guis/make_math_eps new file mode 100755 index 0000000..c8fd32c --- /dev/null +++ b/src/guis/make_math_eps @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# make_math_eps +# .math to .eps GUI wrapper +# +# Neil Gershenfeld 7/4/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_eps import path_eps_panel +# +# command line +# +print "command line: make_math_eps [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_eps",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.eps_panel = path_eps_panel(frame) +frame.sizer.Add(frame.eps_panel,(1,3)) +# +# defaults +# +frame.set_math_eps() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_g b/src/guis/make_math_g new file mode 100755 index 0000000..5030bcd --- /dev/null +++ b/src/guis/make_math_g @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_g +# .math to .g GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_g import path_g_panel +# +# command line +# +print "command line: make_math_g [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_g",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.math_png_panel = math_png_panel(frame) +frame.sizer.Add(frame.math_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.g_panel = path_g_panel(frame) +frame.sizer.Add(frame.g_panel,(1,3)) +# +# defaults +# +frame.set_math_g() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_grb b/src/guis/make_math_grb new file mode 100755 index 0000000..39d3d92 --- /dev/null +++ b/src/guis/make_math_grb @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_math_grb +# .math to .grb GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_grb import png_grb_panel +# +# command line +# +print "command line: make_math_grb [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.grb_panel = png_grb_panel(frame) +frame.sizer.Add(frame.grb_panel,(1,2)) +# +# defaults +# +#frame.set_math_grb() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_ord b/src/guis/make_math_ord new file mode 100755 index 0000000..aa6b34d --- /dev/null +++ b/src/guis/make_math_ord @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_ord +# .math to .ord GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_ord import path_ord_panel +# +# command line +# +print "command line: make_math_ord [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_ord",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.ord_panel = path_ord_panel(frame) +frame.sizer.Add(frame.ord_panel,(1,3)) +# +# defaults +# +frame.set_math_ord() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_rml b/src/guis/make_math_rml new file mode 100755 index 0000000..6d94a0c --- /dev/null +++ b/src/guis/make_math_rml @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_rml +# .math to .rml GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_rml import path_rml_panel +# +# command line +# +print "command line: make_math_rml [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.math_png_panel = math_png_panel(frame) +frame.sizer.Add(frame.math_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.rml_panel = path_rml_panel(frame) +frame.sizer.Add(frame.rml_panel,(1,3)) +# +# defaults +# +frame.set_math_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_sbp b/src/guis/make_math_sbp new file mode 100755 index 0000000..306969a --- /dev/null +++ b/src/guis/make_math_sbp @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_sbp +# .math to .sbp GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_sbp import path_sbp_panel +# +# command line +# +print "command line: make_math_sbp [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_sbp",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.math_png_panel = math_png_panel(frame) +frame.sizer.Add(frame.math_png_panel,(1,1)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.sbp_panel = path_sbp_panel(frame) +frame.sizer.Add(frame.sbp_panel,(1,3)) +# +# defaults +# +frame.set_math_sbp() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_stl b/src/guis/make_math_stl new file mode 100755 index 0000000..4f472ef --- /dev/null +++ b/src/guis/make_math_stl @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_math_stl +# .math to .stl GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 9/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_stl import math_stl_panel +# +# command line +# +print "command line: make_math_stl [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_stl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.stl_panel = math_stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,1)) +# +# defaults +# +frame.defaults = {} +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_math_uni b/src/guis/make_math_uni new file mode 100755 index 0000000..aad7b87 --- /dev/null +++ b/src/guis/make_math_uni @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_math_uni +# .math to .uni GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_math import math_panel +from panel_math_png import math_png_panel +from panel_png_path import png_path_panel +from panel_path_uni import path_uni_panel +# +# command line +# +print "command line: make_math_uni [input_file [size]]" +print " input_file = input .math file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_math_uni",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.math_panel = math_panel(frame) +frame.sizer.Add(frame.math_panel,(1,0)) +frame.png_panel = math_png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,1)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.uni_panel = path_uni_panel(frame) +frame.sizer.Add(frame.uni_panel,(1,3)) +# +# defaults +# +frame.set_math_uni() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_camm b/src/guis/make_png_camm new file mode 100755 index 0000000..6df9e0d --- /dev/null +++ b/src/guis/make_png_camm @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_camm +# .png to .camm GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_camm import path_camm_panel +# +# command line +# +print "command line: make_png_camm [input_file [size]]" +print " input_file = input .camm file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_camm",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.camm_panel = path_camm_panel(frame) +frame.sizer.Add(frame.camm_panel,(1,2)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_camm() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_drl b/src/guis/make_png_drl new file mode 100755 index 0000000..b10543b --- /dev/null +++ b/src/guis/make_png_drl @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_png_grb +# .png to .grb GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/23/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_drl import png_drl_panel +# +# command line +# +print "command line: make_png_drl [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_drl",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.drl_panel = png_drl_panel(frame) +frame.sizer.Add(frame.drl_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# set defaults +# +#frame.set_png_drl() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_dxf b/src/guis/make_png_dxf new file mode 100755 index 0000000..f27fa95 --- /dev/null +++ b/src/guis/make_png_dxf @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_dxf +# .png to .dxf GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/12 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_dxf import path_dxf_panel +# +# command line +# +print "command line: make_png_dxf [input_file [size]]" +print " input_file = input .dxf file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_dxf",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.dxf_panel = path_dxf_panel(frame) +frame.sizer.Add(frame.dxf_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +#frame.set_png_dxf() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_epi b/src/guis/make_png_epi new file mode 100755 index 0000000..44884e3 --- /dev/null +++ b/src/guis/make_png_epi @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_epi +# .png to .epi GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 1/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_epi import path_epi_panel +# +# command line +# +print "command line: make_png_epi [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_epi",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.epi_panel = path_epi_panel(frame) +frame.sizer.Add(frame.epi_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# set defaults +# +frame.set_png_epi() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_epi_halftone b/src/guis/make_png_epi_halftone new file mode 100755 index 0000000..70ffec8 --- /dev/null +++ b/src/guis/make_png_epi_halftone @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_epi_halftone +# .png to .epi halftone GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/12/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path_halftone import png_path_halftone_panel +from panel_path_epi import path_epi_panel +# +# command line +# +print "command line: make_png_epi_halftone [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_epi_halftone",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.epi_panel = path_epi_panel(frame) +frame.sizer.Add(frame.epi_panel,(1,2)) +frame.path_panel = png_path_halftone_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_epi_halftone() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_eps b/src/guis/make_png_eps new file mode 100755 index 0000000..8f45dca --- /dev/null +++ b/src/guis/make_png_eps @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_png_eps +# .png to .eps GUI wrapper +# +# Neil Gershenfeld 7/4/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_eps import path_eps_panel +# +# command line +# +print "command line: make_png_eps [input_file [size]]" +print " input_file = input .eps file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_eps",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.eps_panel = path_eps_panel(frame) +frame.sizer.Add(frame.eps_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_eps() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_eps_halftone b/src/guis/make_png_eps_halftone new file mode 100755 index 0000000..d39a1e2 --- /dev/null +++ b/src/guis/make_png_eps_halftone @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_png_eps_halftone +# .png to .eps halftone GUI wrapper +# +# Neil Gershenfeld 7/4/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path_halftone import png_path_halftone_panel +from panel_path_eps import path_eps_panel +# +# command line +# +print "command line: make_png_eps_halftone [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_eps_halftone",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.eps_panel = path_eps_panel(frame) +frame.sizer.Add(frame.eps_panel,(1,2)) +frame.path_panel = png_path_halftone_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +#frame.set_png_eps_halftone() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_g b/src/guis/make_png_g new file mode 100755 index 0000000..881bc94 --- /dev/null +++ b/src/guis/make_png_g @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_g +# .png to .g GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_g import path_g_panel +# +# command line +# +print "command line: make_png_g [input_file [size]]" +print " input_file = input .g file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_g",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.g_panel = path_g_panel(frame) +frame.sizer.Add(frame.g_panel,(1,2)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_g() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_grb b/src/guis/make_png_grb new file mode 100755 index 0000000..f19c614 --- /dev/null +++ b/src/guis/make_png_grb @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_png_grb +# .png to .grb GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/23/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_grb import png_grb_panel +# +# command line +# +print "command line: make_png_grb [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_grb",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.grb_panel = png_grb_panel(frame) +frame.sizer.Add(frame.grb_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# set defaults +# +#frame.set_png_grb() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_oms b/src/guis/make_png_oms new file mode 100755 index 0000000..ed90da3 --- /dev/null +++ b/src/guis/make_png_oms @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_oms +# .png to .oms GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 5/25/13 +# +# (c) Massachusetts Institute of Technology 2013 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_oms import path_oms_panel +# +# command line +# +print "command line: make_png_oms [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_oms",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.oms_panel = path_oms_panel(frame) +frame.sizer.Add(frame.oms_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# set defaults +# +frame.set_png_oms() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_ord b/src/guis/make_png_ord new file mode 100755 index 0000000..6c956eb --- /dev/null +++ b/src/guis/make_png_ord @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_ord +# .png to .ord GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_ord import path_ord_panel +# +# command line +# +print "command line: make_png_ord [input_file [size]]" +print " input_file = input .ord file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_ord",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.ord_panel = path_ord_panel(frame) +frame.sizer.Add(frame.ord_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_ord() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_plt b/src/guis/make_png_plt new file mode 100755 index 0000000..2729705 --- /dev/null +++ b/src/guis/make_png_plt @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_plt +# .png to .plt GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_plt import path_plt_panel +# +# command line +# +print "command line: make_png_plt [input_file [size]]" +print " input_file = input .plt file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_plt",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.plt_panel = path_plt_panel(frame) +frame.sizer.Add(frame.plt_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_plt() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_png b/src/guis/make_png_png new file mode 100755 index 0000000..b29550e --- /dev/null +++ b/src/guis/make_png_png @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# make_png_png +# .png to .png GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_png import png_png_panel +# +# command line +# +print "command line: make_png_png [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_png",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.png_png_panel = png_png_panel(frame) +frame.sizer.Add(frame.png_png_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.defaults = {} +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_rml b/src/guis/make_png_rml new file mode 100755 index 0000000..39ba4f9 --- /dev/null +++ b/src/guis/make_png_rml @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_rml +# .png to .rml GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_rml import path_rml_panel +# +# command line +# +print "command line: make_png_rml [input_file [size]]" +print " input_file = input .rml file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.rml_panel = path_rml_panel(frame) +frame.sizer.Add(frame.rml_panel,(1,2)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_sbp b/src/guis/make_png_sbp new file mode 100755 index 0000000..3095eea --- /dev/null +++ b/src/guis/make_png_sbp @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_sbp +# .png to .sbp GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_sbp import path_sbp_panel +# +# command line +# +print "command line: make_png_sbp [input_file [size]]" +print " input_file = input .sbp file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_sbp",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.sbp_panel = path_sbp_panel(frame) +frame.sizer.Add(frame.sbp_panel,(1,2)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_sbp() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_snap b/src/guis/make_png_snap new file mode 100755 index 0000000..b0d8787 --- /dev/null +++ b/src/guis/make_png_snap @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_snap +# .png to MTM Snap GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_snap import path_snap_panel +# +# command line +# +print "command line: make_png_snap [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_snap",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.snap_panel = path_snap_panel(frame) +frame.sizer.Add(frame.snap_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +#frame.set_png_snap() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_uni b/src/guis/make_png_uni new file mode 100755 index 0000000..e12e072 --- /dev/null +++ b/src/guis/make_png_uni @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_uni +# .png to .uni GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 1/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path import png_path_panel +from panel_path_uni import path_uni_panel +# +# command line +# +print "command line: make_png_uni [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_uni",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.uni_panel = path_uni_panel(frame) +frame.sizer.Add(frame.uni_panel,(1,2)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_uni() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_png_uni_halftone b/src/guis/make_png_uni_halftone new file mode 100755 index 0000000..b955eb3 --- /dev/null +++ b/src/guis/make_png_uni_halftone @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_png_uni_halftone +# .png to .uni halftone GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/12/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_png import png_panel +from panel_png_path_halftone import png_path_halftone_panel +from panel_path_uni import path_uni_panel +# +# command line +# +print "command line: make_png_uni_halftone [input_file [size]]" +print " input_file = input .png file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_png_uni_halftone",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.uni_panel = path_uni_panel(frame) +frame.sizer.Add(frame.uni_panel,(1,2)) +frame.path_panel = png_path_halftone_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.png_panel = png_panel(frame) +frame.sizer.Add(frame.png_panel,(1,0)) +# +# defaults +# +frame.set_png_uni_halftone() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_stl_g b/src/guis/make_stl_g new file mode 100755 index 0000000..7e21fc0 --- /dev/null +++ b/src/guis/make_stl_g @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_stl_g +# .stl to .g GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_stl import stl_panel +from panel_stl_png import stl_png_panel +from panel_png_path import png_path_panel +from panel_path_g import path_g_panel +# +# command line +# +print "command line: make_stl_g [input_file [size]]" +print " input_file = input .stl file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_stl_g",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.g_panel = path_g_panel(frame) +frame.sizer.Add(frame.g_panel,(1,3)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.stl_png_panel = stl_png_panel(frame) +frame.sizer.Add(frame.stl_png_panel,(1,1)) +frame.stl_panel = stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,0)) +# +# defaults +# +frame.set_stl_g() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_stl_png b/src/guis/make_stl_png new file mode 100755 index 0000000..8eed289 --- /dev/null +++ b/src/guis/make_stl_png @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# make_stl_png +# .stl to .png GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_stl import stl_panel +from panel_stl_png import stl_png_panel +# +# command line +# +print "command line: make_stl_png [input_file [size]]" +print " input_file = input .stl file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_stl_png",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.stl_panel = stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,0)) +frame.stl_png_panel = stl_png_panel(frame) +frame.sizer.Add(frame.stl_png_panel,(1,1)) +# +# defaults +# +frame.defaults = {} +frame.control_panel.defaults.Append('inches') +frame.defaults["inches"] = "\ +self.stl_png_panel.units.SetValue('25.4');\ +self.stl_png_panel.resolution.SetValue('25');" +frame.control_panel.defaults.Append('mm') +frame.defaults["mm"] = "\ +self.stl_png_panel.units.SetValue('1');\ +self.stl_png_panel.resolution.SetValue('25');" +frame.control_panel.defaults.Append('cm') +frame.defaults["cm"] = "\ +self.stl_png_panel.units.SetValue('10');\ +self.stl_png_panel.resolution.SetValue('25');" +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_stl_rml b/src/guis/make_stl_rml new file mode 100755 index 0000000..113e795 --- /dev/null +++ b/src/guis/make_stl_rml @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_stl_rml +# .stl to .rml GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_stl import stl_panel +from panel_stl_png import stl_png_panel +from panel_png_path import png_path_panel +from panel_path_rml import path_rml_panel +# +# command line +# +print "command line: make_stl_rml [input_file [size]]" +print " input_file = input .stl file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_stl_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.rml_panel = path_rml_panel(frame) +frame.sizer.Add(frame.rml_panel,(1,3)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.stl_png_panel = stl_png_panel(frame) +frame.sizer.Add(frame.stl_png_panel,(1,1)) +frame.stl_panel = stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,0)) +# +# defaults +# +frame.set_stl_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_stl_sbp b/src/guis/make_stl_sbp new file mode 100755 index 0000000..6853a15 --- /dev/null +++ b/src/guis/make_stl_sbp @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_stl_sbp +# .stl to .sbp GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_stl import stl_panel +from panel_stl_png import stl_png_panel +from panel_png_path import png_path_panel +from panel_path_sbp import path_sbp_panel +# +# command line +# +print "command line: make_stl_sbp [input_file [size]]" +print " input_file = input .stl file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_stl_sbp",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.sbp_panel = path_sbp_panel(frame) +frame.sizer.Add(frame.sbp_panel,(1,3)) +frame.png_path_panel = png_path_panel(frame) +frame.sizer.Add(frame.png_path_panel,(1,2)) +frame.stl_png_panel = stl_png_panel(frame) +frame.sizer.Add(frame.stl_png_panel,(1,1)) +frame.stl_panel = stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,0)) +# +# defaults +# +frame.set_stl_sbp() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_stl_snap b/src/guis/make_stl_snap new file mode 100755 index 0000000..aedccc6 --- /dev/null +++ b/src/guis/make_stl_snap @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# make_stl_snap +# .stl to MTM Snap GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_stl import stl_panel +from panel_stl_png import stl_png_panel +from panel_png_path import png_path_panel +from panel_path_snap import path_snap_panel +# +# command line +# +print "command line: make_stl_snap [input_file [size]]" +print " input_file = input .stl file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_stl_snap",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.snap_panel = path_snap_panel(frame) +frame.sizer.Add(frame.snap_panel,(1,3)) +frame.path_panel = png_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,2)) +frame.stl_png_panel = stl_png_panel(frame) +frame.sizer.Add(frame.stl_png_panel,(1,1)) +frame.stl_panel = stl_panel(frame) +frame.sizer.Add(frame.stl_panel,(1,0)) +# +# defaults +# +#frame.set_stl_snap() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_camm b/src/guis/make_svg_camm new file mode 100755 index 0000000..18d3e7f --- /dev/null +++ b/src/guis/make_svg_camm @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_camm +# .svg to .camm GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/13/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_camm import path_camm_panel +# +# command line +# +print "command line: make_svg_camm [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_camm",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.camm_panel = path_camm_panel(frame) +frame.sizer.Add(frame.camm_panel,(1,2)) +# +# defaults +# +frame.set_svg_camm() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_epi b/src/guis/make_svg_epi new file mode 100755 index 0000000..9227dcc --- /dev/null +++ b/src/guis/make_svg_epi @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_epi +# .svg to .epi GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_epi import path_epi_panel +# +# command line +# +print "command line: make_svg_epi [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_epi",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.epi_panel = path_epi_panel(frame) +frame.sizer.Add(frame.epi_panel,(1,2)) +# +# defaults +# +frame.set_svg_epi() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_g b/src/guis/make_svg_g new file mode 100755 index 0000000..7d5fb57 --- /dev/null +++ b/src/guis/make_svg_g @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_g +# .svg to .g GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_g import path_g_panel +# +# command line +# +print "command line: make_svg_g [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_g",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.svg_path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.svg_path_panel,(1,1)) +frame.g_panel = path_g_panel(frame) +frame.sizer.Add(frame.g_panel,(1,2)) +# +# defaults +# +frame.set_svg_g() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_oms b/src/guis/make_svg_oms new file mode 100755 index 0000000..42a3eae --- /dev/null +++ b/src/guis/make_svg_oms @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_oms +# .svg to .oms GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 5/25/13 +# +# (c) Massachusetts Institute of Technology 2013 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_oms import path_oms_panel +# +# command line +# +print "command line: make_svg_oms [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_oms",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.oms_panel = path_oms_panel(frame) +frame.sizer.Add(frame.oms_panel,(1,2)) +# +# defaults +# +frame.set_svg_oms() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_ord b/src/guis/make_svg_ord new file mode 100755 index 0000000..fcde224 --- /dev/null +++ b/src/guis/make_svg_ord @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_ord +# .svg to .ord GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_ord import path_ord_panel +# +# command line +# +print "command line: make_svg_ord [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_ord",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.ord_panel = path_ord_panel(frame) +frame.sizer.Add(frame.ord_panel,(1,2)) +# +# defaults +# +frame.set_svg_ord() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_rml b/src/guis/make_svg_rml new file mode 100755 index 0000000..f3e1d1c --- /dev/null +++ b/src/guis/make_svg_rml @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_rml +# .svg to .rml GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_rml import path_rml_panel +# +# command line +# +print "command line: make_svg_rml [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_rml",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.svg_path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.svg_path_panel,(1,1)) +frame.rml_panel = path_rml_panel(frame) +frame.sizer.Add(frame.rml_panel,(1,2)) +# +# defaults +# +frame.set_svg_rml() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_sbp b/src/guis/make_svg_sbp new file mode 100755 index 0000000..d70eaa4 --- /dev/null +++ b/src/guis/make_svg_sbp @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_sbp +# .svg to .sbp GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_sbp import path_sbp_panel +# +# command line +# +print "command line: make_svg_sbp [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_sbp",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.svg_path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.svg_path_panel,(1,1)) +frame.sbp_panel = path_sbp_panel(frame) +frame.sizer.Add(frame.sbp_panel,(1,2)) +# +# defaults +# +frame.set_svg_sbp() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_snap b/src/guis/make_svg_snap new file mode 100755 index 0000000..a3802dc --- /dev/null +++ b/src/guis/make_svg_snap @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_snap +# .svg to MTM Snap GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 11/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_snap import path_snap_panel +# +# command line +# +print "command line: make_svg_snap [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_snap",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.snap_panel = path_snap_panel(frame) +frame.sizer.Add(frame.snap_panel,(1,2)) +# +# defaults +# +#frame.set_svg_snap() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/make_svg_uni b/src/guis/make_svg_uni new file mode 100755 index 0000000..4dd6f3c --- /dev/null +++ b/src/guis/make_svg_uni @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# make_svg_uni +# .svg to .uni GUI wrapper +# +# Neil Gershenfeld +# CBA MIT 7/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,sys +from fab_set import fab_frame +from panel_control import control_panel +from panel_svg import svg_panel +from panel_svg_path import svg_path_panel +from panel_path_uni import path_uni_panel +# +# command line +# +print "command line: make_svg_uni [input_file [size]]" +print " input_file = input .svg file (optional)" +print " size = image panel size (optional)" +# +# start wx +# +app = wx.App() +# +# add panels to frame +# +frame = fab_frame("make_svg_camm",sys.argv) +frame.control_panel = control_panel(frame) +frame.sizer.Add(frame.control_panel,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) +frame.svg_panel = svg_panel(frame) +frame.sizer.Add(frame.svg_panel,(1,0)) +frame.path_panel = svg_path_panel(frame) +frame.sizer.Add(frame.path_panel,(1,1)) +frame.uni_panel = path_uni_panel(frame) +frame.sizer.Add(frame.uni_panel,(1,2)) +# +# defaults +# +frame.set_svg_uni() +# +# fit and show frame +# +frame.Fit() +frame.Show() +# +# start mainloop +# +app.MainLoop() diff --git a/src/guis/rml_send_gui b/src/guis/rml_send_gui new file mode 100755 index 0000000..52d8774 --- /dev/null +++ b/src/guis/rml_send_gui @@ -0,0 +1,524 @@ +#!/usr/bin/env python +# +# rml_send_gui +# graphical interface for sending jobs to the Roland Modela +# +# Brian Mayton +# MIT 2011-2014 +# +# (c) Massachusetts Institute of Technology 2011-2014 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. + +# imports +from __future__ import with_statement +import serial +import sys +import wx +import threading +import time +import math + +# global constants +RML_UNITS=40.0 +SPEED_TRAVERSE = 15.0 + +# utility functions +def dist(x1, y1, z1, x2, y2, z2): + return math.sqrt( + pow(x1-x2, 2.0) + + pow(y1-y2, 2.0) + + pow(z1-z2, 2.0) + ) + +class RMLSender: + """This class implements the parsing of RML files and sending to the + Modela.""" + + def __init__(self, port="/dev/ttyUSB0"): + self.serial = serial.Serial(port, baudrate=9600, rtscts=True, timeout=0) + self.cmds = [] + + self.xr=[0,1]; self.yr=[0,1]; self.zr=[0,1] + self.paths = [] + self.segments_done = [] + self.traverses = [] + self.traverses_done = [] + + self.speed_feed = 15.0 + self.speed_plunge = 5.0 + + self.total_distance = 1.0 + self.distance_milled = 0.0 + + self.total_time = 1.0 + self.time_remaining = 1.0 + self.time_start = None + + self.current_cmd = "" + self.cur_cmd_start = time.time() + self.cur_cmd_duration = 0.0 + + self.running = False + self.thread = threading.Thread(target=self.thread_fn) + self.should_stop = threading.Event() + self.done = threading.Event() + self.aborted = threading.Event() + self.lock = threading.Lock() + + def load_file(self, filename): + self.cmds = [] + f = open(filename, "r") + data = f.read() + f.close() + self.cmds = data.split(";") + self.calculate_metrics() + + def calculate_metrics(self): + paths = [] + traverses = [] + cur_path = [] + xmin, ymin, zmin = 99999999, 999999999, 999999999 + xmax, ymax, zmax = 0, 0, 0 + xpos, ypos, zpos = 0, 0, 0 + zup, zdown = 0, 0 + speeds, speedz = 0.0, 0.0 + total_distance = 0.0 + total_time = 0.0 + in_path = False + for cmd in self.cmds: + cmd=cmd.strip() + try: + if cmd[:3] == "!PZ": + params = cmd[3:].split(',') + if len(params) < 2: + params = cmd[3:].split(' ') + zup = int(params[1]) + zdown = int(params[0]) + print "pen: %d up, %d down" % (zup, zdown) + elif cmd[:2] == "VS": + params = cmd[2:].split(',') + if len(params) < 2: + params = cmd[2:].split(' ') + speeds = float(params[0]) + print "xy speed: %f mm/s" % (speeds) + elif cmd[:3] == "!VZ": + params = cmd[3:].split(',') + if len(params) < 2: + params = cmd[3:].split(' ') + speedz = float(params[0]) + print "z speed: %f mm/s" % (speedz) + elif cmd[:2] == "PU": + params = cmd[2:].split(',') + if len(params) < 2: + params = cmd[2:].split(' ') + if len(params) < 2: + continue + x = int(params[0]) + y = int(params[1]) + z = zup + d = dist(xpos, ypos, zpos, x, y, z) + total_distance += d + total_time += d / RML_UNITS / SPEED_TRAVERSE + traverses.append([(xpos, ypos, zpos), (x, y, z)]) + xpos = x; ypos = y; zpos = z; + xmax = max(x, xmax); ymax = max(y, ymax); zmax = max(z, zmax) + xmin = min(x, xmin); ymin = min(y, ymin); zmin = min(z, zmin) + if len(cur_path) > 0: + paths.append(cur_path) + cur_path = [] + elif cmd[:1] == "Z": + params = cmd[1:].split(',') + if len(params) < 2: + params = cmd[1:].split(' ') + x = int(params[0]) + y = int(params[1]) + z = int(params[2]) + dist_xy = math.hypot(xpos-x, ypos-y) / RML_UNITS + dist_z = float(zpos-z) / RML_UNITS + time_xy = dist_xy / speeds + time_z = dist_z / speedz + total_time += max(time_xy, time_z) + total_distance += dist(xpos, ypos, zpos, x, y, z) + + xpos = x; ypos = y; zpos = z; + xmax = max(x, xmax); ymax = max(y, ymax); zmax = max(z, zmax) + xmin = min(x, xmin); ymin = min(y, ymin); zmin = min(z, zmin) + cur_path.append((x, y, z)) + except: + print "ignoring: %s" % cmd + pass + self.paths = paths + self.traverses = traverses + self.speed_feed = speeds + self.speed_plunge = speedz + self.xr = (xmin, xmax) + self.yr = (ymin, ymax) + self.zr = (zmin, zmax) + self.total_distance = total_distance + if self.total_distance == 0: self.total_distance = 1.0 + self.total_time = total_time + if self.total_time == 0: self.total_time = 1.0 + self.time_remaining = total_time + + def start(self): + self.running = True + self.time_start = time.time() + self.thread.start() + + def abort(self): + if self.running and not self.done.isSet(): + self.should_stop.set() + + def thread_fn(self): + xmax, ymax, zmax = 0, 0, 0 + xpos, ypos, zpos = 0, 0, 0 + zup, zdown = 0, 0 + speeds, speedz = 0.0, 0.0 + with self.lock: + cmds = self.cmds + for cmd in cmds: + cmd = cmd.strip() + if self.should_stop.isSet(): + cmd="PA;PA;!VZ10;!PZ0,100;PU0,0;PD0,0;!MC0;" + self.serial.write(cmd) + self.serial.close() + self.aborted.set() + return + cmd=cmd.strip() + with self.lock: + self.current_cmd = cmd + self.cur_cmd_start = time.time() + self.cur_cmd_duration = 0.0 + while (self.serial.getDSR() != True): + time.sleep(0.001) + self.serial.write(cmd) + try: + if cmd[:3] == "!PZ": + params = cmd[3:].split(',') + if len(params) < 2: + params = cmd[3:].split(' ') + zup = int(params[1]) + zdown = int(params[0]) + elif cmd[:2] == "VS": + params = cmd[2:].split(',') + if len(params) < 2: + params = cmd[2:].split(' ') + speeds = float(params[0]) + with self.lock: + self.speed_feed = speeds + elif cmd[:3] == "!VZ": + params = cmd[3:].split(',') + if len(params) < 2: + params = cmd[3:].split(' ') + speedz = float(params[0]) + with self.lock: + self.speed_plunge = speedz + elif cmd[:2] == "PU": + params = cmd[2:].split(',') + if len(params) < 2: + params = cmd[2:].split(' ') + if len(params) < 2: + continue + x = int(params[0]) + y = int(params[1]) + z = zup + d = dist(xpos, ypos, zpos, x, y, z) + t = d / RML_UNITS / SPEED_TRAVERSE + with self.lock: + self.cur_cmd_duration = t + self.time_remaining -= t + self.distance_milled += d + self.traverses_done.append(((xpos, ypos, zpos), (x, y, z))) + xpos = x; ypos = y; zpos = z; + elif cmd[:1] == "Z": + params = cmd[1:].split(',') + if len(params) < 2: + params = cmd[1:].split(' ') + x = int(params[0]) + y = int(params[1]) + z = int(params[2]) + dist_xy = math.hypot(xpos-x, ypos-y) / RML_UNITS + dist_z = float(zpos-z) / RML_UNITS + time_xy = dist_xy / speeds + time_z = dist_z / speedz + t = max(time_xy, time_z) + with self.lock: + self.cur_cmd_duration = t + self.time_remaining -= t + self.distance_milled += dist(xpos, ypos, zpos, x, y, z) + self.segments_done.append(((xpos, ypos, zpos), (x, y, z))) + xpos = x; ypos = y; zpos = z; + time.sleep(self.cur_cmd_duration) + except: + print "ignoring: %s" % cmd + self.done.set() + + +class RMLSenderGUI(RMLSender): + """This class implements the GUI.""" + + def __init__(self, port="/dev/ttyUSB0"): + RMLSender.__init__(self, port) + self.lines_path = [] + self.lines_traverse = [] + self.lines_seg_done = [] + self.lines_traverse_done = [] + self.n_segs_done = 0 + self.n_traverse_done = 0 + self.distance = 0.0 + self.frame = wx.Frame(None, -1, "Modela Output", size=(640,480)) + top_vbox = wx.BoxSizer(wx.VERTICAL) + + self.frame.SetSizer(top_vbox) + + upper_panel = wx.Panel(self.frame) + upper_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) + upper_panel.SetSizer(upper_panel_sizer) + + self.panel = wx.Panel(upper_panel) + self.gui_xsize, self.gui_ysize = self.panel.GetSize() + self.gui_xoff, self.gui_yoff = 0, 0 + self.gui_scale = 0.5 + self.panel.Bind(wx.EVT_PAINT, self.on_paint) + self.panel.Bind(wx.EVT_SIZE, self.on_size) + upper_panel_sizer.Add(self.panel, 1, wx.EXPAND | wx.ALL, border=4) + + right_panel = wx.Panel(upper_panel, size=(200, 0)) + #right_panel.SetBackgroundColour('gray') + right_panel_sizer = wx.BoxSizer(wx.VERTICAL) + right_panel.SetSizer(right_panel_sizer) + upper_panel_sizer.Add(right_panel, 0, wx.EXPAND) + + origin_label = wx.StaticText(right_panel, label="Origin:") + right_panel_sizer.Add(origin_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.TOP, border=4) + bf = origin_label.GetFont() + bf.SetWeight(wx.BOLD) + origin_label.SetFont(bf) + + self.origin_label_x = wx.StaticText(right_panel, label="x: ") + self.origin_label_y = wx.StaticText(right_panel, label="y: ") + right_panel_sizer.Add(self.origin_label_x, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT, border=4) + right_panel_sizer.Add(self.origin_label_y, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM, border=4) + + size_label = wx.StaticText(right_panel, label="Size:") + size_label.SetFont(bf) + right_panel_sizer.Add(size_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.TOP, border=4) + self.size_label_x = wx.StaticText(right_panel, label="x: ") + self.size_label_y = wx.StaticText(right_panel, label="y: ") + right_panel_sizer.Add(self.size_label_x, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT, border=4) + right_panel_sizer.Add(self.size_label_y, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM, border=4) + + size_label = wx.StaticText(right_panel, label="Speeds:") + size_label.SetFont(bf) + right_panel_sizer.Add(size_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.TOP, border=4) + self.plunge_label = wx.StaticText(right_panel, label="plunge: ") + self.feed_label = wx.StaticText(right_panel, label="feed: ") + right_panel_sizer.Add(self.plunge_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT, border=4) + right_panel_sizer.Add(self.feed_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM, border=4) + + size_label = wx.StaticText(right_panel, label="Time:") + size_label.SetFont(bf) + right_panel_sizer.Add(size_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.TOP, border=4) + self.elapsed_label = wx.StaticText(right_panel, label="elapsed: ") + self.remaining_label = wx.StaticText(right_panel, label="remaining: ") + right_panel_sizer.Add(self.elapsed_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT, border=4) + right_panel_sizer.Add(self.remaining_label, 0, + wx.EXPAND | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM, border=4) + + filler_panel = wx.Panel(right_panel) + right_panel_sizer.Add(filler_panel, 1, wx.EXPAND) + + self.start_button = wx.Button(right_panel, label="Begin Milling") + right_panel_sizer.Add(self.start_button, 0, wx.EXPAND | wx.ALL, border=4) + self.start_button.Bind(wx.EVT_BUTTON, self.on_startstop) + + top_vbox.Add(upper_panel, 1, wx.EXPAND) + + self.gauge = wx.Gauge(self.frame, range=100, size=(0,32)) + + top_vbox.Add(self.gauge, 0, wx.EXPAND) + + self.status_label = wx.StaticText(self.frame, label="Ready.") + top_vbox.Add(self.status_label, 0, wx.EXPAND) + + self.frame.Bind(wx.EVT_CLOSE, self.on_close) + + self.frame.Show() + + def on_close(self, event): + self.abort() + sys.exit(0) + + def transform_point(self, point): + xsize, ysize = self.gui_xsize, self.gui_ysize + xoff, yoff = self.gui_xoff, self.gui_yoff + scale = self.gui_scale + x, y, z = point + x = (x - self.xr[0]) * scale + xoff + y = ysize - (y - self.yr[0]) * scale + yoff + return (x, y, z) + + def update(self): + self.lines_path = [] + self.lines_traverse = [] + self.lines_seg_done = [] + self.lines_traverse_done = [] + self.gui_xsize, self.gui_ysize = self.panel.GetSize() + path_xsize = self.xr[1] - self.xr[0] + path_ysize = self.yr[1] - self.yr[0] + scalex = float(self.gui_xsize) / path_xsize + scaley = float(self.gui_ysize) / path_ysize + if scalex < scaley: + self.gui_scale = scalex + self.gui_yoff = -1* (self.gui_ysize - (path_ysize * scalex)) / 2 + self.gui_xoff = 0 + else: + self.gui_scale = scaley + self.gui_xoff = (self.gui_xsize - (path_xsize * scaley)) / 2 + self.gui_yoff = 0 + + self.origin_label_x.SetLabel("x: %02.01f mm" % (self.xr[0] / RML_UNITS)) + self.origin_label_y.SetLabel("y: %02.01f mm" % (self.yr[0] / RML_UNITS)) + self.size_label_x.SetLabel("x: %02.01f mm" % (path_xsize / RML_UNITS)) + self.size_label_y.SetLabel("y: %02.01f mm" % (path_ysize / RML_UNITS)) + self.plunge_label.SetLabel("plunge: %01.01f mm/s" % (self.speed_plunge)) + self.feed_label.SetLabel("feed: %01.01f mm/s" % (self.speed_feed)) + self.remaining_label.SetLabel("remaining: %02d:%02d s" % (int(self.time_remaining)/60, + int(self.time_remaining) % 60)) + + for path in self.paths: + for i in xrange(len(path)-1): + p1 = self.transform_point(path[i]) + p2 = self.transform_point(path[i+1]) + line = (p1[0], p1[1], p2[0], p2[1]) + self.lines_path.append(line) + for tr in self.traverses: + p1 = self.transform_point(tr[0]) + p2 = self.transform_point(tr[1]) + line = (p1[0], p1[1], p2[0], p2[1]) + self.lines_traverse.append(line) + for seg in self.segments_done: + p1 = self.transform_point(seg[0]) + p2 = self.transform_point(seg[1]) + line = (p1[0], p1[1], p2[0], p2[1]) + self.lines_seg_done.append(line) + for tr in self.traverses_done: + p1 = self.transform_point(tr[0]) + p2 = self.transform_point(tr[1]) + line = (p1[0], p1[1], p2[0], p2[1]) + self.lines_traverse_done.append(line) + self.panel.Refresh() + + def on_paint(self, event): + dc = wx.PaintDC(self.panel) + dc.Clear() + dc.SetPen(wx.Pen('gray', 1)) + dc.DrawLineList(self.lines_traverse) + dc.SetPen(wx.Pen('blue', 1)) + dc.DrawLineList(self.lines_path) + dc.SetPen(wx.Pen('gray', 2)) + dc.DrawLineList(self.lines_traverse_done) + dc.SetPen(wx.Pen('red', 2)) + dc.DrawLineList(self.lines_seg_done) + + def new_segs_check(self, event): + dc = wx.ClientDC(self.panel) + with self.lock: + dc.SetPen(wx.Pen('red', 2)) + for i in xrange(self.n_segs_done, len(self.segments_done)): + seg = self.segments_done[i] + p1 = self.transform_point(seg[0]) + p2 = self.transform_point(seg[1]) + dc.DrawLine(p1[0], p1[1], p2[0], p2[1]) + self.lines_seg_done.append((p1[0], p1[1], p2[0], p2[1])) + self.n_segs_done = len(self.segments_done) + dc.SetPen(wx.Pen('gray', 2)) + for i in xrange(self.n_traverse_done, len(self.traverses_done)): + seg = self.traverses_done[i] + p1 = self.transform_point(seg[0]) + p2 = self.transform_point(seg[1]) + dc.DrawLine(p1[0], p1[1], p2[0], p2[1]) + self.lines_traverse_done.append((p1[0], p1[1], p2[0], p2[1])) + self.n_traverse_done = len(self.traverses_done) + + perc_done = int(round(100.0 * (self.distance_milled / self.total_distance))) + self.gauge.SetValue(perc_done) + self.plunge_label.SetLabel("plunge: %01.01f mm/s" % (self.speed_plunge)) + self.feed_label.SetLabel("feed: %01.01f mm/s" % (self.speed_feed)) + elapsed = time.time() - self.time_start + self.elapsed_label.SetLabel("elapsed: %02d:%02d s" % + (int(elapsed)/60, int(elapsed) % 60)) + self.remaining_label.SetLabel("remaining: %02d:%02d s" % + (int(self.time_remaining)/60, int(self.time_remaining) % 60)) + cmd_elapsed = time.time() - self.cur_cmd_start + cmd_rem = self.cur_cmd_duration - cmd_elapsed + self.status_label.SetLabel("Executing: %s (%d:%02d)" % (self.current_cmd, + cmd_rem / 60, cmd_rem % 60)) + if self.done.isSet(): + self.timer.Stop() + self.start_button.SetLabel("Exit") + self.status_label.SetLabel("Finished.") + elif self.should_stop.isSet(): + self.status_label.SetLabel("Aborting; wait for Modela to stop or switch to view mode and hold up/down buttons to clear buffer") + if self.aborted.isSet(): + sys.exit(0) + + + + def on_size(self, event): + self.update() + + def on_startstop(self, event): + if not self.running: + self.start_button.SetLabel("Abort") + self.start() + self.timer = wx.Timer(self.frame) + self.frame.Bind(wx.EVT_TIMER, self.new_segs_check, self.timer) + self.timer.Start(100) + elif self.done.isSet(): + sys.exit(0) + else: + self.abort() + + def load_file(self, filename): + RMLSender.load_file(self,filename) + self.update() + +if __name__ == '__main__': + if len(sys.argv) < 2: + print "usage: %s file.rml [/dev/ttyUSB0]" % sys.argv[0] + sys.exit(1) + + filename = sys.argv[1] + port = "/dev/ttyUSB0" + if len(sys.argv) > 2: + port = sys.argv[2] + + app = wx.PySimpleApp() + + f = open(filename) + data = f.read() + f.close() + + if len(data) < 150: + sender = RMLSender(port) + sender.load_file(filename) + sender.start() + sender.thread.join() + else: + sender = RMLSenderGUI(port) + sender.load_file(filename) + app.MainLoop() + diff --git a/src/py/CMakeLists.txt b/src/py/CMakeLists.txt new file mode 100644 index 0000000..0d57871 --- /dev/null +++ b/src/py/CMakeLists.txt @@ -0,0 +1,21 @@ +#cmake_minimum_required(VERSION 2.6) + +set(PYs fab_mods.py fab_set.py panel_control.py + cad_shapes.py cad_text.py math_string.py + panel_cad.py panel_cad_png.py panel_cad_stl.py + panel_math.py panel_math_png.py panel_math_stl.py + panel_png.py panel_png_png.py panel_png_path.py + panel_png_path_halftone.py panel_png_grb.py + panel_png_drl.py panel_path.py + panel_path_rml.py panel_path_plt.py panel_path_oms.py + panel_path_sbp.py panel_path_ord.py panel_path_camm.py + panel_path_epi.py panel_path_uni.py panel_path_g.py + panel_path_eps.py panel_path_snap.py panel_path_dxf.py + panel_stl.py panel_stl_png.py + panel_svg.py panel_svg_path.py + panel_gif.py panel_gif_stl.py + CACHE STRING "Python script list") + +if( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + install(FILES ${PYs} DESTINATION ${PROJECT_SOURCE_DIR}/../bin) +endif( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) diff --git a/src/py/cad_shapes.py b/src/py/cad_shapes.py new file mode 100644 index 0000000..f47882b --- /dev/null +++ b/src/py/cad_shapes.py @@ -0,0 +1,497 @@ +# cad_shapes.py +# Standard library of shapes and operations + +# Assembled by Matt Keeter (with code from Neil Gershenfeld) +# matt.keeter@cba.mit.edu + +# kokompe.cba.mit.edu + +############################################################################### + +# 2D shapes: +# circle(x0, y0, r) +# rectangle(x0, x1, y0, y1) +# right_triangle(x0, y0, l) +# triangle(x0, y0, x1, y1, x2, y2) [clockwise order] +# polygon(x, y, r, n) +# tab(x, y, width, height, angle = 0, chamfer = 0.2) + +# 3D shapes: +# extrusion(part, z0, z1) +# cylinder(x0, y0, z0, z1, r) +# sphere(x0, y0, z0, r) +# cube(x0, x1, y0, y1, z0, z1) +# cone(x0, y0, z0, z1, r0) +# pyramid(x0, x1, y0, y1, z0, z1) + +# Logic operations: +# add(part1, part2) +# subtract(part1, part2) +# intersect(part1, part2) +# invert(part) + +# Translation: +# move(part, dx, dy, dz = 0) + +# Rotation: +# rotate(part, angle) +# rotate_90(part) +# rotate_180(part) +# rotate_270(part) +# rotate_x(part, angle) +# rotate_y(part, angle) +# rotate_z(part, angle) + +# Reflection: +# reflect_x(part,x0 = 0) +# reflect_y(part,y0 = 0) +# reflect_z(part,z0 = 0) +# reflect_xy(part) +# reflect_xz(part) +# reflect_yz(part) + +# Scaling: +# scale_x(part, x0, sx) +# scale_y(part, y0, sy) +# scale_z(part, z0, sz) +# scale_xy(part, x0, y0, sxy) +# scale_xyz(part, x0, y0, z0, sxyz) + +# Distortion: +# attract(part, value, x0, y0, z0=0) + +# Coscaling: +# coscale_x_y(part, x0, y0, y1, angle0, angle1, amplitude, offset) +# coscale_x_z(part, x0, z0, z1, angle0, angle1, amplitude, offset) +# coscale_xy_z(part, x0, y0, z0, z1, angle0, angle1, amplitude, offset) + +# Tapering: +# taper_x_y(part, x0, y0, y1, s0, s1) +# taper_x_z(part, x0, z0, z1, s0, s1) +# taper_xy_z(part, x0, y0, z0, z1, s0, s1) + +# Shearing: +# shear_x_y(part, y0, y1, dx0, dx1) +# shear_x_z(part, z0, z1, dx0, dx1) +# coshear_x_z(part, z0, z1, angle0, angle1, amplitude, offset) + +# Color: +# color(color,part) +# +# Colors are implemented as an integer bit-field: +# R = bits 0 through 7 +# G = bits 8 through 15 +# B = bits 16 through 23 +# +# The following colors are pre-defined: +# red, green, blue, gray, white, teal, pink, +# yellow, brown, navy, black + +############################################################################### +from math_string import MString + +from math import pi, sin, cos +import re + +############################################################################### +# 2D Shapes +############################################################################### +def circle(x0, y0, r): + return move(MString("(pow(X,2) + pow(Y,2) <= %f)" % (r*r)), x0, y0) + +def rectangle(x0, x1, y0, y1): + return MString("((X >= %f) && (X <= %f) && " % (x0, x1) + + "(Y >= %f) && (Y <= %f))" % (y0, y1)) + +def right_triangle(x, y, L): + tri = MString("(X < -Y) && (X > -{0}) && (Y > -{0})".format(L)) + return move(tri, x + L, y + L) + +def triangle(x0, y0, x1, y1, x2, y2): # points in clockwise order + tri = ("((((({y1})-({y0}))*(X-({x0}))-(({x1})-({x0}))*(Y-({y0}))) >= 0) && " + \ + "(((({y2})-({y1}))*(X-({x1}))-(({x2})-({x1}))*(Y-({y1}))) >= 0) && " + \ + "(((({y0})-({y2}))*(X-({x2}))-(({x0})-({x2}))*(Y-({y2}))) >= 0))").format( + x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2) + return MString(tri) + +def polygon(x, y, r, n): + if n <= 2: + return '0' + part = circle(0, 0, r) + cutoff = 'Y > -%f' % (cos(pi/n) * r) + for i in range(n): + part = intersect(part, rotate(cutoff, i*360./n)) + return move(MString(part), x, y) + + +def tab(x, y, width, height, angle = 0, chamfer = 0.2): + tab = rectangle(-width/2, width/2, 0, height) + cutout = triangle(width/2 - chamfer*height, height, + width/2, height, + width/2, height - chamfer*height) + cutout = add(cutout, reflect_x(cutout)) + tab = subtract(tab, cutout) + + tab = rotate(tab, angle) + tab = move(tab, x, y) + return MString(tab) + +def slot(x, y, width, height, angle = 0, chamfer = 0.2): + slot = rectangle(-width/2, width/2, -height, 0) + inset = triangle(width/2, 0, + width/2 + height * chamfer, 0, + width/2, -chamfer*height) + inset = add(inset, reflect_x(inset)) + slot = add(slot, inset) + + slot = rotate(slot, angle) + slot = move(slot, x, y) + return MString(slot) + +############################################################################### +# 3D Shapes +############################################################################### +def extrusion(part, z0, z1): + return MString("((%s) && (Z >= %f) && (Z <= %f))" % (part, z0, z1)) + +def cylinder(x0, y0, z0, z1, r): + return extrusion(circle(x0, y0, r), z0, z1) + +def sphere(x0, y0, z0, r): + return move("(pow(X,2) + pow(Y,2) + pow(Z,2) <= %f)" % (r * r), x0, y0, z0) + +def cube(x0, x1, y0, y1, z0, z1): + return MString("((X >= %f) && (X <= %f) && " % (x0, x1) + + " (Y >= %f) && (Y <= %f) && " % (y0, y1) +\ + " (Z >= %f) && (Z <= %f))" % (z0, z1)) + +def cone(x0, y0, z0, z1, r0): + cyl = cylinder(x0, y0, z0, z1, r0) + return taper_xy_z(cyl, x0, y0, z0, z1, 1.0, 0.0) + +def pyramid(x0, x1, y0, y1, z0, z1): + c = cube(x0, x1, y0, y1, z0, z1) + return taper_xy_z(c, (x0+x1)/2., (y0+y1)/2., z0, z1, 1.0, 0.0) + +############################################################################### +# Logic Operations +############################################################################### +def add(part1, part2): + return MString("(%s) || (%s)" % (part1, part2)) + +def subtract(part1, part2): + return MString("(%s) && !(%s)" % (part1, part2)) + +def intersect(part1, part2): + return MString("(%s) && (%s)" % (part1, part2)) + +def invert(part): + return MString("!(%s)" % part) + +############################################################################### +# Translation +############################################################################### +def move(part,dx,dy,dz = 0): + if dx: + part = part.replace('X','(X-%f)' % dx) + if dy: + part = part.replace('Y','(Y-%f)' % dy) + if dz: + part = part.replace('Z','(Z-%f)' % dz) + return part + +############################################################################### +# Rotation +############################################################################### +def rotate(part, angle): + if angle == 90: + return rotate_90(part) + elif angle == 180: + return rotate_180(part) + elif angle == 270: + return rotate_270(part) + elif angle == 0: + return part + + angle = str(angle*pi/180) + + # find all already-rotated points and increment that + # rotation instead of stacking more and more trig + # functions + xrot_regex = re.compile(r'\( cos\(([\-\d.]+)\)\*X\+sin\(\1\)\*Y\)') + yrot_regex = re.compile(r'\(-sin\(([\-\d.]+)\)\*X\+cos\(\1\)\*Y\)') + + def update_angle_x(match, angle): + match = match.groups() + angle = str(float(angle) + float(match[0])) + return '(cos({0})*x+sin({0})*y)'.format(angle) + + def update_angle_y(match, angle): + match = match.groups() + angle = str(float(angle) + float(match[0])) + return '(-sin({0})*x+cos({0})*y)'.format(angle) + + part = xrot_regex.sub(lambda x: update_angle_x(x, angle), str(part)) + part = yrot_regex.sub(lambda x: update_angle_y(x, angle), str(part)) + + # replace all bare X, Y as before + # move all upper to lower case + part = part.replace('X','(cos({0})*X+sin({0})*y)'.format(angle)) + part = part.replace('Y','(-sin({0})*X+cos({0})*y)'.format(angle)) + part = part.replace('y','Y') + part = part.replace('x','X') + + return MString(part) + +def rotate_90(part): + part = reflect_y(part) + part = reflect_xy(part) + return part + +def rotate_180(part): + part = rotate_90(part) + part = rotate_90(part) + return part + +def rotate_270(part): + part = rotate_90(part) + part = rotate_90(part) + part = rotate_90(part) + return part + +def rotate_x(part, angle): + angle = angle*pi/180 + part = part.replace('Y','(cos(angle)*Y+sin(angle)*z)') + part = part.replace('Z','(-sin(angle)*Y+cos(angle)*z)') + part = part.replace('z','Z') + part = part.replace('angle',str(angle)) + return part + +def rotate_y(part, angle): + angle = angle*pi/180 + part = part.replace('X','(cos(angle)*X+sin(angle)*z)') + part = part.replace('Z','(-sin(angle)*X+cos(angle)*z)') + part = part.replace('z','Z') + part = part.replace('angle',str(angle)) + return part + +def rotate_z(part, angle): + return rotate(part, angle) +############################################################################### +# Reflection +############################################################################### +def reflect_x(part, x0 = 0): + return part.replace('X','(%f-X)' % x0) + +def reflect_y(part, y0 = 0): + return part.replace('Y','(%f-Y)' % y0) + +def reflect_z(part,z0): + return part.replace('Z','(%f-Z)' % z0) + return part + +def reflect_xy(part): + part = part.replace('X','temp') + part = part.replace('Y','X') + part = part.replace('temp','Y') + return part + +def reflect_xz(part): + part = part.replace('X','temp') + part = part.replace('Z','X') + part = part.replace('temp','Z') + return part + +def reflect_yz(part): + part = part.replace('Y','temp') + part = part.replace('Z','Y') + part = part.replace('temp','Z') + return part +############################################################################### +# Scaling +############################################################################### +def scale_x(part, x0, sx): + part = part.replace('X','((x0) + (X-(x0))/(sx))') + part = part.replace('x0',str(x0)) + part = part.replace('sx',str(sx)) + return part + +def scale_y(part, y0, sy): + part = part.replace('Y','((y0) + (Y-(y0))/(sy))') + part = part.replace('y0',str(y0)) + part = part.replace('sy',str(sy)) + return part + +def scale_z(part, z0, sz): + part = part.replace('Z','((z0) + (Z-(z0))/(sz))') + part = part.replace('z0',str(z0)) + part = part.replace('sz',str(sz)) + return part + +def scale_xy(part, x0, y0, sxy): + part = part.replace('X','((x0) + (X-(x0))/(sxy))') + part = part.replace('Y','((y0) + (Y-(y0))/(sxy))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('sxy',str(sxy)) + return part + +def scale_xyz(part, x0, y0, z0, sxyz): + part = part.replace('X','((x0) + (X-(x0))/(sxyz))') + part = part.replace('Y','((y0) + (Y-(y0))/(sxyz))') + part = part.replace('Z','((z0) + (Z-(z0))/(sxyz))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('z0',str(z0)) + part = part.replace('sxyz',str(sxyz)) + return part + +############################################################################### +# Distortion: +############################################################################### + +def attract(part, radius, x0, y0, z0=0): + part = part.replace('X', + ('({x0}+(X-{x0})*(1+{r}*exp(-pow(X-{x0},2)+'+ + 'pow(yt-{y0},2)+pow(zt-{z0},2)/{r})))').format( + x0=x0,y0=y0,z0=z0,r=radius)) + part = part.replace('Y', + ('({y0}+(Y-{y0})*(1+{r}*exp(-pow(xt-{x0},2)+'+ + 'pow(Y-{y0},2)+pow(zt-{z0},2)/{r})))').format( + x0=x0,y0=y0,z0=z0,r=radius)) + part = part.replace('Z', + ('({z0}+(Z-{z0})*(1+{r}*exp(-pow(xt-{x0},2)+'+ + 'pow(yt-{y0},2)+pow(Z-{z0},2)/{r})))').format( + x0=x0,y0=y0,z0=z0,r=radius)) + part = part.replace('xt','X') + part = part.replace('yt','Y') + part = part.replace('zt','Z') + return part + +############################################################################### +# Coscaling +############################################################################### + +def coscale_x_y(part, x0, y0, y1, angle0, angle1, amplitude, offset): + phase0 = pi*angle0/180. + phase1 = pi*angle1/180. + part = part.replace('X','((x0) + (X-(x0))/((offset) + (amplitude)*cos((phase0) + ((phase1)-(phase0))*(Y-(y0))/((y1)-(y0)))))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('y1',str(y1)) + part = part.replace('phase0',str(phase0)) + part = part.replace('phase1',str(phase1)) + part = part.replace('amplitude',str(amplitude)) + part = part.replace('offset',str(offset)) + return part + +def coscale_x_z(part, x0, z0, z1, angle0, angle1, amplitude, offset): + phase0 = pi*angle0/180. + phase1 = pi*angle1/180. + part = part.replace('X','((x0) + (X-(x0))/((offset) + (amplitude)*cos((phase0) + ((phase1)-(phase0))*(Z-(z0))/((z1)-(z0)))))') + part = part.replace('x0',str(x0)) + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('phase0',str(phase0)) + part = part.replace('phase1',str(phase1)) + part = part.replace('amplitude',str(amplitude)) + part = part.replace('offset',str(offset)) + return part + +def coscale_xy_z(part, x0, y0, z0, z1, angle0, angle1, amplitude, offset): + phase0 = pi*angle0/180. + phase1 = pi*angle1/180. + part = part.replace('X','((x0) + (X-(x0))/((offset) + (amplitude)*cos((phase0) + ((phase1)-(phase0))*(Z-(z0))/((z1)-(z0)))))') + part = part.replace('Y','((y0) + (Y-(y0))/((offset) + (amplitude)*cos((phase0) + ((phase1)-(phase0))*(Z-(z0))/((z1)-(z0)))))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('phase0',str(phase0)) + part = part.replace('phase1',str(phase1)) + part = part.replace('amplitude',str(amplitude)) + part = part.replace('offset',str(offset)) + return part + +############################################################################### +# Tapering +############################################################################### +def taper_x_y(part, x0, y0, y1, s0, s1): + part = part.replace('X','((x0) + (X-(x0))*((y1)-(y0))/((s1)*(Y-(y0)) + (s0)*((y1)-Y)))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('y1',str(y1)) + part = part.replace('s0',str(s0)) + part = part.replace('s1',str(s1)) + return part + +def taper_x_z(part, x0, z0, z1, s0, s1): + part = part.replace('X','((x0) + (X-(x0))*((z1)-(z0))/((s1)*(Z-(z0)) + (s0)*((z1)-Z)))') + part = part.replace('x0',str(x0)) + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('s0',str(s0)) + part = part.replace('s1',str(s1)) + return part + +def taper_xy_z(part, x0, y0, z0, z1, s0, s1): + part = part.replace('X','((x0) + (X-(x0))*((z1)-(z0))/((s1)*(Z-(z0)) + (s0)*((z1)-Z)))') + part = part.replace('Y','((y0) + (Y-(y0))*((z1)-(z0))/((s1)*(Z-(z0)) + (s0)*((z1)-Z)))') + part = part.replace('x0',str(x0)) + part = part.replace('y0',str(y0)) + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('s0',str(s0)) + part = part.replace('s1',str(s1)) + return part + +############################################################################### +# Shearing +############################################################################### +def shear_x_y(part, y0, y1, dx0, dx1): + part = part.replace('X','(X - (dx0) - ((dx1)-(dx0))*(Y-(y0))/((y1)-(y0)))') + part = part.replace('y0',str(y0)) + part = part.replace('y1',str(y1)) + part = part.replace('dx0',str(dx0)) + part = part.replace('dx1',str(dx1)) + return part + +def shear_x_z(part, z0, z1, dx0, dx1): + part = part.replace('X','(X - (dx0) - ((dx1)-(dx0))*(Z-(z0))/((z1)-(z0)))') + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('dx0',str(dx0)) + part = part.replace('dx1',str(dx1)) + return part + +def coshear_x_z(part, z0, z1, angle0, angle1, amplitude, offset): + phase0 = pi*angle0/180. + phase1 = pi*angle1/180. + part = part.replace('X','(X - (offset) - (amplitude)*cos((phase0) + ((phase1)-(phase0))*(Z-(z0))/((z1)-(z0))))') + part = part.replace('z0',str(z0)) + part = part.replace('z1',str(z1)) + part = part.replace('phase0',str(phase0)) + part = part.replace('phase1',str(phase1)) + part = part.replace('amplitude',str(amplitude)) + part = part.replace('offset',str(offset)) + return part + + +############################################################################### +# Color +############################################################################### +red = (225 << 0) +green = (225 << 8) +blue = (225 << 16) +gray = (128 << 16) + (128 << 8) + (128 << 0) +white = (255 << 16) + (255 << 8) + (255 << 0) +teal = (255 << 16) + (255 << 8) +pink = (255 << 16) + (255 << 0) +yellow = (255 << 8) + (255 << 0) +brown = (45 << 16) + (82 << 8) + (145 << 0) +navy = (128 << 16) + (0 << 8) + (0 << 0) +tan = (60 << 16) + (90 << 8) + (125 << 0) +black = 0 + +def color(color, part): + return MString('(%s * (%s))' % (color, part)) \ No newline at end of file diff --git a/src/py/cad_text.py b/src/py/cad_text.py new file mode 100644 index 0000000..703c7d4 --- /dev/null +++ b/src/py/cad_text.py @@ -0,0 +1,541 @@ +# cad_text.py +# Tools to generate text in the cad format. + +# Assembled by Matt Keeter (with code from Neil Gershenfeld) +# matt.keeter@cba.mit.edu + +# kokompe.cba.mit.edu + +############################################################################### + +# Usage: +# text(text, x, y, height = None, align = 'CC'): +# text is the desired string +# x, y are the position +# height is the glyph height. Defaults to the current font height. +# align sets horizontal (C/L/R) and vertical (C/T/B) alignment + +# set_font(height) +# Pre-renders a set of font glyphs for a given glyph height. + +# When text() is called, it uses the precalculated glyph set if the height is +# correct; otherwise, it renders glyphs of the appropriate height. +# +# Prerendering glyphs of the appropriate size with set_font() can save time +# that would be spent regenerating the font with every call to text(). + +############################################################################### + +from cad_shapes import * + +def make_glyphs(height = 1.0, width = None, line = None): + if not width: + width = 2*height/3 + if not line: + line = height / 6 + + glyphs = {} + + shape = triangle(0, 0, width/2, height, width, 0) + shape = subtract(shape, triangle(line, 0, width/2, height - line*2, width - line, 0)) + shape = add(shape, rectangle(line, width - line, height/4 - line/2, height/4 + line/2)) + glyphs['A'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = add(shape,rectangle(width-line,width,0,height/3)) + glyphs['a'] = shape + + shape = rectangle(0, 2*line, 0, height/2 + line/2) + shape = add(shape, circle(2*line, height/4 + line/4, height/4 + line/4)) + shape = subtract(shape, circle(2*line, height/4 + line/4, height/4 - 3*line/4)) + shape = subtract(shape, rectangle(line, 2*line, line, height/2 - line/2)) + shape = add(shape, move(shape,0, height/2 - line/2)) + glyphs['B'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = add(shape,rectangle(0,line,0,height)) + glyphs['b'] = shape + + shape = circle(width/2,width/2,width/2) + shape = add(shape,circle(width/2,height-width/2,width/2)) + shape = add(shape,rectangle(0,width,width/2, height-width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = subtract(shape,circle(width/2,height -width/2,width/2 - line)) + shape = subtract(shape,rectangle(line,width,width/2, height-width/2)) + glyphs['C'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = subtract(shape,rectangle(width/2,width,width/2-1/(2*line),width/2+1/(2*line))) + glyphs['c'] = shape + + shape = circle(line,height/2,height/2) + shape = subtract(shape,circle(line,height/2,height/2 - line)) + shape = subtract(shape,rectangle(line-height/2,line,0,height)) + shape = add(shape,rectangle(0,line,0,height)) + glyphs['D'] = shape + + shape = rectangle(width-line,width,0,height) + shape = add(shape,circle(width/2,width/2,width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + glyphs['d'] = shape + + shape = rectangle(0,line,0,height) + shape = add(shape,rectangle(0,width,height-line,height)) + shape = add(shape,rectangle(0,2*width/3,height/2-line/2,height/2+line/2)) + shape = add(shape,rectangle(0,width,0,line)) + glyphs['E'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,triangle(width,0,width/2,width/2-line/2,width,width/2-line/2)) + shape = add(shape,rectangle(line/2,width-line/2,width/2-line/2,width/2+line/2)) + glyphs['e'] = shape + + shape = rectangle(0,line,0,height) + shape = add(shape,rectangle(0,width,height-line,height)) + shape = add(shape,rectangle(0,2*width/3,height/2-line/2,height/2+line/2)) + glyphs['F'] = shape + + shape = circle(width-line/2,height-width/2,width/2) + shape = subtract(shape,circle(width-line/2,height-width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width-line/2,0,height-width/2)) + shape = subtract(shape,rectangle(width-line/2,2*width,0,height)) + shape = add(shape,rectangle(width/2-line/2,width/2+line/2,0,height-width/2)) + shape = add(shape,rectangle(width/5,4*width/5,height/2-line/2,height/2+line/2)) + glyphs['f'] = shape + + shape = circle(width/2,width/2,width/2) + shape = add(shape,circle(width/2,height-width/2,width/2)) + shape = add(shape,rectangle(0,width,width/2, height-width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = subtract(shape,circle(width/2,height -width/2,width/2 - line)) + shape = subtract(shape,rectangle(line,width,width/2, height-width/2)) + shape = add(shape, rectangle(width/2, width, width/2, width/2 + line)) + glyphs['G'] = shape + + shape = circle(width/2, 0, width/2) + shape = subtract(shape, circle(width/2, 0, width/2 - line)) + shape = subtract(shape, rectangle(0, width, 0, height)) + shape = add(shape, circle(width/2,width/2,width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = add(shape,rectangle(width-line,width,0,width)) + glyphs['g'] = shape + + shape = rectangle(0,line,0,height) + shape = add(shape,rectangle(width-line,width,0,height)) + shape = add(shape,rectangle(0,width,height/2-line/2,height/2+line/2)) + glyphs['H'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,0,width/2)) + shape = add(shape,rectangle(0,line,0,height)) + shape = add(shape,rectangle(width-line,width,0,width/2)) + glyphs['h'] = shape + + shape = rectangle(width/2-line/2,width/2+line/2,0,height) + shape = add(shape,rectangle(width/5,4*width/5,0,line)) + shape = add(shape,rectangle(width/5,4*width/5,height-line,height)) + glyphs['I'] = shape + + shape = rectangle(width/2-line/2,width/2+line/2,0,height/2) + shape = add(shape,circle(width/2,3*height/4,3*line/5)) + glyphs['i'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,width/2,height)) + shape = add(shape,rectangle(width-line,width,width/2,height)) + glyphs['J'] = shape + + shape = circle(width/2, 0, width/2) + shape = subtract(shape, circle(width/2, 0, width/2 - line)) + shape = subtract(shape, rectangle(0, width, 0, height)) + shape = add(shape,rectangle(width-line,width,0,height/2)) + shape = add(shape,circle(width-line/2,3*height/4,3*line/5)) + glyphs['j'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(line,height,width-line,height,line,height/2+line)) + shape = subtract(shape,triangle(width,0,1.5*line,height/2,width,height)) + shape = subtract(shape,triangle(line,0,line,height/2-line,width-line,0)) + glyphs['K'] = shape + + shape = rectangle(0,3*width/4,0,height) + shape = subtract(shape,triangle(line,height,width-line,height,line,height/3+line)) + shape = subtract(shape,triangle(3*width/4,0,1.5*line,height/3,width,height)) + shape = subtract(shape,triangle(line,0,line,height/2.5-line,3*width/4-line,0)) + shape = subtract(shape, rectangle(line, width, 3*height/4, height)) + glyphs['k'] = shape + + shape = rectangle(0,line,0,height) + shape = add(shape,rectangle(0,width,0,line)) + glyphs['L'] = shape + + shape = rectangle(width/2-line/2,width/2+line/2,0,height) + glyphs['l'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(line,0,line,height/2,width/2-line/3,0)) + shape = subtract(shape,triangle(line,height,width-line,height,width/2,height/4)) + shape = subtract(shape,triangle(width/2+line/3,0,width-line,height/2,width-line,0)) + glyphs['M'] = shape + + shape = circle(width/4 + line/4, width/2, width/4 + line/4) + shape = subtract(shape, circle(width/4 + line/4, width/2, width/4 - 3*line/4)) + shape = subtract(shape, rectangle(0, width, 0, width/2)) + shape = add(shape, move(shape, width/2 - line/2, 0)) + shape = add(shape, rectangle(0, line, 0, width/2 + line)) + shape = add(shape, rectangle(width/2-line/2, width/2+line/2, 0, width/2)) + shape = add(shape, rectangle(width-line, width, 0, width/2)) + glyphs['m'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(4*line/3,height,width-line,height,width-line,height/4)) + shape = subtract(shape,triangle(line,0,line,3*height/4,width - 4*line/3,0)) + glyphs['N'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,0,width/2)) + shape = add(shape,rectangle(0,line,0,width)) + shape = add(shape,rectangle(width-line,width,0,width/2)) + glyphs['n'] = shape + + shape = circle(width/2,width/2,width/2) + shape = add(shape,circle(width/2,height-width/2,width/2)) + shape = add(shape,rectangle(0,width,width/2, height-width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2 - line)) + shape = subtract(shape,circle(width/2,height -width/2,width/2 - line)) + shape = subtract(shape,rectangle(line,width-line,width/2, height-width/2)) + glyphs['O'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + glyphs['o'] = shape + + # P scales a bit strangely + shape = rectangle(0,line,0,height) + shape = add(shape,circle(width/2,height-width/2,width/2)) + shape = add(shape,rectangle(0,width/2,height-width,height)) + shape = subtract(shape,circle(width/2,height-width/2,width/2-line)) + shape = subtract(shape,rectangle(line,width/2,height-width+line,height-line)) + glyphs['P'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = add(shape,rectangle(0,line,-height/3,width)) + glyphs['p'] = shape + + shape = glyphs['O'] + shape = add(shape,move(rotate(rectangle(-line/2,line/2,-width/4,width/4),30),3*width/4,width/4)) + glyphs['Q'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = add(shape,rectangle(width-line,width,-height/3,width)) + glyphs['q'] = shape + + shape = triangle(line,0,line,height,width,0) + shape = subtract(shape,triangle(line,0,line,height-line*2,width-line,0)) + shape = subtract(shape,rectangle(0,width,height/3 + line/2,height)) + shape = add(glyphs['P'],shape) + glyphs['R'] = shape + + shape = circle(width,0,width) + shape = subtract(shape,circle(width,0,width-line)) + shape = subtract(shape,rectangle(.8*width,2*width,-width,width)) + shape = subtract(shape,rectangle(0,width,-width,0)) + shape = add(shape,rectangle(0,line,0,width)) + glyphs['r'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width/2,width/2,width)) + shape = add(shape,move(reflect_y(reflect_x(shape,width),width),0,width-line)) + shape = scale_y(shape,0,height/(2*width-line)) + glyphs['S'] = shape + + w = width/3 + shape = circle(w,w,w) + shape = subtract(shape,circle(w,w,w-line*0.9)) + shape = subtract(shape,rectangle(0,w,w,2*w)) + shape = add(shape,move(reflect_y(reflect_x(shape,2*w),2*w),0,2*w-line*.9)) + shape = scale_y(shape,0,(2*height/3)/(4*w-line*.9)) + shape = move(shape,(width/2)-w,0) + glyphs['s'] = shape + + shape = rectangle(width/2-line/2,width/2+line/2,0,height) + shape = add(shape,rectangle(0,width,height-line,height)) + glyphs['T'] = shape + + shape = circle(0,3*width/8,3*width/8) + shape = subtract(shape,circle(0,3*width/8,3*width/8-line)) + shape = subtract(shape,rectangle(-width,width,3*width/8,height)) + shape = subtract(shape,rectangle(0,width,-height,height)) + shape = move(shape,width/2-line/2+3*width/8,0) + shape = add(shape,rectangle(width/2-line/2,width/2+line/2,width/4,3*height/4)) + shape = add(shape,rectangle(width/5,4*width/5,height/2-line/2,height/2+line/2)) + glyphs['t'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,width/2,height)) + shape = add(shape,rectangle(0,line,width/2,height)) + shape = add(shape,rectangle(width-line,width,width/2,height)) + glyphs['U'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,width/2,height)) + shape = add(shape,rectangle(0,line,width/2,2*height/3)) + shape = add(shape,rectangle(width-line,width,0,2*height/3)) + glyphs['u'] = shape + + shape = triangle(0,height,width,height,width/2,0) + shape = subtract(shape,triangle(0,height+3*line,width,height+3*line,width/2,3*line)) + glyphs['V'] = shape + + w = 2*height/3.0 + shape = triangle(0,w,width,w,width/2,0) + shape = subtract(shape,triangle(0,w+2*line,width,w+2*line,width/2,2*line)) + glyphs['v'] = shape + + shape = triangle(0,height,width,height,width/2,0) + shape = add(shape,move(shape,.6*width,0)) + cutout = triangle(0,height+4*line,width,height+4*line,width/2,4*line) + cutout = add(cutout,move(cutout,.6*width,0)) + shape = subtract(shape,cutout) + shape = scale_x(shape,0,1/1.6) + glyphs['W'] = shape + + glyphs['w'] = scale_y(glyphs['W'],0,width/height) + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(0,0,0,height,width/2-.7*line,height/2)) + shape = subtract(shape,triangle(width,0,width/2+.7*line,height/2,width,height)) + shape = subtract(shape,triangle(line,height,width-line,height,width/2,height/2+line)) + shape = subtract(shape,triangle(line,0,width/2,height/2-line,width-line,0)) + glyphs['X'] = shape + + glyphs['x'] = scale_y(glyphs['X'], 0, width/height) + + shape = rectangle(0,width,height/2,height) + shape = subtract(shape,triangle(0,height/2,0,height,width/2-line/2,height/2)) + shape = subtract(shape,triangle(width/2+line/2,height/2,width,height,width,height/2)) + shape = subtract(shape,triangle(1.1*line,height,width-1.1*line,height,width/2,height/2+1.1*line)) + shape = add(shape,rectangle(width/2-line/2,width/2+line/2,0,height/2)) + glyphs['Y'] = shape + + + shape = rectangle(0,width,-height/3,width) + shape = subtract(shape,triangle(0,-height/3,0,width,width/2-line*0.8,0)) + shape = subtract(shape,triangle(1.1*line,width,width-1.1*line,width,width/2-width*0.05,1.6*line)) + shape = subtract(shape,triangle(width/3,-height/3,width,width,width,-height/3)) + glyphs['y'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(0,line,0,height-line,width-1.4*line,height-line)) + shape = subtract(shape,triangle(1.4*line,line,width,height-line,width,line)) + glyphs['Z'] = shape + + w = 2*height/3 + shape = rectangle(0,width,0,w) + shape = subtract(shape,triangle(0,line,0,w-line,width-1.6*line,w-line)) + shape = subtract(shape,triangle(width,line,1.6*line,line,width,w-line)) + glyphs['z'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-0.8*line)) + shape = scale_y(shape,0,height/width) + glyphs['0'] = shape + + shape = rectangle(width/2-line/2,width/2+line/2,0,height) + w = width/2-line/2 + cutout = circle(0,height,w) + shape = add(shape,rectangle(0,width/2,height-w-line,height)) + shape = subtract(shape,cutout) + shape = move(shape,(width/2+line/2)/4,0) + glyphs['1'] = shape + + shape = circle(width/2,height-width/2,width/2) + shape = subtract(shape,circle(width/2,height-width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width/2,0,height-width/2)) + shape = add(shape,rectangle(0,width,0,height-width/2)) + shape = subtract(shape,triangle(0,line,0,height-width/2,width-line,height-width/2)) + shape = subtract(shape,triangle(1.5*line,line,width,height-width/2-.5*line,width,line)) + glyphs['2'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = scale_y(shape,0,(height/2+line/2)/width) + shape = add(shape,move(shape,0,height/2-line/2)) + shape = subtract(shape,rectangle(0,width/2,height/4,3*height/4)) + glyphs['3'] = shape + + shape = rectangle(width-line,width,0,height) + shape = add(shape,triangle(0,height/3,width-line,height,width-line,height/3)) + shape = subtract(shape,triangle(width/2*line,height/3+line,width-line,height-1.5*line,width-line,height/3+line)) + glyphs['4'] = shape + + ######## + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width/2,width/2,width)) + shape = add(shape,rectangle(0,width/2,width-line,width)) + shape = add(shape,rectangle(0,line,width-line,height)) + shape = add(shape,rectangle(0,width,height-line,height)) + glyphs['5'] = shape + + shape = circle(width/2,height-width/2,width/2) + shape = subtract(shape,circle(width/2,height-width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,0,height-width/2)) + shape = subtract(shape,triangle(width,height,width,height/2,width/2,height/2)) + shape = add(shape,circle(width/2,width/2,width/2)) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = add(shape,rectangle(0,line,width/2,height-width/2)) + glyphs['6'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(0,0,0,height-line,width-line,height-line)) + shape = subtract(shape,triangle(line,0,width,height-line,width,0)) + glyphs['7'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = scale_y(shape,0,(height/2+line/2)/width) + shape = add(shape,move(shape,0,height/2-line/2)) + glyphs['8'] = shape + + shape = circle(width/2,width/2,width/2) + shape = subtract(shape,circle(width/2,width/2,width/2-line)) + shape = subtract(shape,rectangle(0,width,width/2,height)) + shape = subtract(shape,triangle(0,0,0,height/2,width/2,height/2)) + shape = add(shape,circle(width/2,height-width/2,width/2)) + shape = subtract(shape,circle(width/2,height-width/2,width/2-line)) + shape = add(shape,rectangle(width-line,width,width/2,height-width/2)) + glyphs['9'] = shape + + w = width/2 + shape = circle(w,w,w) + shape = subtract(shape,circle(w,w,w-line)) + shape = subtract(shape,rectangle(w,width,0,height)) + shape = scale_y(shape,0,height/width) + shape = move(shape,w/2,0) + glyphs['('] = shape + + shape = reflect_x(glyphs['('],width) + glyphs[')'] = shape + + glyphs[' '] = '0' + + shape = rectangle(width/2-width/3,width/2+width/3,height/2-line/2,height/2+line/2) + shape = add(shape,rectangle(width/2-line/2,width/2+line/2,height/2-width/3,height/2+width/3)) + glyphs['+'] = shape + + shape = rectangle(width/2-width/3,width/2+width/3,height/2-line/2,height/2+line/2) + glyphs['-'] = shape + + shape = circle(width/2,line,3*line/4) + glyphs['.'] = shape + + shape = rectangle(0,width,0,height) + shape = subtract(shape,triangle(4*line/5,0,width,height-4*line/5,width,0)) + shape = subtract(shape,triangle(0,4*line/5,0,height,width-4*line/5,height)) + glyphs['/'] = shape + + # + # to be done + # + # glyphs['~'] = False + # glyphs['!'] = False + # glyphs['@'] = False + # glyphs['#'] = False + # glyphs['$'] = False + # glyphs['%'] = False + # glyphs['^'] = False + # glyphs['&'] = False + # glyphs['&'] = False + # glyphs['_'] = False + # glyphs['='] = False + # glyphs['['] = False + # glyphs['{'] = False + # glyphs[']'] = False + # glyphs['}'] = False + # glyphs[';'] = False + # glyphs[':'] = False + # glyphs["'"] = False + # glyphs['"'] = False + # glyphs[','] = False + # glyphs['<'] = False + # glyphs['>'] = False + # glyphs['?'] = False + + return glyphs, width, height + +def set_font(height): + global glyphs, glyph_width, glyph_height + glyphs, glyph_width, glyph_height = make_glyphs(height) + +def text(text, x, y, height = None, align = 'CC'): + dx = 0 + dy = 0 + + text_shape = '0' + + if height is None: + height = glyph_height + + if height == glyph_height: + width = glyph_width + glyphs_ = glyphs + else: + glyphs_, width, height = make_glyphs(height) + + + for line in text.split('\n'): + line_shape = '0' + for chr in line: + # Only draw characters that we have glyphs for + if not chr in glyphs_.keys(): + print "Unknown character:", chr + continue + + line_shape = add(line_shape, move(glyphs_[chr], dx, dy)) + + dx += 3*width/2 + + # Horizontally align this line of text + dx -= 3*width/2 + if (align[0] == 'L'): + text_shape = add(text_shape, line_shape) + elif (align[0] == 'C'): + text_shape = add(text_shape, move(line_shape, -dx / 2, 0)) + elif (align[0] == 'R'): + text_shape = add(text_shape, move(line_shape, -dx, 0)) + else: + print "Invalid horizontal alignment character." + + dx = 0 + dy -= 3*height/2 + + dy += 3*height/2 + + # Vertically align the text + if (align[1] == 'T'): + pass + elif (align[1] == 'C'): + text_shape = move(text_shape, 0, -dy/2) + elif (align[1] == 'B'): + text_shape = move(text_shape, 0, -dy) + else: + print "Invalid vertical alignment character." + + text_shape = move(text_shape, x, y) + return text_shape + +set_font(1.0) \ No newline at end of file diff --git a/src/py/fab_mods.py b/src/py/fab_mods.py new file mode 100644 index 0000000..a0ea104 --- /dev/null +++ b/src/py/fab_mods.py @@ -0,0 +1,126 @@ +# +# fab_mods.py +# fab module definitions +# +# Neil Gershenfeld 9/1/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys,os +# +# set workflows +# +def set_workflows(frame,formats,workflows): + frame.formats.Append("image (.png)") + formats.append(".png") + frame.formats.Append("volume (.gif)") + formats.append(".gif") + frame.formats.Append("mesh (.stl)") + formats.append(".stl") + frame.formats.Append("drawing (.svg)") + formats.append(".svg") + frame.formats.Append("program (.cad)") + formats.append(".cad") + frame.formats.Append("expression (.math)") + formats.append(".math") + # + frame.processes.Append("image (.png)") + workflows["image (.png) : image (.png)"] = "make_png_png" + workflows["program (.cad) : image (.png)"] = "make_cad_png" + workflows["mesh (.stl) : image (.png)"] = "make_stl_png" + # + frame.processes.Append("Encapsulated PostScript (.eps)") + workflows["image (.png) : Encapsulated PostScript (.eps)"] = "make_png_eps" + workflows["program (.cad) : Encapsulated PostScript (.eps)"] = "make_cad_eps" + workflows["expression (.math) : Encapsulated PostScript (.eps)"] = "make_math_eps" + frame.processes.Append("PostScript halftone (.eps)") + workflows["image (.png) : PostScript halftone (.eps)"] = "make_png_eps_halftone" + # + frame.processes.Append("DXF (.dxf)") + workflows["image (.png) : DXF (.dxf)"] = "make_png_dxf" + workflows["program (.cad) : DXF (.dxf)"] = "make_cad_dxf" + workflows["expression (.math) : DXF (.dxf)"] = "make_math_dxf" + # + frame.processes.Append("Gerber (.grb)") + workflows["image (.png) : Gerber (.grb)"] = "make_png_grb" + workflows["program (.cad) : Gerber (.grb)"] = "make_cad_grb" + workflows["expression (.math) : Gerber (.grb)"] = "make_math_grb" + # + frame.processes.Append("Excellon (.drl)") + workflows["image (.png) : Excellon (.drl)"] = "make_png_drl" + workflows["program (.cad) : Excellon (.drl)"] = "make_cad_drl" + workflows["expression (.math) : Excellon (.drl)"] = "make_math_drl" + # + frame.processes.Append("Epilog lasercutter (.epi)") + workflows["image (.png) : Epilog lasercutter (.epi)"] = "make_png_epi" + workflows["program (.cad) : Epilog lasercutter (.epi)"] = "make_cad_epi" + workflows["expression (.math) : Epilog lasercutter (.epi)"] = "make_math_epi" + workflows["drawing (.svg) : Epilog lasercutter (.epi)"] = "make_svg_epi" + frame.processes.Append("Epilog halftone (.epi)") + workflows["image (.png) : Epilog halftone (.epi)"] = "make_png_epi_halftone" + # + frame.processes.Append("Universal lasercutter (.uni)") + workflows["image (.png) : Universal lasercutter (.uni)"] = "make_png_uni" + workflows["program (.cad) : Universal lasercutter (.uni)"] = "make_cad_uni" + workflows["expression (.math) : Universal lasercutter (.uni)"] = "make_math_uni" + workflows["drawing (.svg) : Universal lasercutter (.uni)"] = "make_svg_uni" + # + frame.processes.Append("Universal halftone (.uni)") + workflows["image (.png) : Universal halftone (.uni)"] = "make_png_uni_halftone" + # + frame.processes.Append("Resonetics excimer (.oms)") + workflows["image (.png) : Resonetics excimer (.oms)"] = "make_png_oms" + workflows["drawing (.svg) : Resonetics excimer (.oms)"] = "make_svg_oms" + # + frame.processes.Append("Omax waterjet (.ord)") + workflows["image (.png) : Omax waterjet (.ord)"] = "make_png_ord" + workflows["program (.cad) : Omax waterjet (.ord)"] = "make_cad_ord" + workflows["expression (.math) : Omax waterjet (.ord)"] = "make_math_ord" + workflows["drawing (.svg) : Omax waterjet (.ord)"] = "make_svg_ord" + # + frame.processes.Append("mesh (.stl)") + workflows["volume (.gif) : mesh (.stl)"] = "make_gif_stl" + workflows["program (.cad) : mesh (.stl)"] = "make_cad_stl" + workflows["expression (.math) : mesh (.stl)"] = "make_math_stl" + # + frame.processes.Append("Roland vinylcutter (.camm)") + workflows["image (.png) : Roland vinylcutter (.camm)"] = "make_png_camm" + workflows["program (.cad) : Roland vinylcutter (.camm)"] = "make_cad_camm" + workflows["expression (.math) : Roland vinylcutter (.camm)"] = "make_math_camm" + workflows["drawing (.svg) : Roland vinylcutter (.camm)"] = "make_svg_camm" + # + frame.processes.Append("Roland Modela (.rml)") + workflows["image (.png) : Roland Modela (.rml)"] = "make_png_rml" + workflows["program (.cad) : Roland Modela (.rml)"] = "make_cad_rml" + workflows["expression (.math) : Roland Modela (.rml)"] = "make_math_rml" + workflows["mesh (.stl) : Roland Modela (.rml)"] = "make_stl_rml" + workflows["drawing (.svg) : Roland Modela (.rml)"] = "make_svg_rml" + workflows["image (.png) : Roland Modela (.rml)"] = "make_png_rml" + # + frame.processes.Append("G-codes (.g)") + workflows["image (.png) : G-codes (.g)"] = "make_png_g" + workflows["program (.cad) : G-codes (.g)"] = "make_cad_g" + workflows["expression (.math) : G-codes (.g)"] = "make_math_g" + workflows["mesh (.stl) : G-codes (.g)"] = "make_stl_g" + workflows["drawing (.svg) : G-codes (.g)"] = "make_svg_g" + # + frame.processes.Append("ShopBot (.sbp)") + workflows["image (.png) : ShopBot (.sbp)"] = "make_png_sbp" + workflows["program (.cad) : ShopBot (.sbp)"] = "make_cad_sbp" + workflows["expression (.math) : ShopBot (.sbp)"] = "make_math_sbp" + workflows["mesh (.stl) : ShopBot (.sbp)"] = "make_stl_sbp" + workflows["drawing (.svg) : ShopBot (.sbp)"] = "make_svg_sbp" + # + frame.processes.Append("MTM Snap") + workflows["image (.png) : MTM Snap"] = "make_png_snap" + workflows["program (.cad) : MTM Snap"] = "make_cad_snap" + workflows["mesh (.stl) : MTM Snap"] = "make_stl_snap" + workflows["drawing (.svg) : MTM Snap"] = "make_svg_snap" diff --git a/src/py/fab_set.py b/src/py/fab_set.py new file mode 100644 index 0000000..1161a08 --- /dev/null +++ b/src/py/fab_set.py @@ -0,0 +1,1299 @@ +# +# fab_set.py +# fab modules frame and set workflow defaults +# +# Neil Gershenfeld 9/1/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,sys,os +# +# frame class +# +class fab_frame(wx.Frame): + # + # set .png .epi defaults + # + def set_png_epi(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('25');\ + self.epi_panel.speed_2D.SetValue('75');\ + self.epi_panel.min_power_3D.SetValue('5');\ + self.epi_panel.max_power_3D.SetValue('25');\ + self.epi_panel.speed_3D.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('75');\ + self.epi_panel.speed_2D.SetValue('25');\ + self.epi_panel.min_power_3D.SetValue('25');\ + self.epi_panel.max_power_3D.SetValue('75');\ + self.epi_panel.speed_3D.SetValue('25');" + # + # set .png .epi halftone defaults + # + def set_png_epi_halftone(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.epi_panel.power_2D.SetValue('25');\ + self.epi_panel.speed_2D.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.epi_panel.power_2D.SetValue('75');\ + self.epi_panel.speed_2D.SetValue('25');" + # + # set .cad .epi defaults + # + def set_cad_epi(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.cad_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('25');\ + self.epi_panel.speed_2D.SetValue('75');\ + self.epi_panel.min_power_3D.SetValue('5');\ + self.epi_panel.max_power_3D.SetValue('25');\ + self.epi_panel.speed_3D.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.cad_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('75');\ + self.epi_panel.speed_2D.SetValue('25');\ + self.epi_panel.min_power_3D.SetValue('25');\ + self.epi_panel.max_power_3D.SetValue('75');\ + self.epi_panel.speed_3D.SetValue('25');" + # + # set .math .epi defaults + # + def set_math_epi(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('25');\ + self.epi_panel.speed_2D.SetValue('75');\ + self.epi_panel.min_power_3D.SetValue('5');\ + self.epi_panel.max_power_3D.SetValue('25');\ + self.epi_panel.speed_3D.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.diameter_finish.SetValue('0.25');\ + self.png_path_panel.clearance_diameter_finish.SetValue('0.25');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.error_2D.SetValue('1.5');\ + self.epi_panel.power_2D.SetValue('75');\ + self.epi_panel.speed_2D.SetValue('25');\ + self.epi_panel.min_power_3D.SetValue('25');\ + self.epi_panel.max_power_3D.SetValue('75');\ + self.epi_panel.speed_3D.SetValue('25');" + # + # set .svg .epi defaults + # + def set_svg_epi(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.epi_panel.power_2D.SetValue('25');\ + self.epi_panel.speed_2D.SetValue('75');\ + self.epi_panel.min_power_3D.SetValue('5');\ + self.epi_panel.max_power_3D.SetValue('25');\ + self.epi_panel.speed_3D.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.epi_panel.power_2D.SetValue('75');\ + self.epi_panel.speed_2D.SetValue('25');\ + self.epi_panel.min_power_3D.SetValue('25');\ + self.epi_panel.max_power_3D.SetValue('75');\ + self.epi_panel.speed_3D.SetValue('25');" + # + # set .png .uni defaults + # + def set_png_uni(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('25');\ + self.uni_panel.speed.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('75');\ + self.uni_panel.speed.SetValue('25');" + # + # set .png .uni halftone defaults + # + def set_png_uni_halftone(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.uni_panel.power.SetValue('25');\ + self.uni_panel.speed.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.uni_panel.power.SetValue('75');\ + self.uni_panel.speed.SetValue('25');" + # + # set .cad .uni defaults + # + def set_cad_uni(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('25');\ + self.uni_panel.speed.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('75');\ + self.uni_panel.speed.SetValue('25');" + # + # set .math .uni defaults + # + def set_math_uni(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('25');\ + self.uni_panel.speed.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.uni_panel.power.SetValue('75');\ + self.uni_panel.speed.SetValue('25');" + # + # set .svg .uni defaults + # + def set_svg_uni(self): + self.defaults = {} + self.control_panel.defaults.Append('cardboard') + self.defaults["cardboard"]\ + = "self.uni_panel.power.SetValue('25');\ + self.uni_panel.speed.SetValue('75');" + self.control_panel.defaults.Append('acrylic') + self.defaults["acrylic"]\ + = "self.uni_panel.power.SetValue('75');\ + self.uni_panel.speed.SetValue('25');" + # + # set .png .rml defaults + # + def set_png_rml(self): + self.defaults = {} + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_path_panel.diameter_plane.SetValue('0.4');\ + self.png_path_panel.number_plane.SetValue('4');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('mill traces (0.010)') + self.defaults["mill traces (0.010)"]\ + = "self.png_path_panel.diameter_plane.SetValue('0.254');\ + self.png_path_panel.number_plane.SetValue('1');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('2');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_path_panel.diameter_rough.SetValue('0.79');\ + self.png_path_panel.number_rough.SetValue('1');\ + self.png_path_panel.itop_rough.SetValue('0.5');\ + self.png_path_panel.ibot_rough.SetValue('0.5');\ + self.png_path_panel.ztop_rough.SetValue('-0.6');\ + self.png_path_panel.zbot_rough.SetValue('-1.7');\ + self.png_path_panel.zstep_rough.SetValue('0.6');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('-10');\ + self.png_path_panel.ztop_rough.SetValue('0');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('-10');\ + self.png_path_panel.ztop_finish.SetValue('0');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.path_type = '3D finish';\ + self.update_panels();" + # + # set .cad .rml defaults + # + def set_cad_rml(self): + self.defaults = {} + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_plane.SetValue('0.4');\ + self.png_path_panel.number_plane.SetValue('4');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('mill traces (0.010)') + self.defaults["mill traces (0.010)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_plane.SetValue('0.254');\ + self.png_path_panel.number_plane.SetValue('1');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('2');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_rough.SetValue('0.79');\ + self.png_path_panel.number_rough.SetValue('1');\ + self.png_path_panel.itop_rough.SetValue('0.5');\ + self.png_path_panel.ibot_rough.SetValue('0.5');\ + self.png_path_panel.ztop_rough.SetValue('-0.6');\ + self.png_path_panel.zbot_rough.SetValue('-1.7');\ + self.png_path_panel.zstep_rough.SetValue('0.6');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.path_type = '3D finish';\ + self.update_panels();" + # + # set .math .rml defaults + # + def set_math_rml(self): + self.defaults = {} + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter.SetValue('0.4');\ + self.png_path_panel.number.SetValue('4');\ + self.png_path_panel.z.SetValue('-0.1');\ + self.png_path_panel.frame3_ztop.SetValue('');\ + self.png_path_panel.frame3_zbot.SetValue('');\ + self.png_path_panel.frame3_zstep.SetValue('');\ + self.png_path_panel.frame3_xy.SetValue(False);\ + self.png_path_panel.frame3_xz.SetValue(False);\ + self.png_path_panel.frame3_yz.SetValue(False);\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');" + self.control_panel.defaults.Append('mill traces (0.010)') + self.defaults["mill traces (0.010)"]\ + = "self.png_path_panel.diameter.SetValue('0.254');\ + self.png_path_panel.number.SetValue('1');\ + self.png_path_panel.z.SetValue('-0.1');\ + self.png_path_panel.frame3_ztop.SetValue('');\ + self.png_path_panel.frame3_zbot.SetValue('');\ + self.png_path_panel.frame3_zstep.SetValue('');\ + self.png_path_panel.frame3_xy.SetValue(False);\ + self.png_path_panel.frame3_xz.SetValue(False);\ + self.png_path_panel.frame3_yz.SetValue(False);\ + self.rml_panel.speed.SetValue('2');\ + self.rml_panel.zjog.SetValue('1.0');" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter.SetValue('0.79');\ + self.png_path_panel.number.SetValue('1');\ + self.png_path_panel.frame3_itop.SetValue('0.5');\ + self.png_path_panel.frame3_ibot.SetValue('0.5');\ + self.png_path_panel.frame3_ztop.SetValue('-0.6');\ + self.png_path_panel.frame3_zbot.SetValue('-1.7');\ + self.png_path_panel.frame3_zstep.SetValue('0.6');\ + self.png_path_panel.frame3_xy.SetValue(True);\ + self.png_path_panel.frame3_xz.SetValue(False);\ + self.png_path_panel.frame3_yz.SetValue(False);\ + self.rml_panel.speed.SetValue('4');\ + self.rml_panel.zjog.SetValue('1.0');" + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter.SetValue('3.175');\ + self.png_path_panel.number.SetValue('-1');\ + self.png_path_panel.overlap.SetValue('0.25');\ + self.png_path_panel.error.SetValue('1.5');\ + self.png_path_panel.frame3_xy.SetValue(True);\ + self.png_path_panel.frame3_xz.SetValue(False);\ + self.png_path_panel.frame3_yz.SetValue(False);\ + self.png_path_panel.frame3_zstep.SetValue('0.5');\ + self.rml_panel.speed.SetValue('20');" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter.SetValue('3.175');\ + self.png_path_panel.number.SetValue('1');\ + self.png_path_panel.overlap.SetValue('0.5');\ + self.png_path_panel.error.SetValue('1.5');\ + self.png_path_panel.frame3_xy.SetValue(False);\ + self.png_path_panel.frame3_xz.SetValue(True);\ + self.png_path_panel.frame3_yz.SetValue(True);\ + self.rml_panel.speed.SetValue('20');" + # + # set .stl .rml defaults + # + def set_stl_rml(self): + self.defaults = {} + self.control_panel.defaults.Append('inches, 1/8, wax, rough') + self.defaults["inches, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('inches, 1/8, wax, finish') + self.defaults["inches, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, rough') + self.defaults["mm, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, finish') + self.defaults["mm, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.rml_panel.button.Hide();\ + self.rml_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .svg .rml defaults + # + def set_svg_rml(self): + self.defaults = {} + self.control_panel.defaults.Append('wax') + self.defaults["wax"]\ + = "self.rml_panel.speed.SetValue('20');" + # + # set .png .sbp defaults + # + def set_png_sbp(self): + self.defaults = {} + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('-10');\ + self.png_path_panel.ztop_rough.SetValue('0');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('-10');\ + self.png_path_panel.ztop_finish.SetValue('0');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.path_type = '3D finish';\ + self.update_panels();" + # + # set .png .plt defaults + # + def set_png_plt(self): + self.defaults = {} + # + # set .cad .sbp defaults + # + def set_cad_sbp(self): + self.defaults = {} + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .math .sbp defaults + # + def set_math_sbp(self): + self.defaults = {} + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.math_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.math_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .stl .sbp defaults + # + def set_stl_sbp(self): + self.defaults = {} + self.control_panel.defaults.Append('inches, 1/8, wax, rough') + self.defaults["inches, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('inches, 1/8, wax, finish') + self.defaults["inches, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, rough') + self.defaults["mm, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, finish') + self.defaults["mm, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.sbp_panel.button.Hide();\ + self.sbp_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .svg .sbp defaults + # + def set_svg_sbp(self): + self.defaults = {} + self.control_panel.defaults.Append('wax') + self.defaults["wax"]\ + = "self.sbp_panel.speed.SetValue('20');\ + self.sbp_panel.button.Hide();\ + self.svg_path_panel.zmin.SetValue('-10.0');\ + self.svg_path_panel.zmax.SetValue('0.0');\ + self.path_type='3D';\ + self.update_panels();" + # + # set .png .g defaults + # + def set_png_g(self): + self.defaults = {} + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_path_panel.diameter_plane.SetValue('0.4');\ + self.png_path_panel.number_plane.SetValue('4');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_path_panel.diameter_rough.SetValue('0.79');\ + self.png_path_panel.number_rough.SetValue('1');\ + self.png_path_panel.itop_rough.SetValue('0.5');\ + self.png_path_panel.ibot_rough.SetValue('0.5');\ + self.png_path_panel.ztop_rough.SetValue('-0.6');\ + self.png_path_panel.zbot_rough.SetValue('-1.7');\ + self.png_path_panel.zstep_rough.SetValue('0.6');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('-10');\ + self.png_path_panel.ztop_rough.SetValue('0');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('-10');\ + self.png_path_panel.ztop_finish.SetValue('0');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.path_type = '3D finish';\ + self.update_panels();" + # + # set .cad .g defaults + # + def set_cad_g(self): + self.defaults = {} + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_plane.SetValue('0.4');\ + self.png_path_panel.number_plane.SetValue('4');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('mill traces (0.010)') + self.defaults["mill traces (0.010)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_plane.SetValue('0.254');\ + self.png_path_panel.number_plane.SetValue('1');\ + self.png_path_panel.z_plane.SetValue('-0.1');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D plane';\ + self.update_panels();" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.diameter_rough.SetValue('0.79');\ + self.png_path_panel.number_rough.SetValue('1');\ + self.png_path_panel.itop_rough.SetValue('0.5');\ + self.png_path_panel.ibot_rough.SetValue('0.5');\ + self.png_path_panel.ztop_rough.SetValue('-0.6');\ + self.png_path_panel.zbot_rough.SetValue('-1.7');\ + self.png_path_panel.zstep_rough.SetValue('0.6');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.cad_png_panel.resolution.SetValue('25');\ + self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.path_type = '3D finish';\ + self.update_panels();" + # + # set .math .g defaults + # + def set_math_g(self): + self.defaults = {} + self.control_panel.defaults.Append('wax rough cut (1/8)') + self.defaults["wax rough cut (1/8)"]\ + = "self.math_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.units = 25.4;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('wax finish cut (1/8)') + self.defaults["wax finish cut (1/8)"]\ + = "self.math_png_panel.resolution.SetValue('10');\ + self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('4');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .stl .g defaults + # + def set_stl_g(self): + self.defaults = {} + self.control_panel.defaults.Append('inches, 1/8, wax, rough') + self.defaults["inches, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type = '3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('inches, 1/8, wax, finish') + self.defaults["inches, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.units = 25.4;\ + self.path_type='3D finish';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, rough') + self.defaults["mm, 1/8, wax, rough"]\ + = "self.png_path_panel.diameter_rough.SetValue('3.175');\ + self.png_path_panel.number_rough.SetValue('-1');\ + self.png_path_panel.overlap_rough.SetValue('0.25');\ + self.png_path_panel.error_rough.SetValue('1.5');\ + self.png_path_panel.zstep_rough.SetValue('1');\ + self.png_path_panel.ibot_rough.SetValue('0');\ + self.png_path_panel.itop_rough.SetValue('1');\ + self.png_path_panel.zbot_rough.SetValue('');\ + self.png_path_panel.ztop_rough.SetValue('');\ + self.stl_png_panel.units.SetValue('1');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D rough';\ + self.update_panels();" + self.control_panel.defaults.Append('mm, 1/8, wax, finish') + self.defaults["mm, 1/8, wax, finish"]\ + = "self.png_path_panel.diameter_finish.SetValue('3.175');\ + self.png_path_panel.clearance_diameter_finish.SetValue('3.175');\ + self.png_path_panel.overlap_finish.SetValue('0.5');\ + self.png_path_panel.error_finish.SetValue('1.5');\ + self.png_path_panel.xz_finish.SetValue(True);\ + self.png_path_panel.yz_finish.SetValue(True);\ + self.png_path_panel.ibot_finish.SetValue('0');\ + self.png_path_panel.itop_finish.SetValue('1');\ + self.png_path_panel.zbot_finish.SetValue('');\ + self.png_path_panel.ztop_finish.SetValue('');\ + self.stl_png_panel.units.SetValue('1');\ + self.stl_png_panel.resolution.SetValue('25');\ + self.g_panel.button.Hide();\ + self.g_panel.speed.SetValue('20');\ + self.units = 1;\ + self.path_type='3D finish';\ + self.update_panels();" + # + # set .svg .g defaults + # + def set_svg_g(self): + self.defaults = {} + self.control_panel.defaults.Append('wax') + self.defaults["wax"]\ + = "self.g_panel.speed.SetValue('20');" + # + # set .png .eps defaults + # + def set_png_eps(self): + self.defaults = {} + self.control_panel.defaults.Append('outline') + self.defaults["outline"]\ + = "self.png_path_panel.error_plane.SetValue('1');\ + self.png_path_panel.diameter_plane.SetValue('0');\ + self.png_path_panel.set_path_type('3D plane');\ + self.png_path_panel.number_plane.SetValue('1');" + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_path_panel.error_plane.SetValue('1');\ + self.png_path_panel.diameter_plane.SetValue('0.4');\ + self.png_path_panel.set_path_type('3D plane');\ + self.png_path_panel.number_plane.SetValue('4');" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_path_panel.error_plane.SetValue('1');\ + self.png_path_panel.diameter_plane.SetValue('0.8');\ + self.png_path_panel.set_path_type('3D plane');\ + self.png_path_panel.number_plane.SetValue('1');" + # + # set .cad .eps defaults + # + def set_cad_eps(self): + self.defaults = {} + self.control_panel.defaults.Append('outline') + self.defaults["outline"]\ + = "self.cad_png_panel.resolution.SetValue('50');\ + self.png_path_panel.error_plane.SetValue('1');\ + self.png_path_panel.diameter_plane.SetValue('0');\ + self.png_path_panel.number_plane.SetValue('1');\ + self.path_type = '3D plane';\ + self.update_panels();" + # + # set .math .eps defaults + # + def set_math_eps(self): + self.defaults = {} + self.control_panel.defaults.Append('outline') + self.defaults["outline"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0');\ + self.png_path_panel.number.SetValue('1');" + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0.4');\ + self.png_path_panel.number.SetValue('4');" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0.8');\ + self.png_path_panel.number.SetValue('1');" + # + # set .svg .eps defaults + # + def set_svg_eps(self): + self.defaults = {} + self.control_panel.defaults.Append('outline') + self.defaults["outline"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0');\ + self.png_path_panel.number.SetValue('1');" + self.control_panel.defaults.Append('mill traces (1/64)') + self.defaults["mill traces (1/64)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0.4');\ + self.png_path_panel.number.SetValue('4');" + self.control_panel.defaults.Append('cut out board (1/32)') + self.defaults["cut out board (1/32)"]\ + = "self.png_panel.resolution.SetValue('50');\ + self.png_path_panel.error.SetValue('1');\ + self.png_path_panel.diameter.SetValue('0.8');\ + self.png_path_panel.number.SetValue('1');" + # + # set .png .camm defaults + # + def set_png_camm(self): + self.defaults = {} + self.control_panel.defaults.Append('vinyl') + self.defaults["vinyl"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.camm_panel.force.SetValue('45');\ + self.camm_panel.velocity.SetValue('5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('copper') + self.defaults["copper"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.camm_panel.force.SetValue('55');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('epoxy') + self.defaults["epoxy"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('0.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.camm_panel.force.SetValue('90');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + # + # set .cad .camm defaults + # + def set_cad_camm(self): + self.defaults = {} + self.control_panel.defaults.Append('vinyl') + self.defaults["vinyl"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('45');\ + self.camm_panel.velocity.SetValue('5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('copper') + self.defaults["copper"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('55');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('epoxy') + self.defaults["epoxy"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('90');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + # + # set .math .camm defaults + # + def set_math_camm(self): + self.defaults = {} + self.control_panel.defaults.Append('vinyl') + self.defaults["vinyl"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('45');\ + self.camm_panel.velocity.SetValue('5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('copper') + self.defaults["copper"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('55');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('epoxy') + self.defaults["epoxy"]\ + = "self.png_path_panel.error_2D.SetValue('1.5');\ + self.png_path_panel.diameter_2D.SetValue('.25');\ + self.png_path_panel.number_2D.SetValue('1');\ + self.png_panel.resolution.SetValue('10');\ + self.camm_panel.force.SetValue('90');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + # + # set .svg .camm defaults + # + def set_svg_camm(self): + self.defaults = {} + self.control_panel.defaults.Append('vinyl') + self.defaults["vinyl"]\ + = "self.camm_panel.force.SetValue('45');\ + self.camm_panel.velocity.SetValue('5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('copper') + self.defaults["copper"]\ + = "self.camm_panel.force.SetValue('55');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + self.control_panel.defaults.Append('epoxy') + self.defaults["epoxy"]\ + = "self.camm_panel.force.SetValue('90');\ + self.camm_panel.velocity.SetValue('2.5');\ + self.path_type = '2D';\ + self.update_panels();" + # + # set .png .ord defaults + # + def set_png_ord(self): + self.defaults = {} + # + # set .cad .ord defaults + # + def set_cad_ord(self): + self.defaults = {} + # + # set .math .ord defaults + # + def set_math_ord(self): + self.defaults = {} + # + # set .svg .ord defaults + # + def set_svg_ord(self): + self.defaults = {} + # + # set .png .oms defaults + # + def set_png_oms(self): + self.defaults = {} + # + # set .svg .oms defaults + # + def set_svg_oms(self): + self.defaults = {} + # + # init + # + def __init__(self,title,argv): + self.tmp = "fab_mod_" # default temporary file prefix + # + # set default panel size from screen size + # + (screen_x,screen_y) = wx.DisplaySize() + self.size = screen_y/2.1 + # + # frame + # + wx.Frame.__init__(self,None,title=title) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # resize event + # + self.Bind(wx.EVT_SIZE,self.resize_handler) + # + # arguments + # + self.rootname = "" + self.filename = "" + self.basename = "" + if (len(argv) > 1): + if (argv[1] != '""'): + self.filename = sys.argv[1] + self.basename = os.path.basename(self.filename) + if (len(argv) > 2): + self.size = int(sys.argv[2]) + # + # defaults handler + # + def defaults_handler(self,event): + value = self.control_panel.defaults.GetValue() + string = self.defaults[value] + exec(string) + # + # resize handler + # + def resize_handler(self,event): + (sizex,sizey) = self.GetSize() + self.update_sizes(sizex,sizey) + # + # update children size + # + def update_sizes(self,sizex,sizey): + for child in self.GetChildren(): + if hasattr(child,"update_size"): + child.update_size(sizex,sizey) + self.Layout() + self.Fit() + # + # update child panels + # + def update_panels(self): + for child in self.GetChildren(): + if hasattr(child,"update_panel"): + child.update_panel() + self.Layout() + self.Fit() diff --git a/src/py/math_string.py b/src/py/math_string.py new file mode 100644 index 0000000..f68f49e --- /dev/null +++ b/src/py/math_string.py @@ -0,0 +1,57 @@ +class MString: + def __init__(self, string): + if string.__class__ is MString: + self.s = string.s + else: + self.s = string + + def __repr__(self): + return 'MString(%s)' % self.s + + def __str__(self): + return self.s + + def __eq__(self, other): + if other.__class__ is not MString: + raise TypeError('Expected MString, got object of %s' + % type(other)) + return self.s == other.s + + def __neq__(self, other): + return not self.__eq__(other) + + def __len__(self): + return len(self.s) + + def __hash__(self): + return self.s.__hash__() + + def __or__(self, other): + return MString("(%s) || (%s)" % (self.s, other)) + + def __ror__(self, other): + return MString("(%s) || (%s)" % (other, self.s)) + + def __and__(self, other): + return MString("(%s) && (%s)" % (self.s, other)) + + def __rand__(self, other): + return MString("(%s) && (%s)" % (other, self.s)) + + def __invert__(self): + return MString("!(%s)" % (self.s)) + + def __add__(self, other): + return self | other + + def __radd__(self, other): + return other | self + + def __sub__(self, other): + return self & ~MString(other) + + def __rsub__(self, other): + return other & ~MString(self) + + def replace(self, target, substitution): + return MString(self.s.replace(target, substitution)) \ No newline at end of file diff --git a/src/py/panel_cad.py b/src/py/panel_cad.py new file mode 100644 index 0000000..0414307 --- /dev/null +++ b/src/py/panel_cad.py @@ -0,0 +1,104 @@ +# +# panel_cad.py +# read and edit .cad +# +# Neil Gershenfeld +# CBA MIT 2/18/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +# +# panel class +# +class cad_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # load file + # + def load_file(event): + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".cad") + if (pos == -1): + pos = string.find(self.parent.basename,".CAD") + if (pos == -1): + print 'cad_panel: oops -- must be .cad' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + cad_file = open(self.parent.filename,'r') + cad_string = cad_file.read() + cad_file.close() + self.text.SetValue(cad_string) + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.cad", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + pos = string.find(self.parent.basename,".cad") + if (pos == -1): + print 'cad_panel: oops -- must be .cad' + sys.exit() + else: + self.parent.rootname = self.parent.basename[:pos] + cad_file = open(self.parent.filename,'r') + cad_string = cad_file.read() + cad_file.close() + self.text.SetValue(cad_string) + # + # save file + # + def save_file(event): + result = wx.SaveFileSelector('.cad','.cad',self.parent.filename) + if (result != ''): + cad_file = open(result,'w') + cad_file.write(self.text.GetValue()) + cad_file.close() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: cad') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # text + # + self.text = wx.TextCtrl(self,-1,'',size=(self.parent.size,self.parent.size),style=wx.TE_MULTILINE) + self.sizer.Add(self.text,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + # + # controls + # + load = wx.Button(self,label='load .cad') + load.Bind(wx.EVT_BUTTON,select_file) + self.sizer.Add(load,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + rload = wx.Button(self,label='reload .cad') + rload.Bind(wx.EVT_BUTTON,load_file) + self.sizer.Add(rload,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + save = wx.Button(self,label='save .cad') + save.Bind(wx.EVT_BUTTON,save_file) + self.sizer.Add(save,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() diff --git a/src/py/panel_cad_png.py b/src/py/panel_cad_png.py new file mode 100644 index 0000000..11c16ab --- /dev/null +++ b/src/py/panel_cad_png.py @@ -0,0 +1,149 @@ +# +# panel_cad_png.py +# make .png from .cad +# +# Neil Gershenfeld +# CBA MIT 4/18/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class cad_png_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get png info + # + def png_info(name): + temp_name = self.parent.tmp+'png_info' + command = 'png_size '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make png + # + def make_png(event): + if (self.parent.rootname == ''): + return + # + # generate .math file + # + tmp_cad_file = self.parent.tmp+self.parent.rootname+'.cad' + cad_file = open(tmp_cad_file,'w') + cad_file.write(self.parent.cad_panel.text.GetValue()) + cad_file.close() + cad_info_name = self.parent.tmp+'cad_info' + math_file = self.parent.tmp+self.parent.rootname+'.math' + command = 'cad_math '+'\"'+tmp_cad_file+'\"'+' '+'\"'+math_file+'\"'+' > '+'\"'+cad_info_name+'\"' + print command + os.system(command) + cad_info_file = open(cad_info_name,'r') + cad_info = cad_info_file.read() + cad_info_file.close() + start = string.find(cad_info,"write") + cad_info = cad_info[start:] + start = 7+string.find(cad_info,'units:') + end = string.find(cad_info,'\n',start) + units = float(cad_info[start:end]) + start = 4+string.find(cad_info,'dz:') + end = string.find(cad_info,'\n',start) + dz = float(cad_info[start:end]) + start = 6+string.find(cad_info,'zmin:') + end = string.find(cad_info,'\n',start) + zmin = float(cad_info[start:end]) + start = 8+string.find(cad_info,'layers:') + resolution = self.parent.cad_png_panel.resolution.GetValue() + if (start > 7): + end = string.find(cad_info,'\n',start) + number = int(cad_info[start:end]) + elif (dz > 0): + number = int(dz*units*float(resolution)) + else: + number = 1 + parent.zmin = zmin + parent.zmax = zmin+dz + parent.units = units + # + # generate .png file + # + self.parent.png_file = self.parent.tmp+self.parent.rootname+'.png' + command = 'math_png '+'\"'+math_file+'\"'+' '+'\"'+self.parent.png_file+'\"'+' '+resolution+' '+str(number) + print command + os.system(command) + # + # update image + # + info = png_info(self.parent.png_file) + self.info.SetLabel(cad_info+info) + png_image = wx.Image(self.parent.png_file) + (nx,ny) = png_image.GetSize() + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = self.parent.size/ratio + else: + self.parent.ysize = self.parent.size*ratio + self.parent.xsize = self.parent.size + wx.Image.Rescale(png_image,self.parent.xsize,self.parent.ysize) + png_bitmap = png_image.ConvertToBitmap() + self.bitmap.SetBitmap(png_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # update panels + # + parent.update_panels() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: png') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + image = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, (self.parent.size,self.parent.size)) + self.bitmap = wx.StaticBitmap(self,-1,image) + self.sizer.Add(self.bitmap,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + # + # controls + # + make = wx.Button(self,label='make .png') + make.Bind(wx.EVT_BUTTON,make_png) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'1') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_cad_stl.py b/src/py/panel_cad_stl.py new file mode 100644 index 0000000..0d56622 --- /dev/null +++ b/src/py/panel_cad_stl.py @@ -0,0 +1,124 @@ +# +# panel_cad_stl.py +# make .stl from .cad +# +# Neil Gershenfeld +# CBA MIT 3/22/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class cad_stl_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get stl info + # + def stl_info(name): + temp_name = self.parent.tmp+'stl_info' + command = 'stl_info '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make stl + # + def make_stl(event): + if (self.parent.rootname == ''): + return + tmp_cad_file = self.parent.tmp+self.parent.rootname+'.cad' + cad_file = open(tmp_cad_file,'w') + cad_file.write(self.parent.cad_panel.text.GetValue()) + cad_file.close() + cad_info_name = self.parent.tmp+'cad_info' + math_file = self.parent.tmp+self.parent.rootname+'.math' + command = 'cad_math '+'\"'+tmp_cad_file+'\"'+' '+'\"'+math_file+'\"'+' > '+'\"'+cad_info_name+'\"' + print command + os.system(command) + cad_info_file = open(cad_info_name,'r') + cad_info = cad_info_file.read() + cad_info_file.close() + start = string.find(cad_info,"write") + cad_info = cad_info[start:] + start = 7+string.find(cad_info,'units:') + end = string.find(cad_info,'\n',start) + units = float(cad_info[start:end]) + start = 4+string.find(cad_info,'dz:') + end = string.find(cad_info,'\n',start) + dz = float(cad_info[start:end]) + start = 6+string.find(cad_info,'zmin:') + end = string.find(cad_info,'\n',start) + zmin = float(cad_info[start:end]) + parent.zmin = zmin + parent.zmax = zmin+dz + parent.units = units + self.parent.stl_file = self.parent.tmp+self.parent.rootname+'.stl' + resolution = self.parent.stl_panel.resolution.GetValue() + command = 'math_stl '+'\"'+math_file+'\"'+' '+'\"'+self.parent.stl_file+'\"'+' '+resolution + print command + os.system(command) + info = stl_info(self.parent.stl_file) + self.info.SetLabel(cad_info+info) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.stl_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: stl') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .stl') + make.Bind(wx.EVT_BUTTON,make_stl) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'1') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_control.py b/src/py/panel_control.py new file mode 100644 index 0000000..b1c8bea --- /dev/null +++ b/src/py/panel_control.py @@ -0,0 +1,68 @@ +# +# panel_control.py +# control panel +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +# +# panel class +# +class control_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # quit + # + def quits(event): + command = 'ls '+'\"'+self.parent.tmp+'\"'+'*; rm '+'\"'+self.parent.tmp+'\"'+'*' + print command + os.system(command) + sys.exit() + # + # controls + # + self.defaults = wx.ComboBox(self,value='defaults',style=wx.CB_READONLY) + self.defaults.Bind(wx.EVT_COMBOBOX,self.parent.defaults_handler) + self.sizer.Add(self.defaults,(0,0)) + # + d = 4 + w = 1 + l = 6*d+2*w + def logo_paint(event): + dc = wx.PaintDC(self.logo_panel) + dc.SetBrush(wx.Brush('white')) + dc.SetPen(wx.Pen('white', 0)) + dc.DrawRectangleRect((0, 0, l, l)) + dc.SetBrush(wx.Brush('red')) + dc.DrawCircle(d,d,d) + dc.DrawCircle(3*d+w,3*d+w,d) + dc.SetBrush(wx.Brush('blue')) + dc.DrawRectangleRect((2*d+w,0,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,0,2*d,2*d)) + dc.DrawRectangleRect((0,2*d+w,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,2*d+w,2*d,2*d)) + dc.DrawRectangleRect((0,4*d+2*w,2*d,2*d)) + dc.DrawRectangleRect((2*d+w,4*d+2*w,2*d,2*d)) + dc.DrawRectangleRect((4*d+2*w,4*d+2*w,2*d,2*d)) + self.logo_panel = wx.Panel(self,size=(l,l)) + self.logo_panel.Bind(wx.EVT_PAINT,logo_paint) + self.sizer.Add(self.logo_panel,(0,1)) + # + quit = wx.Button(self,label='quit') + quit.Bind(wx.EVT_BUTTON,quits) + self.sizer.Add(quit,(0,2)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_gif.py b/src/py/panel_gif.py new file mode 100644 index 0000000..b4f5e99 --- /dev/null +++ b/src/py/panel_gif.py @@ -0,0 +1,153 @@ +# +# panel_gif.py +# read .gif +# +# Neil Gershenfeld +# CBA MIT 3/25/14 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +from panel_path import path_panel +# +# panel class +# +class gif_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.stl_file = '' + # + # get stl info + # + def stl_info(name): + # + # construct command + # + temp_name = self.parent.tmp+'stl_info' + command = 'stl_info '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + print output + if (string.find(output,'must be binary') != -1): + sys.exit(-1) + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + # + # read limits + # + start = 6+string.find(output,'xmax:') + space = string.find(output,' ',start) + end = string.find(output,'ymin',space)-4 + self.parent.xmin = float(output[start:space]) + self.parent.xmax = float(output[1+space:end]) + start = 6+string.find(output,'ymax:') + space = string.find(output,' ',start) + end = string.find(output,'zmin',space)-4 + self.parent.ymin = float(output[start:space]) + self.parent.ymax = float(output[1+space:end]) + start = 6+string.find(output,'zmax:') + space = string.find(output,' ',start) + self.parent.zmin = float(output[start:space]) + self.parent.zmax = float(output[space+1:-1]) + # + # move origin to top corner + # + # + self.parent.xmax = self.parent.xmax - self.parent.xmin + self.parent.xmin = 0 + self.parent.ymax = self.parent.ymax - self.parent.ymin + self.parent.ymin = 0 + self.parent.zmin = self.parent.zmin - self.parent.zmax + self.parent.zmax = 0 + # + return output + # + # load file + # + def load_file(event): + # + # get file name + # + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".stl") + if (pos == -1): + pos = string.find(self.parent.basename,".STL") + if (pos == -1): + print 'stl_panel: oops -- must be .stl' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + self.parent.stl_file = self.parent.filename + # + # get file info + # + info = stl_info(self.parent.filename) + self.info.SetLabel(info) + temp_name = self.parent.tmp+'stl.path' + # + # draw + # + if (self.path_viewer.view_type != "none"): + units = 1.0 + resolution = 100 + command = 'stl_path '+'\"'+self.parent.stl_file+'\"'+' '+'\"'+temp_name+'\"'+' '+str(units)+' '+str(resolution) + print command + ret = os.system(command) + if (ret == 0): + self.path_viewer.draw(temp_name) + # + # fit + # + self.parent.Layout() + self.parent.Fit() + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.stl;*.STL", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + load_file(0) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: gif') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + self.path_viewer = path_panel(self) + self.sizer.Add(self.path_viewer,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.path_viewer.view_type = "segments" + # + # controls + # + load = wx.Button(self,label='load .stl') + load.Bind(wx.EVT_BUTTON,select_file) + self.sizer.Add(load,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() diff --git a/src/py/panel_gif_stl.py b/src/py/panel_gif_stl.py new file mode 100644 index 0000000..a1ae387 --- /dev/null +++ b/src/py/panel_gif_stl.py @@ -0,0 +1,137 @@ +# +# panel_gif_stl.py +# make .stl from .gif +# +# Neil Gershenfeld +# CBA MIT 3/25/14 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class gif_stl_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get stl info + # + def stl_info(name): + temp_name = self.parent.tmp+'stl_info' + command = 'stl_info '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make stl + # + def make_stl(event): + if (self.parent.rootname == ''): + return + + math_text = self.parent.math_panel.text.GetValue() + tmp_math_file = self.parent.tmp+self.parent.rootname+'.math' + math_file = open(tmp_math_file,'w') + math_file.write(math_text) + math_file.close() + start = string.find(math_text,"dx dy dz:") + if (start == -1): + start = string.find(math_text,"dx dy:") + if (start == -1): + print "panel_math_png: oops, can't find bounding box" + return + dz = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+10):end].split()] + dz = array[2] + start = string.find(math_text,"xmin ymin zmin:") + if (start == -1): + start = string.find(math_text,"xmin ymin:") + if (start == -1): + print "panel_math_png: oops, can't find origin" + return + zmin = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+15):end].split()] + zmin = array[2] + start = string.find(math_text,"mm per unit:") + if (start == -1): + print "panel_math_png: oops, can't find units" + return + end = string.find(math_text,"\n",start) + units = float(math_text[(start+12):end]) + print units + parent.zmin = zmin + parent.zmax = zmin+dz + parent.units = units + + self.parent.stl_file = self.parent.tmp+self.parent.rootname+'.stl' + resolution = self.parent.stl_panel.resolution.GetValue() + command = 'math_stl '+'\"'+tmp_math_file+'\"'+' '+'\"'+self.parent.stl_file+'\"'+' '+resolution + print command + os.system(command) + info = stl_info(self.parent.stl_file) + self.info.SetLabel(info) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.stl_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: stl') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .stl') + make.Bind(wx.EVT_BUTTON,make_stl) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'1') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_math.py b/src/py/panel_math.py new file mode 100644 index 0000000..4ea5d12 --- /dev/null +++ b/src/py/panel_math.py @@ -0,0 +1,104 @@ +# +# panel_math.py +# read and edit .math +# +# Neil Gershenfeld +# CBA MIT 4/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +# +# panel class +# +class math_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # load file + # + def load_file(event): + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".math") + if (pos == -1): + pos = string.find(self.parent.basename,".MATH") + if (pos == -1): + print 'math_panel: oops -- must be .math' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + math_file = open(self.parent.filename,'r') + math_string = math_file.read() + math_file.close() + self.text.SetValue(math_string) + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.math", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + pos = string.find(self.parent.basename,".math") + if (pos == -1): + print 'math_panel: oops -- must be .math' + sys.exit() + else: + self.parent.rootname = self.parent.basename[:pos] + math_file = open(self.parent.filename,'r') + math_string = math_file.read() + math_file.close() + self.text.SetValue(math_string) + # + # save file + # + def save_file(event): + result = wx.SaveFileSelector('.math','.math',self.parent.filename) + if (result != ''): + math_file = open(result,'w') + math_file.write(self.text.GetValue()) + math_file.close() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: math') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # text + # + self.text = wx.TextCtrl(self,-1,'',size=(self.parent.size,self.parent.size),style=wx.TE_MULTILINE) + self.sizer.Add(self.text,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + # + # controls + # + load = wx.Button(self,label='load .math') + load.Bind(wx.EVT_BUTTON,select_file) + self.sizer.Add(load,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + rload = wx.Button(self,label='reload .math') + rload.Bind(wx.EVT_BUTTON,load_file) + self.sizer.Add(rload,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + save = wx.Button(self,label='save .math') + save.Bind(wx.EVT_BUTTON,save_file) + self.sizer.Add(save,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() diff --git a/src/py/panel_math_png.py b/src/py/panel_math_png.py new file mode 100644 index 0000000..8797a7a --- /dev/null +++ b/src/py/panel_math_png.py @@ -0,0 +1,143 @@ +# +# panel_math_png.py +# make .png from .math +# +# Neil Gershenfeld +# CBA MIT 5/19/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class math_png_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get png info + # + def png_info(name): + temp_name = self.parent.tmp+'png_info' + command = 'png_size '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make png + # + def make_png(event): + if (self.parent.rootname == ''): + return + math_text = self.parent.math_panel.text.GetValue() + tmp_math_file = self.parent.tmp+self.parent.rootname+'.math' + math_file = open(tmp_math_file,'w') + math_file.write(math_text) + math_file.close() + start = string.find(math_text,"dx dy dz:") + if (start == -1): + start = string.find(math_text,"dx dy:") + if (start == -1): + print "panel_math_png: oops, can't find bounding box" + return + dz = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+10):end].split()] + dz = array[2] + start = string.find(math_text,"xmin ymin zmin:") + if (start == -1): + start = string.find(math_text,"xmin ymin:") + if (start == -1): + print "panel_math_png: oops, can't find origin" + return + zmin = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+15):end].split()] + zmin = array[2] + start = string.find(math_text,"mm per unit:") + if (start == -1): + print "panel_math_png: oops, can't find units" + return + end = string.find(math_text,"\n",start) + units = float(math_text[(start+12):end]) + print units + parent.zmin = zmin + parent.zmax = zmin+dz + parent.units = units + resolution = self.parent.math_png_panel.resolution.GetValue() + self.parent.png_file = self.parent.tmp+self.parent.rootname+'.png' + command = 'math_png '+'\"'+tmp_math_file+'\"'+' '+'\"'+self.parent.png_file+'\"'+' '+resolution + print command + os.system(command) + info = png_info(self.parent.png_file) + self.info.SetLabel(info) + png_image = wx.Image(self.parent.png_file) + (nx,ny) = png_image.GetSize() + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = self.parent.size/ratio + else: + self.parent.ysize = self.parent.size*ratio + self.parent.xsize = self.parent.size + wx.Image.Rescale(png_image,self.parent.xsize,self.parent.ysize) + png_bitmap = png_image.ConvertToBitmap() + self.bitmap.SetBitmap(png_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # update panels + # + parent.update_panels() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: png') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + image = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, (self.parent.size,self.parent.size)) + self.bitmap = wx.StaticBitmap(self,-1,image) + self.sizer.Add(self.bitmap,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + # + # controls + # + make = wx.Button(self,label='make .png') + make.Bind(wx.EVT_BUTTON,make_png) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'10') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_math_stl.py b/src/py/panel_math_stl.py new file mode 100644 index 0000000..ba2933c --- /dev/null +++ b/src/py/panel_math_stl.py @@ -0,0 +1,137 @@ +# +# panel_math_stl.py +# make .stl from .math +# +# Neil Gershenfeld +# CBA MIT 9/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class math_stl_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get stl info + # + def stl_info(name): + temp_name = self.parent.tmp+'stl_info' + command = 'stl_info '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make stl + # + def make_stl(event): + if (self.parent.rootname == ''): + return + + math_text = self.parent.math_panel.text.GetValue() + tmp_math_file = self.parent.tmp+self.parent.rootname+'.math' + math_file = open(tmp_math_file,'w') + math_file.write(math_text) + math_file.close() + start = string.find(math_text,"dx dy dz:") + if (start == -1): + start = string.find(math_text,"dx dy:") + if (start == -1): + print "panel_math_png: oops, can't find bounding box" + return + dz = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+10):end].split()] + dz = array[2] + start = string.find(math_text,"xmin ymin zmin:") + if (start == -1): + start = string.find(math_text,"xmin ymin:") + if (start == -1): + print "panel_math_png: oops, can't find origin" + return + zmin = 0 + else: + end = string.find(math_text,"\n",start) + array = [float(s) for s in math_text[(start+15):end].split()] + zmin = array[2] + start = string.find(math_text,"mm per unit:") + if (start == -1): + print "panel_math_png: oops, can't find units" + return + end = string.find(math_text,"\n",start) + units = float(math_text[(start+12):end]) + print units + parent.zmin = zmin + parent.zmax = zmin+dz + parent.units = units + + self.parent.stl_file = self.parent.tmp+self.parent.rootname+'.stl' + resolution = self.parent.stl_panel.resolution.GetValue() + command = 'math_stl '+'\"'+tmp_math_file+'\"'+' '+'\"'+self.parent.stl_file+'\"'+' '+resolution + print command + os.system(command) + info = stl_info(self.parent.stl_file) + self.info.SetLabel(info) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.stl_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: stl') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .stl') + make.Bind(wx.EVT_BUTTON,make_stl) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'1') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path.py b/src/py/panel_path.py new file mode 100644 index 0000000..3cfac2c --- /dev/null +++ b/src/py/panel_path.py @@ -0,0 +1,411 @@ +# +# panel_path.py +# .path viewer +# +# Neil Gershenfeld 10/14/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,math + +# +# panel class +# +class path_panel(wx.Panel): + # + # constructor + # + def __init__(self,parent): + self.parent = parent + class path_object(object): + def __init__(self): + self.segments = [] + self.path = path_object() + self.scale = 1.0 + self.zx = 0 + self.zy = 0 + self.px = 0 + self.py = 0 + self.ox = 0 + self.oy = 0 + self.sx = [] + self.sy = [] + self.rx = [] + self.ry = [] + self.theta_x = 0 + self.theta_z = 0 + # + # drawing panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + self.panel = wx.Panel(self,size=(self.parent.parent.size,self.parent.parent.size)) + self.panel.SetBackgroundColour('white') + self.panel.Bind(wx.EVT_PAINT,self.paint) + self.panel.Bind(wx.EVT_MOUSEWHEEL,self.mouse_wheel) + self.panel.Bind(wx.EVT_LEFT_DOWN,self.mouse_left_down) + self.panel.Bind(wx.EVT_LEFT_UP,self.mouse_left_up) + self.panel.Bind(wx.EVT_MOTION,self.mouse_move) + self.panel.Bind(wx.EVT_RIGHT_DOWN,self.mouse_right_down) + self.panel.Bind(wx.EVT_RIGHT_UP,self.mouse_right_up) + self.sizer.Add(self.panel,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + control_panel = wx.Panel(self) + control_sizer = wx.GridBagSizer(10,10) + control_panel.SetSizer(control_sizer) + self.message = wx.StaticText(control_panel,label='') + control_sizer.Add(self.message,(0,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + # + reset_button = wx.Button(control_panel,label='reset view') + reset_button.Bind(wx.EVT_BUTTON,self.reset_view) + control_sizer.Add(reset_button,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.view_types = ["none","segments","segments+directions","segments+directions+connections"] + self.view_type_control = wx.ComboBox(control_panel,size=(100,-1),value="view type",choices=self.view_types,style=wx.CB_READONLY) + self.view_type = "segments+directions+connections" + self.view_type_control.Bind(wx.EVT_COMBOBOX,self.view_type_handler) + control_sizer.Add(self.view_type_control,(0,2)) + # + self.sizer.Add(control_panel,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # view type handler + # + def view_type_handler(self,event): + self.view_type = self.view_types[event.GetSelection()] + self.panel.Refresh() + # + # read path + # + def read_path(self,path_file_name): + class path_object(object): + def __init__(self): + self.segments = [] + path = path_object() + path_file = open(path_file_name,'r') + while 1: + line = path_file.readline() + if (line == ''): + break + elif (0 == line.find("dof:")): + path.dof = int(line.split()[1]) + elif (0 == line.find("units:")): + if (path.dof >= 2): + path.ux = line.split()[1] + path.uy = line.split()[2] + if (path.dof > 2): + path.uz = line.split()[3] + elif (0 == line.find("nx ny")): + if (path.dof == 2): + path.nx = int(line.split()[2]) + path.ny = int(line.split()[3]) + if (path.dof > 2): + path.nx = int(line.split()[3]) + path.ny = int(line.split()[4]) + path.nz = int(line.split()[5]) + elif (0 == line.find("dx dy")): + if (path.dof == 2): + path.dx = float(line.split()[2]) + path.dy = float(line.split()[3]) + if (path.dof > 2): + path.dx = float(line.split()[3]) + path.dy = float(line.split()[4]) + path.dz = float(line.split()[5]) + elif (0 == line.find("xmin ymin")): + if (path.dof == 2): + path.xmin = float(line.split()[2]) + path.ymin = float(line.split()[3]) + if (path.dof > 2): + path.xmin = float(line.split()[3]) + path.ymin = float(line.split()[4]) + path.zmin = float(line.split()[5]) + elif (0 == line.find("segment start:")): + path.segments.append([]) + while 1: + line = path_file.readline() + if (0 == line.find("segment end:")): + break + if (path.dof == 2): + x = float(line.split()[0]) + y = float(line.split()[1]) + path.segments[-1].append([x,y]) + if (path.dof == 3): + x = float(line.split()[0]) + y = float(line.split()[1]) + z = float(line.split()[2]) + path.segments[-1].append([x,y,z]) + if (path.dof == 2): + self.message.SetLabel('left: pan, scroll: zoom') + elif (path.dof > 2): + if (path.dz > 0): + self.message.SetLabel('left: pan, scroll: zoom, right: rotate') + else: + self.message.SetLabel('left: pan, scroll: zoom') + self.parent.Layout() + self.parent.Fit() + path_file.close() + return path + # + # draw path + # + def draw(self,path_file): + self.path = self.read_path(path_file) + self.panel.Refresh() + # + # rotate point + # + def rotate(self,x,y,z): + x -= self.path.nx/2.0 + y -= self.path.ny/2.0 + z -= self.path.nz/2.0 + angle = self.theta_z + xtemp = math.cos(angle)*x - math.sin(angle)*y + ytemp = math.sin(angle)*x + math.cos(angle)*y + x = xtemp + y = ytemp + angle = self.theta_x + ytemp = math.cos(angle)*y - math.sin(angle)*z + ztemp = math.sin(angle)*y + math.cos(angle)*z + y = ytemp + z = ztemp + x += self.path.nx/2.0 + y += self.path.ny/2.0 + z += self.path.nz/2.0 + return(x,y,z) + # + # scale and draw line + # + def draw_line(self,p0,p1,color,shading='off',end='none'): + # + # set aspect ratio + # + size = self.parent.parent.size + ratio = float(self.path.ny)/float(self.path.nx) + if (ratio > 1): + ysize = size + xsize = size/ratio + else: + ysize = size*ratio + xsize = size + # + # get points + # + if (len(p0) >= 2): + x0 = p0[0] + x1 = p1[0] + y0 = p0[1] + y1 = p1[1] + if (len(p0) >= 3): + z0 = p0[2] + z1 = p1[2] + # + # set 3D shading + # + if (self.path.dof > 2): + if ((self.path.nz > 1) & (shading == 'z')): + i = 0.8*((z0+z1)/2.0)/(self.path.nz-1.0) + color = (255.0*i+color[0]*(1.0-i),255.0*i+color[1]*(1.0-i),255.0*i+color[2]*(1.0-i)) + # + # rotate + # + if (self.path.dof > 2): + if (self.path.nz > 1): + (x0,y0,z0) = self.rotate(x0,y0,z0) + (x1,y1,z1) = self.rotate(x1,y1,z1) + # + # pan + # + if (self.sx != []): + self.px = self.mx - self.sx + if (self.sy != []): + self.py = self.my - self.sy + # + # zoom + # + xi0 = self.ox + self.px + self.zx + self.scale*(xsize*(x0/(self.path.nx-1.0))-self.zx) + xi1 = self.ox + self.px + self.zx + self.scale*(xsize*(x1/(self.path.nx-1.0))-self.zx) + yi0 = self.oy + self.py + self.zy + self.scale*(ysize*(y0/(self.path.ny-1.0))-self.zy) + yi1 = self.oy + self.py + self.zy + self.scale*(ysize*(y1/(self.path.ny-1.0))-self.zy) + # + # draw line + # + self.dc.SetPen(wx.Pen(color,1)) + self.dc.DrawLine(xi0,yi0,xi1,yi1) + # + # draw arrow head + # + if (end == "arrow"): + d = math.sqrt((xi1-xi0)*(xi1-xi0)+(yi1-yi0)*(yi1-yi0)) + if (d > 0): + dx = 4*(xi1-xi0)/d + dy = 4*(yi1-yi0)/d + self.dc.DrawLine(xi1,yi1,xi1-dx+dy,yi1-dy-dx) + self.dc.DrawLine(xi1,yi1,xi1-dx-dy,yi1-dy+dx) + self.dc.DrawLine(xi1-dx+dy,yi1-dy-dx,xi1-dx-dy,yi1-dy+dx) + # + # real to panel coordinates + # + def coords(self,p): + if (len(p) == 2): + ix = self.path.nx*(p[0]-self.path.xmin)/self.path.dx + iy = self.path.nx*(self.path.ymin+self.path.dy-p[1])/self.path.dx + return([ix,iy]) + elif (len(p) >= 3): + ix = self.path.nx*(p[0]-self.path.xmin)/self.path.dx + iy = self.path.nx*(self.path.ymin+self.path.dy-p[1])/self.path.dx + iz = self.path.nx*(p[2]-self.path.zmin)/self.path.dx + return([ix,iy,iz]) + # + # paint panel + # + def paint(self,event): + self.dc = wx.PaintDC(self.panel) + # + # return if no path + # + if (len(self.path.segments) == 0): + return + # + # return if view none + # + if (self.view_type == "none"): + return + # + # draw axes + # + if (self.path.dof == 2): + self.draw_line(self.coords([0,0]),self.coords([self.path.dx/10.0,0]),(0,255,0),end="arrow") + self.draw_line(self.coords([0,0]),self.coords([0,self.path.dx/10.0]),(0,255,255),end="arrow") + elif (self.path.dof >= 3): + self.draw_line(self.coords([0,0,0]),self.coords([self.path.dx/10.0,0,0]),(0,255,0),end="arrow") + self.draw_line(self.coords([0,0,0]),self.coords([0,self.path.dx/10.0,0]),(0,255,255),end="arrow") + self.draw_line(self.coords([0,0,0]),self.coords([0,0,self.path.dx/10.0]),(255,0,255),end="arrow") + # + # loop over segments + # + if (self.view_type == "segments"): + for segment in range(len(self.path.segments)): + s0 = self.path.segments[segment] + # + # loop over points + # + for point in range(len(s0)-1): + self.draw_line(s0[point],s0[point+1],(0,0,255),shading='z',end="none") + elif (self.view_type == "segments+directions"): + for segment in range(len(self.path.segments)): + s0 = self.path.segments[segment] + # + # loop over points + # + for point in range(len(s0)-1): + self.draw_line(s0[point],s0[point+1],(0,0,255),shading='z',end="arrow") + elif (self.view_type == "segments+directions+connections"): + for segment in range(len(self.path.segments)): + s0 = self.path.segments[segment] + # + # loop over points + # + for point in range(len(s0)-1): + self.draw_line(s0[point],s0[point+1],(0,0,255),shading='z',end="arrow") + # + # draw path to next segment + # + if (segment < (len(self.path.segments)-1)): + s1 = self.path.segments[segment+1] + self.draw_line(s0[-1],s1[0],(255,0,0),shading='z',end="arrow") + # + # mouse move: pan + # + def mouse_move(self,event): + self.mx = event.GetX() + self.my = event.GetY() + size = self.parent.parent.size + if (self.sx != []): + # + # panning + # + self.panel.Refresh() + if (self.rx != []): + # + # rotating + # + self.theta_z = self.theta_zs + math.pi*(self.mx-self.rx)/(size-1.0) + self.theta_x = self.theta_xs + math.pi*(self.ry-self.my)/(size-1.0) + self.panel.Refresh() + # + # mouse left down: start pan + # + def mouse_left_down(self,event): + self.sx = event.GetX() + self.sy = event.GetY() + # + # mouse left up: stop pan + # + def mouse_left_up(self,event): + self.sx = [] + self.sy = [] + self.ox = self.ox + self.px + self.oy = self.oy + self.py + self.px = 0 + self.py = 0 + # + # mouse right down: start rotate + # + def mouse_right_down(self,event): + self.rx = event.GetX() + self.ry = event.GetY() + self.theta_xs = self.theta_x + self.theta_zs = self.theta_z + # + # mouse right up: stop rotate + # + def mouse_right_up(self,event): + self.rx = [] + self.ry = [] + # + # mouse wheel: zoom + # + def mouse_wheel(self,event): + mx = (event.GetX() - self.ox - self.zx)/self.scale + self.zx + my = (event.GetY() - self.oy - self.zy)/self.scale + self.zy + self.ox = self.ox + (self.scale - 1.0)*(mx - self.zx) + self.oy = self.oy + (self.scale - 1.0)*(my - self.zy) + self.zx = mx + self.zy = my + if (event.GetWheelRotation() > 0): + self.scale *= 1.1 + else: + self.scale *= 0.9 + self.panel.Refresh() + # + # reset view + # + def reset_view(self,event): + self.scale = 1.0 + self.zx = 0 + self.zy = 0 + self.px = 0 + self.py = 0 + self.ox = 0 + self.oy = 0 + self.sx = [] + self.sy = [] + self.theta_x = 0 + self.theta_z = 0 + self.panel.Refresh() + # + # parent call to update size + # + def update_size(self,sizex,sizey): + self.Layout() + self.Fit() diff --git a/src/py/panel_path_camm.py b/src/py/panel_path_camm.py new file mode 100644 index 0000000..ae0301e --- /dev/null +++ b/src/py/panel_path_camm.py @@ -0,0 +1,120 @@ +# +# panel_path_camm.py +# make .camm from .path +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class path_camm_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make file + # + def make_file(event): + if (self.parent.path_file == ''): + print 'panel_path_camm: oops -- need path file' + return + self.parent.camm_file = self.parent.tmp+self.parent.rootname+'.camm' + force = self.force.GetValue() + velocity = self.velocity.GetValue() + ox = self.origin_x.GetValue() + oy = self.origin_y.GetValue() + if self.top_left.GetValue(): + loc = 'L' + elif self.top_right.GetValue(): + loc = 'R' + elif self.bottom_left.GetValue(): + loc = 'l' + elif self.bottom_right.GetValue(): + loc = 'r' + command = 'path_camm '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.camm_file+'\"'+' '+force+' '+velocity+' '+ox+' '+oy+' '+loc + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.camm_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: camm') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .camm') + make.Bind(wx.EVT_BUTTON,make_file) + self.sizer.Add(make,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + force_panel = wx.Panel(self) + force_sizer = wx.GridBagSizer(10,10) + force_panel.SetSizer(force_sizer) + force_sizer.Add(wx.StaticText(force_panel,label='force (g)'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.force = wx.TextCtrl(force_panel,-1,'45') + force_sizer.Add(self.force,(0,1),flag=wx.ALIGN_LEFT) + # + force_sizer.Add(wx.StaticText(force_panel,label='velocity (cm/2)'),(1,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.velocity = wx.TextCtrl(force_panel,-1,'2') + force_sizer.Add(self.velocity,(1,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(force_panel,(3,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + origin_panel = wx.Panel(self) + origin_sizer = wx.GridBagSizer(10,10) + origin_panel.SetSizer(origin_sizer) + self.top_left = wx.RadioButton(origin_panel,-1,'left',(10,10),style=wx.RB_GROUP) + origin_sizer.Add(self.top_left,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + origin_sizer.Add(wx.StaticText(origin_panel,label='top'),(0,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.top_right = wx.RadioButton(origin_panel,-1,'right',(10,10)) + origin_sizer.Add(self.top_right,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.origin_x = wx.TextCtrl(origin_panel,-1,'0') + origin_sizer.Add(self.origin_x,(1,0),flag=wx.ALIGN_RIGHT) + origin_sizer.Add(wx.StaticText(origin_panel,label='x origin (mm) y'),(1,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.origin_y = wx.TextCtrl(origin_panel,-1,'0') + origin_sizer.Add(self.origin_y,(1,2),flag=wx.ALIGN_LEFT) + # + self.bottom_left = wx.RadioButton(origin_panel,-1,'left',(10,10)) + origin_sizer.Add(self.bottom_left,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.bottom_left.SetValue(True) + origin_sizer.Add(wx.StaticText(origin_panel,label='bottom'),(2,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bottom_right = wx.RadioButton(origin_panel,-1,'right',(10,10)) + origin_sizer.Add(self.bottom_right,(2,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.sizer.Add(origin_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_dxf.py b/src/py/panel_path_dxf.py new file mode 100644 index 0000000..17c1e6b --- /dev/null +++ b/src/py/panel_path_dxf.py @@ -0,0 +1,73 @@ +# +# panel_path_dxf.py +# make .dxf from .path +# +# Neil Gershenfeld +# CBA MIT 8/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class path_dxf_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make dxf + # + def make_dxf(event): + if (self.parent.path_file == ''): + print 'panel_path_dxf: oops -- need path file' + return + self.parent.dxf_file = self.parent.tmp+self.parent.rootname+'.dxf' + command = 'path_dxf '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.dxf_file+'\"' + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.dxf_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: dxf') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .dxf') + make.Bind(wx.EVT_BUTTON,make_dxf) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_epi.py b/src/py/panel_path_epi.py new file mode 100644 index 0000000..c277291 --- /dev/null +++ b/src/py/panel_path_epi.py @@ -0,0 +1,248 @@ +# +# panel_path_epi.py +# make .epi from .path +# +# Neil Gershenfeld 8/19/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# + +# +# imports +# +import wx,os,string +# +# panel class +# +class path_epi_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make epi + # + def make_epi(event): + if (self.parent.path_file == ''): + print 'panel_path_epi: oops -- need path file' + return + self.parent.epi_file = self.parent.tmp+self.parent.rootname+'.epi' + if (string.find(self.parent.path_type,"2D") != -1): + power = self.power_2D.GetValue() + if (self.focus_2D.GetValue()): + focus = '1' + else: + focus = '0' + ox = self.origin_x_2D.GetValue() + oy = self.origin_y_2D.GetValue() + if self.top_left_2D.GetValue(): + loc = 'L' + elif self.top_right_2D.GetValue(): + loc = 'R' + elif self.bottom_left_2D.GetValue(): + loc = 'l' + elif self.bottom_right_2D.GetValue(): + loc = 'r' + speed = self.speed_2D.GetValue() + rate = self.rate_2D.GetValue() + command = 'path_epi '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.epi_file+'\"'+' '+power+' '+speed+' '+focus+' '+ox+' '+oy+' '+loc+' '+' '+rate + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + elif (string.find(self.parent.path_type,"3D") != -1): + min_power = self.min_power_3D.GetValue() + max_power = self.max_power_3D.GetValue() + if (self.focus_3D.GetValue()): + focus = '1' + else: + focus = '0' + ox = self.origin_x_3D.GetValue() + oy = self.origin_y_3D.GetValue() + if self.top_left_3D.GetValue(): + loc = 'L' + elif self.top_right_3D.GetValue(): + loc = 'R' + elif self.bottom_left_3D.GetValue(): + loc = 'l' + elif self.bottom_right_3D.GetValue(): + loc = 'r' + speed = self.speed_3D.GetValue() + rate = self.rate_3D.GetValue() + command = 'path_epi '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.epi_file+'\"'+' '+min_power+' '+speed+' '+focus+' '+ox+' '+oy+' '+loc+' '+' '+rate+' '+max_power + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + else: + print "panel_path_epi: oops -- don't recognize path type" + return + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.epi_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: epi') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .epi') + make.Bind(wx.EVT_BUTTON,make_epi) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # 2D panel + # + self.panel_2D = wx.Panel(self) + sizer_2D = wx.GridBagSizer(10,10) + self.panel_2D.SetSizer(sizer_2D) + # + self.focus_2D = wx.CheckBox(self.panel_2D,-1,'autofocus') + sizer_2D.Add(self.focus_2D,(0,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_2D.Add(wx.StaticText(self.panel_2D,label='power (%)'),(1,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.power_2D = wx.TextCtrl(self.panel_2D,-1,'25') + sizer_2D.Add(self.power_2D,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + set_panel_2D = wx.Panel(self.panel_2D) + set_sizer_2D = wx.GridBagSizer(10,10) + set_panel_2D.SetSizer(set_sizer_2D) + # + set_sizer_2D.Add(wx.StaticText(set_panel_2D,label='speed (%)'),(0,0),flag=wx.ALIGN_RIGHT) + set_sizer_2D.Add(wx.StaticText(set_panel_2D,label='rate'),(0,1),flag=wx.ALIGN_LEFT) + # + self.speed_2D = wx.TextCtrl(set_panel_2D,-1,'75') + set_sizer_2D.Add(self.speed_2D,(1,0),flag=wx.ALIGN_RIGHT) + self.rate_2D = wx.TextCtrl(set_panel_2D,-1,'500') + set_sizer_2D.Add(self.rate_2D,(1,1),flag=wx.ALIGN_LEFT) + # + sizer_2D.Add(set_panel_2D,(3,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + origin_panel_2D = wx.Panel(self.panel_2D) + origin_sizer_2D = wx.GridBagSizer(10,10) + origin_panel_2D.SetSizer(origin_sizer_2D) + # + self.top_left_2D = wx.RadioButton(origin_panel_2D,-1,'left',(10,10),style=wx.RB_GROUP) + origin_sizer_2D.Add(self.top_left_2D,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + origin_sizer_2D.Add(wx.StaticText(origin_panel_2D,label='top'),(0,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.top_right_2D = wx.RadioButton(origin_panel_2D,-1,'right',(10,10)) + origin_sizer_2D.Add(self.top_right_2D,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.origin_x_2D = wx.TextCtrl(origin_panel_2D,-1,'10') + origin_sizer_2D.Add(self.origin_x_2D,(1,0),flag=wx.ALIGN_RIGHT) + origin_sizer_2D.Add(wx.StaticText(origin_panel_2D,label='x origin (mm) y'),(1,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.origin_y_2D = wx.TextCtrl(origin_panel_2D,-1,'10') + origin_sizer_2D.Add(self.origin_y_2D,(1,2),flag=wx.ALIGN_LEFT) + # + self.bottom_left_2D = wx.RadioButton(origin_panel_2D,-1,'left',(10,10)) + origin_sizer_2D.Add(self.bottom_left_2D,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + origin_sizer_2D.Add(wx.StaticText(origin_panel_2D,label='bottom'),(2,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bottom_right_2D = wx.RadioButton(origin_panel_2D,-1,'right',(10,10)) + # + origin_sizer_2D.Add(self.bottom_right_2D,(2,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + sizer_2D.Add(origin_panel_2D,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + self.sizer.Add(self.panel_2D,(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + self.path_type = "2D" + # + # 3D panel + # + self.panel_3D = wx.Panel(self) + sizer_3D = wx.GridBagSizer(10,10) + self.panel_3D.SetSizer(sizer_3D) + # + self.focus_3D = wx.CheckBox(self.panel_3D,-1,'autofocus') + sizer_3D.Add(self.focus_3D,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + set_panel_3D = wx.Panel(self.panel_3D) + set_sizer_3D = wx.GridBagSizer(10,10) + set_panel_3D.SetSizer(set_sizer_3D) + # + set_sizer_3D.Add(wx.StaticText(set_panel_3D,label='min z power (%)'),(0,0),flag=wx.ALIGN_RIGHT) + set_sizer_3D.Add(wx.StaticText(set_panel_3D,label='max z power (%)'),(0,1),flag=wx.ALIGN_LEFT) + # + self.min_power_3D = wx.TextCtrl(set_panel_3D,-1,'25') + set_sizer_3D.Add(self.min_power_3D,(1,0),flag=wx.ALIGN_RIGHT) + self.max_power_3D = wx.TextCtrl(set_panel_3D,-1,'25') + set_sizer_3D.Add(self.max_power_3D,(1,1),flag=wx.ALIGN_LEFT) + # + set_sizer_3D.Add(wx.StaticText(set_panel_3D,label='speed (%)'),(2,0),flag=wx.ALIGN_RIGHT) + set_sizer_3D.Add(wx.StaticText(set_panel_3D,label='rate'),(2,1),flag=wx.ALIGN_LEFT) + # + self.speed_3D = wx.TextCtrl(set_panel_3D,-1,'75') + set_sizer_3D.Add(self.speed_3D,(3,0),flag=wx.ALIGN_RIGHT) + self.rate_3D = wx.TextCtrl(set_panel_3D,-1,'500') + set_sizer_3D.Add(self.rate_3D,(3,1),flag=wx.ALIGN_LEFT) + # + sizer_3D.Add(set_panel_3D,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + origin_panel_3D = wx.Panel(self.panel_3D) + origin_sizer_3D = wx.GridBagSizer(10,10) + origin_panel_3D.SetSizer(origin_sizer_3D) + # + self.top_left_3D = wx.RadioButton(origin_panel_3D,-1,'left',(10,10),style=wx.RB_GROUP) + origin_sizer_3D.Add(self.top_left_3D,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + origin_sizer_3D.Add(wx.StaticText(origin_panel_3D,label='top'),(0,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.top_right_3D = wx.RadioButton(origin_panel_3D,-1,'right',(10,10)) + origin_sizer_3D.Add(self.top_right_3D,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.origin_x_3D = wx.TextCtrl(origin_panel_3D,-1,'10') + origin_sizer_3D.Add(self.origin_x_3D,(1,0),flag=wx.ALIGN_RIGHT) + origin_sizer_3D.Add(wx.StaticText(origin_panel_3D,label='x origin (mm) y'),(1,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.origin_y_3D = wx.TextCtrl(origin_panel_3D,-1,'10') + origin_sizer_3D.Add(self.origin_y_3D,(1,2),flag=wx.ALIGN_LEFT) + # + self.bottom_left_3D = wx.RadioButton(origin_panel_3D,-1,'left',(10,10)) + origin_sizer_3D.Add(self.bottom_left_3D,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + origin_sizer_3D.Add(wx.StaticText(origin_panel_3D,label='bottom'),(2,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bottom_right_3D = wx.RadioButton(origin_panel_3D,-1,'right',(10,10)) + origin_sizer_3D.Add(self.bottom_right_3D,(2,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + sizer_3D.Add(origin_panel_3D,(2,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + self.panel_3D.Hide() + # + # parent call to update panel + # + def update_panel(self): + if (string.find(self.parent.path_type,"3D") != -1): + self.sizer.Detach(self.panel_2D) + self.panel_2D.Hide() + self.sizer.Add(self.panel_3D,(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + self.panel_3D.Show() + elif (string.find(self.parent.path_type,"2D") != -1): + self.sizer.Detach(self.panel_3D) + self.panel_3D.Hide() + self.sizer.Add(self.panel_2D,(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + self.panel_2D.Show() + self.Layout() + self.Fit() diff --git a/src/py/panel_path_eps.py b/src/py/panel_path_eps.py new file mode 100644 index 0000000..8e46d42 --- /dev/null +++ b/src/py/panel_path_eps.py @@ -0,0 +1,76 @@ +# +# panel_path_eps.py +# make .eps from .path +# +# Neil Gershenfeld 7/4/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,os +# +# panel class +# +class path_eps_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make eps + # + def make_eps(event): + if (self.parent.path_file == ''): + print 'make_png_eps: oops -- need path file' + return + self.parent.eps_file = self.parent.tmp+self.parent.rootname+'.eps' + command = 'path_eps '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.eps_file+'\"' + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.eps_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: eps') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .eps') + make.Bind(wx.EVT_BUTTON,make_eps) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_g.py b/src/py/panel_path_g.py new file mode 100644 index 0000000..7315a37 --- /dev/null +++ b/src/py/panel_path_g.py @@ -0,0 +1,167 @@ +# +# panel_path_g.py +# make .g from .path +# +# Neil Gershenfeld +# CBA MIT 2/26/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class path_g_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make file + # + def make_file(event): + if (self.parent.path_file == ''): + print 'panel_path_g: oops -- need path file' + return + self.parent.g_file = self.parent.tmp+self.parent.rootname+'.g' + if (self.conv.GetValue()): + direction = '0' + else: + direction = '1' + height = self.height.GetValue() + plunge = self.plunge.GetValue() + speed = self.speed.GetValue() + spindle = self.spindle.GetValue() + tool = self.tool.GetValue() + if (self.on.GetValue()): + coolant = '1' + else: + coolant = '0' + command = 'path_g '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.g_file+'\"'+' '+direction+' '+height+' '+speed+' '+plunge+' '+spindle+' '+tool+' '+coolant + print command + os.system(command) + temp_name = self.parent.tmp+'path_info' + command = 'path_time '+'\"'+self.parent.path_file+'\"'+' '+speed+' '+height+' > '+'\"'+temp_name+'\"' + print command + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + start = 11+string.find(output,'path time: ') + end = 5+string.find(output,'hours',start) + times = output[start:end] + self.info.SetLabel(times) + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.g_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: g') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # info + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + make = wx.Button(self,label='make .g') + make.Bind(wx.EVT_BUTTON,make_file) + self.sizer.Add(make,(3,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + dir_panel = wx.Panel(self) + dir_sizer = wx.GridBagSizer(10,10) + dir_panel.SetSizer(dir_sizer) + self.conv = wx.RadioButton(dir_panel,label='conventional',style=wx.RB_GROUP) + dir_sizer.Add(self.conv,(0,0)) + self.climb = wx.RadioButton(dir_panel,label='climb') + dir_sizer.Add(self.climb,(0,1)) + self.sizer.Add(dir_panel,(4,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row5_panel = wx.Panel(self) + row5_sizer = wx.GridBagSizer(10,10) + row5_panel.SetSizer(row5_sizer) + row5_sizer.Add(wx.StaticText(row5_panel,label=' cut speed (mm/s)'),(0,0),flag=(wx.ALIGN_RIGHT)) + row5_sizer.Add(wx.StaticText(row5_panel,label='plunge speed (mm/s)'),(0,1),flag=(wx.ALIGN_LEFT)) + self.sizer.Add(row5_panel,(5,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + self.speed = wx.TextCtrl(row6_panel,-1,'5') + row6_sizer.Add(self.speed,(0,0),flag=(wx.ALIGN_RIGHT)) + self.plunge = wx.TextCtrl(row6_panel,-1,'2.5') + row6_sizer.Add(self.plunge,(0,1),flag=(wx.ALIGN_LEFT)) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + row7_sizer.Add(wx.StaticText(row7_panel,label='spindle speed (RPM)'),(0,0),flag=(wx.ALIGN_RIGHT)) + row7_sizer.Add(wx.StaticText(row7_panel,label='jog height (mm) '),(0,1),flag=(wx.ALIGN_LEFT)) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row8_panel = wx.Panel(self) + row8_sizer = wx.GridBagSizer(10,10) + row8_panel.SetSizer(row8_sizer) + self.spindle = wx.TextCtrl(row8_panel,-1,'10000') + row8_sizer.Add(self.spindle,(0,0),flag=(wx.ALIGN_RIGHT)) + self.height = wx.TextCtrl(row8_panel,-1,'5') + row8_sizer.Add(self.height,(0,1),flag=(wx.ALIGN_LEFT)) + self.sizer.Add(row8_panel,(8,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row9_panel = wx.Panel(self) + row9_sizer = wx.GridBagSizer(10,10) + row9_panel.SetSizer(row9_sizer) + row9_sizer.Add(wx.StaticText(row9_panel,label='tool number'),(0,0),flag=(wx.ALIGN_RIGHT)) + row9_sizer.Add(wx.StaticText(row9_panel,label='coolant '),(0,1),flag=(wx.ALIGN_LEFT)) + self.sizer.Add(row9_panel,(9,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row10_panel = wx.Panel(self) + row10_sizer = wx.GridBagSizer(10,10) + row10_panel.SetSizer(row10_sizer) + self.tool = wx.TextCtrl(row10_panel,-1,'1') + row10_sizer.Add(self.tool,(0,0),flag=(wx.ALIGN_RIGHT)) + coolant_panel = wx.Panel(row10_panel) + coolant_sizer = wx.GridBagSizer(10,10) + coolant_panel.SetSizer(coolant_sizer) + self.on = wx.RadioButton(coolant_panel,label='on',style=wx.RB_GROUP) + coolant_sizer.Add(self.on,(0,0)) + self.off = wx.RadioButton(coolant_panel,label='no') + coolant_sizer.Add(self.off,(0,1)) + row10_sizer.Add(coolant_panel,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(row10_panel,(10,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_oms.py b/src/py/panel_path_oms.py new file mode 100644 index 0000000..1f7b577 --- /dev/null +++ b/src/py/panel_path_oms.py @@ -0,0 +1,113 @@ +# +# panel_path_oms.py +# make .oms from .path +# +# Neil Gershenfeld +# CBA MIT 5/25/13 +# +# (c) Massachusetts Institute of Technology 2013 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class path_oms_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make oms + # + def make_oms(event): + if (self.parent.path_file == ''): + print 'panel_path_oms: oops -- need path file' + return + self.parent.oms_file = self.parent.tmp+self.parent.rootname+'.oms' + velocity = self.velocity.GetValue() + accel = self.accel.GetValue() + period = self.period.GetValue() + command = 'path_oms '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.oms_file+'\"'+' '+velocity+' '+accel+' '+period + print command + os.system(command) + self.button.SetMaxSize((self.parent.xsize,self.parent.ysize)) + self.button.SetMinSize((self.parent.xsize,self.parent.ysize)) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.oms_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: oms') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .oms') + make.Bind(wx.EVT_BUTTON,make_oms) + self.sizer.Add(make,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row3_panel = wx.Panel(self) + row3_sizer = wx.GridBagSizer(10,10) + row3_panel.SetSizer(row3_sizer) + row3_sizer.Add(wx.StaticText(row3_panel,label='velocity'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row3_panel,(3,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row4_panel = wx.Panel(self) + row4_sizer = wx.GridBagSizer(10,10) + row4_panel.SetSizer(row4_sizer) + self.velocity = wx.TextCtrl(row4_panel,-1,'0.1') + row4_sizer.Add(self.velocity,(0,0)) + self.sizer.Add(row4_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row5_panel = wx.Panel(self) + row5_sizer = wx.GridBagSizer(10,10) + row5_panel.SetSizer(row5_sizer) + row5_sizer.Add(wx.StaticText(row5_panel,label='acceleration'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row5_panel,(5,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + self.accel = wx.TextCtrl(row6_panel,-1,'5.0') + row6_sizer.Add(self.accel,(0,0)) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + row7_sizer.Add(wx.StaticText(row7_panel,label='period'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row8_panel = wx.Panel(self) + row8_sizer = wx.GridBagSizer(10,10) + row8_panel.SetSizer(row8_sizer) + self.period = wx.TextCtrl(row8_panel,-1,'10000') + row8_sizer.Add(self.period,(0,0)) + self.sizer.Add(row8_panel,(8,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) diff --git a/src/py/panel_path_ord.py b/src/py/panel_path_ord.py new file mode 100644 index 0000000..f3b6fa8 --- /dev/null +++ b/src/py/panel_path_ord.py @@ -0,0 +1,91 @@ +# +# panel_path_ord.py +# make .ord from .path +# +# Neil Gershenfeld +# CBA MIT 2/26/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class path_ord_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make file + # + def make_file(event): + if (self.parent.path_file == ''): + print 'panel_path_ord: oops -- need path file' + return + self.parent.ord_file = self.parent.tmp+self.parent.rootname+'.ord' + lead = self.lead.GetValue() + quality = self.quality.GetValue() + command = 'path_ord '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.ord_file+'\"'+' '+lead+' '+quality + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.ord_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: ord') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .ord') + make.Bind(wx.EVT_BUTTON,make_file) + self.sizer.Add(make,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row3_panel = wx.Panel(self) + row3_sizer = wx.GridBagSizer(10,10) + row3_panel.SetSizer(row3_sizer) + row3_sizer.Add(wx.StaticText(row3_panel,label='lead in/out (mm)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row3_sizer.Add(wx.StaticText(row3_panel,label='cut quality '),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row3_panel,(3,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row4_panel = wx.Panel(self) + row4_sizer = wx.GridBagSizer(10,10) + row4_panel.SetSizer(row4_sizer) + self.lead= wx.TextCtrl(row4_panel,-1,'2') + row4_sizer.Add(self.lead,(0,0)) + self.quality= wx.TextCtrl(row4_panel,-1,'-3') + row4_sizer.Add(self.quality,(0,1)) + self.sizer.Add(row4_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_plt.py b/src/py/panel_path_plt.py new file mode 100755 index 0000000..30a374e --- /dev/null +++ b/src/py/panel_path_plt.py @@ -0,0 +1,121 @@ +# +# panel_path_plt.py +# make .plt from .path +# +# by Kenny Cheung CBA MIT 21Aug2012 +# from panel_path_plt.py Neil Gershenfeld CBA MIT 19Feb2011 +# +# imports +# +import wx,os +# +# panel class +# +class path_plt_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make file + # + def make_file(event): + if (self.parent.path_file == ''): + print 'panel_path_plt: oops -- need path file' + return + self.parent.plt_file = self.parent.tmp+self.parent.rootname+'.plt' + if (self.conv.GetValue()): + direction = '0' + else: + direction = '1' + self.parent.plt_file = self.parent.tmp+self.parent.rootname+'.plt' + spindle = self.spindle.GetValue() + speed = self.speed.GetValue() + jog = self.jog.GetValue() + height = self.height.GetValue() + command = 'path_plt '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.plt_file+'\"'+' '+direction+' '+spindle+' '+speed+' '+speed+' '+jog+' '+jog+' '+height + print command + os.system(command) + self.button.SetMaxSize((self.parent.xsize,self.parent.ysize)) + self.button.SetMinSize((self.parent.xsize,self.parent.ysize)) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.plt_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: plt') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .plt') + make.Bind(wx.EVT_BUTTON,make_file) + self.sizer.Add(make,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + dir_panel = wx.Panel(self) + dir_sizer = wx.GridBagSizer(10,10) + dir_panel.SetSizer(dir_sizer) + self.conv = wx.RadioButton(dir_panel,label='conventional',style=wx.RB_GROUP) + dir_sizer.Add(self.conv,(0,0)) + self.climb = wx.RadioButton(dir_panel,label='climb') + dir_sizer.Add(self.climb,(0,1)) + self.sizer.Add(dir_panel,(3,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row4_panel = wx.Panel(self) + row4_sizer = wx.GridBagSizer(10,10) + row4_panel.SetSizer(row4_sizer) + row4_sizer.Add(wx.StaticText(row4_panel,label='cut speed (mm/s)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row4_sizer.Add(wx.StaticText(row4_panel,label='jog speed (mm/s)'),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row4_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row5_panel = wx.Panel(self) + row5_sizer = wx.GridBagSizer(10,10) + row5_panel.SetSizer(row5_sizer) + self.speed = wx.TextCtrl(row5_panel,-1,'15') + row5_sizer.Add(self.speed,(0,0)) + self.jog = wx.TextCtrl(row5_panel,-1,'75') + row5_sizer.Add(self.jog,(0,1)) + self.sizer.Add(row5_panel,(5,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + row6_sizer.Add(wx.StaticText(row6_panel,label='spindle speed (RPM)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row6_sizer.Add(wx.StaticText(row6_panel,label='jog height (mm) '),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + self.spindle = wx.TextCtrl(row7_panel,-1,'10000') + row7_sizer.Add(self.spindle,(0,0)) + self.height = wx.TextCtrl(row7_panel,-1,'5') + row7_sizer.Add(self.height,(0,1)) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_rml.py b/src/py/panel_path_rml.py new file mode 100644 index 0000000..8dbd4f0 --- /dev/null +++ b/src/py/panel_path_rml.py @@ -0,0 +1,140 @@ +# +# panel_path_rml.py +# make .rml from .path +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class path_rml_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make rml + # + def make_rml(event): + if (self.parent.path_file == ''): + print 'panel_path_rml: oops -- need path file' + return + self.parent.rml_file = self.parent.tmp+self.parent.rootname+'.rml' + speed = self.speed.GetValue() + direction = '1' + zjog = self.zjog.GetValue() + xmin = self.xmin.GetValue() + ymin = self.ymin.GetValue() + command = 'path_rml '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.rml_file+'\"'+' '+speed+' '+direction+' '+zjog+' '+xmin+' '+ymin + print command + os.system(command) + temp_name = self.parent.tmp+'path_info' + command = 'path_time '+'\"'+self.parent.path_file+'\"'+' '+speed+' '+zjog+' > '+'\"'+temp_name+'\"' + print command + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + start = 11+string.find(output,'path time: ') + end = 5+string.find(output,'hours',start) + times = output[start:end] + self.info.SetLabel(times) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # rml move + # + def move_rml(event): + xmin = self.xmin.GetValue() + ymin = self.ymin.GetValue() + command = 'rml_move '+xmin+' '+ymin + print command + os.system(command) + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.rml_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: rml') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # info + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + make = wx.Button(self,label='make .rml') + make.Bind(wx.EVT_BUTTON,make_rml) + self.sizer.Add(make,(3,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row4_panel = wx.Panel(self) + row4_sizer = wx.GridBagSizer(10,10) + row4_panel.SetSizer(row4_sizer) + row4_sizer.Add(wx.StaticText(row4_panel,label='speed (mm/s)'),(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + row4_sizer.Add(wx.StaticText(row4_panel,label='jog (mm) '),(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.sizer.Add(row4_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row5_panel = wx.Panel(self) + row5_sizer = wx.GridBagSizer(10,10) + row5_panel.SetSizer(row5_sizer) + self.speed = wx.TextCtrl(row5_panel,-1,'4') + row5_sizer.Add(self.speed,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.zjog = wx.TextCtrl(row5_panel,-1,'1') + row5_sizer.Add(self.zjog,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.sizer.Add(row5_panel,(5,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + row6_sizer.Add(wx.StaticText(row6_panel,label='xmin (mm)'),(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + row6_sizer.Add(wx.StaticText(row6_panel,label='ymin (mm)'),(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + self.xmin = wx.TextCtrl(row7_panel,-1,'20') + row7_sizer.Add(self.xmin,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.ymin = wx.TextCtrl(row7_panel,-1,'20') + row7_sizer.Add(self.ymin,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + move = wx.Button(self,label='move to xmin,ymin') + move.Bind(wx.EVT_BUTTON,move_rml) + self.sizer.Add(move,(8,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_sbp.py b/src/py/panel_path_sbp.py new file mode 100644 index 0000000..3ce34bf --- /dev/null +++ b/src/py/panel_path_sbp.py @@ -0,0 +1,154 @@ +# +# panel_path_sbp.py +# make .sbp from .path +# +# Neil Gershenfeld +# CBA MIT 3/23/13 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class path_sbp_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make file + # + def make_file(event): + if (self.parent.path_file == ''): + print 'panel_path_sbp: oops -- need path file' + return + self.parent.sbp_file = self.parent.tmp+self.parent.rootname+'.sbp' + if (self.conv.GetValue()): + direction = '0' + else: + direction = '1' + if (self.inches.GetValue()): + units = '25.4' + else: + units = '1' + self.parent.sbp_file = self.parent.tmp+self.parent.rootname+'.sbp' + spindle = self.spindle.GetValue() + speed = self.speed.GetValue() + jog = self.jog.GetValue() + height = self.height.GetValue() + command = 'path_sbp '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.sbp_file+'\"'+' '+direction+' '+spindle+' '+speed+' '+speed+' '+jog+' '+jog+' '+height+' '+units + print command + os.system(command) + temp_name = self.parent.tmp+'path_info' + command = 'path_time '+'\"'+self.parent.path_file+'\"'+' '+speed+' '+height+' '+jog+' > '+'\"'+temp_name+'\"' + print command + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + start = 11+string.find(output,'path time: ') + end = 5+string.find(output,'hours',start) + times = output[start:end] + self.info.SetLabel(times) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.sbp_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: sbp') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # info + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + make = wx.Button(self,label='make .sbp') + make.Bind(wx.EVT_BUTTON,make_file) + self.sizer.Add(make,(3,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + units_panel = wx.Panel(self) + units_sizer = wx.GridBagSizer(10,10) + units_panel.SetSizer(units_sizer) + units_sizer.Add(wx.StaticText(units_panel,label='file units:'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.inches = wx.RadioButton(units_panel,label='inches',style=wx.RB_GROUP) + units_sizer.Add(self.inches,(0,1)) + self.mm = wx.RadioButton(units_panel,label='mm') + units_sizer.Add(self.mm,(0,2)) + self.sizer.Add(units_panel,(4,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + dir_panel = wx.Panel(self) + dir_sizer = wx.GridBagSizer(10,10) + dir_panel.SetSizer(dir_sizer) + self.conv = wx.RadioButton(dir_panel,label='conventional',style=wx.RB_GROUP) + dir_sizer.Add(self.conv,(0,0)) + self.climb = wx.RadioButton(dir_panel,label='climb') + dir_sizer.Add(self.climb,(0,1)) + self.sizer.Add(dir_panel,(5,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + row6_sizer.Add(wx.StaticText(row6_panel,label='cut speed (mm/s)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row6_sizer.Add(wx.StaticText(row6_panel,label='jog speed (mm/s)'),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + self.speed = wx.TextCtrl(row7_panel,-1,'15') + row7_sizer.Add(self.speed,(0,0)) + self.jog = wx.TextCtrl(row7_panel,-1,'75') + row7_sizer.Add(self.jog,(0,1)) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row8_panel = wx.Panel(self) + row8_sizer = wx.GridBagSizer(10,10) + row8_panel.SetSizer(row8_sizer) + row8_sizer.Add(wx.StaticText(row8_panel,label='spindle speed (RPM)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row8_sizer.Add(wx.StaticText(row8_panel,label='jog height (mm) '),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row8_panel,(8,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row9_panel = wx.Panel(self) + row9_sizer = wx.GridBagSizer(10,10) + row9_panel.SetSizer(row9_sizer) + self.spindle = wx.TextCtrl(row9_panel,-1,'10000') + row9_sizer.Add(self.spindle,(0,0)) + self.height = wx.TextCtrl(row9_panel,-1,'5') + row9_sizer.Add(self.height,(0,1)) + self.sizer.Add(row9_panel,(9,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_snap.py b/src/py/panel_path_snap.py new file mode 100644 index 0000000..181fc7b --- /dev/null +++ b/src/py/panel_path_snap.py @@ -0,0 +1,633 @@ +# +# panel_path_snap.py +# MTM Snap virtual machine +# +# Neil Gershenfeld +# CBA MIT 12/13/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# todo +# process text entry +# acceleration +# job times +# +# imports +# +import wx,os,serial,time +from math import * +# +# machine definitions +# +mm_per_xstep = 0.00635 # stepper step size (400 steps/rev, 10 revs/in) +mm_per_ystep = 0.00635 # stepper step size '' +mm_per_zstep = 0.00635 # stepper step size '' +mm_per_jog_step = 0.1 # jog step size +char_delay = 0.001 # delay between command chars in seconds +# +# global variables +# +xstep = ystep = zstep = 0 # stepper position (step units) +spindle_state = 0 # on/off +move_state = 0 # on/off +# +# panel class +# +class path_snap_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # start/stop spindle + # + def spindle(event): + global spindle_state + spindle_state = 1 - spindle_state + if (spindle_state == 1): + spindle_button.SetLabel('OFF') + else: + spindle_button.SetLabel('on') + # + # start/stop job + # + def start(event,start_line=5): + global move_state,ser + move_state = 1 - move_state + if (move_state == 1): + if (self.parent.path_file == ''): + print "panel_path_snap: oops -- need path file" + move_state = 0 + return + start_button.SetLabel('STOP') + pause_button.SetLabel('pause') + ser = serial.Serial(port.GetValue(),115200) + ser.setDTR() + start = time.time() + send_job(start_line) + end = time.time() + ser.close() + nsegment = float(segment.GetValue()) + print "%f sec, %f sec/segment"%((end-start),(end-start)/nsegment) + else: + start_button.SetLabel('start') + # + # send job + # + def send_job(start_line): + global move_state + global nx,ny,nz,dx,dy,dz,x0,y0,z0 + # + # read path + # + path_file = open(self.parent.path_file,'r') + lines = path_file.readlines() + segment_label.SetLabel("/"+str(len(lines)-1)) + dof = int(lines[0].split()[0]) + if (dof != 3): + print "panel_path_snap: oops -- need a 3D path" + return + units = lines[1] # currently ignored, mm assumed + nx = int(lines[2].split()[0]) + ny = int(lines[2].split()[1]) + nz = int(lines[2].split()[2]) + dx = float(lines[3].split()[0]) + dy = float(lines[3].split()[1]) + dz = float(lines[3].split()[2]) + x0 = float(lines[4].split()[0]) + y0 = float(lines[4].split()[1]) + z0 = float(lines[4].split()[2]) + path_file.close() + # + # get GUI values + # + speed_move = float(move_speed.GetValue()) + speed_jog = float(jog_speed.GetValue()) + height_jog = float(jog_height.GetValue()) + # + # loop over path + # + (xold,yold,zold) = ([],[],[]) + for i in range(start_line,len(lines)): + # + # check for GUI events + # + wx.Yield() + # + # quit if stopped + # + if (move_state == 0): + return + # + # read next line + # + line = lines[i].split() + # + # start of new segment? + # + if (line[0] == '.'): + # + # yes, clear old point and continue + # + (xold,yold,zold) = ([],[],[]) + continue + # + # no, go to next point + # + x = int(line[0]) + y = int(line[1]) + z = int(line[2]) + # + # first point in segment? + # + if (xold == []): + # + # yes, jog there and move down + # + move_z_abs_mm(height_jog,speed_jog) + move_xy_abs_path(x,y,speed_jog) + move_z_abs_path(z,speed_move) + else: + # + # no, move there + # + move_xyz_abs_path(x,y,z,speed_move) + # + # save old point + # + (xold,yold,zold) = (x,y,z) + # + # update segment counter and continue + # + segment.SetValue(str(i)) + # + # finish + # + move_state = 0 + start_button.SetLabel('start') + segment_label.SetLabel("segment") + # + # pause + # + def pause(event): + global move_state + print "pause" + if (move_state == 1): + move_state = 0 + start_button.SetLabel("start") + pause_button.SetLabel("CONTINUE") + elif (pause_button.GetLabel() == "CONTINUE"): + start(0,int(segment.GetValue())) + # + # write command to bus and read acknowledgement + # + def bus_send(command): + global ser + for i in range(len(command)): + print "%d: %c = %d"%(i,command[i],ord(command[i])) + ser.write(command[i]) + time.sleep(char_delay) + ack = ser.read() + # + # send z, stepper step units, ms time units + # + def send_z(dz,dt): + command = "" + if (dz >= 0): + zcmd = 'Z' + else: + zcmd = 'z' + dz1 = (abs(dz) >> 8) & 255 + dz0 = abs(dz) & 255 + command += zcmd+chr(2)+chr(dz1)+chr(dz0) + t1 = (abs(dt) >> 8) & 255 + t0 = abs(dt) & 255 + command += 'T'+chr(2)+chr(t1)+chr(t0) + command += 'G' + bus_send(command) + # + # send xy, stepper step units, ms time units + # + def send_xy(dx,dy,dt): + command = "" + if (dx >= 0): + xcmd = 'X' + else: + xcmd = 'x' + dx1 = (abs(dx) >> 8) & 255 + dx0 = abs(dx) & 255 + command += xcmd+chr(2)+chr(dx1)+chr(dx0) + if (dy >= 0): + ycmd = 'Y' + else: + ycmd = 'y' + dy1 = (abs(dy) >> 8) & 255 + dy0 = abs(dy) & 255 + command += ycmd+chr(2)+chr(dy1)+chr(dy0) + t1 = (abs(dt) >> 8) & 255 + t0 = abs(dt) & 255 + command += 'T'+chr(2)+chr(t1)+chr(t0) + command += 'G' + bus_send(command) + # + # send xyz, stepper step units, ms time units + # + def send_xyz(dx,dy,dz,dt): + command = "" + if (dx >= 0): + xcmd = 'X' + else: + xcmd = 'x' + dx1 = (abs(dx) >> 8) & 255 + dx0 = abs(dx) & 255 + command += xcmd+chr(2)+chr(dx1)+chr(dx0) + if (dy >= 0): + ycmd = 'Y' + else: + ycmd = 'y' + dy1 = (abs(dy) >> 8) & 255 + dy0 = abs(dy) & 255 + command += ycmd+chr(2)+chr(dy1)+chr(dy0) + if (dz >= 0): + zcmd = 'Z' + else: + zcmd = 'z' + dz1 = (abs(dz) >> 8) & 255 + dz0 = abs(dz) & 255 + command += zcmd+chr(2)+chr(dz1)+chr(dz0) + t1 = (abs(dt) >> 8) & 255 + t0 = abs(dt) & 255 + command += 'T'+chr(2)+chr(t1)+chr(t0) + command += 'G' + bus_send(command) + # + # move xy absolute, path units + # + def move_xy_abs_path(xi,yi,speed): + global xstep,ystep + global mm_per_xstep,mm_per_ystep + global nx,ny,nz,dx,dy,dz,x0,y0 + if (nx != 1): + x = x0 + dx*xi/(nx-1.0) + else: + x = x0 + if (ny != 1): + y = y0 + dy*yi/(ny-1.0) + else: + y = y0 + xpos.SetValue("%.3f"%x) + ypos.SetValue("%.3f"%y) + deltax = x - xstep*mm_per_xstep + deltay = y - ystep*mm_per_ystep + dxstep = int(deltax/mm_per_xstep) + xstep += dxstep + dystep = int(deltay/mm_per_ystep) + ystep += dystep + distance = sqrt(deltax*deltax+deltay*deltay) + dt = int(1000* distance / speed) + send_xy(dxstep,dystep,dt) + # + # move xyz absolute, path units + # + def move_xyz_abs_path(xi,yi,zi,speed): + global xstep,ystep,zstep + global mm_per_xstep,mm_per_ystep,mm_per_zstep + global nx,ny,nz,dx,dy,dz,x0,y0,z0 + if (nx != 1): + x = x0 + dx*xi/(nx-1.0) + else: + x = x0 + if (ny != 1): + y = y0 + dy*yi/(ny-1.0) + else: + y = y0 + if (nz != 1): + z = z0 + dz*zi/(nz-1.0) + else: + z = z0 + xpos.SetValue("%.3f"%x) + ypos.SetValue("%.3f"%y) + zpos.SetValue("%.3f"%z) + deltax = x - xstep*mm_per_xstep + deltay = y - ystep*mm_per_ystep + deltaz = z - zstep*mm_per_zstep + dxstep = int(deltax/mm_per_xstep) + xstep += dxstep + dystep = int(deltay/mm_per_ystep) + ystep += dystep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltax*deltax+deltay*deltay+deltaz*deltaz) + dt = int(1000* distance / speed) + send_xyz(dxstep,dystep,dzstep,dt) + # + # move z absolute, path units + # + def move_z_abs_path(z,speed): + global zstep + global mm_per_zstep + global nz,dz,z0 + if (nz != 1): + z = z0 + dz*zi/(nz-1.0) + else: + z = z0 + zpos.SetValue("%.3f"%z) + deltaz = z - zstep*mm_per_zstep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltaz*deltaz) + dt = int(1000* distance / speed) + send_z(dzstep,dt) + # + # move z absolute, mm units + # + def move_z_abs_mm(z,speed): + global zstep + global mm_per_zstep + zpos.SetValue("%.3f"%z) + deltaz = z - zstep*mm_per_zstep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltaz*deltaz) + dt = int(1000* distance / speed) + send_z(dzstep,dt) + # + # move xyz relative, mm units + # + def move_xyz_rel_mm(dx,dy,dz,speed): + global xstep,ystep,zstep + global mm_per_xstep,mm_per_ystep,mm_per_zstep + dxstep = int(dx / mm_per_xstep) + xstep += dxstep + xpos.SetValue("%.3f"%(xstep*mm_per_xstep)) + dystep = int(dy / mm_per_xstep) + ystep += dystep + ypos.SetValue("%.3f"%(ystep*mm_per_xstep)) + dzstep = int(dz / mm_per_xstep) + zstep += dzstep + zpos.SetValue("%.3f"%(zstep*mm_per_xstep)) + distance = sqrt(dx*dx+dy*dy+dz*dz) + dt = int(1000* distance / speed) + send_xyz(dxstep,dystep,dzstep,dt) + # + # move left mouse down + # + def left_down(event): + global move_state + move_state = 1 + left_button.SetLabel('LEFT') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(-mm_per_jog_step,0,0,float(jog_speed.GetValue())) + # + # move left mouse up + # + def left_up(event): + global move_state + move_state = 0 + left_button.SetLabel('left') + # + # move right mouse down + # + def right_down(event): + global move_state + move_state = 1 + right_button.SetLabel('RIGHT') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(mm_per_jog_step,0,0,float(jog_speed.GetValue())) + # + # move right mouse up + # + def right_up(event): + global move_state + move_state = 0 + right_button.SetLabel('right') + # + # move forward mouse down + # + def forward_down(event): + global move_state + move_state = 1 + forward_button.SetLabel('FORWARD') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,-mm_per_jog_step,0,float(jog_speed.GetValue())) + # + # move forward mouse up + # + def forward_up(event): + global move_state + move_state = 0 + forward_button.SetLabel('forward') + # + # move back mouse down + # + def back_down(event): + global move_state + move_state = 1 + back_button.SetLabel('BACK') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,mm_per_jog_step,0,float(jog_speed.GetValue())) + # + # move back mouse up + # + def back_up(event): + global move_state + move_state = 0 + back_button.SetLabel('back') + # + # move up mouse down + # + def up_down(event): + global move_state + move_state = 1 + up_button.SetLabel('UP') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,0,mm_per_jog_step,float(jog_speed.GetValue())) + # + # move up mouse up + # + def up_up(event): + global move_state + move_state = 0 + up_button.SetLabel('up') + # + # move down mouse down + # + def down_down(event): + global move_state + move_state = 1 + down_button.SetLabel('DOWN') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,0,-mm_per_jog_step,float(jog_speed.GetValue())) + # + # move down mouse up + # + def down_up(event): + global move_state + move_state = 0 + down_button.SetLabel('down') + # + # zero x + # + def zero_x(event): + global xstep + xstep = 0 + xpos.SetValue("0.000") + # + # zero y + # + def zero_y(event): + global ystep + ystep = 0 + ypos.SetValue("0.000") + # + # zero z + # + def zero_z(event): + global zstep + zstep = 0 + zpos.SetValue("0.000") + # + # zero xyz + # + def zero_xyz(event): + global xstep,ystep,zstep + xstep = 0 + xpos.SetValue("0.000") + ystep = 0 + ypos.SetValue("0.000") + zstep = 0 + zpos.SetValue("0.000") + # + # home + # + def home(event): + speed_jog = float(jog_speed.GetValue()) + height_jog = float(jog_height.GetValue()) + move_z_abs_mm(height_jog,speed_jog) + move_xy_abs_path(0,0,speed_jog) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: MTM Snap') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + mtm_panel = wx.Panel(self) + mtm_sizer = wx.GridBagSizer(10,10) + mtm_panel.SetSizer(mtm_sizer) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='x y z (mm)'),(0,0),flag=wx.ALIGN_RIGHT) + xpos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(xpos,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + ypos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(ypos,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + zpos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(zpos,(0,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + zero_xyz_button = wx.Button(mtm_panel,label='zero xyz') + zero_xyz_button.Bind(wx.EVT_BUTTON,zero_xyz) + mtm_sizer.Add(zero_xyz_button,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_x_button = wx.Button(mtm_panel,label='zero x') + zero_x_button.Bind(wx.EVT_BUTTON,zero_x) + mtm_sizer.Add(zero_x_button,(1,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_y_button = wx.Button(mtm_panel,label='zero y') + zero_y_button.Bind(wx.EVT_BUTTON,zero_y) + mtm_sizer.Add(zero_y_button,(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_z_button = wx.Button(mtm_panel,label='zero z') + zero_z_button.Bind(wx.EVT_BUTTON,zero_z) + mtm_sizer.Add(zero_z_button,(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + home_button = wx.Button(mtm_panel,label='home') + home_button.Bind(wx.EVT_BUTTON,home) + mtm_sizer.Add(home_button,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + left_button = wx.Button(mtm_panel,label='left') + left_button.Bind(wx.EVT_LEFT_DOWN,left_down) + left_button.Bind(wx.EVT_LEFT_UP,left_up) + mtm_sizer.Add(left_button,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + back_button = wx.Button(mtm_panel,label='back') + back_button.Bind(wx.EVT_LEFT_DOWN,back_down) + back_button.Bind(wx.EVT_LEFT_UP,back_up) + mtm_sizer.Add(back_button,(2,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='jog'),(3,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER)) + forward_button = wx.Button(mtm_panel,label='forward') + forward_button.Bind(wx.EVT_LEFT_DOWN,forward_down) + forward_button.Bind(wx.EVT_LEFT_UP,forward_up) + mtm_sizer.Add(forward_button,(4,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + right_button = wx.Button(mtm_panel,label='right') + right_button.Bind(wx.EVT_LEFT_DOWN,right_down) + right_button.Bind(wx.EVT_LEFT_UP,right_up) + mtm_sizer.Add(right_button,(3,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + up_button = wx.Button(mtm_panel,label='up') + up_button.Bind(wx.EVT_LEFT_DOWN,up_down) + up_button.Bind(wx.EVT_LEFT_UP,up_up) + mtm_sizer.Add(up_button,(2,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + down_button = wx.Button(mtm_panel,label='down') + down_button.Bind(wx.EVT_LEFT_DOWN,down_down) + down_button.Bind(wx.EVT_LEFT_UP,down_up) + mtm_sizer.Add(down_button,(3,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='speed (mm/s)'),(4,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)) + move_speed = wx.TextCtrl(mtm_panel,-1,'1') + mtm_sizer.Add(move_speed,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='jog speed (mm/s) z (mm)'),(4,2),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)) + jog_speed = wx.TextCtrl(mtm_panel,-1,'10') + mtm_sizer.Add(jog_speed,(5,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + jog_height = wx.TextCtrl(mtm_panel,-1,'1') + mtm_sizer.Add(jog_height,(5,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='spindle'),(6,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + spindle_button = wx.Button(mtm_panel,label='on') + spindle_button.Bind(wx.EVT_BUTTON,spindle) + mtm_sizer.Add(spindle_button,(6,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='speed (rpm)'),(6,2),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + spindle_speed = wx.TextCtrl(mtm_panel,-1,'10000') + mtm_sizer.Add(spindle_speed,(6,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + start_button = wx.Button(mtm_panel,label='start') + start_button.Bind(wx.EVT_BUTTON,start) + mtm_sizer.Add(start_button,(7,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + pause_button = wx.Button(mtm_panel,label='pause') + pause_button.Bind(wx.EVT_BUTTON,pause) + mtm_sizer.Add(pause_button,(7,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + segment = wx.TextCtrl(mtm_panel,-1,'0') + mtm_sizer.Add(segment,(7,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + segment_label = wx.StaticText(mtm_panel,label='segment') + mtm_sizer.Add(segment_label,(7,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='port'),(8,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + port = wx.TextCtrl(mtm_panel,-1,'/dev/ttyUSB0') + mtm_sizer.Add(port,(8,1),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND) + # + self.sizer.Add(mtm_panel,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_snap_apa.py b/src/py/panel_path_snap_apa.py new file mode 100644 index 0000000..cef85e5 --- /dev/null +++ b/src/py/panel_path_snap_apa.py @@ -0,0 +1,574 @@ +# +# panel_path_snap.py +# MTM Snap virtual machine +# +# Neil Gershenfeld +# CBA MIT 11/28/11 +# nmp update dec 3 2011: mm_per_step +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# todo +# APA out +# APA send +# process text entry +# acceleration +# job times +# +# imports +# +import wx,os +from math import * +import time +# +# machine definitions +# +mm_per_xstep = 0.00635 # stepper step size (400 steps/rev, 10 revs/in) +mm_per_ystep = 0.00635 # stepper step size '' +mm_per_zstep = 0.00635 # stepper step size '' +mm_per_jog_step = 0.00635 # jog step size +x_path = "" # APA path to x axis +y_path = "0" # APA path to y axis +z_path = "1" # APA path to z axis +spindle = "11" # APA path to spindle +# +# global variables +# +xstep = ystep = zstep = 0 # stepper position (step units) +spindle_state = 0 # on/off +move_state = 0 # on/off +# +# panel class +# +class path_snap_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # start/stop spindle + # + def spindle(event): + global spindle_state + spindle_state = 1 - spindle_state + if (spindle_state == 1): + spindle_button.SetLabel('OFF') + else: + spindle_button.SetLabel('on') + # + # start/stop job + # + def start(event,start_line=5): + global move_state + move_state = 1 - move_state + if (move_state == 1): + if (self.parent.path_file == ''): + print "panel_path_snap: oops -- need path file" + move_state = 0 + return + start_button.SetLabel('STOP') + pause_button.SetLabel('pause') + start = time.time() + send_job(start_line) + end = time.time() + nsegment = float(segment.GetValue()) + print "%f sec, %f sec/segment"%((end-start),(end-start)/nsegment) + else: + start_button.SetLabel('start') + # + # send job + # + def send_job(start_line): + global move_state + global nx,ny,nz,dx,dy,dz,x0,y0,z0 + # + # read path + # + path_file = open(self.parent.path_file,'r') + lines = path_file.readlines() + segment_label.SetLabel("/"+str(len(lines)-1)) + dof = int(lines[0].split()[0]) + if (dof != 3): + print "panel_path_snap: oops -- need a 3D path" + return + units = lines[1] # currently ignored, mm assumed + nx = int(lines[2].split()[0]) + ny = int(lines[2].split()[1]) + nz = int(lines[2].split()[2]) + dx = float(lines[3].split()[0]) + dy = float(lines[3].split()[1]) + dz = float(lines[3].split()[2]) + x0 = float(lines[4].split()[0]) + y0 = float(lines[4].split()[1]) + z0 = float(lines[4].split()[2]) + path_file.close() + # + # get GUI values + # + speed_move = float(move_speed.GetValue()) + speed_jog = float(jog_speed.GetValue()) + height_jog = float(jog_height.GetValue()) + # + # loop over path + # + for i in range(start_line,len(lines)): + # + # check for GUI events + # + wx.Yield() + # + # quit if stopped + # + if (move_state == 0): + return + # + # read next line + # + line = lines[i].split() + # + # start of new segment? + # + if (line[0] == '.'): + # + # yes, clear old point and continue + # + (xold,yold,zold) = ([],[],[]) + continue + # + # no, go to next point + # + x = int(line[0]) + y = int(line[1]) + z = int(line[2]) + # + # first point in segment? + # + if (xold == []): + # + # yes, jog there and move down + # + move_z_abs_mm(height_jog,speed_jog) + move_xy_abs_path(x,y,speed_jog) + move_z_abs_path(z,speed_move) + else: + # + # no, move there + # + move_xyz_abs_path(x,y,z,speed_move) + # + # save old point + # + (xold,yold,zold) = (x,y,z) + # + # update segment counter and continue + # + segment.SetValue(str(i)) + # + # finish + # + move_state = 0 + start_button.SetLabel('start') + segment_label.SetLabel("segment") + # + # pause + # + def pause(event): + global move_state + print "pause" + if (move_state == 1): + move_state = 0 + start_button.SetLabel("start") + pause_button.SetLabel("CONTINUE") + elif (pause_button.GetLabel() == "CONTINUE"): + start(0,int(segment.GetValue())) + # + # APA send z, stepper step units, ms time units + # + def apa_send_z(dz,time): + command = "apa_send {^"+z_path+"|"+str(dz)+","+str(time)+"}" + #print command + os.system('echo "'+command+'" > /dev/null') + # os.system(command) + # + # APA send xy, stepper step units, ms time units + # + def apa_send_xy(dx,dy,time): + command = "apa_send {^"+x_path+"|"+str(dx)+","+str(time)+"}{^"+y_path+"|"+str(dy)+","+str(time)+"}" + #print command + os.system('echo "'+command+'" > /dev/null') + # os.system(command) + # + # APA send xyz, stepper step units, ms time units + # + def apa_send_xyz(dx,dy,dz,time): + command = "apa_send {^"+x_path+"|"+str(dx)+","+str(time)+"}{^"+y_path+"|"+str(dy)+","+str(time)+"}{^"+z_path+"|"+str(dz)+","+str(time)+"}" + #print command + os.system('echo "'+command+'" > /dev/null') + # os.system(command) + # + # move xy absolute, path units + # + def move_xy_abs_path(xi,yi,speed): + global xstep,ystep + global mm_per_xstep,mm_per_ystep + global nx,ny,nz,dx,dy,dz,x0,y0 + if (nx != 1): + x = x0 + dx*xi/(nx-1.0) + else: + x = x0 + if (ny != 1): + y = y0 + dy*yi/(ny-1.0) + else: + y = y0 + xpos.SetValue("%.3f"%x) + ypos.SetValue("%.3f"%y) + deltax = x - xstep*mm_per_xstep + deltay = y - ystep*mm_per_ystep + dxstep = int(deltax/mm_per_xstep) + xstep += dxstep + dystep = int(deltay/mm_per_ystep) + ystep += dystep + distance = sqrt(deltax*deltax+deltay*deltay) + time = int(1000* distance / speed) + apa_send_xy(dxstep,dystep,time) + # + # move xyz absolute, path units + # + def move_xyz_abs_path(xi,yi,zi,speed): + global xstep,ystep,zstep + global mm_per_xstep,mm_per_ystep,mm_per_zstep + global nx,ny,nz,dx,dy,dz,x0,y0,z0 + if (nx != 1): + x = x0 + dx*xi/(nx-1.0) + else: + x = x0 + if (ny != 1): + y = y0 + dy*yi/(ny-1.0) + else: + y = y0 + if (nz != 1): + z = z0 + dz*zi/(nz-1.0) + else: + z = z0 + xpos.SetValue("%.3f"%x) + ypos.SetValue("%.3f"%y) + zpos.SetValue("%.3f"%z) + deltax = x - xstep*mm_per_xstep + deltay = y - ystep*mm_per_ystep + deltaz = z - zstep*mm_per_zstep + dxstep = int(deltax/mm_per_xstep) + xstep += dxstep + dystep = int(deltay/mm_per_ystep) + ystep += dystep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltax*deltax+deltay*deltay+deltaz*deltaz) + time = int(1000* distance / speed) + apa_send_xyz(dxstep,dystep,dzstep,time) + # + # move z absolute, path units + # + def move_z_abs_path(z,speed): + global zstep + global mm_per_zstep + global nz,dz,z0 + if (nz != 1): + z = z0 + dz*zi/(nz-1.0) + else: + z = z0 + zpos.SetValue("%.3f"%z) + deltaz = z - zstep*mm_per_zstep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltaz*deltaz) + time = int(1000* distance / speed) + apa_send_z(dzstep,time) + # + # move z absolute, mm units + # + def move_z_abs_mm(z,speed): + global zstep + global mm_per_zstep + zpos.SetValue("%.3f"%z) + deltaz = z - zstep*mm_per_zstep + dzstep = int(deltaz/mm_per_zstep) + zstep += dzstep + distance = sqrt(deltaz*deltaz) + time = int(1000* distance / speed) + apa_send_z(dzstep,time) + # + # move xyz relative, mm units + # + def move_xyz_rel_mm(dx,dy,dz,speed): + global xstep,ystep,zstep + global mm_per_xstep,mm_per_ystep,mm_per_zstep + dxstep = int(dx / mm_per_xstep) + xstep += dxstep + xpos.SetValue("%.3f"%(xstep*mm_per_xstep)) + dystep = int(dy / mm_per_xstep) + ystep += dystep + ypos.SetValue("%.3f"%(ystep*mm_per_xstep)) + dzstep = int(dz / mm_per_xstep) + zstep += dzstep + zpos.SetValue("%.3f"%(zstep*mm_per_xstep)) + distance = sqrt(dx*dx+dy*dy+dz*dz) + time = int(1000* distance / speed) + apa_send_xyz(dxstep,dystep,dzstep,time) + # + # move left mouse down + # + def left_down(event): + global move_state + move_state = 1 + left_button.SetLabel('LEFT') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(-mm_per_jog_step,0,0,float(jog_speed.GetValue())) + # + # move left mouse up + # + def left_up(event): + global move_state + move_state = 0 + left_button.SetLabel('left') + # + # move right mouse down + # + def right_down(event): + global move_state + move_state = 1 + right_button.SetLabel('RIGHT') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(mm_per_jog_step,0,0,float(jog_speed.GetValue())) + # + # move right mouse up + # + def right_up(event): + global move_state + move_state = 0 + right_button.SetLabel('right') + # + # move forward mouse down + # + def forward_down(event): + global move_state + move_state = 1 + forward_button.SetLabel('FORWARD') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,-mm_per_jog_step,0,float(jog_speed.GetValue())) + # + # move forward mouse up + # + def forward_up(event): + global move_state + move_state = 0 + forward_button.SetLabel('forward') + # + # move back mouse down + # + def back_down(event): + global move_state + move_state = 1 + back_button.SetLabel('BACK') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,mm_per_jog_step,0,float(jog_speed.GetValue())) + # + # move back mouse up + # + def back_up(event): + global move_state + move_state = 0 + back_button.SetLabel('back') + # + # move up mouse down + # + def up_down(event): + global move_state + move_state = 1 + up_button.SetLabel('UP') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,0,mm_per_jog_step,float(jog_speed.GetValue())) + # + # move up mouse up + # + def up_up(event): + global move_state + move_state = 0 + up_button.SetLabel('up') + # + # move down mouse down + # + def down_down(event): + global move_state + move_state = 1 + down_button.SetLabel('DOWN') + while 1: + wx.Yield() + if (move_state == 0): + return + move_xyz_rel_mm(0,0,-mm_per_jog_step,float(jog_speed.GetValue())) + # + # move down mouse up + # + def down_up(event): + global move_state + move_state = 0 + down_button.SetLabel('down') + # + # zero x + # + def zero_x(event): + global xstep + xstep = 0 + xpos.SetValue("0.000") + # + # zero y + # + def zero_y(event): + global ystep + ystep = 0 + ypos.SetValue("0.000") + # + # zero z + # + def zero_z(event): + global zstep + zstep = 0 + zpos.SetValue("0.000") + # + # zero xyz + # + def zero_xyz(event): + global xstep,ystep,zstep + xstep = 0 + xpos.SetValue("0.000") + ystep = 0 + ypos.SetValue("0.000") + zstep = 0 + zpos.SetValue("0.000") + # + # home + # + def home(event): + speed_jog = float(jog_speed.GetValue()) + height_jog = float(jog_height.GetValue()) + move_z_abs_mm(height_jog,speed_jog) + move_xy_abs_path(0,0,speed_jog) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: MTM Snap') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + mtm_panel = wx.Panel(self) + mtm_sizer = wx.GridBagSizer(10,10) + mtm_panel.SetSizer(mtm_sizer) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='x y z (mm)'),(0,0),flag=wx.ALIGN_RIGHT) + xpos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(xpos,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + ypos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(ypos,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + zpos = wx.TextCtrl(mtm_panel,-1,'0.000') + mtm_sizer.Add(zpos,(0,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + zero_xyz_button = wx.Button(mtm_panel,label='zero xyz') + zero_xyz_button.Bind(wx.EVT_BUTTON,zero_xyz) + mtm_sizer.Add(zero_xyz_button,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_x_button = wx.Button(mtm_panel,label='zero x') + zero_x_button.Bind(wx.EVT_BUTTON,zero_x) + mtm_sizer.Add(zero_x_button,(1,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_y_button = wx.Button(mtm_panel,label='zero y') + zero_y_button.Bind(wx.EVT_BUTTON,zero_y) + mtm_sizer.Add(zero_y_button,(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + zero_z_button = wx.Button(mtm_panel,label='zero z') + zero_z_button.Bind(wx.EVT_BUTTON,zero_z) + mtm_sizer.Add(zero_z_button,(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + home_button = wx.Button(mtm_panel,label='home') + home_button.Bind(wx.EVT_BUTTON,home) + mtm_sizer.Add(home_button,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + left_button = wx.Button(mtm_panel,label='left') + left_button.Bind(wx.EVT_LEFT_DOWN,left_down) + left_button.Bind(wx.EVT_LEFT_UP,left_up) + mtm_sizer.Add(left_button,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + back_button = wx.Button(mtm_panel,label='back') + back_button.Bind(wx.EVT_LEFT_DOWN,back_down) + back_button.Bind(wx.EVT_LEFT_UP,back_up) + mtm_sizer.Add(back_button,(2,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='jog'),(3,1),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER)) + forward_button = wx.Button(mtm_panel,label='forward') + forward_button.Bind(wx.EVT_LEFT_DOWN,forward_down) + forward_button.Bind(wx.EVT_LEFT_UP,forward_up) + mtm_sizer.Add(forward_button,(4,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + right_button = wx.Button(mtm_panel,label='right') + right_button.Bind(wx.EVT_LEFT_DOWN,right_down) + right_button.Bind(wx.EVT_LEFT_UP,right_up) + mtm_sizer.Add(right_button,(3,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + up_button = wx.Button(mtm_panel,label='up') + up_button.Bind(wx.EVT_LEFT_DOWN,up_down) + up_button.Bind(wx.EVT_LEFT_UP,up_up) + mtm_sizer.Add(up_button,(2,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + down_button = wx.Button(mtm_panel,label='down') + down_button.Bind(wx.EVT_LEFT_DOWN,down_down) + down_button.Bind(wx.EVT_LEFT_UP,down_up) + mtm_sizer.Add(down_button,(3,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='speed (mm/s)'),(4,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)) + move_speed = wx.TextCtrl(mtm_panel,-1,'1') + mtm_sizer.Add(move_speed,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='jog speed (mm/s) z (mm)'),(4,2),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_BOTTOM)) + jog_speed = wx.TextCtrl(mtm_panel,-1,'10') + mtm_sizer.Add(jog_speed,(5,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + jog_height = wx.TextCtrl(mtm_panel,-1,'1') + mtm_sizer.Add(jog_height,(5,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + mtm_sizer.Add(wx.StaticText(mtm_panel,label='spindle'),(6,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + spindle_button = wx.Button(mtm_panel,label='on') + spindle_button.Bind(wx.EVT_BUTTON,spindle) + mtm_sizer.Add(spindle_button,(6,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + mtm_sizer.Add(wx.StaticText(mtm_panel,label='speed (rpm)'),(6,2),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + spindle_speed = wx.TextCtrl(mtm_panel,-1,'10000') + mtm_sizer.Add(spindle_speed,(6,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + start_button = wx.Button(mtm_panel,label='start') + start_button.Bind(wx.EVT_BUTTON,start) + mtm_sizer.Add(start_button,(7,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + pause_button = wx.Button(mtm_panel,label='pause') + pause_button.Bind(wx.EVT_BUTTON,pause) + mtm_sizer.Add(pause_button,(7,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + segment = wx.TextCtrl(mtm_panel,-1,'0') + mtm_sizer.Add(segment,(7,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + segment_label = wx.StaticText(mtm_panel,label='segment') + mtm_sizer.Add(segment_label,(7,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + self.sizer.Add(mtm_panel,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # fit + # + self.Fit() diff --git a/src/py/panel_path_uni.py b/src/py/panel_path_uni.py new file mode 100644 index 0000000..899b711 --- /dev/null +++ b/src/py/panel_path_uni.py @@ -0,0 +1,123 @@ +# +# panel_path_uni.py +# make .uni from .path +# +# Neil Gershenfeld +# CBA MIT 3/10/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class path_uni_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make uni + # + def make_uni(event): + if (self.parent.path_file == ''): + print 'panel_path_uni: oops -- need path file' + return + self.parent.uni_file = self.parent.tmp+self.parent.rootname+'.uni' + power = self.power.GetValue() + speed = self.speed.GetValue() + xmin = self.xmin.GetValue() + ymin = self.ymin.GetValue() + rate = self.rate.GetValue() + maxpower = self.maxpower.GetValue() + command = 'path_uni '+'\"'+self.parent.path_file+'\"'+' '+'\"'+self.parent.uni_file+'\"'+' '+power+' '+speed+' '+xmin+' '+ymin+' '+' '+rate+' '+maxpower + print command + os.system(command) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.uni_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: uni') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .uni') + make.Bind(wx.EVT_BUTTON,make_uni) + self.sizer.Add(make,(2,0),span=(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + row3_panel = wx.Panel(self) + row3_sizer = wx.GridBagSizer(10,10) + row3_panel.SetSizer(row3_sizer) + row3_sizer.Add(wx.StaticText(row3_panel,label='2D power (%)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row3_sizer.Add(wx.StaticText(row3_panel,label='speed (%) '),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row3_panel,(3,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row4_panel = wx.Panel(self) + row4_sizer = wx.GridBagSizer(10,10) + row4_panel.SetSizer(row4_sizer) + self.power = wx.TextCtrl(row4_panel,-1,'25') + row4_sizer.Add(self.power,(0,0)) + self.speed = wx.TextCtrl(row4_panel,-1,'75') + row4_sizer.Add(self.speed,(0,1)) + self.sizer.Add(row4_panel,(4,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row5_panel = wx.Panel(self) + row5_sizer = wx.GridBagSizer(10,10) + row5_panel.SetSizer(row5_sizer) + row5_sizer.Add(wx.StaticText(row5_panel,label='xmin (mm)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row5_sizer.Add(wx.StaticText(row5_panel,label='ymin (mm)'),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row5_panel,(5,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row6_panel = wx.Panel(self) + row6_sizer = wx.GridBagSizer(10,10) + row6_panel.SetSizer(row6_sizer) + self.xmin = wx.TextCtrl(row6_panel,-1,'0') + row6_sizer.Add(self.xmin,(0,0)) + self.ymin = wx.TextCtrl(row6_panel,-1,'0') + row6_sizer.Add(self.ymin,(0,1)) + self.sizer.Add(row6_panel,(6,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row7_panel = wx.Panel(self) + row7_sizer = wx.GridBagSizer(10,10) + row7_panel.SetSizer(row7_sizer) + row7_sizer.Add(wx.StaticText(row7_panel,label='3D power (%)'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + row7_sizer.Add(wx.StaticText(row7_panel,label='rate '),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.sizer.Add(row7_panel,(7,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + row8_panel = wx.Panel(self) + row8_sizer = wx.GridBagSizer(10,10) + row8_panel.SetSizer(row8_sizer) + self.maxpower = wx.TextCtrl(row8_panel,-1,'100') + row8_sizer.Add(self.maxpower,(0,0)) + self.rate = wx.TextCtrl(row8_panel,-1,'500') + row8_sizer.Add(self.rate,(0,1)) + self.sizer.Add(row8_panel,(8,0),span=(1,2),flag=(wx.ALIGN_CENTER_HORIZONTAL)) diff --git a/src/py/panel_png.py b/src/py/panel_png.py new file mode 100644 index 0000000..292acf5 --- /dev/null +++ b/src/py/panel_png.py @@ -0,0 +1,242 @@ +# +# panel_png.py +# read .png +# +# Neil Gershenfeld +# CBA MIT 2/19/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +# +# panel class +# +class png_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # get png info + # + def png_info(name): + temp_name = self.parent.tmp+'png_dimension' + command = 'png_size '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + print output + self.parent.units = 1 + self.parent.xmin = 0 + start = string.find(output,"dx:") + end = string.find(output,"mm",start) + self.parent.xmax = float(output[start+4:end]) + self.parent.ymin = 0 + start = string.find(output,"dy:") + end = string.find(output,"mm",start) + self.parent.ymax = float(output[start+4:end]) + if "dz:" in output: + self.parent.zmin = 0 + start = string.find(output,"dz:") + end = string.find(output,"mm",start) + self.parent.zmax = float(output[start+4:end]) + return output + # + # file open dialog + # + def file_dialog(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.png", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + load_file(0) + # + # load file + # + def load_file(event): + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".png") + if (pos == -1): + pos = string.find(self.parent.basename,".PNG") + if (pos == -1): + print 'png_panel: oops -- must be .png' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + self.parent.png_file = self.parent.filename + info = png_info(self.parent.filename) + self.info.SetLabel(info) + png_image = wx.Image(self.parent.filename) + (nx,ny) = png_image.GetSize() + pixels = "size: (%d,%d)"%(nx,ny) + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = int(self.parent.size/ratio) + else: + self.parent.ysize = int(self.parent.size*ratio) + self.parent.xsize = self.parent.size + wx.Image.Rescale(png_image,self.parent.xsize,self.parent.ysize) + png_bitmap = png_image.ConvertToBitmap() + self.bitmap.SetBitmap(png_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.cad", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + pos = string.find(self.parent.basename,".cad") + if (pos == -1): + print 'cad_panel: oops -- must be .cad' + sys.exit() + else: + self.parent.rootname = self.parent.basename[:pos] + cad_file = open(self.parent.filename,'r') + cad_string = cad_file.read() + cad_file.close() + self.text.SetValue(cad_string) + # + # invert + # + def invert_dialog(event): + command = 'png_scale '+'\"'+self.parent.png_file+'\" \"'+self.parent.png_file+'\" 1 0' + print command + os.system(command) + load_file(0) + # + # resize + # + def resize_dialog(event): + resize.dx = self.parent.xmax + resize.dy = self.parent.ymax + resize_width.SetValue(str(resize.dx)) + resize_height.SetValue(str(resize.dy)) + resize.Show() + def resize_dialog_cancel(event): + resize.Hide() + def resize_dialog_resize(event): + width = resize_width.GetValue() + height = resize_height.GetValue() + print width,height + command = 'png_size '+'\"'+self.parent.png_file+'\" '+width+' '+height + print command + os.system(command) + load_file(0) + resize.Hide() + def resize_width_handler(event): + if resize.prop.GetValue(): + dx = float(resize_width.GetValue()) + dy = dx * resize.dy/resize.dx + resize_height.Unbind(wx.EVT_TEXT) + resize_height.SetValue(str(dy)) + resize_height.Bind(wx.EVT_TEXT,resize_height_handler) + def resize_height_handler(event): + if resize.prop.GetValue(): + dy = float(resize_height.GetValue()) + dx = dy * resize.dx/resize.dy + resize_width.Unbind(wx.EVT_TEXT) + resize_width.SetValue(str(dx)) + resize_width.Bind(wx.EVT_TEXT,resize_width_handler) + # + resize = wx.Frame(None, -1, 'resize') + resize_sizer = wx.GridBagSizer(10,10) + resize.SetSizer(resize_sizer) + # + resize_sizer.Add(wx.StaticText(resize,label='width (mm):'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + resize_width = wx.TextCtrl(resize,-1,'0') + resize_width.Bind(wx.EVT_TEXT,resize_width_handler) + resize_sizer.Add(resize_width,(0,1)) + # + resize_sizer.Add(wx.StaticText(resize,label='height (mm):'),(0,2),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + resize_height = wx.TextCtrl(resize,-1,'0') + resize_height.Bind(wx.EVT_TEXT,resize_height_handler) + resize_sizer.Add(resize_height,(0,3)) + # + resize.prop = wx.CheckBox(resize,label='proportional',style=wx.RB_GROUP) + resize.prop.SetValue(True) + resize_sizer.Add(resize.prop,(1,1)) + # + resize_resize = wx.Button(resize,label='resize') + resize_resize.Bind(wx.EVT_BUTTON,resize_dialog_resize) + resize_sizer.Add(resize_resize,(1,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + resize_cancel = wx.Button(resize,label='cancel') + resize_cancel.Bind(wx.EVT_BUTTON,resize_dialog_cancel) + resize_sizer.Add(resize_cancel,(1,3),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + resize.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: png') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + self.bitmap = wx.StaticBitmap(self) + self.sizer.Add(self.bitmap,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + def mouse_move(event): + x = self.parent.xmin + (self.parent.xmax-self.parent.xmin)*event.GetX()/float(self.parent.xsize) + y = self.parent.ymin + (self.parent.ymax-self.parent.ymin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize) + self.position.SetLabel("x: %.3f mm y: %.3f mm"%(x,y)) + self.Layout() + self.Fit() + self.bitmap.Bind(wx.EVT_MOTION,mouse_move) + # + # controls + # + control_panel = wx.Panel(self) + control_sizer = wx.GridBagSizer(10,10) + control_panel.SetSizer(control_sizer) + # + button = wx.Button(control_panel,label='load .png') + button.Bind(wx.EVT_BUTTON,file_dialog) + control_sizer.Add(button,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + button = wx.Button(control_panel,label='resize .png') + button.Bind(wx.EVT_BUTTON,resize_dialog) + control_sizer.Add(button,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + button = wx.Button(control_panel,label='invert .png') + button.Bind(wx.EVT_BUTTON,invert_dialog) + control_sizer.Add(button,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.sizer.Add(control_panel,(2,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + self.position= wx.StaticText(self,label="") + self.sizer.Add(self.position,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info= wx.StaticText(self,label="") + self.sizer.Add(self.info,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() + # + # parent call to update size + # + def update_size(self,sizex,sizey): + self.Layout() + self.Fit() diff --git a/src/py/panel_png_drl.py b/src/py/panel_png_drl.py new file mode 100644 index 0000000..d049fe9 --- /dev/null +++ b/src/py/panel_png_drl.py @@ -0,0 +1,75 @@ +# +# panel_png_drl.py +# make .drl from .png +# +# Neil Gershenfeld +# CBA MIT 11/25/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class png_drl_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make drl + # + def make_drl(event): + if (self.parent.png_file == ''): + print 'make_png_drl: oops -- need .png file' + return + self.parent.drl_file = self.parent.tmp+self.parent.rootname+'.drl' + command = 'png_drl '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.drl_file+'\"' + print command + os.system(command) + self.button.SetMaxSize((self.parent.xsize,self.parent.ysize)) + self.button.SetMinSize((self.parent.xsize,self.parent.ysize)) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.drl_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: Excellon') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .drl') + make.Bind(wx.EVT_BUTTON,make_drl) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_png_grb.py b/src/py/panel_png_grb.py new file mode 100644 index 0000000..9b6485c --- /dev/null +++ b/src/py/panel_png_grb.py @@ -0,0 +1,75 @@ +# +# panel_png_grb.py +# make .grb from .png +# +# Neil Gershenfeld +# CBA MIT 11/23/12 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class png_grb_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.path_file = '' + # + # make grb + # + def make_grb(event): + if (self.parent.png_file == ''): + print 'make_png_grb: oops -- need .png file' + return + self.parent.grb_file = self.parent.tmp+self.parent.rootname+'.grb' + command = 'png_grb '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.grb_file+'\"' + print command + os.system(command) + self.button.SetMaxSize((self.parent.xsize,self.parent.ysize)) + self.button.SetMinSize((self.parent.xsize,self.parent.ysize)) + self.button.Show() + self.parent.Layout() + self.parent.Fit() + # + # send + # + def fab_send(event): + command = 'fab_send '+'\"'+self.parent.grb_file+'\"' + print command + os.system(command) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: Gerber') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # send + # + self.button = wx.Button(self,label='send it!') + self.button.Bind(wx.EVT_BUTTON,fab_send) + self.button.SetFont(bold_font) + self.sizer.Add(self.button,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.button.Hide() + # + # controls + # + make = wx.Button(self,label='make .grb') + make.Bind(wx.EVT_BUTTON,make_grb) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_png_path.py b/src/py/panel_png_path.py new file mode 100644 index 0000000..498c707 --- /dev/null +++ b/src/py/panel_png_path.py @@ -0,0 +1,346 @@ +# +# panel_png_path.py +# make .path from .png +# +# Neil Gershenfeld 9/3/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# +# imports +# +import wx,os,string +from panel_path import path_panel +# +# panel class +# +class png_path_panel(wx.Panel): + # + # constructor + # + def __init__(self,parent): + self.parent = parent + self.parent.png_file = '' + self.parent.zmin = '' + self.parent.zmax = '' + self.parent.units = 1 + # + # make path + # + def make_path(event): + if (self.parent.png_file == ''): + print "png_path: oops -- must make .png first" + return + self.parent.path_file = self.parent.tmp+self.parent.rootname+'.path' + path_png = self.parent.tmp+self.parent.rootname+'.path.png' + selection = self.path_type.GetValue() + if (selection == "2D"): + diameter = self.diameter_2D.GetValue() + number = self.number_2D.GetValue() + overlap = self.overlap_2D.GetValue() + error = self.error_2D.GetValue() + intensity = self.intensity_2D.GetValue() + command = 'png_path '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+error+' '+diameter+' '+number+' '+overlap+' '+intensity + elif (selection == "3D plane"): + diameter = self.diameter_plane.GetValue() + number = self.number_plane.GetValue() + overlap = self.overlap_plane.GetValue() + error = self.error_plane.GetValue() + intensity = self.intensity_plane.GetValue() + z = self.z_plane.GetValue() + command = 'png_path '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+error+' '+diameter+' '+number+' '+overlap+' '+intensity+' '+intensity+' '+z + elif (selection == "3D rough"): + diameter = self.diameter_rough.GetValue() + number = self.number_rough.GetValue() + overlap = self.overlap_rough.GetValue() + error = self.error_rough.GetValue() + itop = self.itop_rough.GetValue() + ibot = self.ibot_rough.GetValue() + ztop = self.ztop_rough.GetValue() + zbot = self.zbot_rough.GetValue() + zstep = self.zstep_rough.GetValue() + command = 'png_path '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+error+' '+diameter+' '+number+' '+overlap+' '+itop+' '+ibot+' '+ztop+' '+zbot+' '+zstep + elif (selection == "3D finish"): + diameter = self.diameter_finish.GetValue() + overlap = self.overlap_finish.GetValue() + error = self.error_finish.GetValue() + itop = self.itop_finish.GetValue() + ibot = self.ibot_finish.GetValue() + ztop = self.ztop_finish.GetValue() + zbot = self.zbot_finish.GetValue() + clearance_length = self.clearance_length_finish.GetValue() + clearance_diameter = self.clearance_diameter_finish.GetValue() + number = '0' + zstep = '0' + if self.xz_finish.GetValue(): + xz = "1" + else: + xz = "0" + if self.yz_finish.GetValue(): + yz = "1" + else: + yz = "0" + xy = "0" + if self.flat_end_finish.GetValue(): + tool_type = 'f' + elif self.ball_end_finish.GetValue(): + tool_type = 'b' + command = 'png_path '+'\"'+self.parent.png_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+error+' '+diameter+' '+number+' '+overlap+' '+itop+' '+ibot+' '+ztop+' '+zbot+' '+zstep+' '+xz+' '+yz+' '+xy+' '+tool_type+' '+clearance_length+' '+clearance_diameter + print command + ret = os.system(command) + if (ret == 0): + self.path_viewer.draw(self.parent.path_file) + #self.parent.Layout() + #self.parent.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: path') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + self.path_viewer = path_panel(self) + self.sizer.Add(self.path_viewer,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + make_panel = wx.Panel(self) + make_sizer = wx.GridBagSizer(10,10) + make_panel.SetSizer(make_sizer) + make_button = wx.Button(make_panel,label='make .path') + make_button.Bind(wx.EVT_BUTTON,make_path) + make_sizer.Add(make_button,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + make_sizer.Add(wx.StaticText(make_panel,label='type:'),(0,1),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.path_types = ["2D","3D plane","3D rough","3D finish"] + self.path_type = wx.ComboBox(make_panel,size=(100,-1),value="2D",choices=self.path_types,style=wx.CB_READONLY) + self.parent.path_type = "2D" + self.path_type.Bind(wx.EVT_COMBOBOX,self.path_type_handler) + make_sizer.Add(self.path_type,(0,2),flag=wx.ALIGN_LEFT) + self.sizer.Add(make_panel,(2,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # 2D panel + # + panel_2D = wx.Panel(self) + sizer_2D = wx.GridBagSizer(10,10) + panel_2D.SetSizer(sizer_2D) + # + sizer_2D.Add(wx.StaticText(panel_2D,label='diameter (mm)'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.diameter_2D = wx.TextCtrl(panel_2D,-1,'0.25') + sizer_2D.Add(self.diameter_2D,(0,1),flag=(wx.ALIGN_LEFT)) + self.number_2D = wx.TextCtrl(panel_2D,-1,'1') + sizer_2D.Add(self.number_2D,(0,2),flag=(wx.ALIGN_RIGHT)) + sizer_2D.Add(wx.StaticText(panel_2D,label='offsets (-1 to fill)'),(0,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_2D.Add(wx.StaticText(panel_2D,label='overlap (0-1)'),(1,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.overlap_2D = wx.TextCtrl(panel_2D,-1,'0.5') + sizer_2D.Add(self.overlap_2D,(1,1),flag=(wx.ALIGN_RIGHT)) + self.error_2D = wx.TextCtrl(panel_2D,-1,'1.1') + sizer_2D.Add(self.error_2D,(1,2),flag=(wx.ALIGN_RIGHT)) + sizer_2D.Add(wx.StaticText(panel_2D,label='error (pixels)'),(1,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_2D.Add(wx.StaticText(panel_2D,label='intensity (0-1)'),(2,1),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.intensity_2D = wx.TextCtrl(panel_2D,-1,'0.5') + sizer_2D.Add(self.intensity_2D,(2,2),flag=(wx.ALIGN_RIGHT)) + # + self.sizer.Add(panel_2D,(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + self.type_panel = panel_2D + self.type_panels = [panel_2D] + # + # 3D plane panel + # + panel_3D_plane = wx.Panel(self) + sizer_3D_plane = wx.GridBagSizer(10,10) + panel_3D_plane.SetSizer(sizer_3D_plane) + # + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label=' diameter (mm)'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.diameter_plane = wx.TextCtrl(panel_3D_plane,-1,'0.25') + sizer_3D_plane.Add(self.diameter_plane,(0,1),flag=(wx.ALIGN_LEFT)) + self.number_plane = wx.TextCtrl(panel_3D_plane,-1,'1') + sizer_3D_plane.Add(self.number_plane,(0,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label='offsets (-1 to fill)'),(0,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label='overlap (0-1)'),(1,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.overlap_plane = wx.TextCtrl(panel_3D_plane,-1,'0.5') + sizer_3D_plane.Add(self.overlap_plane,(1,1),flag=(wx.ALIGN_LEFT)) + self.error_plane = wx.TextCtrl(panel_3D_plane,-1,'1.1') + sizer_3D_plane.Add(self.error_plane,(1,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label='error (pixels)'),(1,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label='intensity (0-1) '),(2,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.intensity_plane = wx.TextCtrl(panel_3D_plane,-1,'0.5') + sizer_3D_plane.Add(self.intensity_plane,(2,1),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + self.z_plane = wx.TextCtrl(panel_3D_plane,-1,'0') + sizer_3D_plane.Add(self.z_plane,(2,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_plane.Add(wx.StaticText(panel_3D_plane,label='z (mm)'),(2,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + panel_3D_plane.Hide() + self.type_panels.append(panel_3D_plane) + # + # 3D rough panel + # + panel_3D_rough = wx.Panel(self) + sizer_3D_rough = wx.GridBagSizer(10,10) + panel_3D_rough.SetSizer(sizer_3D_rough) + # + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='diameter (mm)'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.diameter_rough = wx.TextCtrl(panel_3D_rough,-1,'0.25') + sizer_3D_rough.Add(self.diameter_rough,(0,1),flag=(wx.ALIGN_LEFT)) + self.number_rough = wx.TextCtrl(panel_3D_rough,-1,'-1') + sizer_3D_rough.Add(self.number_rough,(0,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='offsets (-1 to fill)'),(0,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='overlap (0-1)'),(1,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.overlap_rough = wx.TextCtrl(panel_3D_rough,-1,'0.5') + sizer_3D_rough.Add(self.overlap_rough,(1,1),flag=(wx.ALIGN_LEFT)) + self.error_rough = wx.TextCtrl(panel_3D_rough,-1,'1.1') + sizer_3D_rough.Add(self.error_rough,(1,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='error (pixels)'),(1,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='top intensity (0-1)'),(2,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.itop_rough = wx.TextCtrl(panel_3D_rough,-1,'1') + sizer_3D_rough.Add(self.itop_rough,(2,1),flag=(wx.ALIGN_LEFT)) + self.ztop_rough = wx.TextCtrl(panel_3D_rough,-1,'0') + sizer_3D_rough.Add(self.ztop_rough,(2,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='top z (mm)'),(2,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='bot intensity (0-1)'),(3,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.ibot_rough = wx.TextCtrl(panel_3D_rough,-1,'0') + sizer_3D_rough.Add(self.ibot_rough,(3,1),flag=(wx.ALIGN_LEFT)) + self.zbot_rough = wx.TextCtrl(panel_3D_rough,-1,'') + sizer_3D_rough.Add(self.zbot_rough,(3,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='bot z (mm)'),(3,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_rough.Add(wx.StaticText(panel_3D_rough,label='cut depth (mm)'),(4,1),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + self.zstep_rough = wx.TextCtrl(panel_3D_rough,-1,'1') + sizer_3D_rough.Add(self.zstep_rough,(4,2),flag=(wx.ALIGN_RIGHT)) + # + panel_3D_rough.Hide() + self.type_panels.append(panel_3D_rough) + # + # 3D finish panel + # + panel_3D_finish = wx.Panel(self) + sizer_3D_finish = wx.GridBagSizer(10,10) + panel_3D_finish.SetSizer(sizer_3D_finish) + # + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='tool diameter (mm)'),(0,1),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.diameter_finish = wx.TextCtrl(panel_3D_finish,-1,'0.25') + sizer_3D_finish.Add(self.diameter_finish,(0,2),flag=(wx.ALIGN_LEFT)) + # + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='overlap (0-1)'),(1,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.overlap_finish = wx.TextCtrl(panel_3D_finish,-1,'0.5') + sizer_3D_finish.Add(self.overlap_finish,(1,1),flag=(wx.ALIGN_LEFT)) + self.error_finish = wx.TextCtrl(panel_3D_finish,-1,'1.1') + sizer_3D_finish.Add(self.error_finish,(1,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='error (pixels)'),(1,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='top intensity (0-1)'),(2,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.itop_finish = wx.TextCtrl(panel_3D_finish,-1,'1') + sizer_3D_finish.Add(self.itop_finish,(2,1),flag=(wx.ALIGN_LEFT)) + self.ztop_finish = wx.TextCtrl(panel_3D_finish,-1,'0') + sizer_3D_finish.Add(self.ztop_finish,(2,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='top z (mm)'),(2,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='bot intensity (0-1)'),(3,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.ibot_finish = wx.TextCtrl(panel_3D_finish,-1,'0') + sizer_3D_finish.Add(self.ibot_finish,(3,1),flag=(wx.ALIGN_LEFT)) + self.zbot_finish = wx.TextCtrl(panel_3D_finish,-1,'') + sizer_3D_finish.Add(self.zbot_finish,(3,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='bot z (mm)'),(3,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='clearance length (mm)'),(4,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.clearance_length_finish = wx.TextCtrl(panel_3D_finish,-1,'0') + sizer_3D_finish.Add(self.clearance_length_finish,(4,1),flag=(wx.ALIGN_LEFT)) + self.clearance_diameter_finish = wx.TextCtrl(panel_3D_finish,-1,'0') + sizer_3D_finish.Add(self.clearance_diameter_finish,(4,2),flag=(wx.ALIGN_RIGHT)) + sizer_3D_finish.Add(wx.StaticText(panel_3D_finish,label='clearance diameter (mm)'),(4,3),flag=(wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)) + # + panel_3D_finish_4 = wx.Panel(panel_3D_finish) + sizer_3D_finish_4 = wx.GridBagSizer(10,10) + panel_3D_finish_4.SetSizer(sizer_3D_finish_4) + sizer_3D_finish_4.Add(wx.StaticText(panel_3D_finish_4,label='direction:'),(0,0),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.xz_finish = wx.CheckBox(panel_3D_finish_4,-1,'xz',(10,10)) + self.xz_finish.SetValue(True) + sizer_3D_finish_4.Add(self.xz_finish,(0,1),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.yz_finish = wx.CheckBox(panel_3D_finish_4,-1,'yz',(10,10)) + self.yz_finish.SetValue(True) + sizer_3D_finish_4.Add(self.yz_finish,(0,2),flag=wx.ALIGN_CENTER_HORIZONTAL) + sizer_3D_finish_4.Add(wx.StaticText(panel_3D_finish_4,label='type:'),(0,3),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.flat_end_finish = wx.RadioButton(panel_3D_finish_4,-1,'flat end',(10,10),style=wx.RB_GROUP) + sizer_3D_finish_4.Add(self.flat_end_finish,(0,4),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.ball_end_finish = wx.RadioButton(panel_3D_finish_4,-1,'ball end',(10,10)) + #self.ball_end_finish.Enable(False) + sizer_3D_finish_4.Add(self.ball_end_finish,(0,5),flag=wx.ALIGN_CENTER_HORIZONTAL) + sizer_3D_finish.Add(panel_3D_finish_4,(5,0),span=(1,4),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + panel_3D_finish.Hide() + self.type_panels.append(panel_3D_finish) + # + # fit + # + self.Fit() + # + # + # path type handler + # + def path_type_handler(self,event): + self.parent.path_type = self.path_types[event.GetSelection()] + self.parent.update_panels() + # + # parent call to update panel + # + def update_panel(self): + index = self.path_types.index(self.parent.path_type) + self.path_type.SetSelection(index) + self.sizer.Detach(self.type_panel) + self.type_panel.Hide() + self.sizer.Add(self.type_panels[index],(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_TOP)) + self.type_panels[index].Show() + self.type_panel = self.type_panels[index] + # + # check for 3D info in PNG + # + if (self.parent.png_file != ''): + temp_name = self.parent.tmp+'png_info' + command = 'png_size '+'\"'+self.parent.png_file+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + info = output_file.read() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + start = 3+string.find(info,'dz:') + if (start > 2): + # + # 3D info found, update + # + end = string.find(info,'mm',start)-1 + self.parent.zmin = -float(info[start:end])/self.parent.units + self.parent.zmax = 0 + if (self.parent.path_type == "3D rough"): + self.ztop_rough.SetValue(str(self.parent.units*self.parent.zmax)) + self.zbot_rough.SetValue(str(self.parent.units*self.parent.zmin)) + elif (self.parent.path_type == "3D finish"): + self.ztop_finish.SetValue(str(self.parent.units*self.parent.zmax)) + self.zbot_finish.SetValue(str(self.parent.units*self.parent.zmin)) + self.Layout() + self.Fit() + # + # parent call to update size + # + def update_size(self,sizex,sizey): + self.Layout() + self.Fit() diff --git a/src/py/panel_png_path_halftone.py b/src/py/panel_png_path_halftone.py new file mode 100644 index 0000000..323121a --- /dev/null +++ b/src/py/panel_png_path_halftone.py @@ -0,0 +1,121 @@ +# +# panel_png_path_halftone.py +# make .path from .png halftone +# +# Neil Gershenfeld +# CBA MIT 3/12/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class png_path_halftone_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.png_file = '' + # + # make path + # + def make_path(event): + if (self.parent.png_file == ''): + print "png_path: oops -- must make .png first" + return + self.parent.path_file = self.parent.tmp+self.parent.rootname+'.path' + path_png = self.parent.tmp+self.parent.rootname+'.path.png' + threshold = self.threshold.GetValue() + points = self.points.GetValue() + spot_size = self.size.GetValue() + spacing = self.spacing.GetValue() + offset = self.offset.GetValue() + invert = self.invert.GetValue() + if (invert == False): + invert = '0' + else: + invert = '1' + command = 'png_halftone '+'\"'+self.parent.filename+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+threshold+' '+points+' '+spot_size+' '+spacing+' '+offset+' '+invert + print command + os.system(command) + command = 'path_png '+'\"'+self.parent.path_file+'\"'+' '+'\"'+path_png+'\"' + print command + os.system(command) + command = 'png_scale '+'\"'+path_png+'\"'+' '+'\"'+path_png+'\"'+' 1 0' + print command + os.system(command) + path_image = wx.Image(path_png) + path_image = wx.Image.Blur(path_image,1) + (nx,ny) = path_image.GetSize() + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = self.parent.size/ratio + else: + self.parent.ysize = self.parent.size*ratio + self.parent.xsize = self.parent.size + wx.Image.Rescale(path_image,self.parent.xsize,self.parent.ysize,quality=wx.IMAGE_QUALITY_HIGH) + path_bitmap = path_image.ConvertToBitmap() + self.bitmap.SetBitmap(path_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: halftone path') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + image = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, (self.parent.size,self.parent.size)) + self.bitmap = wx.StaticBitmap(self,-1,image) + self.sizer.Add(self.bitmap,(1,0),span=(1,4),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + # + # controls + # + make = wx.Button(self,label='make .path') + make.Bind(wx.EVT_BUTTON,make_path) + self.sizer.Add(make,(2,0),span=(1,4),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.sizer.Add(wx.StaticText(self,label='minimum spot radius (pixels):'),(3,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.threshold = wx.TextCtrl(self,-1,'1') + self.sizer.Add(self.threshold,(3,1)) + # + self.sizer.Add(wx.StaticText(self,label='points per spot:'),(3,2),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.points = wx.TextCtrl(self,-1,'8') + self.sizer.Add(self.points,(3,3)) + # + self.sizer.Add(wx.StaticText(self,label='max spot size (mm):'),(4,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.size = wx.TextCtrl(self,-1,'1') + self.sizer.Add(self.size,(4,1)) + # + self.sizer.Add(wx.StaticText(self,label='spot spacing (1 = spot size):'),(4,2),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.spacing = wx.TextCtrl(self,-1,'1') + self.sizer.Add(self.spacing,(4,3)) + # + self.sizer.Add(wx.StaticText(self,label='row offset (1 = spot size):'),(5,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.offset = wx.TextCtrl(self,-1,'0.5') + self.sizer.Add(self.offset,(5,1)) + # + self.invert = wx.CheckBox(self,-1,"invert image") + self.invert.SetValue(False) + self.sizer.Add(self.invert,(5,2)) + # + self.parent.path_type = "2D" + # + # fit + # + self.Fit() diff --git a/src/py/panel_png_png.py b/src/py/panel_png_png.py new file mode 100644 index 0000000..0b26670 --- /dev/null +++ b/src/py/panel_png_png.py @@ -0,0 +1,100 @@ +# +# panel_png_png.py +# make .pngfrom .png +# +# Neil Gershenfeld +# CBA MIT 7/24/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os +# +# panel class +# +class png_png_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.png_file = '' + # + # make png + # + def make_path(event): + if (self.parent.png_file == ''): + print "png_png: oops -- must make .png first" + return + png_png_file = self.parent.tmp+self.parent.rootname+'.png' + threshold = self.threshold.GetValue() + if self.distances.GetValue(): + distances = '1' + else: + distances = '0' + command = 'png_distances '+'\"'+self.parent.png_file+'\"'+' '+'\"'+png_png_file+'\"'+' '+threshold+' '+distances + print command + os.system(command) + png_image = wx.Image(png_png_file) + png_image = wx.Image.Blur(png_image,1) + (nx,ny) = png_image.GetSize() + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = self.parent.size/ratio + else: + self.parent.ysize = self.parent.size*ratio + self.parent.xsize = self.parent.size + wx.Image.Rescale(png_image,self.parent.xsize,self.parent.ysize,quality=wx.IMAGE_QUALITY_HIGH) + path_bitmap = png_image.ConvertToBitmap() + self.bitmap.SetBitmap(path_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: png') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + image = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, (self.parent.size,self.parent.size)) + self.bitmap = wx.StaticBitmap(self,-1,image) + self.sizer.Add(self.bitmap,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + # + # controls + # + make = wx.Button(self,label='make .png') + make.Bind(wx.EVT_BUTTON,make_path) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + threshold_panel = wx.Panel(self) + threshold_sizer = wx.GridBagSizer(10,10) + threshold_panel.SetSizer(threshold_sizer) + threshold_sizer.Add(wx.StaticText(threshold_panel,label='threshold (0-1):'),(0,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.threshold = wx.TextCtrl(threshold_panel,-1,'0.5') + threshold_sizer.Add(self.threshold,(0,1)) + self.sizer.Add(threshold_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + type_panel = wx.Panel(self) + type_sizer = wx.GridBagSizer(10,10) + type_panel.SetSizer(type_sizer) + self.interior = wx.RadioButton(type_panel,label='interior',style=wx.RB_GROUP) + type_sizer.Add(self.interior,(0,0)) + self.distances = wx.RadioButton(type_panel,label='distances') + type_sizer.Add(self.distances,(0,1)) + self.sizer.Add(type_panel,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() diff --git a/src/py/panel_stl.py b/src/py/panel_stl.py new file mode 100644 index 0000000..80b01e7 --- /dev/null +++ b/src/py/panel_stl.py @@ -0,0 +1,153 @@ +# +# panel_stl.py +# read .stl +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +from panel_path import path_panel +# +# panel class +# +class stl_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.stl_file = '' + # + # get stl info + # + def stl_info(name): + # + # construct command + # + temp_name = self.parent.tmp+'stl_info' + command = 'stl_info '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + print output + if (string.find(output,'must be binary') != -1): + sys.exit(-1) + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + # + # read limits + # + start = 6+string.find(output,'xmax:') + space = string.find(output,' ',start) + end = string.find(output,'ymin',space)-4 + self.parent.xmin = float(output[start:space]) + self.parent.xmax = float(output[1+space:end]) + start = 6+string.find(output,'ymax:') + space = string.find(output,' ',start) + end = string.find(output,'zmin',space)-4 + self.parent.ymin = float(output[start:space]) + self.parent.ymax = float(output[1+space:end]) + start = 6+string.find(output,'zmax:') + space = string.find(output,' ',start) + self.parent.zmin = float(output[start:space]) + self.parent.zmax = float(output[space+1:-1]) + # + # move origin to top corner + # + # + self.parent.xmax = self.parent.xmax - self.parent.xmin + self.parent.xmin = 0 + self.parent.ymax = self.parent.ymax - self.parent.ymin + self.parent.ymin = 0 + self.parent.zmin = self.parent.zmin - self.parent.zmax + self.parent.zmax = 0 + # + return output + # + # load file + # + def load_file(event): + # + # get file name + # + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".stl") + if (pos == -1): + pos = string.find(self.parent.basename,".STL") + if (pos == -1): + print 'stl_panel: oops -- must be .stl' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + self.parent.stl_file = self.parent.filename + # + # get file info + # + info = stl_info(self.parent.filename) + self.info.SetLabel(info) + temp_name = self.parent.tmp+'stl.path' + # + # draw + # + if (self.path_viewer.view_type != "none"): + units = 1.0 + resolution = 100 + command = 'stl_path '+'\"'+self.parent.stl_file+'\"'+' '+'\"'+temp_name+'\"'+' '+str(units)+' '+str(resolution) + print command + ret = os.system(command) + if (ret == 0): + self.path_viewer.draw(temp_name) + # + # fit + # + self.parent.Layout() + self.parent.Fit() + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.stl;*.STL", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + load_file(0) + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: stl') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + self.path_viewer = path_panel(self) + self.sizer.Add(self.path_viewer,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.path_viewer.view_type = "segments" + # + # controls + # + load = wx.Button(self,label='load .stl') + load.Bind(wx.EVT_BUTTON,select_file) + self.sizer.Add(load,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() diff --git a/src/py/panel_stl_png.py b/src/py/panel_stl_png.py new file mode 100644 index 0000000..ad92d7b --- /dev/null +++ b/src/py/panel_stl_png.py @@ -0,0 +1,210 @@ +# +# panel_stl_png.py +# make .png from .stl +# +# Neil Gershenfeld +# CBA MIT 3/6/11 +# +# (c) Massachusetts Institute of Technology 2012 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,os,string +# +# panel class +# +class stl_png_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.png_file = '' + # + # get png info + # + def png_info(name): + temp_name = self.parent.tmp+'png_info' + command = 'png_size '+'\"'+name+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + return output + # + # make png + # + def make_png(event): + if (self.parent.stl_file == ''): + print "panel_stl_png: oops -- must read .stl first" + return + # + # construct command + # + self.parent.png_file = self.parent.tmp+self.parent.rootname+'.png' + units = self.units.GetValue() + self.parent.units = float(units) + resolution = self.resolution.GetValue() + if (self.x.GetValue()): + axis = 'x' + elif (self.X.GetValue()): + axis = 'X' + elif (self.y.GetValue()): + axis = 'y' + self.parent.zmin = 1234 + elif (self.Y.GetValue()): + axis = 'Y' + elif (self.z.GetValue()): + axis = 'z' + elif (self.Z.GetValue()): + axis = 'Z' + command = 'stl_png '+'\"'+self.parent.stl_file+'\"'+' '+'\"'+self.parent.png_file+'\"'+' '+units+' '+resolution+' '+axis + # + # generate PNG + # + print command + os.system(command) + # + # get image info + # + info = png_info(self.parent.png_file) + self.info.SetLabel(info) + start = 3+string.find(info,'dx:') + end = string.find(info,'mm',start)-1 + self.parent.xmin = 0 + self.parent.xmax = float(info[start:end])/self.parent.units + start = 3+string.find(info,'dy:') + end = string.find(info,'mm',start)-1 + self.parent.ymin = 0 + self.parent.ymax = float(info[start:end])/self.parent.units + start = 3+string.find(info,'dz:') + end = string.find(info,'mm',start)-1 + self.parent.zmin = -float(info[start:end])/self.parent.units + self.parent.zmax = 0 + # + # update panels + # + parent.update_panels() + # + # show image + # + png_image = wx.Image(self.parent.png_file) + (nx,ny) = png_image.GetSize() + ratio = float(ny)/float(nx) + if (ratio > 1): + self.parent.ysize = self.parent.size + self.parent.xsize = self.parent.size/ratio + else: + self.parent.ysize = self.parent.size*ratio + self.parent.xsize = self.parent.size + wx.Image.Rescale(png_image,self.parent.xsize,self.parent.ysize) + png_bitmap = png_image.ConvertToBitmap() + self.bitmap.SetBitmap(png_bitmap) + self.bitmap.Show() + self.parent.Layout() + self.parent.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: png') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + image = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, (self.parent.size,self.parent.size)) + self.bitmap = wx.StaticBitmap(self,-1,image) + self.sizer.Add(self.bitmap,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + self.bitmap.Hide() + def mouse_move(event): + if (self.x.GetValue()): + y = self.parent.units*(self.parent.ymin + (self.parent.ymax-self.parent.ymin)*event.GetX()/float(self.parent.xsize)) + z = self.parent.units*(self.parent.zmin + (self.parent.zmax-self.parent.zmin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("y: %.3f mm z: %.3f mm"%(y,z)) + elif (self.X.GetValue()): + y = self.parent.units*(self.parent.ymin + (self.parent.ymax-self.parent.ymin)*event.GetX()/float(self.parent.xsize)) + z = self.parent.units*(self.parent.zmin + (self.parent.zmax-self.parent.zmin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("y: %.3f mm z: %.3f mm"%(y,z)) + elif (self.y.GetValue()): + z = self.parent.units*(self.parent.zmin + (self.parent.zmax-self.parent.zmin)*event.GetX()/float(self.parent.xsize)) + x = self.parent.units*(self.parent.xmin + (self.parent.xmax-self.parent.xmin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("x: %.3f mm z: %.3f mm"%(x,z)) + elif (self.Y.GetValue()): + z = self.parent.units*(self.parent.zmin + (self.parent.zmax-self.parent.zmin)*(self.parent.xsize-event.GetX())/float(self.parent.xsize)) + x = self.parent.units*(self.parent.ymin + (self.parent.ymax-self.parent.ymin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("x: %.3f mm z: %.3f mm"%(x,z)) + elif (self.z.GetValue()): + x = self.parent.units*(self.parent.xmin + (self.parent.xmax-self.parent.xmin)*event.GetX()/float(self.parent.xsize)) + y = self.parent.units*(self.parent.ymin + (self.parent.ymax-self.parent.ymin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("x: %.3f mm y: %.3f mm"%(x,y)) + elif (self.Z.GetValue()): + x = self.parent.units*(self.parent.xmin + (self.parent.xmax-self.parent.xmin)*(self.parent.xsize-event.GetX())/float(self.parent.xsize)) + y = self.parent.units*(self.parent.ymin + (self.parent.ymax-self.parent.ymin)*(self.parent.ysize-event.GetY())/float(self.parent.ysize)) + self.position.SetLabel("x: %.3f mm y: %.3f mm"%(x,y)) + self.Layout() + self.Fit() + self.bitmap.Bind(wx.EVT_MOTION,mouse_move) + # + # controls + # + make = wx.Button(self,label='make .png') + make.Bind(wx.EVT_BUTTON,make_png) + self.sizer.Add(make,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + units_panel = wx.Panel(self) + units_panel_sizer = wx.GridBagSizer(10,10) + units_panel.SetSizer(units_panel_sizer) + units_panel_sizer.Add(wx.StaticText(units_panel,label='stl units (mm/unit):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.units = wx.TextCtrl(units_panel,-1,'1') + units_panel_sizer.Add(self.units,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(units_panel,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + res_panel = wx.Panel(self) + res_panel_sizer = wx.GridBagSizer(10,10) + res_panel.SetSizer(res_panel_sizer) + res_panel_sizer.Add(wx.StaticText(res_panel,label='png resolution (pixels/mm):'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.resolution = wx.TextCtrl(res_panel,-1,'25') + res_panel_sizer.Add(self.resolution,(0,1),flag=wx.ALIGN_LEFT) + self.sizer.Add(res_panel,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + axis_panel = wx.Panel(self) + axis_sizer = wx.GridBagSizer(10,10) + axis_panel.SetSizer(axis_sizer) + axis_sizer.Add(wx.StaticText(axis_panel,label='side:'),(0,0),flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + self.x = wx.RadioButton(axis_panel,label='x',style=wx.RB_GROUP) + axis_sizer.Add(self.x,(0,1)) + self.X = wx.RadioButton(axis_panel,label='-x') + axis_sizer.Add(self.X,(0,2)) + self.y = wx.RadioButton(axis_panel,label='y') + axis_sizer.Add(self.y,(0,3)) + self.Y = wx.RadioButton(axis_panel,label='-y') + axis_sizer.Add(self.Y,(0,4)) + self.z = wx.RadioButton(axis_panel,label='z') + axis_sizer.Add(self.z,(0,5)) + self.Z = wx.RadioButton(axis_panel,label='-z') + axis_sizer.Add(self.Z,(0,6)) + self.sizer.Add(axis_panel,(5,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + self.z.SetValue(True) + # + self.position= wx.StaticText(self,label="") + self.sizer.Add(self.position,(6,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + self.info = wx.StaticText(self,label="") + self.sizer.Add(self.info,(7,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # fit + # + self.Fit() + # + # parent call to update panel for workflow + # + def update_panel(self): + self.units.SetValue(str(self.parent.units)) + diff --git a/src/py/panel_svg.py b/src/py/panel_svg.py new file mode 100644 index 0000000..531e03b --- /dev/null +++ b/src/py/panel_svg.py @@ -0,0 +1,104 @@ +# +# panel_svg.py +# read and edit .svg +# +# Neil Gershenfeld +# CBA MIT 7/13/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# imports +# +import wx,string,os,sys +# +# panel class +# +class svg_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + # + # load file + # + def load_file(event): + if (self.parent.basename == ""): + return + pos = string.find(self.parent.basename,".svg") + if (pos == -1): + pos = string.find(self.parent.basename,".SVG") + if (pos == -1): + print 'svg_panel: oops -- must be .svg' + sys.exit() + self.parent.rootname = self.parent.basename[:pos] + svg_file = open(self.parent.filename,'r') + svg_string = svg_file.read() + svg_file.close() + self.text.SetValue(svg_string) + # + # select file + # + def select_file(event): + dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.svg", wx.OPEN) + if (dialog.ShowModal() == wx.ID_OK): + self.parent.filename = dialog.GetPath() + self.parent.basename = os.path.basename(self.parent.filename) + pos = string.find(self.parent.basename,".svg") + if (pos == -1): + print 'svg_panel: oops -- must be .svg' + sys.exit() + else: + self.parent.rootname = self.parent.basename[:pos] + svg_file = open(self.parent.filename,'r') + svg_string = svg_file.read() + svg_file.close() + self.text.SetValue(svg_string) + # + # save file + # + def save_file(event): + result = wx.SaveFileSelector('.svg','.svg',self.parent.filename) + if (result != ''): + svg_file = open(result,'w') + svg_file.write(self.text.GetValue()) + svg_file.close() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='from: svg') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # text + # + self.text = wx.TextCtrl(self,-1,'',size=(self.parent.size,self.parent.size),style=wx.TE_MULTILINE) + self.sizer.Add(self.text,(1,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)) + # + # controls + # + load = wx.Button(self,label='load .svg') + load.Bind(wx.EVT_BUTTON,select_file) + self.sizer.Add(load,(2,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + rload = wx.Button(self,label='reload .svg') + rload.Bind(wx.EVT_BUTTON,load_file) + self.sizer.Add(rload,(3,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + save = wx.Button(self,label='save .svg') + save.Bind(wx.EVT_BUTTON,save_file) + self.sizer.Add(save,(4,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # file + # + load_file(0) + # + # fit + # + self.Fit() diff --git a/src/py/panel_svg_path.py b/src/py/panel_svg_path.py new file mode 100644 index 0000000..9f8a1e6 --- /dev/null +++ b/src/py/panel_svg_path.py @@ -0,0 +1,189 @@ +# +# panel_svg_path.py +# make .path from .svg +# +# Neil Gershenfeld 9/8/13 +# (c) Massachusetts Institute of Technology 2013 +# +# This work may be reproduced, modified, distributed, +# performed, and displayed for any purpose, but must +# acknowledge the fab modules project. Copyright is +# retained and must be preserved. The work is provided +# as is; no warranty is provided, and users accept all +# liability. +# + +# +# imports +# +import wx,os,string +from panel_path import path_panel +# +# panel class +# +class svg_path_panel(wx.Panel): + def __init__(self,parent): + self.parent = parent + self.parent.zmin = 0 + self.parent.zmax = 0 + self.parent.units = 1 + # + # make path + # + def make_path(event): + if (self.parent.rootname == ''): + return + tmp_svg_file = self.parent.tmp+self.parent.rootname+'.svg' + svg_file = open(tmp_svg_file,'w') + svg_file.write(self.parent.svg_panel.text.GetValue()) + svg_file.close() + self.parent.path_file = self.parent.tmp+self.parent.rootname+'.path' + path_png = self.parent.tmp+self.parent.rootname+'.path.png' + if (self.path_type.GetValue() == '3D'): + scale = self.scale_3D.GetValue() + points = self.points_3D.GetValue() + resolution = self.resolution_3D.GetValue() + zmin = self.zmin.GetValue() + zmax = self.zmax.GetValue() + command = 'svg_path '+'\"'+tmp_svg_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+scale+' '+points+' '+resolution+' '+zmin+' '+zmax + print command + os.system(command) + temp_name = self.parent.tmp+'path_info' + command = 'path_info '+'\"'+self.parent.path_file+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + self.info_3D.SetLabel(output) + elif (self.path_type.GetValue() == '2D'): + scale = self.scale_2D.GetValue() + points = self.points_2D.GetValue() + resolution = self.resolution_2D.GetValue() + command = 'svg_path '+'\"'+tmp_svg_file+'\"'+' '+'\"'+self.parent.path_file+'\"'+' '+scale+' '+points+' '+resolution + print command + os.system(command) + temp_name = self.parent.tmp+'path_info' + command = 'path_info '+'\"'+self.parent.path_file+'\"'+' > '+'\"'+temp_name+'\"' + os.system(command) + output_file = open(temp_name,'r') + output = output_file.read() + output_file.close() + command = 'rm '+'\"'+temp_name+'\"' + os.system(command) + self.info_2D.SetLabel(output) + self.path_viewer.draw(self.parent.path_file) + self.parent.Layout() + self.parent.Fit() + # + # panel + # + wx.Panel.__init__(self,parent) + self.sizer = wx.GridBagSizer(10,10) + self.SetSizer(self.sizer) + # + # label + # + label = wx.StaticText(self,label='to: path') + bold_font = wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD) + label.SetFont(bold_font) + self.sizer.Add(label,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # image + # + self.path_viewer = path_panel(self) + self.sizer.Add(self.path_viewer,(1,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + # + # controls + # + make_panel = wx.Panel(self) + make_sizer = wx.GridBagSizer(10,10) + make_panel.SetSizer(make_sizer) + make_button = wx.Button(make_panel,label='make .path') + make_button.Bind(wx.EVT_BUTTON,make_path) + make_sizer.Add(make_button,(0,0),flag=wx.ALIGN_CENTER_HORIZONTAL) + make_sizer.Add(wx.StaticText(make_panel,label='type:'),(0,1),flag=(wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)) + self.path_types = ["2D","3D"] + self.path_type = wx.ComboBox(make_panel,size=(100,-1),value="2D",choices=self.path_types,style=wx.CB_READONLY) + self.parent.path_type = "2D" + self.path_type.Bind(wx.EVT_COMBOBOX,self.path_type_handler) + make_sizer.Add(self.path_type,(0,2),flag=wx.ALIGN_LEFT) + self.sizer.Add(make_panel,(2,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + # + # 2D panel + # + panel_2D = wx.Panel(self) + sizer_2D = wx.GridBagSizer(10,10) + panel_2D.SetSizer(sizer_2D) + # + sizer_2D.Add(wx.StaticText(panel_2D,label='scale factor'),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.scale_2D = wx.TextCtrl(panel_2D,-1,'1.0') + sizer_2D.Add(self.scale_2D,(0,2),flag=wx.ALIGN_LEFT) + # + sizer_2D.Add(wx.StaticText(panel_2D,label='curve points'),(1,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.points_2D = wx.TextCtrl(panel_2D,-1,'10') + sizer_2D.Add(self.points_2D,(1,1),flag=wx.ALIGN_LEFT) + self.resolution_2D = wx.TextCtrl(panel_2D,-1,'10000') + sizer_2D.Add(self.resolution_2D,(1,2),flag=wx.ALIGN_RIGHT) + sizer_2D.Add(wx.StaticText(panel_2D,label='path resolution'),(1,3),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)) + # + self.info_2D = wx.StaticText(panel_2D,label="") + sizer_2D.Add(self.info_2D,(2,0),span=(1,4),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) + # + self.sizer.Add(panel_2D,(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL)) + self.type_panel = panel_2D + self.type_panels = [panel_2D] + # + # 3D panel + # + panel_3D = wx.Panel(self) + sizer_3D = wx.GridBagSizer(10,10) + panel_3D.SetSizer(sizer_3D) + # + sizer_3D.Add(wx.StaticText(panel_3D,label='scale factor'),(0,1),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.scale_3D = wx.TextCtrl(panel_3D,-1,'1.0') + sizer_3D.Add(self.scale_3D,(0,2),flag=wx.ALIGN_LEFT) + # + sizer_3D.Add(wx.StaticText(panel_3D,label='curve points'),(1,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.points_3D = wx.TextCtrl(panel_3D,-1,'10') + sizer_3D.Add(self.points_3D,(1,1),flag=wx.ALIGN_LEFT) + self.resolution_3D = wx.TextCtrl(panel_3D,-1,'10000') + sizer_3D.Add(self.resolution_3D,(1,2),flag=wx.ALIGN_RIGHT) + sizer_3D.Add(wx.StaticText(panel_3D,label='path resolution'),(1,3),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)) + # + sizer_3D.Add(wx.StaticText(panel_3D,label='min intensity z (mm)'),(2,0),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)) + self.zmin = wx.TextCtrl(panel_3D,-1,'0') + sizer_3D.Add(self.zmin,(2,1),flag=wx.ALIGN_LEFT) + self.zmax = wx.TextCtrl(panel_3D,-1,'0') + sizer_3D.Add(self.zmax,(2,2),flag=wx.ALIGN_RIGHT) + sizer_3D.Add(wx.StaticText(panel_3D,label='max intensity z (mm)'),(2,3),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)) + # + self.info_3D = wx.StaticText(panel_3D,label="") + sizer_3D.Add(self.info_3D,(3,0),span=(1,4),flag=(wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL)) + # + panel_3D.Hide() + self.type_panels.append(panel_3D) + # + # fit + # + self.Fit() + # + # path type handler + # + def path_type_handler(self,event): + self.parent.path_type = self.path_types[event.GetSelection()] + self.parent.update_panels() + # + # parent call to update panel + # + def update_panel(self): + index = self.path_types.index(self.parent.path_type) + self.path_type.SetSelection(index) + self.sizer.Detach(self.type_panel) + self.type_panel.Hide() + self.sizer.Add(self.type_panels[index],(3,0),flag=(wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_TOP)) + self.type_panels[index].Show() + self.type_panel = self.type_panels[index] + self.Layout() + self.Fit() diff --git a/src/py/png_l.py b/src/py/png_l.py new file mode 100755 index 0000000..32f9b16 --- /dev/null +++ b/src/py/png_l.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# +# png_l.py +# converted a PNG image to a grayscale integer lattice +# png_l input.png output.l +# +# Neil Gershenfeld +# CBA MIT 7/2/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# todo +# C image library port +# pipe I/O +# variable bit depth +# z layers +# + +import sys, struct, Image +from numpy import * + +# +# read command line +# + +if len(sys.argv) == 3: + infile_name = sys.argv[1] + outfile_name = sys.argv[2] +else: + print "command line: png_l input.png output.l" + sys.exit() + + +# +# read image +# + +image = Image.open(infile_name) +(nx,ny) = image.size +nz = 1 +info = image.info +if ('dpi' in info): + (xdpi,ydpi) = info['dpi'] +else: + (xdpi,ydpi) = (1,1) +print "nx:",nx,"ny:",ny,"xdpi:",xdpi,"ydpi",ydpi + +# +# convert to grayscale +# + +image = image.convert("L") + +# +# set variables +# + +x0 = 0 +y0 = 0 +dx = nx/float(xdpi) +dy = ny/float(ydpi) +nz = 1 +z0 = 0 +dz = 0 +bytes_per_pixel = 1 + +# +# construct file buffer +# + +buf = struct.pack('I',nx) +buf += struct.pack('I',ny) +buf += struct.pack('I',nz) +buf += struct.pack('f',dx) +buf += struct.pack('f',dy) +buf += struct.pack('f',dz) +buf += struct.pack('f',x0) +buf += struct.pack('f',y0) +buf += struct.pack('f',z0) +buf += struct.pack('I',bytes_per_pixel) + +for y in range(ny): + for x in range(nx): + buf += struct.pack('B',image.getpixel((x,y))) + +# +# write to file +# + +outfile = open(outfile_name,"wb") +outfile.write(buf) +outfile.close() diff --git a/src/scripts/CMakeLists.txt b/src/scripts/CMakeLists.txt new file mode 100644 index 0000000..9f5492c --- /dev/null +++ b/src/scripts/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.6) + +set(SCRIPTS cad_png cad_view path_view rml_move + fab_send fab_update cad_math math_png_py math_stl_py + png_tile eagle_png + + CACHE STRING "Script file list") + +if( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + install(PROGRAMS ${SCRIPTS} DESTINATION ${PROJECT_SOURCE_DIR}/../bin) +endif( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) diff --git a/src/scripts/cad_math b/src/scripts/cad_math new file mode 100755 index 0000000..07cd904 --- /dev/null +++ b/src/scripts/cad_math @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# +# cad_math +# convert .cad to .math +# +# Neil Gershenfeld +# CBA MIT 4/18/11 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# + +import sys + +# Some older files need these imported +from math import * +from string import * + +class cad_variables: + # + # cad variables + # + def __init__(self): + self.xmin = 0 # minimum x value to render + self.xmax = 0 # maximum x value to render + self.ymin = 0 # minimum y value to render + self.ymax = 0 # maximum y value to render + self.zmin = 0 # minimum z value to render + self.zmax = 0 # maximum z value to render + self.layers = [] # optional number of layers to render + self.function = '' # cad function + self.labels = [] # display labels + self.mm_per_unit = 1.0 # file units + self.type = 'Boolean' # math string type + +cad = cad_variables() + +# +# command line args +# + +if (len(sys.argv) < 3): + print "command line: cad_math in.cad out.math [args]" + print " in.cad = input design file" + print " out.math = output math string file" + print " args = arguments to cad script" + print " (delivered in sys.argv)" + sys.exit() + + +# This line allows python to find other modules in the same folder +# as a .cad file. +sys.path.append('/'.join(sys.argv[1].split('/')[:-1])) + +# This allows for multi-file cad documents (e.g. a bunch of individual +# parts that all look to a set of common constants) + +# read & evaluate .cad file +input_file_name = sys.argv[1] +output_file_name = sys.argv[2] + +sys.argv = [input_file_name] + sys.argv[3:] +with open(input_file_name, 'r') as f: + exec(f.read()) + +print "read "+input_file_name + +# +# write .math file +# + +output_file = open(output_file_name,'wb') +output_file.write("format: %s\n" % cad.type) +output_file.write("mm per unit: %f\n" % cad.mm_per_unit) +output_file.write("dx dy dz: %f %f %f\n" % (cad.xmax-cad.xmin, + cad.ymax-cad.ymin, + cad.zmax-cad.zmin)) +output_file.write("xmin ymin zmin: %f %f %f\n" % (cad.xmin, + cad.ymin, + cad.zmin)) +output_file.write("expression: %s" % cad.function) + +print "write "+output_file_name +print " type: "+cad.type +print " units:",cad.mm_per_unit +print " dx: %f, dy: %f, dz: %f"%(cad.xmax-cad.xmin,cad.ymax-cad.ymin,cad.zmax-cad.zmin) +print " xmin: %f, ymin: %f, zmin: %f"%(cad.xmin,cad.ymin,cad.zmin) +if (cad.layers != []): + print " layers: %d"%cad.layers + diff --git a/src/scripts/cad_path b/src/scripts/cad_path new file mode 100755 index 0000000..bf86c6a --- /dev/null +++ b/src/scripts/cad_path @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# +# cad_path +# .cad to .path +# +# Neil Gershenfeld +# CBA MIT 11/6/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +import sys, os, string + +# +# command line args +# + +if ((len(sys.argv) < 3) | (len(sys.argv) > 11)): + print "command line: cad_path in.cad out.path [resolution [error [offset_diameter [offset_number [offset_overlap [z_thickness [z_top [z_bottom]]]]]]]]" + print " in.cad = input .cad file" + print " out.path = output .path file" + print " resolution = pixels per mm (optional, default 10)" + print " error = allowable vector fit deviation (optional, pixels, default 1.1)" + print " offset_diameter = diameter to offset (optional, mm, default 0)" + print " offset_number = number of contours to offset (optional, -1 to fill all, default 1)" + print " offset_overlap = tool offset overlap fraction (optional, 0 (no overlap) - 1 (complete overlap, default 0.5))" + print " z_thickness = slice z thickness (optional, mm, default in.cad value)" + print " z_top = top slice z value (optional, mm, default in.cad value)" + print " z_bottom = bottom slice z value (optional, mm, default in.cad value)" + sys.exit() + +resolution = "10" +if (len(sys.argv) > 3): + resolution = sys.argv[3] +error = "1.1" +if (len(sys.argv) > 4): + error = sys.argv[4] +offset_diameter = "0" +if (len(sys.argv) > 5): + offset_diameter = sys.argv[5] +offset_numer = "1" +if (len(sys.argv) > 6): + offset_number = sys.argv[6] +offset_overlap = ".5" +if (len(sys.argv) > 7): + offset_overlap = sys.argv[7] + +# +# convert to .math +# + +cad_file_name = sys.argv[1] +math_file_name = (os.path.splitext(cad_file_name)[0])+".math" +os.system("cad_math "+cad_file_name+" "+math_file_name) + +# +# get dims from .math +# + +math_file = open(math_file_name,'r') +file_type = math_file.readline() +units = float(math_file.readline()) +(dx,dy,dz) = string.split(math_file.readline()) +dx = units*float(dx) +dy = units*float(dy) +dz = units*float(dz) +(xmin,ymin,zmin) = string.split(math_file.readline()) +xmin = units*float(xmin) +ymin = units*float(ymin) +zmin = units*float(zmin) +math_file.close() + +z_thickness = dz +if (len(sys.argv) > 8): + z_thickness = float(sys.argv[8]) +z_top = zmin + dz +if (len(sys.argv) > 9): + z_top = float(sys.argv[9]) +z_bottom = zmin +if (len(sys.argv) > 10): + z_bottom = float(sys.argv[10]) + +# +# make image +# + +png_file_name = (os.path.splitext(cad_file_name)[0])+".png" +nz = int(1 + (z_top-z_bottom)/z_thickness) +os.system("math_png %s %s %s %d"%(math_file_name,png_file_name,resolution,nz)) + +# +# make path +# + +os.system("png_path %s %s %s %s %s %s 1 0 %f %f %f"%(png_file_name,sys.argv[2],error,offset_diameter,offset_number,offset_overlap,z_top,z_bottom,z_thickness)) diff --git a/src/scripts/cad_png b/src/scripts/cad_png new file mode 100755 index 0000000..e15b391 --- /dev/null +++ b/src/scripts/cad_png @@ -0,0 +1,34 @@ +#!/bin/bash +# +# cad_png +# convert .cad to PNG +# +# Neil Gershenfeld +# CBA MIT 10/27/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +# +# check command line +# +if [ $# -eq 0 ]; then + echo "command line: cad_png in.cad [args]" + echo " in.cad = input .cad file" + echo " args = math_png arguments (optional)" + exit + fi + +# +# convert to math string +# +name=$1 +cad_math $name ${name%.*}.math + +# +# convert to PNG +# +shift +math_png ${name%.*}.math ${name%.*}.png $@ diff --git a/src/scripts/cad_view b/src/scripts/cad_view new file mode 100755 index 0000000..9313782 --- /dev/null +++ b/src/scripts/cad_view @@ -0,0 +1,42 @@ +#!/bin/bash +# +# cad_view +# view .cad +# +# Neil Gershenfeld +# CBA MIT 10/27/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +viewer="eog" + +# +# check command line +# +if [ $# -eq 0 ]; then + echo "command line: cad_view in.cad [args]" + echo " in.cad = input .cad file" + echo " args = math_png arguments (optional)" + echo " image viewer = " $viewer + exit + fi + +# +# convert to math string +# +name=$1 +cad_math $name ${name%.*}.math + +# +# convert to PNG +# +shift +math_png ${name%.*}.math ${name%.*}.png $@ + +# +# view +# +$viewer ${name%.*}.png diff --git a/src/scripts/eagle_png b/src/scripts/eagle_png new file mode 100755 index 0000000..aecab39 --- /dev/null +++ b/src/scripts/eagle_png @@ -0,0 +1,185 @@ +#!/usr/bin/env python + +import os +import sys +import platform +import glob +import subprocess +import hashlib + +def find_eagle(): + if platform.uname()[0] == 'Darwin': + try: + eagle_dir = glob.glob('/Applications/EAGLE*')[-1] + except IndexError: + sys.stderr.write("Error: EAGLE not found.\n") + sys.exit(1) + + return eagle_dir + '/EAGLE.app/Contents/MacOS/EAGLE' + else: + if subprocess.call(['which','eagle'], + stdout = open(os.devnull, 'w')): + sys.stderr.write("Error: EAGLE not found.\n") + sys.exit(1) + return 'eagle' + +def create_images(name, resolution = 1500): + for img in ['top','bottom','cutout','holes','vias']: + file = '%s.%s.png' % (name, img) + if os.path.isfile(file): + os.remove(file) + + script = ''' +ratsnest; write; +set palette black; window; +display none top vias pads; +export image '{name}.top.png' monochrome {resolution}; +display none bottom vias pads; +export image '{name}.bottom.png' monochrome {resolution}; +display none milling; +export image '{name}.cutout.png' monochrome {resolution}; +display none holes; +export image '{name}.holes.png' monochrome {resolution}; +display none vias pads; +export image '{name}.vias.png' monochrome {resolution}; +quit'''.format(name = name, resolution = resolution) + subprocess.call([find_eagle(), '-C', script, name + '.brd']) + +def md5(filename): + with open(filename,'rb') as f: + m = hashlib.md5() + for chunk in iter(lambda: f.read(m.block_size*128), ''): + m.update(chunk) + return m.digest() + +def clean_up(name): + preserve = ['top','bottom','cutout'] + for img in ['top','bottom','cutout','holes','vias']: + file = '%s.%s.png' % (name, img) + file_ = '%s.%s_.png' % (name, img) + if os.path.isfile(file) and img not in preserve: + os.remove(file) + if os.path.isfile(file_): + os.remove(file_) + +def print_help(): + print """command line: eagle_png [options] target.brd + target.brd = EAGLE brd file to render + The board outline should be a solid polygon on the 'milling' layer + Internal cutouts should be solid shapes on the 'holes' layer + + Valid options: + --resolution NUM : sets output image resolution + --doublesided : forces double-sided mode""" + sys.exit(1) + +if __name__ == '__main__': + if len(sys.argv) == 1: + print_help() + sys.exit(1) + + # Parse arguments + sys.argv = sys.argv[1:] + resolution = 1500 + force_doublesided = False + + while sys.argv: + if sys.argv[0] == '--resolution': + try: + resolution = sys.argv[1] + sys.argv = sys.argv[2:] + except IndexError: + sys.stderr.write("Error: No resolution provided.\n") + sys.exit(1) + try: + resolution = int(resolution) + except ValueError: + sys.stderr.write("Error: Invalid resolution.\n") + sys.exit(1) + + elif sys.argv[0] == '--doublesided': + force_doublesided = True + sys.argv = sys.argv[1:] + + elif len(sys.argv) == 1: + break + else: + sys.stderr.write("Error: No filename provided.\n") + sys.exit(1) + + name = sys.argv[0].replace('.brd','') + if not os.path.isfile(name+'.brd'): + sys.stderr.write("Error: .brd file does not exist.\n") + sys.exit(1) + + vias = name + '.vias.png' + cutout = name + '.cutout.png' + top = name + '.top.png' + bottom = name + '.bottom.png' + holes = name + '.holes.png' + + print "Rendering images." + create_images(name, resolution) + + # Check to make sure that imagemagick is installed. + if subprocess.call(['which','convert'], stdout = open(os.devnull, 'w')): + sys.stderr.write("""Error: 'convert' not found. +ImageMagick command-line tools must be installed to use eagle_png.""") + sys.exit(1) + + print "Processing images." + + # The following command is a set of ImageMagick instructions that + # combine all of the images. + + # The following steps take place: + # - Perform a white flood fill on the vias image, starting in the upper + # left corner. This makes the via image a set of black holes on + # a uniform white background + # - Multiply the vias and cutout images, to cut the via holes from + # the cutout region. + # - Invert the cutout image. + # - Lighten the top and bottom traces with the inverted cutout. This + # ensures that we don't waste time milling traces in regions that + # will be cut out of the PCB. + # - Subtract the holes image from the original cutout image + # - Save this combined cutout image + + command = [ 'convert', + vias, '-fill', 'white', '-draw', 'color 0,0 floodfill', + cutout, '-compose', 'Darken', '-composite', + '-compose','Lighten', + '(', + '+clone', + '-negate' + ] + + # If this is a two-sided board, then process the bottom layer + if md5(bottom) != md5(vias) or force_doublesided: + command += [ + '(', + '+clone', bottom, '-composite', + '-flop', '-write', bottom, '+delete', + ')' + ] + else: + os.remove(bottom) + + # Process the top layer + command += [ + top, '-composite', '-write', top, + '+delete', + ')', + holes, '-compose', 'Minus_Src', '-composite', cutout + ] + + # Execute this whole mess + subprocess.call(command) + + os.remove(vias) + os.remove(holes) + + if bottom in command: + print "Generated %s, %s, %s." % (top, bottom, cutout) + else: + print "Generated %s, %s." % (top, cutout) diff --git a/src/scripts/fab_send b/src/scripts/fab_send new file mode 100755 index 0000000..84b15d5 --- /dev/null +++ b/src/scripts/fab_send @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# +# fab_send +# fab modules file send and configuration +# +# Neil Gershenfeld +# CBA MIT 9/16/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +# +# file type commands +# + +commands = { + '.eps': 'inkscape "$file"', + '.grb': 'gerbv "$file"', + '.drl': 'gerbv "$file"', + '.dxf': 'gedit "$file"', + '.epi': 'printer=laser; lprm -P$printer -; lpr -P$printer "$file"', + '.uni': 'port=/dev/lp0; cat "$file" > $port', + '.stl': 'meshlab "$file"', + '.ord': 'gedit "$file"', + '.camm': 'printer=vinyl; lpr -P$printer "$file"', + '.rml': 'port=/dev/ttyUSB0; rml_send_gui "$file" $port', + '.g': 'gedit "$file"', + '.sbp': 'gedit "$file"', + '.plt': 'gedit "$file"', + '.oms': 'gedit "$file"', + } + +# +# imports +# + +import sys,os + +# +# command line +# + +if (len(sys.argv) == 1): + print "command line: fab_send [file]" + print " file = file to send" + print " file type commands:" + print " ",commands + sys.exit() + +# +# get command +# + +filename = sys.argv[1] + +filetype = os.path.splitext(filename)[-1] + +if (not commands.has_key(filetype)): + print "fab_send:",filetype,"not defined" + sys.exit() + +command = 'file="'+filename+'"; '+commands[filetype] + +# +# execute +# + +print command +os.system(command) + diff --git a/src/scripts/fab_update b/src/scripts/fab_update new file mode 100755 index 0000000..6ea08e6 --- /dev/null +++ b/src/scripts/fab_update @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +import datetime +import os +import re +import subprocess +import shutil +import sys +import urllib2 + +src_zip = os.path.join(os.getenv('HOME'), '__fab_src__.zip') +src_dir = os.path.join(os.getenv('HOME'), '__fab_src__') + +# Check when this script was installed +my_date = datetime.datetime.fromtimestamp(os.path.getmtime(sys.argv[0])) + +def get_date(): + '''Extracts the snapshot date from the kokompe downloads page.''' + html = urllib2.urlopen('http://kokompe.cba.mit.edu/downloads.html').read() + date = re.search('Snapshot from ([^\)]*)', html).group(1) + return datetime.datetime.strptime(date, '%B %d, %Y, %I:%M%p') + +def download(): + '''Downloads fab_src.zip, saving it in the user's home directory.''' + if os.path.isfile(src_zip): + print '''Error: Working file ~/__fab_src__.zip already exists. +Please delete it then rerun fab_update.''' + sys.exit(1) + zip = urllib2.urlopen('http://kokompe.cba.mit.edu/fab_src.zip') + open(src_zip,'wb').write(zip.read()) + +def unzip(): + '''Unzips fab_src.zip then removes the zip file.''' + if os.path.isdir(src_dir): + print '''Error: Working directory ~/__fab_src__ already exists. +Please delete it then rerun fab_update''' + sys.exit(1) + os.mkdir(src_dir) + os.chdir(src_dir) + subprocess.call(['unzip', src_zip]) + os.remove(src_zip) + +def print_help(): + print '''command line: fab_update [check|install] + check will inform you if a newer version of the fab modules is available. + install will install a newer version of the fab modules, if applicable.''' + +if __name__ == '__main__': + if len(sys.argv) == 1: + print_help() + sys.exit(1) + + # Check the date on the web to figure out if it is newer. + web_date = get_date() + date_info = ''' Your version was installed %s + Online version is dated %s''' % (my_date.strftime('%B %d, %Y, %I:%M%p'), + web_date.strftime('%B %d, %Y, %I:%M%p')) + outdated = web_date > my_date + + # Check to see if the web version is newer than our version. + if sys.argv[1] == 'check': + web_date = get_date() + if outdated: + print 'Newer version is available:\n%s' % date_info + else: + print 'No newer version available:\n%s' % date_info + + # Download & install if the web version is newer than this version + elif sys.argv[1] == 'install': + web_date = get_date() + if not outdated: + print 'No newer version available:\n%s' % date_info + sys.exit(0) + print "Downloading source" + download() + print "Unzipping source" + unzip() + print "Installing" + if subprocess.call(['make','fab']) != 0: + print 'Build failed. Please make sure your dependancies are up-to-date.' + shutil.rmtree(src_dir) + sys.exit(1) + subprocess.call(['make','install']) + shutil.rmtree(src_dir) + + # Invalid option + else: + print 'Invalid option "%s"' % ' '.join(sys.argv[1:]) + print_help() + sys.exit(1) diff --git a/src/scripts/math_png_py b/src/scripts/math_png_py new file mode 100755 index 0000000..623ba7a --- /dev/null +++ b/src/scripts/math_png_py @@ -0,0 +1,656 @@ +#!/usr/bin/env python +# +# math_png +# compile and evaluate .math to PNG +# +# Neil Gershenfeld +# CBA MIT 4/18/11 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# todo +# rotated view +# + +import sys +import string +import Image +import os +from numpy import * + +# +# command line args +# + +if (not((len(sys.argv) == 3) | (len(sys.argv) == 4) | (len(sys.argv) == 5) | (len(sys.argv) == 6)| (len(sys.argv) == 9))): + print "command line: math_png_py in.math out.png [resolution [number [view [rx ry rx]]]]" + print " in.math = input math string file" + print " out.png = output PNG image" + print " resolution = pixels per mm (optional, default 10)" + print " number = number of z slices to evaluate (optional, default 1)" + print " view = view projection(s) (optional, z|3, default z)" + print " rx ry rz = 3D view angle (optional, degrees, default 70 0 20)" + print "[This command is deprecated; use math_png instead.]" + sys.exit() + +resolution = "10" +if (len(sys.argv) > 3): + resolution = sys.argv[3] + +number = "1" +if (len(sys.argv) > 4): + number = sys.argv[4] + +view = "z" +if (len(sys.argv) > 5): + view = sys.argv[5] + +rx = "70" +ry = "10" +rz = "20" +if (len(sys.argv) > 6): + rx = sys.argv[6] + ry = sys.argv[7] + rz = sys.argv[8] +# +# read .math file +# + +input_file_name = sys.argv[1] +output_file_name = sys.argv[2] +input_file = open(input_file_name,'r') +file_type = string.split(input_file.readline(), ': ')[1][:-1] +units = float(string.split(input_file.readline(), ': ')[1][:-1]) +dx,dy,dz = string.split(input_file.readline())[3:] +xmin,ymin,zmin = string.split(input_file.readline())[3:] +math_string = input_file.readline()[1][:-1] +input_file.close() +print "read "+input_file_name +print " math string type: "+file_type +print " ",units,"mm per unit" +print " dx: "+dx+", dy: "+dy+", dz: "+dz +print " xmin: "+xmin+", ymin: "+ymin+", zmin: "+zmin + +# +# write evaluation program +# + +program = """// +// math_png_eval.c +// math string to PNG evaluation generated by math_png +// +// Neil Gershenfeld +// CBA MIT 3/6/11 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include +#include +#include +#include +#include +#include + +// +// data structures +// + +struct fab_vars { + unsigned char empty; + unsigned char interior; + unsigned char edge; + unsigned char north; + unsigned char south; + unsigned char east; + unsigned char west; + unsigned char stop; + unsigned char corner; + unsigned char corner2; + unsigned char direction; + unsigned int nx,ny,nz; + unsigned int bit_depth; + unsigned int word_size; + double dx,dy,dz; + double xmin,ymin,zmin; + uint8_t **red,**green,**blue; + uint16_t **intensity; + short int **xptr, **yptr; + struct fab_path_type *path; + struct fab_mesh_type *mesh; + png_bytep *row_pointers; + png_structp png_ptr; + png_infop info_ptr; + }; + +void fab_write_png_K16(struct fab_vars *v, char *output_file_name) { + // + // write 16-bit grayscale PNG from fab_vars + // + FILE *output_file; + int x,y; + png_uint_32 res_x,res_y; + int unit_type; + png_byte color_type; + png_byte bit_depth; + png_byte *ptr; + // + // open PNG file + // + output_file = fopen(output_file_name, "wb"); + v->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + v->info_ptr = png_create_info_struct(v->png_ptr); + png_init_io(v->png_ptr, output_file); + // + // set vars + // + bit_depth = 16; + color_type = PNG_COLOR_TYPE_GRAY; + png_set_IHDR(v->png_ptr, v->info_ptr, v->nx, v->ny, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + res_x = 1000 * v->nx / v->dx; + res_y = 1000 * v->ny / v->dy; + png_set_pHYs(v->png_ptr, v->info_ptr, res_x, res_y, PNG_RESOLUTION_METER); + png_write_info(v->png_ptr, v->info_ptr); + // + // allocate pixels + // + v->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * v->ny); + for (y = 0; y < v->ny; ++y) + v->row_pointers[y] = (png_byte*) malloc(v->info_ptr->rowbytes); + // + // set pixels + // + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*2]); + ptr[0] = (v->intensity[y][x] >> 8) & 255; + ptr[1] = v->intensity[y][x] & 255; + } + // + // write, close, and return + // + png_write_image(v->png_ptr, v->row_pointers); + png_write_end(v->png_ptr, NULL); + fclose(output_file); + printf("write %s\\n",output_file_name); + printf(" x pixels: %d, y pixels: %d\\n",v->nx,v->ny); + printf(" x pixels/m: %d, y pixels/m: %d\\n",(int) res_x,(int) res_y); + printf(" dx: %f mm, dy: %f mm\\n",v->dx,v->dy); + } + +void fab_write_png_RGB24(struct fab_vars *v, char *output_file_name) { + // + // write 24-bit RGB PNG from fab_vars + // + FILE *output_file; + int x,y; + png_uint_32 res_x,res_y; + int unit_type; + png_byte color_type; + png_byte bit_depth; + png_byte *ptr; + // + // open PNG file + // + output_file = fopen(output_file_name, "wb"); + v->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + v->info_ptr = png_create_info_struct(v->png_ptr); + png_init_io(v->png_ptr, output_file); + // + // set vars + // + bit_depth = 8; + color_type = PNG_COLOR_TYPE_RGB; + png_set_IHDR(v->png_ptr, v->info_ptr, v->nx, v->ny, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + res_x = 1000 * v->nx / v->dx; + res_y = 1000 * v->ny / v->dy; + png_set_pHYs(v->png_ptr, v->info_ptr, res_x, res_y, PNG_RESOLUTION_METER); + png_write_info(v->png_ptr, v->info_ptr); + // + // allocate pixels + // + v->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * v->ny); + for (y = 0; y < v->ny; ++y) + v->row_pointers[y] = (png_byte*) malloc(v->info_ptr->rowbytes); + // + // set pixels + // + for (y = 0; y < v->ny; ++y) + for (x = 0; x < v->nx; ++x) { + ptr = &(v->row_pointers[y][x*3]); + ptr[0] = v->red[y][x]; + ptr[1] = v->green[y][x]; + ptr[2] = v->blue[y][x]; + } + // + // write, close, and return + // + png_write_image(v->png_ptr, v->row_pointers); + png_write_end(v->png_ptr, NULL); + fclose(output_file); + printf("write %s\\n",output_file_name); + printf(" x pixels: %d, y pixels: %d\\n",v->nx,v->ny); + printf(" x pixels/m: %d, y pixels/m: %d\\n",(int) res_x,(int) res_y); + printf(" dx: %f mm, dy: %f mm\\n",v->dx,v->dy); + } + +struct fab_vars init_vars() { + // + // fab_vars constructor + // + struct fab_vars v; + // + v.empty = 0; + v.interior = 1; + v.edge = (1 << 1); + v.north = (1 << 2); + v.west = (2 << 2); + v.east = (3 << 2); + v.south = (4 << 2); + v.stop = (5 << 2); + v.corner = (6 << 2); + v.corner2 = (7 << 2); + v.direction = (7 << 2); + // + return v; + } + +""" +if (view == 'z'): + program +=""" +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v = init_vars(&v); + double units = 25.4; + double X,Y,Z; + v.dx = units*"""+dx+"""; + v.dy = units*"""+dy+"""; + v.dz = units*"""+dz+"""; + v.xmin = units*"""+xmin+"""; + v.ymin = units*"""+ymin+"""; + v.zmin = units*"""+zmin+"""; + double resolution="""+resolution+"""; + v.nx = resolution*v.dx; + v.ny = resolution*v.dy; + v.nz = """+number+"""; + int x,y,z; + uint32_t val; + uint8_t byte; + float scale; + // + // create arrays + // + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + v.intensity = malloc(v.ny*sizeof(uint16_t *)); + for (y = 0; y < v.ny; ++y) { + v.intensity[y] = (uint16_t*) malloc(v.nx*sizeof(uint16_t)); + } + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + v.red = malloc(v.ny*sizeof(uint16_t *)); + v.green = malloc(v.ny*sizeof(uint16_t *)); + v.blue = malloc(v.ny*sizeof(uint16_t *)); + for (y = 0; y < v.ny; ++y) { + v.red[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + v.green[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + v.blue[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + } + } + else { + printf("math_png: oops -- file type not recognized\\n"); + exit(-1); + } + // + // evaluate + // + for (z = 0; z < v.nz; ++z) { + if (v.nz == 1) { + Z = v.zmin/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535; + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = 1; + } + else { + Z = (v.zmin + v.dz*z/(v.nz-1.0))/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535 * z/(v.nz-1.0); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = z/(v.nz-1.0); + } + printf(" Z = %f\\n",Z); + for (y = 0; y < v.ny; ++y) { + Y = (v.ymin + v.dy*(v.ny-y-1)/(v.ny-1.0))/units; + for (x = 0; x < v.nx; ++x) { + X = (v.xmin + v.dx*x/(v.nx-1.0))/units; + val = """+math_string+"""; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + val = scale*val; + if (val > v.intensity[y][x]) + v.intensity[y][x] = val; + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + byte = scale * (val & 255); + if (val > v.red[y][x]) + v.red[y][x] = byte; + byte = scale * ((val >> 8) & 255); + if (val > v.green[y][x]) + v.green[y][x] = byte; + byte = scale * ((val >> 16) & 255); + if (val > v.blue[y][x]) + v.blue[y][x] = byte; + } + } + } + } + // + // write PNG + // + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + fab_write_png_K16(&v,\""""+output_file_name+"""\"); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + fab_write_png_RGB24(&v,\""""+output_file_name+"""\"); + } +""" +elif (view == 'r'): + program +=""" +main(int argc, char **argv) { + // + // to be completed + // + // local vars + // + struct fab_vars v = init_vars(&v); + double units = 25.4; + double X,Y,Z,X0,Y0,Z0,X1,Y1,Z1; + v.dx = units*"""+dx+"""; + v.dy = units*"""+dy+"""; + v.dz = units*"""+dz+"""; + v.xmin = units*"""+xmin+"""; + v.ymin = units*"""+ymin+"""; + v.zmin = units*"""+zmin+"""; + double resolution="""+resolution+"""; + int nx = resolution*v.dx; + int ny = resolution*v.dy; + int nz = resolution*v.dz; + v.nx = resolution*(v.dx); + v.ny = resolution*(v.dy); + v.nz = """+number+"""; + int x,y,z; + uint32_t val; + int scale; + double pi = 3.14159; + double rx = pi*"""+rx+"""/180.0; + double ry = pi*"""+ry+"""/180.0; + double rz = pi*"""+rz+"""/180.0; + // + // create RGB array + // + v.rgb = malloc(v.ny*sizeof(uint32_t *)); + for (y = 0; y < v.ny; ++y) + v.rgb[y] = (uint32_t*) malloc(2*v.nx*sizeof(uint32_t)); + // + // evaluate xyz + // + for (z = 0; z < v.nz; ++z) { + if (v.nz == 1) { + Z0 = v.zmin/units; + scale = 1; + } + else { + Z0 = (v.zmin + v.dz*z/(v.nz-1.0))/units; + scale = 255 * z/(v.nz-1.0); + } + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = scale + (scale << 8) + (scale << 16); + printf(" Z = %f\\n",Z0); + for (y = 0; y < v.ny; ++y) { + Y0 = (v.ymin + v.dy*(v.ny-y-1)/(v.ny-1.0))/units; + for (x = 0; x < v.nx; ++x) { + X0 = (v.xmin + v.dx*x/(v.nx-1.0))/units; + X1 = X0; + Y1 = cos(rx)*Y0 - sin(rx)*Z0; + Z1 = sin(rx)*Y0 + cos(rx)*Z0; + X = cos(rz)*X1 - sin(rz)*Y1; + Y = sin(rz)*X1 + cos(rz)*Y1; + Z = Z1; + val = """+math_string+"""; + val = scale*val; + if (val > v.rgb[y][x]) { + v.rgb[y][x] = val; + } + } + } + } + // + // write PNG + // + fab_write_png(&v,\""""+output_file_name+"""\"); + } +""" +elif (view == '3'): + program +=""" +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v = init_vars(&v); + double units = 25.4; + double X,Y,Z,X0,Y0,Z0,X1,Y1,Z1; + v.dx = units*"""+dx+"""; + v.dy = units*"""+dy+"""; + v.dz = units*"""+dz+"""; + v.xmin = units*"""+xmin+"""; + v.ymin = units*"""+ymin+"""; + v.zmin = units*"""+zmin+"""; + double resolution="""+resolution+"""; + int nx = resolution*v.dx; + int ny = resolution*v.dy; + int nz = resolution*v.dz; + int border = nx/25; + v.nx = border + nx + nz; + v.ny = border + ny + nz; + v.nz = """+number+"""; + int x,y,z; + uint32_t val; + uint8_t byte; + float scale; + // + // create arrays + // + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + v.intensity = malloc(v.ny*sizeof(uint16_t *)); + for (y = 0; y < v.ny; ++y) { + v.intensity[y] = (uint16_t*) malloc(v.nx*sizeof(uint16_t)); + } + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + v.red = malloc(v.ny*sizeof(uint16_t *)); + v.green = malloc(v.ny*sizeof(uint16_t *)); + v.blue = malloc(v.ny*sizeof(uint16_t *)); + for (y = 0; y < v.ny; ++y) { + v.red[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + v.green[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + v.blue[y] = (uint8_t*) malloc(v.nx*sizeof(uint8_t)); + } + } + else { + printf("math_png: oops -- file type not recognized\\n"); + exit(-1); + } + // + // evaluate xy + // + for (z = 0; z < v.nz; ++z) { + if (v.nz == 1) { + Z = v.zmin/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535; + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = 1; + } + else { + Z = (v.zmin + v.dz*z/(v.nz-1.0))/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535 * z/(v.nz-1.0); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = z/(v.nz-1.0); + } + printf(" Z = %f\\n",Z); + for (y = 0; y < ny; ++y) { + Y = (v.ymin + v.dy*(ny-y-1)/(ny-1.0))/units; + for (x = 0; x < nx; ++x) { + X = (v.xmin + v.dx*x/(nx-1.0))/units; + val = """+math_string+"""; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + val = scale*val; + if (val > v.intensity[y][x]) + v.intensity[y][x] = val; + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + byte = scale * (val & 255); + if (val > v.red[y][x]) + v.red[y][x] = byte; + byte = scale * ((val >> 8) & 255); + if (val > v.green[y][x]) + v.green[y][x] = byte; + byte = scale * ((val >> 16) & 255); + if (val > v.blue[y][x]) + v.blue[y][x] = byte; + } + } + } + } + // + // evaluate xz + // + for (y = 0; y < v.nz; ++y) { + if (v.nz == 1) { + Y = v.ymin/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535; + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = 1; + } + else { + Y = (v.ymin + v.dy*(v.nz-y-1)/(v.nz-1.0))/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535 * y/(v.nz-1.0); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = y/(v.nz-1.0); + } + printf(" Y = %f\\n",Y); + for (z = 0; z < nz; ++z) { + Z = (v.zmin + v.dz*(nz-z-1)/(nz-1.0))/units; + for (x = 0; x < nx; ++x) { + X = (v.xmin + v.dx*x/(nx-1.0))/units; + val = """+math_string+"""; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + val = scale*val; + if (val > v.intensity[ny+border+z][x]) + v.intensity[ny+border+z][x] = val; + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + byte = scale * (val & 255); + if (val > v.red[y][x]) + v.red[y][x] = byte; + byte = scale * ((val >> 8) & 255); + if (val > v.green[y][x]) + v.green[y][x] = byte; + byte = scale * ((val >> 16) & 255); + if (val > v.blue[y][x]) + v.blue[y][x] = byte; + } + } + } + } + // + // evaluate zy + // + for (x = 0; x < v.nz; ++x) { + if (v.nz == 1) { + X = v.xmin/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535; + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = 1; + } + else { + X = (v.xmin + v.dx*x/(v.nz-1.0))/units; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + scale = 65535 * x/(v.nz-1.0); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + scale = x/(v.nz-1.0); + } + printf(" X = %f\\n",X); + for (y = 0; y < ny; ++y) { + Y = (v.ymin + v.dy*(ny-y-1)/(ny-1.0))/units; + for (z = 0; z < nz; ++z) { + Z = (v.zmin + v.dz*(nz-z-1)/(nz-1.0))/units; + val = """+math_string+"""; + if (0 == strcmp(\""""+file_type+"""\","Boolean")) { + val = scale*val; + if (val > v.intensity[y][nx+border+z]) + v.intensity[y][nx+border+z] = val; + } + else if (0 == strcmp(\""""+file_type+"""\","RGB")) { + byte = scale * (val & 255); + if (val > v.red[y][x]) + v.red[y][x] = byte; + byte = scale * ((val >> 8) & 255); + if (val > v.green[y][x]) + v.green[y][x] = byte; + byte = scale * ((val >> 16) & 255); + if (val > v.blue[y][x]) + v.blue[y][x] = byte; + } + } + } + } + // + // write PNG + // + if (0 == strcmp(\""""+file_type+"""\","Boolean")) + fab_write_png_K16(&v,\""""+output_file_name+"""\"); + else if (0 == strcmp(\""""+file_type+"""\","RGB")) + fab_write_png_RGB24(&v,\""""+output_file_name+"""\"); + } +""" +else: + print "view "+view+" not recognized" + sys.exit() + +eval_file = open("math_png_eval.c",'w') +eval_file.write(program) +eval_file.close() + +# +# compile +# + +print "compile" +if os.uname()[0] == 'Darwin': + os.system("gcc -O math_png_eval.c -o math_png_eval -lm -I/usr/X11/include -L/usr/X11/lib -lpng") +else: + os.system("gcc -O math_png_eval.c -o math_png_eval -lm -lpng") + +# +# execute +# + +print "execute" +os.system("./math_png_eval") +#os.system("rm ./math_png_eval.c") +os.system("rm ./math_png_eval") diff --git a/src/scripts/math_stl_py b/src/scripts/math_stl_py new file mode 100755 index 0000000..3eb04e5 --- /dev/null +++ b/src/scripts/math_stl_py @@ -0,0 +1,465 @@ +#!/usr/bin/env python +# +# math_stl +# compile and evaluate .math to STL +# +# todo +# run-length code +# prune triangulation +# +# Neil Gershenfeld +# CBA MIT 10/29/11 +# +# (c) Massachusetts Institute of Technology 2011 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# +# + +import sys +import string +import Image +import os +from numpy import * + +# +# command line args +# + +if (not((len(sys.argv) == 3) | (len(sys.argv) == 4))): + print "command line: math_stl in.math out.stl [resolution]" + print " in.math = input math string file" + print " out.stl = output STL image" + print " resolution = pixels per mm (optional, default 1)" + sys.exit() + +resolution = "1" +if (len(sys.argv) == 4): + resolution = sys.argv[3] + +# +# read .math file +# + +input_file_name = sys.argv[1] +output_file_name = sys.argv[2] +input_file = open(input_file_name,'r') +(file_type,) = string.split(input_file.readline()) +(units,) = string.split(input_file.readline()) +units = float(units) +(dx,dy,dz) = string.split(input_file.readline()) +(xmin,ymin,zmin) = string.split(input_file.readline()) +math_string = input_file.readline() +input_file.close() +print "read "+input_file_name +print " math string type: "+file_type +print " ",units,"mm per unit" +print " dx: "+dx+", dy: "+dy+", dz: "+dz +print " xmin: "+xmin+", ymin: "+ymin+", zmin: "+zmin + +# +# write evaluation program +# + +program = """// +// math_stl_eval.c +// math string to STL evaluation generated by math_stl +// +// Neil Gershenfeld +// CBA MIT 10/29/11 +// +// (c) Massachusetts Institute of Technology 2011 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +#include +#include +#include +#include +#include + +// +// data structures +// + +struct fab_vars { + unsigned char empty; + unsigned char interior; + unsigned char edge; + unsigned char north; + unsigned char south; + unsigned char east; + unsigned char west; + unsigned char stop; + unsigned char corner; + unsigned char corner2; + unsigned char direction; + unsigned int nx,ny,nz; + unsigned int bit_depth; + unsigned int word_size; + double dx,dy,dz; + double xmin,ymin,zmin; + unsigned char **array; + uint32_t **rgb0,**rgb1; + short int **xptr, **yptr; + struct fab_path_type *path; + struct fab_mesh_type *mesh; + png_bytep *row_pointers; + png_structp png_ptr; + png_infop info_ptr; + }; + +struct fab_vars init_vars() { + // + // fab_vars constructor + // + struct fab_vars v; + // + v.empty = 0; + v.interior = 1; + v.edge = (1 << 1); + v.north = (1 << 2); + v.west = (2 << 2); + v.east = (3 << 2); + v.south = (4 << 2); + v.stop = (5 << 2); + v.corner = (6 << 2); + v.corner2 = (7 << 2); + v.direction = (7 << 2); + // + return v; + } + +main(int argc, char **argv) { + // + // local vars + // + struct fab_vars v = init_vars(&v); + double units = 25.4; + double X,Y,Z; + double dx,dy,dz; + v.dx = units*"""+dx+"""; + v.dy = units*"""+dy+"""; + v.dz = units*"""+dz+"""; + v.xmin = units*"""+xmin+"""; + v.ymin = units*"""+ymin+"""; + v.zmin = units*"""+zmin+"""; + double resolution="""+resolution+"""; + v.nx = resolution*v.dx; + v.ny = resolution*v.dy; + v.nz = resolution*v.dz; + int x,y,z; + uint32_t val; + // + // create RGB arrays + // + v.rgb0 = malloc(v.ny*sizeof(uint32_t *)); + for (y = 0; y < v.ny; ++y) + v.rgb0[y] = (uint32_t*) malloc(v.nx*sizeof(uint32_t)); + v.rgb1 = malloc(v.ny*sizeof(uint32_t *)); + for (y = 0; y < v.ny; ++y) + v.rgb1[y] = (uint32_t*) malloc(v.nx*sizeof(uint32_t)); + // + // create triangle array + // + uint32_t triangle_count=0; + struct triangle_type { + int v0x,v0y,v0z; + int v1x,v1y,v1z; + int v2x,v2y,v2z; + struct triangle_type *next; + }; + struct triangle_type *t,*tstart,*tnew; + t = malloc(sizeof(struct triangle_type)); + tstart = t; + // + // loop over layers + // + for (z = 0; z < v.nz; ++z) { + Z = (v.zmin + v.dz*z/(v.nz-1.0))/units; + printf(" Z = %f\\n",Z); + // + // evaluate new layer + // + for (y = 0; y < v.ny; ++y) { + Y = (v.ymin + v.dy*(v.ny-y-1)/(v.ny-1.0))/units; + for (x = 0; x < v.nx; ++x) { + X = (v.xmin + v.dx*x/(v.nx-1.0))/units; + v.rgb0[y][x] = v.rgb1[y][x]; + v.rgb1[y][x] = """+math_string+"""; + } + } + // + // check voxel faces + // + for (y = 0; y < (v.ny-1); ++y) { + for (x = 0; x < (v.nx-1); ++x) { + // + // left + // + if ((v.rgb0[y][x] != 0) && (v.rgb0[y+1][x] != 0) && (v.rgb1[y][x] != 0) && (v.rgb1[y+1][x] != 0)) { + if ((v.rgb0[y][x+1] == 0) || (v.rgb0[y+1][x+1] == 0) || (v.rgb1[y][x+1] == 0) || (v.rgb1[y+1][x+1] == 0)) { + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x; + (*t).v1y = y; + (*t).v1z = z+1; + (*t).v2x = x; + (*t).v2y = y+1; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x; + (*t).v1y = y+1; + (*t).v1z = z+1; + (*t).v2x = x; + (*t).v2y = y+1; + (*t).v2z = z; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + // + // right + // + if ((v.rgb0[y][x+1] != 0) && (v.rgb0[y+1][x+1] != 0) && (v.rgb1[y][x+1] != 0) && (v.rgb1[y+1][x+1] != 0)) { + if ((v.rgb0[y][x] == 0) || (v.rgb0[y+1][x] == 0) || (v.rgb1[y][x] == 0) || (v.rgb1[y+1][x] == 0)) { + triangle_count += 1; + (*t).v0x = x+1; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z+1; + (*t).v2x = x+1; + (*t).v2y = y; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x+1; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z; + (*t).v2x = x+1; + (*t).v2y = y+1; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + // + // front + // + if ((v.rgb0[y][x] != 0) && (v.rgb0[y][x+1] != 0) && (v.rgb1[y][x] != 0) && (v.rgb1[y][x+1] != 0)) { + if ((v.rgb0[y+1][x] == 0) || (v.rgb0[y+1][x+1] == 0) || (v.rgb1[y+1][x] == 0) || (v.rgb1[y+1][x+1] == 0)) { + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y; + (*t).v1z = z; + (*t).v2x = x+1; + (*t).v2y = y; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y; + (*t).v1z = z+1; + (*t).v2x = x; + (*t).v2y = y; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + // + // back + // + if ((v.rgb0[y+1][x] != 0) && (v.rgb0[y+1][x+1] != 0) && (v.rgb1[y+1][x] != 0) && (v.rgb1[y+1][x+1] != 0)) { + if ((v.rgb0[y][x] == 0) || (v.rgb0[y][x+1] == 0) || (v.rgb1[y][x] == 0) || (v.rgb1[y][x+1] == 0)) { + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y+1; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z; + (*t).v2x = x+1; + (*t).v2y = y+1; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y+1; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z+1; + (*t).v2x = x; + (*t).v2y = y+1; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + // + // top + // + if ((v.rgb0[y][x] != 0) && (v.rgb0[y][x+1] != 0) && (v.rgb0[y+1][x] != 0) && (v.rgb0[y+1][x+1] != 0)) { + if ((v.rgb1[y][x] == 0) || (v.rgb1[y][x+1] == 0) || (v.rgb1[y+1][x] == 0) || (v.rgb1[y+1][x+1] == 0)) { + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z; + (*t).v2x = x; + (*t).v2y = y+1; + (*t).v2z = z; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z; + (*t).v1x = x+1; + (*t).v1y = y; + (*t).v1z = z; + (*t).v2x = x+1; + (*t).v2y = y+1; + (*t).v2z = z; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + // + // bottom + // + if ((v.rgb1[y][x] != 0) && (v.rgb1[y][x+1] != 0) && (v.rgb1[y+1][x] != 0) && (v.rgb1[y+1][x+1] != 0)) { + if ((v.rgb0[y][x] == 0) || (v.rgb0[y][x+1] == 0) || (v.rgb0[y+1][x] == 0) || (v.rgb0[y+1][x+1] == 0)) { + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z+1; + (*t).v1x = x+1; + (*t).v1y = y+1; + (*t).v1z = z+1; + (*t).v2x = x+1; + (*t).v2y = y; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + triangle_count += 1; + (*t).v0x = x; + (*t).v0y = y; + (*t).v0z = z+1; + (*t).v1x = x; + (*t).v1y = y+1; + (*t).v1z = z+1; + (*t).v2x = x+1; + (*t).v2y = y+1; + (*t).v2z = z+1; + tnew = malloc(sizeof(struct triangle_type)); + (*t).next = tnew; + t = tnew; + } + } + } + } + } + // + // write STL + // + char header[80]; + uint16_t attribute; + int i; + t = tstart; + float v0x,v0y,v0z; + float v1x,v1y,v1z; + float v2x,v2y,v2z; + FILE *output_file; + output_file = fopen(\""""+output_file_name+"""\","wb"); + fwrite(header,1,80,output_file); + fwrite(&triangle_count,4,1,output_file); + float zero = 0; + for (i = 0; i < triangle_count; ++i) { + fwrite(&zero,4,1,output_file); + fwrite(&zero,4,1,output_file); + fwrite(&zero,4,1,output_file); + v0x = (v.xmin + v.dx*((*t).v0x)/(v.nx-1.0))/units; + fwrite(&v0x,4,1,output_file); + v0y = (v.ymin + v.dy*((*t).v0y)/(v.ny-1.0))/units; + fwrite(&v0y,4,1,output_file); + v0z = (v.zmin + v.dz*((*t).v0z)/(v.nz-1.0))/units; + fwrite(&v0z,4,1,output_file); + v1x = (v.xmin + v.dx*((*t).v1x)/(v.nx-1.0))/units; + fwrite(&v1x,4,1,output_file); + v1y = (v.ymin + v.dy*((*t).v1y)/(v.ny-1.0))/units; + fwrite(&v1y,4,1,output_file); + v1z = (v.zmin + v.dz*((*t).v1z)/(v.nz-1.0))/units; + fwrite(&v1z,4,1,output_file); + v2x = (v.xmin + v.dx*((*t).v2x)/(v.nx-1.0))/units; + fwrite(&v2x,4,1,output_file); + v2y = (v.ymin + v.dy*((*t).v2y)/(v.ny-1.0))/units; + fwrite(&v2y,4,1,output_file); + v2z = (v.zmin + v.dz*((*t).v2z)/(v.nz-1.0))/units; + fwrite(&v2z,4,1,output_file); + fwrite(&attribute,2,1,output_file); + t = (*t).next; + } + fclose(output_file); + } +""" + +eval_file = open("math_stl_eval.c",'w') +eval_file.write(program) +eval_file.close() + +# +# compile +# + +print "compile" +if os.uname()[0] == 'Darwin': + os.system("gcc -O math_stl_eval.c -o math_stl_eval -lm -I/usr/X11/include -L/usr/X11/lib -lpng") +else: + os.system("gcc -O math_stl_eval.c -o math_stl_eval -lm -lpng") + + +# +# execute +# + +print "execute" +os.system("./math_stl_eval") +os.system("rm ./math_stl_eval.c") +os.system("rm ./math_stl_eval") diff --git a/src/scripts/path_view b/src/scripts/path_view new file mode 100755 index 0000000..e35d1ed --- /dev/null +++ b/src/scripts/path_view @@ -0,0 +1,43 @@ +#!/bin/bash +# +# path_view +# view path file +# +# Neil Gershenfeld +# CBA MIT 9/18/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +# +# check command line +# +if [ $# -eq 0 ] || [ $# -gt 3 ]; then + echo "command line: path_view in.path [view [viewer]]" + echo " in.path = input path file" + echo " view = view projection(s) (optional, z|3, default z)" + echo " viewer = PostScript viewer [default evince]" + exit + fi +# +# get command line arguments +# +view="z" +if [ $# -eq 2 ] + then + view=$2 + fi +# +viewer="evince" +if [ $# -eq 3 ] + then + viewer=$3 + fi +# +# view file +# +path_ps $1 $1.ps $view +$viewer $1.ps +rm $1.ps diff --git a/src/scripts/png_tile b/src/scripts/png_tile new file mode 100755 index 0000000..6ffe2e2 --- /dev/null +++ b/src/scripts/png_tile @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +import sys +import subprocess + +if len(sys.argv) < 3: + print "command line: png_tile rows cols file1.png file2.png ..." + print " rows = number of horizontal copies" + print " cols = number of vertical copies" + print " file1.png to fileN.png = files to tile" + sys.exit(1) + +rows = int(sys.argv[1]) +cols = int(sys.argv[2]) + +for file in sys.argv[3:]: + target = file.replace('.png','.tiled.png') + print "Processing %s:\n\tTiling vertically" % file + command = ['convert'] + [file]*rows + ['-append'] + [target] + subprocess.call(command) + print "\tTiling horizontally" + command = ['convert'] + [target]*cols + ['+append'] + [target] + subprocess.call(command) \ No newline at end of file diff --git a/src/scripts/rml_move b/src/scripts/rml_move new file mode 100755 index 0000000..24965f4 --- /dev/null +++ b/src/scripts/rml_move @@ -0,0 +1,33 @@ +#!/bin/bash +# +# rml_move +# move Roland Modela +# +# Neil Gershenfeld +# CBA MIT 9/18/10 +# +# (c) Massachusetts Institute of Technology 2010 +# Permission granted for experimental and personal use; +# license for commercial sale available from MIT. +# + +# +# check command line +# + +if [ $# -eq 0 ] || [ $# -gt 2 ]; then + echo command line: rml_move x y + echo " x,y, = position to move to (mm)" + exit + fi + +# +# move +# + +x=$(echo "(40.0*$1)/1" | bc) # 40/mm +y=$(echo "(40.0*$2)/1" | bc) +echo "PA;PA;!VZ10;!PZ0,100;PU $x $y;PD $x $y;!MC0;" > rml_move.rml +cat rml_move.rml +fab_send rml_move.rml +rm rml_move.rml diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt new file mode 100755 index 0000000..4db7efc --- /dev/null +++ b/src/solver/CMakeLists.txt @@ -0,0 +1,47 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +find_package(Boost REQUIRED COMPONENTS thread system) +include_directories(${Boost_INCLUDE_DIR}) + +find_package(PNG REQUIRED) +include_directories(${PNG_INCLUDE_DIR}) + +set(CMAKE_CXX_FLAGS "-Wall -O3") +#set(CMAKE_CXX_FLAGS "-Wall -g") + +ADD_LIBRARY(MathTree + parser.cpp math_tree.cpp region.cpp + numeric_nodes.cpp logic_nodes.cpp + translator_nodes.cpp color_nodes.cpp + fabvars.cpp node.cpp opcodes.cpp geometry.cpp + progress_bar.cpp task_buffer.cpp solver.cpp) + +ADD_EXECUTABLE(math_png math_png.cpp imagesolver.cpp) +ADD_EXECUTABLE(math_ray math_ray.cpp raycaster.cpp) +ADD_EXECUTABLE(math_dot math_dot.cpp) +ADD_EXECUTABLE(math_stl math_stl.cpp trisolver.cpp) +ADD_EXECUTABLE(math_svg math_svg.cpp edgesolver.cpp) +ADD_EXECUTABLE(math_stats math_stats.cpp volsolver.cpp) + +SET(LIBRARIES + MathTree ${PNG_LIBRARY} + ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} pthread) + +TARGET_LINK_LIBRARIES (math_png ${LIBRARIES}) +TARGET_LINK_LIBRARIES (math_ray ${LIBRARIES}) +TARGET_LINK_LIBRARIES (math_dot ${LIBRARIES}) +TARGET_LINK_LIBRARIES (math_stl ${LIBRARIES}) +TARGET_LINK_LIBRARIES (math_svg ${LIBRARIES}) +TARGET_LINK_LIBRARIES (math_stats ${LIBRARIES}) + +if( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + install(TARGETS math_png DESTINATION ${PROJECT_SOURCE_DIR}/../bin) + install(TARGETS math_ray DESTINATION ${PROJECT_SOURCE_DIR}/../bin) + install(TARGETS math_dot DESTINATION ${PROJECT_SOURCE_DIR}/../bin) + install(TARGETS math_stl DESTINATION ${PROJECT_SOURCE_DIR}/../bin) + install(TARGETS math_svg DESTINATION ${PROJECT_SOURCE_DIR}/../bin) + install(TARGETS math_stats DESTINATION ${PROJECT_SOURCE_DIR}/../bin) +endif( ${CMAKE_PROJECT_NAME} MATCHES fabmod ) + +set(SOLVER_EXECUTABLES math_png math_dot math_stl math_svg + CACHE STRING "Revised solver executables") diff --git a/src/solver/Makefile b/src/solver/Makefile new file mode 100644 index 0000000..ab6f445 --- /dev/null +++ b/src/solver/Makefile @@ -0,0 +1,40 @@ +CFLAGS = -O3 +#CFLAGS = -g + +LDFLAGS = -lpng -lboost_thread -lboost_system + +UNAME := $(shell uname) +ifeq ($(UNAME), Darwin) + # Look in the X11 folder for system default libpng + LDFLAGS += -L/usr/X11/lib + CFLAGS += -I/usr/X11/include + + # Check for MacPorts installation, if found look there for libraries + OPT := $(shell test -e /opt/local/lib; echo $$?) + ifeq ($(OPT), 0) + LDFLAGS += -L/opt/local/lib + endif +endif + +CPP = converter.cpp parser.cpp solver.cpp \ + fabtools.cpp numeric_tree.cpp rect.cpp tree.cpp \ + logic_tree.cpp opcodes.cpp roots.cpp lattice.cpp \ + solver_tp.cpp +HPP = converter.hpp logic_tree.hpp parser.hpp switches.hpp \ + fab_interval.hpp numeric_nodes.hpp rect.hpp tree.hpp \ + fabtools.hpp numeric_tree.hpp roots.hpp \ + logic_node.hpp opcodes.hpp solver.hpp lattice.hpp \ + solver_tp.hpp +OBJS = $(CPP:.cpp=.o) + +all: math_png + +math_png: main.cpp $(OBJS) + g++ $(CFLAGS) $(OBJS) main.cpp -o math_png $(LDFLAGS) + +%.o: %.cpp $(HPP) + g++ $(CFLAGS) -c $< + +clean: + @echo " Removing solver files" + @rm -f $(OBJS) math_png diff --git a/src/solver/color_nodes.cpp b/src/solver/color_nodes.cpp new file mode 100644 index 0000000..0d49c8a --- /dev/null +++ b/src/solver/color_nodes.cpp @@ -0,0 +1,78 @@ +#include "color_nodes.hpp" + +using namespace std; +//////////////////////////////////////////////////////////////////////////////// +ColorAnd::ColorAnd() + : BinaryNode(COLOR_AND) +{ + // Nothing to do here. +} + +void ColorAnd::eval(const float X, const float Y, const float Z) +{ + result_color = left->result_color & right->result_color; +} + +void ColorAnd::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + // Black ANDed with anything remains black. + if (left->result_color == 0 || right->result_color == 0) + result_color = 0; + else if (left->result_color == -1 || right->result_color == -1) + result_color = -1; + else + result_color = left->result_color & right->result_color; + marked = (result_color != -1); +} + +//////////////////////////////////////////////////////////////////////////////// +ColorOr::ColorOr() + : BinaryNode(COLOR_OR) +{ + // Nothing to do here. +} + +void ColorOr::eval(const float X, const float Y, const float Z) +{ + result_color = left->result_color | right->result_color; +} + +void ColorOr::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + // Pure white OR-ed with anything remains white. + const int WHITE = 255 + (255 << 8) + (255 << 16); + if (left->result_color == WHITE || right->result_color == WHITE) + result_color = WHITE; + else if (left->result_color == -1 || right->result_color == -1) + result_color = -1; + else + result_color = left->result_color | right->result_color; + marked = (result_color != -1); +} + +//////////////////////////////////////////////////////////////////////////////// +ColorNot::ColorNot() + : UnaryNode(COLOR_NOT) +{ + // Nothing to do here. +} + +void ColorNot::eval(const float X, const float Y, const float Z) +{ + result_color = ~child->result_color; +} + +void ColorNot::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + if (child->result_color == -1) + result_color = -1; + else + result_color = ~child->result_color; + marked = (result_color != -1); +} \ No newline at end of file diff --git a/src/solver/color_nodes.hpp b/src/solver/color_nodes.hpp new file mode 100644 index 0000000..3fcd41b --- /dev/null +++ b/src/solver/color_nodes.hpp @@ -0,0 +1,13 @@ +#ifndef COLOR_NODES_H +#define COLOR_NODES_H + +#include "node.hpp" +#include "node_macro.hpp" + +// This header file defines nodes that take in colors +// as inputs. +NODE(ColorAnd, BinaryNode); +NODE(ColorOr, BinaryNode); +NODE(ColorNot, UnaryNode); + +#endif \ No newline at end of file diff --git a/src/solver/edgesolver.cpp b/src/solver/edgesolver.cpp new file mode 100644 index 0000000..6426ef3 --- /dev/null +++ b/src/solver/edgesolver.cpp @@ -0,0 +1,179 @@ +#include "edgesolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" + +#include "switches.hpp" + + +#include +#include + +using namespace std; +using boost::logic::tribool; +using boost::logic::indeterminate; +using boost::thread; + +const Vec3f OFFSETS[] = { + Vec3f(0, 0), Vec3f(1, 0), Vec3f(1, 1), Vec3f(0, 1) +}; + +const int EDGE_MAP[16][2][2] = { + {{-1,-1}, {-1,-1}}, // ---- + {{ 0, 1}, { 0, 3}}, // ---0 + {{ 1, 2}, { 1, 0}}, // --1- + {{ 1, 2}, { 0, 3}}, // --10 + {{ 2, 3}, { 2, 1}}, // -2-- + {{-2,-2}, {-2,-2}}, // -2-0 + {{ 2, 3}, { 1, 0}}, // -21- + {{ 2, 3}, { 0, 3}}, // -210 + + {{ 3, 0}, { 3, 2}}, // 3--- + {{ 0, 1}, { 3, 2}}, // 3--0 + {{-2,-2}, {-2,-2}}, // 3-1- + {{ 1, 2}, { 3, 2}}, // 3-10 + {{ 3, 0}, { 2, 1}}, // 32-- + {{ 0, 1}, { 2, 1}}, // 32-0 + {{ 3, 0}, { 1, 0}}, // 321- + {{-1,-1}, {-1,-1}} // 3210 +}; + + +/////////////////////////////////////////////////////////////////////////////// + +EdgeSolver::EdgeSolver(FabVars& v) + : Solver(v), paths(v.decimation_error) +{ + // Nothing to do here. +} + +EdgeSolver::EdgeSolver(MathTree* tree, FabVars& v) + : Solver(tree, v), paths(v.decimation_error) +{ + // Nothing to do here. +} + +void EdgeSolver::save() +{ + v.add_paths(paths); +} + +// Evaluate a single region, either with point-by-point evaluation or +// interval math + recursion. Operates in a single thread and spawns +// no children. +void EdgeSolver::evaluate_region(Region r) +{ + // For sufficiently small fractions of the space, do a + // point-by-point evaluation rather than recursing. + if (r.volume == 1) { + evaluate_voxel(r); + v.pb.update(r.volume); + return; + } + + // Convert from pixel regions to intervals + FabInterval X = v.x(r.imin, r.imax); + FabInterval Y = v.y(r.jmin, r.jmax); + FabInterval Z = v.z(r.kmin, r.kmax); + + tree->eval(X, Y, Z); + + // If the result was unambiguous, then we don't care since it + // is either entirely inside or outside the image. + bool result = false; + if (v.mode == SOLVE_BOOL) + result = !indeterminate(tree->root->result_bool); + else if (v.mode == SOLVE_REAL) + result = !indeterminate(tree->root->result_interval < FabInterval(0)); + + if (result) { + v.pb.update(r.volume); + return; + } + + // Split the region and recurse + list subregions = r.split(); + +#if PRUNE_TREE + tree->push(); +#endif + + list::iterator it; + for (it = subregions.begin(); it != subregions.end(); ++it) + evaluate_region(*it); + +#if PRUNE_TREE + tree->pop(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +// Evaluate a single rectangle, using interpolation to smooth the edges. +void EdgeSolver::evaluate_voxel(Region r) +{ + Vec3f corner(r.imin, r.jmin, r.kmin); + Vec3f v1, v2; // edge vertices + + Vec3f vertices[4]; + for (int i = 0; i < 4; ++i) + vertices[i] = corner + OFFSETS[i]; + + int lookup = 0; + for (int i = 3; i >= 0; --i) { + lookup <<= 1; + Vec3f pos = vertices[i]; + + if (point_cache.find(pos) == point_cache.end()) { + tree->eval(v.x(pos.x), v.y(pos.y), v.z(pos.z)); + + if (v.mode == SOLVE_BOOL) + point_cache[pos] = tree->root->result_bool; + else if (v.mode == SOLVE_REAL) + point_cache[pos] = tree->root->result_float < 0; + } + + if (point_cache[pos]) + lookup++; + } + + if (EDGE_MAP[lookup][0][0] == -1) + return; + if (EDGE_MAP[lookup][0][0] == -2) + return; + + v1 = interpolate(vertices[EDGE_MAP[lookup][0][0]], + vertices[EDGE_MAP[lookup][0][1]]); + v2 = interpolate(vertices[EDGE_MAP[lookup][1][0]], + vertices[EDGE_MAP[lookup][1][1]]); + paths += Path(v1, v2); + +} + +// Interpolates between a full and empty point, using caching to +// reduce the number of lookups required. +Vec3f EdgeSolver::interpolate(Vec3f filled, Vec3f empty) +{ + std::map::iterator it; + it = edge_cache.find(Edge(filled, empty)); + if (it != edge_cache.end()) + return it->second; + + float step_size = 0.25; + float interp = 0.5; + Vec3f offset = empty - filled; + + for (int i = 0; i < v.quality; ++i) { + Vec3f pos = filled + offset * interp; + + tree->eval(v.x(pos.x), v.y(pos.y), v.z(pos.z)); + if ((v.mode == SOLVE_BOOL && tree->root->result_bool) || + (v.mode == SOLVE_REAL && tree->root->result_float < 0)) + interp += step_size; + else + interp -= step_size; + step_size /= 2; + } + edge_cache[Edge(filled, empty)] = filled + offset * interp; + + return filled + offset * interp; +} \ No newline at end of file diff --git a/src/solver/edgesolver.hpp b/src/solver/edgesolver.hpp new file mode 100644 index 0000000..be4dd29 --- /dev/null +++ b/src/solver/edgesolver.hpp @@ -0,0 +1,62 @@ +#ifndef EDGESOLVER_H +#define EDGESOLVER_H + +#include +#include + +#include "solver.hpp" +#include "geometry.hpp" + +class EdgeSolver : public Solver +{ +public: + /* EdgeSolver(FabVars& v) + * EdgeSolver(MathTree* tree, FabVars& v) + * + * Constructs an EdgeSolver instance. + */ + EdgeSolver(FabVars& v); + EdgeSolver(MathTree* tree, FabVars& v); + + virtual ~EdgeSolver() { /* Nothing to do here */ } + + /* virtual void evaluate_region(Region R) + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R); + + /* void evaluate_voxel(Region R) + * + * Evaluate a single unit cube. + */ + void evaluate_voxel(Region R); + + /* virtual void save() + * + * Saves the results of our calculation by copying paths into our + * reference to FabVars v. + */ + virtual void save(); + + /* Vec3f interpolate(Vec3f filled, Vec3f empty) + * + * Interpolates between a filled and an empty point using binary search. + * Values are saved in a cache, and the cache is checked before the + * search is run. + */ + Vec3f interpolate(Vec3f filled, Vec3f empty); + +private: + // True / False cached values + std::map point_cache; + + // Interpolation cached values + std::map edge_cache; + + // Saved paths + PathSet paths; + +}; +#endif \ No newline at end of file diff --git a/src/solver/fab_interval.hpp b/src/solver/fab_interval.hpp new file mode 100644 index 0000000..f6867d9 --- /dev/null +++ b/src/solver/fab_interval.hpp @@ -0,0 +1,101 @@ +#ifndef FAB_INTERVAL_H +#define FAB_INTERVAL_H + +#include + +#include +#include + +// We are using a specific type of Boost interval, which we define +// in this unreasonably long typedef. +typedef boost::numeric::interval + >, + boost::numeric::interval_lib::checking_base + > +> FabInterval; + +// Interval comparisons should be done with tribool logic. +#include +using namespace boost::numeric::interval_lib::compare::tribool; + +/* interval atan2(interval y, interval x) + * + * Computes atan2 of two intervals. + */ +template +boost::numeric::interval atan2( + const boost::numeric::interval& y, + const boost::numeric::interval& x) +{ + + // Do the 9 atan2 cases + // Interval could be entirely within a quadrant (4 cases) + // could span an axis without containing the origin (4 cases) + // or could contain the origin (1 case) + + // For each case, when we draw the rectangle representing the + // domain of atan2 on the plane, the range of possible angles is + // spanned by the angles from the origin to two of the corners of + // the rectangle. (These corners are enumerated below, from drawing + // the picture.) + + if (x.lower() > 0) { // To the right of the y axis + if (y.lower() > 0) // 1st quadrant + return boost::numeric::interval(atan2(y.lower(), x.upper()), atan2(y.upper(), x.lower())); + else if (y.upper() < 0) // 4th quadrant + return boost::numeric::interval(atan2(y.lower(), x.lower()), atan2(y.upper(), x.upper())); + else // straddling the positive x axis + return boost::numeric::interval(atan2(y.lower(), x.lower()), atan2(y.upper(), x.lower())); + } else if (x.upper() < 0) { // To the left of the y axis + + if (y.lower() > 0) // 2nd quadrant + return boost::numeric::interval(atan2(y.upper(), x.upper()), atan2(y.lower(), x.lower())); + else if (y.upper() < 0) // 3rd quadrant + return boost::numeric::interval(atan2(y.upper(),x.lower()), atan2(y.lower(),x.upper())); + else // straddling the negative x axis + // branch cut --- all we can say is -pi to pi + return boost::numeric::interval(-M_PI, M_PI); + } + else { // Straddling the y axis + if (y.lower() > 0) // straddling the positive y axis + return boost::numeric::interval(atan2(y.lower(),x.upper()), atan2(y.lower(),x.lower())); + else if (y.upper() < 0) // straddling the negative y axis + return boost::numeric::interval(atan2(y.upper(),x.lower()), atan2(y.upper(),x.upper())); + else // interval contains the origin + // all we can say is -pi to pi + return boost::numeric::interval(-M_PI, M_PI); + } +} + +/* interval sgn(interval x) + * + * Returns the sign of the input interval, which is either -1, 1, 0, or + * interval(-1, 1) + */ +template +boost::numeric::interval sgn( + const boost::numeric::interval& x) +{ + if (x.lower() > 0) + return 1; + else if (x.upper() < 0) + return -1; + else if (x.lower() == 0 and x.upper() == 0) + return 0; + else + return boost::numeric::interval(-1, 1); +} + +/* ostream& operator<<(ostream& o, interval& i) + * + * Prints an interval + */ +template +std::ostream& operator<<(std::ostream& o, const boost::numeric::interval& i) +{ + return o << '[' << i.lower() << ' ' << i.upper() << ']'; +} +#endif \ No newline at end of file diff --git a/src/solver/fabvars.cpp b/src/solver/fabvars.cpp new file mode 100644 index 0000000..814f881 --- /dev/null +++ b/src/solver/fabvars.cpp @@ -0,0 +1,570 @@ +#include +#include +#include + +#include + +#include "fabvars.hpp" +#include "region.hpp" + +using namespace std; +FabVars::FabVars(output_mode o, int argc, char** argv) + : ni(-1), nj(-1), nk(-1), + min_volume(-1), min_area(-1), + xmin(0), ymin(0), zmin(0), + dx(0), dy(0), dz(0), + pixels_per_mm(10), mm_per_unit(-1), quality(8), + decimation_error(1), + mode(SOLVE_BOOL), output(o), projection(false), + infile_name(""), outfile_name(""), + red(NULL), green(NULL), blue(NULL), intensity(NULL), + volume(0) +{ + + infile_name = argv[0]; + + if (output != OUTPUT_STATS) + outfile_name = argv[1]; + + pixels_per_mm = 10; + + // The different programs have different input argument orders. + if (output == OUTPUT_PNG) { + if (argc >= 3) + pixels_per_mm = atof(argv[2]); + if (argc >= 4) + nk = atoi(argv[3]); + } + else if (output == OUTPUT_STL) { + if (argc >= 3) + pixels_per_mm = atof(argv[2]); + if (argc >= 4) + quality = atoi(argv[3]); + } + else if (output == OUTPUT_SVG) { + if (argc >= 3) + pixels_per_mm = atof(argv[2]); + if (argc >= 4) + nk = atoi(argv[3]); + if (argc >= 5) + decimation_error = atof(argv[4]); + if (argc >= 6) + quality = atoi(argv[7]); + } + else if (output == OUTPUT_STATS) { + if (argc >= 2) + pixels_per_mm = atof(argv[1]); + } + // Load data from the input file + load(); +} + +FabVars::~FabVars() +{ + if (mode == SOLVE_RGB && red && green && blue) { + for (int y = 0; y < nj; ++y) { + delete [] red[y]; + delete [] green[y]; + delete [] blue[y]; + } + delete [] red; + red = NULL; + delete [] green; + green = NULL; + delete [] blue; + blue = NULL; + } else if ((mode == SOLVE_BOOL || mode == SOLVE_REAL) && intensity) { + for (int y = 0; y < nj; ++y) + delete [] intensity[y]; + delete [] intensity; + intensity = NULL; + } +} + +void FabVars::load() +{ + if (infile_name == "") { + cerr << "No input file provided!" << endl; + exit(1); + } + + fstream input; + + // Open the input file + input.open(infile_name.c_str(), ios::in); + if (!input.good()) { + cerr << "Failed to open input file.\n"; + exit(1); + } + + // Read and parse the file + string line; + while (getline(input, line)) + if (line.find("format:") != string::npos) + if (line.find("Boolean") != string::npos) + mode = SOLVE_BOOL; + else if (line.find("RGB") != string::npos) + mode = SOLVE_RGB; + else if (line.find("Real") != string::npos) + mode = SOLVE_REAL; + else { + cerr << "Input math string must be Boolean, RGB, or Real, not " + << line.substr(8,string::npos) << "." << endl; + exit(4); + } + else if (line.find("mm per unit:") != string::npos) + sscanf(line.substr(12,string::npos).c_str(),"%lf", + &mm_per_unit); + else if (line.find("dx dy dz:") != string::npos) + sscanf(line.substr(9,string::npos).c_str(),"%lf %lf %lf", + &dx, &dy, &dz); + else if (line.find("xmin ymin zmin:") != string::npos) + sscanf(line.substr(15,string::npos).c_str(),"%lf %lf %lf", + &xmin, &ymin, &zmin); + else if (line.find("expression: ") != string::npos) + math_string = line.substr(12,string::npos); + + ni = dx * mm_per_unit * pixels_per_mm; + nj = dy * mm_per_unit * pixels_per_mm; + // Default Z slices: 10 for SVG output, equivalent resolution + // for other output modes. + if (nk == -1) { + if (output == OUTPUT_SVG) + nk = dz ? 10 : 1; + else + nk = dz * mm_per_unit * pixels_per_mm; + } + + // Make sure that these are all non-zero. + ni = ni ? ni : 1; + nj = nj ? nj : 1; + nk = nk ? nk : 1; + pb.full = uint64_t(ni)*uint64_t(nj)*uint64_t(nk); + + // Pick a minimum volume below which we won't do + // octree recursion. + min_volume = 64; + min_area = 8; + + // Pick a stroke size for drawing SVGs + stroke = min(ni, nj) / (pixels_per_mm * 1000.); + + // Convert decimation error in mm^2 into something that can + // directly be compared with a simplified Heron's formula output. + decimation_error = pow(decimation_error*4, 2); + paths.decimation_error = decimation_error; + + // Everything below this point is allocating memory for the images, + // so return early if we have a different output format. + if (output != OUTPUT_PNG) + return; + + // Allocate memory for the image. + if (mode == SOLVE_RGB) { + red = new uint8_t*[nj]; + green = new uint8_t*[nj]; + blue = new uint8_t*[nj]; + for (int y = 0; y < nj; ++y) { + red[y] = new uint8_t[ni]; + green[y] = new uint8_t[ni]; + blue[y] = new uint8_t[ni]; + for (int x = 0; x < ni; ++x) + { + red[y][x] = 0; + green[y][x] = 0; + blue[y][x] = 0; + } + } + } else { + intensity = new uint16_t*[nj]; + for (int y = 0; y < nj; ++y) { + intensity[y] = new uint16_t[ni]; + for (int x = 0; x < ni; ++x) + intensity[y][x] = 0; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +float FabVars::x(float i) const +{ + return xmin + dx*i / float(ni); +} + +float FabVars::y(float j) const +{ + return ymin + dy*j / float(nj); +} + +float FabVars::z(float k) const +{ + return zmin + dz*k / float(nk); +} + +//////////////////////////////////////////////////////////////////////////////// + +FabInterval FabVars::x(float imin, float imax) const +{ + return FabInterval(xmin + dx * imin / float(ni), + xmin + dx * imax / float(ni)); +} + +FabInterval FabVars::y(float jmin, float jmax) const +{ + return FabInterval(ymin + dy * jmin / float(nj), + ymin + dy * jmax / float(nj)); +} + +FabInterval FabVars::z(float kmin, float kmax) const +{ + return FabInterval(zmin + dz * kmin / float(nk), + zmin + dz * kmax / float(nk)); +} + +float FabVars::scale(unsigned int k) const +{ + if (nk == 1) { + if (mode == SOLVE_BOOL || mode == SOLVE_REAL) + return 65535; + else + return 1; + } + + return k/float(nk - 1) * + ((mode == SOLVE_BOOL || mode == SOLVE_REAL) ? 65535 : 1); +} + +//////////////////////////////////////////////////////////////////////////////// + +int FabVars::k(float z) const +{ + return (z - zmin) * float(nk) / dz; +} + +//////////////////////////////////////////////////////////////////////////////// + +void FabVars::fill(Region r) +{ + float s = scale(r.kmax - 1); + for (int i = r.imin; i < r.imax; ++i) + for (int j = r.jmin; j < r.jmax; ++j) + if (s > intensity[nj - j - 1][i]) + intensity[nj - j - 1][i] = s; +} + +void FabVars::fill(Region r, unsigned char R, unsigned char G, unsigned char B) +{ + float s = scale(r.kmax); + for (int j = r.jmin; j < r.jmax; ++j) + for (int i = r.imin; i < r.imax; ++i) { + if (R * s > red[nj - j - 1][i]) + red[nj - j - 1][i] = R * s; + if (G * s > green[nj - j - 1][i]) + green[nj - j - 1][i] = G * s; + if (B * s > blue[nj - j - 1][i]) + blue[nj - j - 1][i] = B * s; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +void FabVars::add_triangles(std::list tris) +{ + geometry_lock.lock(); + triangles.splice(triangles.begin(), tris); + geometry_lock.unlock(); +} + +void FabVars::add_paths(const PathSet& p) +{ + geometry_lock.lock(); + + list::const_iterator it; + for (it = p.begin(); it != p.end(); ++it) + paths += *it; + + geometry_lock.unlock(); +} + +void FabVars::add_volume(const uint64_t v) +{ + geometry_lock.lock(); + volume += v; + geometry_lock.unlock(); +} +//////////////////////////////////////////////////////////////////////////////// + +void FabVars::write_png() +{ + if (mode == SOLVE_BOOL || mode == SOLVE_REAL) + fab_write_png_K16(this, outfile_name.c_str()); + else if (mode == SOLVE_RGB) + fab_write_png_RGB24(this, outfile_name.c_str()); +} + +void FabVars::write_stl() +{ + fstream stl_out; + stl_out.open(outfile_name.c_str(), fstream::trunc | fstream::out); + + // The first 80 characters are undefined, so let's leave an informative message! + stl_out << "This is a binary STL file created by math_stl. Learn more at kokompe.cba.mit.edu"; + stl_out << " "; + + uint32_t stl_faces = 0; + + list::iterator it; + for (it = triangles.begin(); it != triangles.end(); ++it) + { + // Write the normal as all zeros + for (int i = 0; i < 12; ++i) + stl_out << char(0); + + // Extract vertices from the list + Vec3f v1 = it->v1; + Vec3f v2 = it->v2; + Vec3f v3 = it->v3; + + // Convert into world coordinates + v1.x = x(v1.x); + v1.y = y(v1.y); + v1.z = z(v1.z); + // Write out each of the floats, byte by byte + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v1.x)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v1.y)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v1.z)[i]; + + v2.x = x(v2.x); + v2.y = y(v2.y); + v2.z = z(v2.z); + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v2.x)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v2.y)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v2.z)[i]; + + v3.x = x(v3.x); + v3.y = y(v3.y); + v3.z = z(v3.z); + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v3.x)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v3.y)[i]; + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&v3.z)[i]; + + stl_out << char(0) << char(0); + + stl_faces++; + } + + stl_out.seekp(80); + for (int i = 0; i < 4; ++i) + stl_out << ((char*)&stl_faces)[i]; + + stl_out.close(); +} + +void FabVars::write_svg() +{ + float scale = pixels_per_mm * 0.352778; // 72 dpi + + fstream svg_out; + svg_out.open(outfile_name.c_str(), fstream::trunc | fstream::out); + svg_out << "\n" + << "\n" + << "\n" + << "\n" + << "\n"; + + list::iterator it; + for (it = paths.begin(); it != paths.end(); ++it) { + svg_out << " front().x / scale + << ' ' << (nj - it->front().y - 1) / scale; + Path::iterator p = it->begin(); + Path::iterator path_end = it->end(); + bool loop = (it->front() == it->back()); + if (loop) + path_end--; + while (++p != path_end) + svg_out << " L" << p->x / scale + << ' ' << (nj - p->y - 1) / scale; + if (loop) + svg_out << " Z"; + svg_out << "\"/>\n"; + } + + svg_out << "\n"; + svg_out.close(); +} +// Based on code from math_png +// with attribution +// Neil Gershenfeld +// CBA MIT 3/6/11 +// +// (c) Massachusetts Institute of Technology 2010 +// Permission granted for experimental and personal use; +// license for commercial sale available from MIT. +// + +void fab_write_png_K16(FabVars *v, const char* output_file_name) { + // + // write 16-bit grayscale PNG from FabVars + // + FILE *output_file; + int x,y; + png_uint_32 res_x,res_y; + png_byte color_type; + png_byte bit_depth; + png_byte *ptr; + // + // open PNG file + // + output_file = fopen(output_file_name, "wb"); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + png_infop info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, output_file); + // + // set vars + // + bit_depth = 16; + color_type = PNG_COLOR_TYPE_GRAY; + png_set_IHDR(png_ptr, info_ptr, v->ni, v->nj, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + res_x = 1000 * v->ni / (v->dx * v->mm_per_unit); + res_y = 1000 * v->nj / (v->dy * v->mm_per_unit); + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); + + png_text text[2]; + + char zmin[10]; + snprintf(zmin, 10, "%g", v->zmin*v->mm_per_unit); + text[0].compression = PNG_TEXT_COMPRESSION_NONE; + text[0].key = (char*)"zmin"; + text[0].text = zmin; + + char zmax[10]; + snprintf(zmax, 10, "%g", (v->zmin+v->dz)*v->mm_per_unit); + text[1].compression = PNG_TEXT_COMPRESSION_NONE; + text[1].key = (char*)"zmax"; + text[1].text = zmax; + png_set_text(png_ptr, info_ptr, text, 2); + + png_write_info(png_ptr, info_ptr); + // + // allocate pixels + // + png_bytep* row_pointers = new png_bytep[v->nj]; + for (y = 0; y < v->nj; ++y) + row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; + + // + // set pixels + // + for (y = 0; y < v->nj; ++y) + for (x = 0; x < v->ni; ++x) { + ptr = &(row_pointers[y][x*2]); + ptr[0] = (v->intensity[y][x] >> 8) & 255; + ptr[1] = v->intensity[y][x] & 255; + } + // + // write, close, and return + // + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, NULL); + fclose(output_file); + png_destroy_write_struct(&png_ptr, &info_ptr); + + cout << "write " << output_file_name + << "\n x pixels: " << v->ni << ", y pixels: " << v->nj + << "\n x pixels/m: " << res_x << ", y pixels/m: " << res_y + << "\n dx: " << v->dx << " mm, dy: " << v->dy <<" mm" << endl; + + for (y = 0; y < v->nj; ++y) + delete [] row_pointers[y]; + delete [] row_pointers; +} + +void fab_write_png_RGB24(FabVars *v, const char *output_file_name) { + // + // write 24-bit RGB PNG from FabVars + // + FILE *output_file; + int x,y; + png_uint_32 res_x,res_y; + + png_byte color_type; + png_byte bit_depth; + png_byte *ptr; + // + // open PNG file + // + output_file = fopen(output_file_name, "wb"); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + png_infop info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, output_file); + // + // set vars + // + bit_depth = 8; + color_type = PNG_COLOR_TYPE_RGB; + png_set_IHDR(png_ptr, info_ptr, v->ni, v->nj, + bit_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + res_x = 1000 * v->ni / (v->dx * v->mm_per_unit); + res_y = 1000 * v->nj / (v->dy * v->mm_per_unit); + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, PNG_RESOLUTION_METER); + png_write_info(png_ptr, info_ptr); + // + // allocate pixels + // + png_bytep* row_pointers = new png_bytep[v->nj]; + for (y = 0; y < v->nj; ++y) + row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; + // + // set pixels + // + for (y = 0; y < v->nj; ++y) + for (x = 0; x < v->ni; ++x) { + ptr = &(row_pointers[y][x*3]); + ptr[0] = v->red[y][x]; + ptr[1] = v->green[y][x]; + ptr[2] = v->blue[y][x]; + } + // + // write, close, and return + // + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, NULL); + fclose(output_file); + png_destroy_write_struct(&png_ptr, &info_ptr); + + cout << "write " << output_file_name + << "\n x pixels: " << v->ni << ", y pixels: " << v->nj + << "\n x pixels/m: " << res_x << ", y pixels/m: " << res_y + << "\n dx: " << v->dx << " mm, dy: " << v->dy <<" mm" << endl; + + for (y = 0; y < v->nj; ++y) + delete [] row_pointers[y]; + delete [] row_pointers; +} + diff --git a/src/solver/fabvars.hpp b/src/solver/fabvars.hpp new file mode 100644 index 0000000..5ea3564 --- /dev/null +++ b/src/solver/fabvars.hpp @@ -0,0 +1,205 @@ +#ifndef FABTOOLS_H +#define FABTOOLS_H + +#include +#include +#include + +#include +#include + +#include + +#include "fab_interval.hpp" +#include "geometry.hpp" +#include "region.hpp" +#include "progress_bar.hpp" + +enum solver_mode { SOLVE_BOOL, SOLVE_RGB, SOLVE_REAL }; +enum output_mode { OUTPUT_PNG, OUTPUT_STL, + OUTPUT_SVG, OUTPUT_STATS, OUTPUT_NONE }; + +typedef struct FabVars { + /* FabVars(output_mode o) + * + * Constructor, taking in an output mode. + */ + FabVars(output_mode o, int argc, char** argv); + + /* ~FabVars() + * + * Destructor. Deletes pixel arrays if they have been allocated. + */ + ~FabVars(); + + /* void load() + * + * Imports the provided .math file and stores relevant values. + */ + void load(); + + + /* void fill(Region r) + void fill(Region r, unsigned char R, unsigned char G, unsigned char B) + * + * Fills a region of the image with either solid white (with the first + * signature) or with a provided color. + */ + void fill(Region r); + void fill(Region r, unsigned char R, unsigned char G, unsigned char B); + + + /* void add_triangles(std::list tris) + * + * Adds a list of triangles to the stored triangle list by splicing + * the lists together. + */ + void add_triangles(std::list tris); + + /* void add_paths(const PathSet& p) + * + * Adds a set of paths to the stored set of paths, automatically + * decimating contiguous paths. + */ + void add_paths(const PathSet& p); + + /* void add_volume(const int v) + * + * Increments the saved volume count. + */ + void add_volume(const uint64_t v); + + /* void write_png() + * + * Writes out a png (either greyscale or RGB) based on data in either + * intensity or red, green, blue arrays. + */ + void write_png(); + + + /* void write_stl() + * + * Writes out an stl file from data stored in triangles. + */ + void write_stl(); + + + /* void write_stl() + * + * Writes out an svg file from data in paths. + */ + void write_svg(); + + + + /* float x(float i) const + float y(float j) const + float z(float k) const + * + * Converts from lattice coordinates to real coordinates. + */ + float x(float i) const; + float y(float j) const; + float z(float k) const; + + + /* float x(float i) const + float y(float j) const + float z(float k) const + * + * Converts from lattice intervals to real intervals. + */ + FabInterval x(float imin, float imax) const; + FabInterval y(float jmin, float jmax) const; + FabInterval z(float kmin, float kmax) const; + + + /* int k(float z) const + * + * Converts from z coordinate to pixel grid value k + */ + int k(float z) const; + + /* float scale(unsigned int k) const + * + * Returns pixel brightness at a given lattice height. + * For greyscale images, this is between 0 and 65535; for RGB + * it is between 0 and 1. + */ + float scale(unsigned int k) const; + + // Size of the lattice grid, in pixels/voxels + int ni,nj,nk; + + // Minimum volume below which octree recursion won't occur. + unsigned min_volume; + // Minimum area below which quadtree recursion won't occur. + int min_area; + + // Position and size of the lattice in cad units + double xmin,ymin,zmin; + double dx,dy,dz; + + // Scale factors + double pixels_per_mm; + double mm_per_unit; + + // Interpolation count for stl, svg + int quality; + + // SVG stroke + float stroke; + + // SVG decimation error (in pixels^2) + float decimation_error; + + // Color, boolean, or real (distance metric) + solver_mode mode; + + // png, svg, stl, or none + output_mode output; + + // 2D or 3D evaluation style? + bool projection; + + // Input and output file names + std::string infile_name; + std::string outfile_name; + + // The math string of interest + std::string math_string; + + // Pixel arrays for output images + uint8_t **red,**green,**blue; + uint16_t **intensity; + + // Mutex to lock geometry entities + boost::mutex geometry_lock; + + // Saved set of triangles + std::list triangles; + + // Filled solid volume + uint64_t volume; + + // Saved set of paths + PathSet paths; + + // A progress bar that displays progress in ASCII + ProgressBar pb; + +} FabVars; + +/* void fab_write_png_K16(FabVars* v, const char* output_file_name) + * + * Outputs a 16-bit PNG based on v.intensity + */ +void fab_write_png_K16(FabVars* v, const char* output_file_name); + +/* void fab_write_png_RGB24(FabVars* v, const char* output_file_name) + * + * Outputs a 24-bit PNG based on v.{red, green, blue} + */ +void fab_write_png_RGB24(FabVars* v, const char* output_file_name); + +#endif diff --git a/src/solver/geometry.cpp b/src/solver/geometry.cpp new file mode 100644 index 0000000..42b3785 --- /dev/null +++ b/src/solver/geometry.cpp @@ -0,0 +1,260 @@ +#include + +#include "geometry.hpp" + +using namespace std; + +Vec3f::Vec3f() + : x(0), y(0), z(0) +{ /* Nothing to do here */ } + +Vec3f::Vec3f(float x, float y) + : x(x), y(y), z(0) +{ + // Nothing to do here. +} + +Vec3f::Vec3f(float x, float y, float z) + : x(x), y(y), z(z) +{ + // Nothing to do here. +} + +Vec3f Vec3f::operator+(const Vec3f& rhs) const +{ + return Vec3f(x + rhs.x, y + rhs.y, z + rhs.z); +} + +Vec3f Vec3f::operator-(const Vec3f& rhs) const +{ + return Vec3f(x - rhs.x, y - rhs.y, z - rhs.z); +} + +Vec3f Vec3f::operator*(const float rhs) const +{ + return Vec3f(x*rhs, y*rhs, z*rhs); +} + +Vec3f Vec3f::operator/(const float rhs) const +{ + return Vec3f(x/rhs, y/rhs, z/rhs); +} + +bool Vec3f::operator<(const Vec3f& rhs) const +{ + if (x != rhs.x) + return x < rhs.x; + if (y != rhs.y) + return y < rhs.y; + return z < rhs.z; +} + +bool Vec3f::operator==(const Vec3f& rhs) const +{ + return x == rhs.x && y == rhs.y && z == rhs.z; +} + +bool Vec3f::operator!=(const Vec3f& rhs) const +{ + return x != rhs.x || y != rhs.y || z != rhs.z; +} + +float Vec3f::len() const +{ + return sqrt(x*x + y*y + z*z); +} + +Vec3f Vec3f::norm() const +{ + float len = sqrt(x*x + y*y + z*z); + return Vec3f(x / len, y / len, z / len); +} + +Vec3f Vec3f::rotate90() const +{ + return Vec3f(-y, x); +} + +float Vec3f::dot(const Vec3f& rhs) const +{ + return x*rhs.x + y*rhs.y + z*rhs.z; +} + +std::ostream& operator<<(std::ostream& o, const Vec3f& v) +{ + o << '(' << v.x << ", " << v.y << ", " << v.z << ')'; + return o; +} + +//////////////////////////////////////////////////////////////////////////////// + +Triangle::Triangle(Vec3f v1, Vec3f v2, Vec3f v3) + : v1(v1), v2(v2), v3(v3) +{ /* Nothing to do here */ } + +bool Triangle::operator<(const Triangle& rhs) const +{ + if (v1 != rhs.v1) + return v1 < rhs.v1; + if (v2 != rhs.v2) + return v2 < rhs.v2; + return v3 < rhs.v3; +} + +//////////////////////////////////////////////////////////////////////////////// + +Edge::Edge(Vec3f v1, Vec3f v2) + : v1(v1), v2(v2) +{ /* Nothing to do here */ } + +bool Edge::operator<(const Edge& rhs) const +{ + if (v1 != rhs.v1) + return v1 < rhs.v1; + return v2 < rhs.v2; +} + +//////////////////////////////////////////////////////////////////////////////// +Path::Path() + : std::list() +{ /* Nothing to do here */ } + + +Path::Path(Vec3f v1, Vec3f v2) + : std::list() +{ + this->push_back(v1); + this->push_back(v2); +} + +bool Path::operator<(const Path& rhs) const +{ + Path::const_iterator it1 = this->begin(); + Path::const_iterator it2 = rhs.begin(); + + while (true) { + if (it2 == rhs.end()) + return false; + if (it1 == this->end()) + return true; + + if (*it1 != *it2) + return *it1 < *it2; + + ++it1; + ++it2; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +PathSet& PathSet::operator+=(Path rhs) +{ + Vec3f start = rhs.front(); + Vec3f end = rhs.back(); + + // Check to see if we can weld the end of an old path to the start of this + // new path. + std::map::iterator>::iterator it; + it = endings.find(start); + + if (it != endings.end()) { + // Find the existing path that we're going to join + list::iterator target = it->second; + + // Remove the existing path from the look-up maps, since + // it's about to be modified + beginnings.erase(target->front()); + endings.erase(target->back()); + + // Check to see if we should merge this new segment. + // + // Ascii art rendition: + // B + // -----> + // ^ / + // A | / C + // | / + // |/ + // + // A is the last segment of the existing path + // B is the first segment of the path being appended + // C is the path that we will get if we merge the two. + // + // Decimation depends on the area of the triangle ABC. + Path::const_iterator it = target->end(); + Vec3f a = *(--it); + a = a - *(--it); + Vec3f c = *it; + + it = rhs.begin(); + Vec3f b = *(it++); + b = b - *(it); + c = c - *it; + + float A = a.len(); + float B = b.len(); + float C = c.len(); + float area = (A+B+C)*(B+C-A)*(A+C-B)*(A+B-C); + + // Merge segments if the area of the resulting triangle + // is sufficiently small. + if (area < decimation_error) + target->pop_back(); + + // We remove the front node (since it is the end of one path + // and the start of the other), then splice the paths together. + rhs.pop_front(); + rhs.splice(rhs.begin(), *target); + + paths.erase(target); + + start = rhs.front(); + } + + // Check to see if we can weld the end of this new path to the start + // of an old path. + it = beginnings.find(end); + if (it != beginnings.end()) { + list::iterator target = it->second; + beginnings.erase(target->front()); + endings.erase(target->back()); + + // Check to see if we should merge this new segment. + // We calculate the area of the triangle that will be deleted + // if we decimate, then compare it to the variable decimation_error. + Path::const_iterator it = target->begin(); + Vec3f a = *(it); + a = a - *(++it); + Vec3f c = *it; + + it = rhs.end(); + Vec3f b = *(--it); + b = b - *(--it); + c = c - *it; + + float A = a.len(); + float B = b.len(); + float C = c.len(); + float area = (A+B+C)*(B+C-A)*(A+C-B)*(A+B-C); + + // Merge segments if the area of the resulting triangle + // is sufficiently small. + if (area < decimation_error) + target->pop_front(); + + rhs.pop_back(); + rhs.splice(rhs.end(), *target); + + beginnings.erase(end); + paths.erase(target); + + end = rhs.back(); + } + + paths.push_front(rhs); + + beginnings[start] = paths.begin(); + endings[end] = paths.begin(); + return *this; +} \ No newline at end of file diff --git a/src/solver/geometry.hpp b/src/solver/geometry.hpp new file mode 100644 index 0000000..347a9fc --- /dev/null +++ b/src/solver/geometry.hpp @@ -0,0 +1,167 @@ +#ifndef GEOMETRY +#define GEOMETRY + +#include +#include +#include + +// Lightweight 3D vector with overloaded operations +class Vec3f +{ +public: + + /* Vec3f() + Vec3f(float x, float y) + Vec3f(float x, float y, float z) + + * Constructors. Unspecified variables are set to 0. + */ + Vec3f(); + Vec3f(float x, float y); + Vec3f(float x, float y, float z); + + + /* Vec3f operator+(const Vec3f& rhs) const + Vec3f operator-(const Vec3f& rhs) const + Vec3f operator*(const float rhs) const + Vec3f operator/(const float rhs) const + + * Overloaded arithmetic operators. + */ + Vec3f operator+(const Vec3f& rhs) const; + Vec3f operator-(const Vec3f& rhs) const; + Vec3f operator*(const float rhs) const; + Vec3f operator/(const float rhs) const; + + /* bool operator<(const Vec3f& rhs) const + bool operator==(const Vec3f& rhs) const + bool operator!=(const Vec3f& rhs) const + + * Overloaded logical operators. + */ + bool operator<(const Vec3f& rhs) const; + bool operator==(const Vec3f& rhs) const; + bool operator!=(const Vec3f& rhs) const; + + /* Vec3f norm() const + * + * Calculates a normalized (unit) vector. + */ + Vec3f norm() const; + + /* float len() const + * + * Calculates the vector's length. + */ + float len() const; + + /* Vec3f rotate90() const + * + * Returns the vector rotated by 90 degrees about the z axis. + */ + Vec3f rotate90() const; + + + /* float dot(const Vec3f& rhs) const + * + * Calculates the dot product of two vectors. + */ + float dot(const Vec3f& rhs) const; + + // Output operator. + friend std::ostream& operator<<(std::ostream& o, const Vec3f& v); + + float x, y, z; +}; + +// Output operator. +std::ostream& operator<<(std::ostream& o, const Vec3f& v); + +//////////////////////////////////////////////////////////////////////////////// + +// Structure to hold a triangle (three Vec3fs) +typedef struct Triangle { + Triangle(Vec3f v1, Vec3f v2, Vec3f v3); + bool operator<(const Triangle& rhs) const; + + Vec3f v1, v2, v3; +} Triangle; + +//////////////////////////////////////////////////////////////////////////////// + +// Structure to hold an edge (two Vec3fs) +typedef struct Edge { + Edge(Vec3f v1, Vec3f v2); + bool operator<(const Edge& rhs) const; + + Vec3f v1, v2; +} Edge; + +//////////////////////////////////////////////////////////////////////////////// + +// A path is a list of vectors overloaded with a comparison operator. +class Path : public std::list +{ +public: + Path(); + Path(Vec3f v1, Vec3f v2); + + bool operator<(const Path& rhs) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +// A set of paths. From the outside, it looks like a list, but it also +// supports the += operator and performs decimation on appended paths. +class PathSet +{ +public: + /* PathSet() + * + * Default constructor. + */ + PathSet() : decimation_error(1) { /* Nothing to do here */ } + + /* PathSet(float de) + * + * Constructor which sets decimation_error. + */ + PathSet(float de) : decimation_error(de) { /* Nothing to do here */ } + + /* PathSet& operator+=(Path p) + * + * Appends a path to the set, with automatic path decimation: + * If the path's start or end coincides with another path's end + * or start, then it may merge them depending on the resulting + * decimation error. + */ + PathSet& operator+=(Path p); + + /* std::list::iterator begin() + std::list::iterator end() + std::list::const_iterator begin() + std::list::const_iterator end() + * + * Various iterators, which allows us to look like a list + * to outside users. + */ + std::list::iterator begin() { return paths.begin(); } + std::list::iterator end() { return paths.end(); } + std::list::const_iterator begin() const { return paths.begin(); } + std::list::const_iterator end() const { return paths.end(); } + + // List of active paths + std::list paths; + + // Maximum allowed decimation error + float decimation_error; + +private: + // Maps points to paths for which they are the start. + std::map::iterator> beginnings; + + // Maps points to paths for which they are the end. + std::map::iterator> endings; +}; + +#endif \ No newline at end of file diff --git a/src/solver/imagesolver.cpp b/src/solver/imagesolver.cpp new file mode 100644 index 0000000..64fe7df --- /dev/null +++ b/src/solver/imagesolver.cpp @@ -0,0 +1,210 @@ +#include "imagesolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "task_buffer.hpp" + +#include "switches.hpp" + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +ImageSolver::ImageSolver(FabVars& v) + : Solver(v) +{ + // Nothing to do here. +} + +ImageSolver::ImageSolver(MathTree* tree, FabVars& v) + : Solver(tree, v) +{ + // Nothing to do here. +} + +/////////////////////////////////////////////////////////////////////////////// + +// Evaluate a single region, either with point-by-point evaluation or +// interval math + recursion. Operates in a single thread and spawns +// no children. +void ImageSolver::evaluate_region(Region r) +{ + // For sufficiently small fractions of the space, do a + // point-by-point evaluation rather than recursing. + if (r.volume <= v.min_volume) { + evaluate_points(r); + v.pb.update(r.volume); + return; + } + + // Convert from pixel regions to intervals + FabInterval X = v.x(r.imin, r.imax); + FabInterval Y = v.y(r.jmin, r.jmax); + FabInterval Z = v.z(r.kmin, r.kmax); + + tree->eval(X, Y, Z); + + // If the result was unambiguous, then fill in that part + // of the image, then return. + if (v.mode == SOLVE_BOOL) { + tribool result = tree->root->result_bool; + if (result) + v.fill(r); + if (!indeterminate(result)) { + v.pb.update(r.volume); + return; + } + } else if (v.mode == SOLVE_REAL) { + tribool result = tree->root->result_interval <= FabInterval(0); + + if (result) + v.fill(r); + if (!indeterminate(result)) { + v.pb.update(r.volume); + return; + } + } else if (v.mode == SOLVE_RGB) { + int result = tree->root->result_color; + if (result != -1) { + v.fill(r, result & 255, + (result >> 8) & 255, + (result >> 16) & 255); + v.pb.update(r.volume); + return; + } + } + + // Split the region and recurse + list subregions = r.split(); + +#if CULL_Z + if (v.nk > 1) + cull_regions(subregions); + if (subregions.size() == 0) + return; +#endif + +#if PRUNE_TREE + tree->push(); +#endif + + list::iterator it; + +/* + // Implementing a full-on thread pool seems to slow it down + Region mine = subregions.front(); + subregions.pop_front(); + for (it = subregions.begin(); it != subregions.end(); ++it) + if (!task_buffer->add(*it, tree)) + evaluate_region(*it); + evaluate_region(mine); + + tree->wait_for_clones(); +*/ + + for (it = subregions.begin(); it != subregions.end(); ++it) + evaluate_region(*it); + + +#if PRUNE_TREE + tree->pop(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +// Evalutes a region full of points, one at a time. +void ImageSolver::evaluate_points(Region r) +{ + for (int k = r.kmax - 1; k >= r.kmin; --k) + { + + // Calculate Z coordinate and height-map scaling. + float Z = v.z(k); + float scale = v.scale(k); + + for (int i = r.imin; i < r.imax; ++i) + { // X loop + float X = v.x(i); + + for (int j = r.jmin; j < r.jmax; ++j) + { // Y loop + float Y = v.y(j); + + // If we can't brighten the image, skip this point. + if ((v.mode == SOLVE_BOOL || v.mode == SOLVE_REAL) + && scale <= v.intensity[v.nj - j - 1][i]) + continue; + + // Evaluate tree + tree->eval(X, Y, Z); + + // Fill in greyscale image + if ((v.mode == SOLVE_BOOL && tree->root->result_bool) || + (v.mode == SOLVE_REAL && tree->root->result_float <= 0)) + { + v.intensity[v.nj - j - 1][i] = scale; + } + // Fill in color image + else if (v.mode == SOLVE_RGB) { + int result = tree->root->result_color; + + // Extract colors from bit-field + unsigned char r = (result & 255) * scale, + g = ((result >> 8) & 255) * scale, + b = ((result >> 16) & 255) * scale; + + // Only brighten the image. + if (r > v.red[v.nj - j - 1][i]) + v.red[v.nj - j - 1][i] = r; + if (g > v.green[v.nj - j - 1][i]) + v.green[v.nj - j - 1][i] = g; + if (b > v.blue[v.nj - j - 1][i]) + v.blue[v.nj - j - 1][i] = b; + } + + } // Y loop + } // X loop + } // Z loop +} + +/////////////////////////////////////////////////////////////////////////////// + +// Removes any regions that cannot change the image. +void ImageSolver::cull_regions(list& subregions) +{ + list::iterator it = subregions.begin(); + + if (v.mode == SOLVE_BOOL || v.mode == SOLVE_REAL) { + while (it != subregions.end()) { + int scale = v.scale(it->kmax - 1); + bool cull = true; + for (int i = it->imin; i < it->imax && cull; ++i) + for (int j = it->jmin; j < it->jmax && cull; ++j) + if (v.intensity[v.nj - j - 1][i] < scale) + cull = false; + if (cull) { + v.pb.update(it->volume); + it = subregions.erase(it); + } + else + ++it; + } + } else if (v.mode == SOLVE_RGB) { + while (it != subregions.end()) { + int scale = v.scale(it->kmax - 1) * 255; + bool cull = true; + for (int i = it->imin; i < it->imax && cull; ++i) + for (int j = it->jmin; j < it->jmax && cull; ++j) + if (scale > v.red[v.nj - j - 1][i] || + scale > v.green[v.nj - j - 1][i] || + scale > v.blue[v.nj - j - 1][i]) + cull = false; + if (cull) { + v.pb.update(it->volume); + it = subregions.erase(it); + } else + ++it; + } + } +} + diff --git a/src/solver/imagesolver.hpp b/src/solver/imagesolver.hpp new file mode 100644 index 0000000..7fdb55f --- /dev/null +++ b/src/solver/imagesolver.hpp @@ -0,0 +1,48 @@ +#ifndef IMAGESOLVER_H +#define IMAGESOLVER_H + +#include + +#include "solver.hpp" + +class ImageSolver : public Solver +{ +public: + /* ImageSolver(FabVars& v) + * ImageSolver(MathTree* tree, FabVars& v) + * + * Constructs an ImageSolver instance. + */ + ImageSolver(FabVars& v); + ImageSolver(MathTree* tree, FabVars& v); + virtual ~ImageSolver() { /* Nothing to do here */ } + + /* virtual void evaluate_region(Region R) + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R); + + /* void evaluate_points(Region R) + * + * Evaluate a region in space + */ + void evaluate_points(Region R); + + /* void cull_regions(list& subregions) + * + * Deletes a regions that can no longer affect the output + * image (i.e. anything that is darker than the existing value + * in that location). + */ + void cull_regions(std::list& subregions); + + /* virtual void save() + * + * Nothing needs to happen here, since evaluate_region and + * evalue_points dump data into the image. + */ + void save() { /* Nothing to do here */ } +}; +#endif \ No newline at end of file diff --git a/src/solver/logic_nodes.cpp b/src/solver/logic_nodes.cpp new file mode 100644 index 0000000..a87a2ea --- /dev/null +++ b/src/solver/logic_nodes.cpp @@ -0,0 +1,187 @@ +#include "logic_nodes.hpp" + +using boost::logic::indeterminate; +using namespace boost::numeric::interval_lib; + +//////////////////////////////////////////////////////////////////////////////// +LogicAnd::LogicAnd() + : BinaryNode(OP_AND) +{ + // Nothing to do here +} + +void LogicAnd::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_bool && right->result_bool; +} + +void LogicAnd::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_bool = left->result_bool && right->result_bool; + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +LogicOr::LogicOr() + : BinaryNode(OP_OR) +{ + // Nothing to do here +} + +void LogicOr::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_bool || right->result_bool; +} + +void LogicOr::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_bool = left->result_bool || right->result_bool; + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +LogicNeq::LogicNeq() + : BinaryNode(OP_NEQ) +{ + // Nothing to do here +} + +void LogicNeq::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_bool != right->result_bool; +} + +void LogicNeq::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_bool = left->result_bool != right->result_bool; + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +LogicNot::LogicNot() + : UnaryNode(OP_NOT) +{ + // Nothing to do here. +} + +void LogicNot::eval(const float X, const float Y, const float Z) +{ + result_bool = !child->result_bool; +} + +void LogicNot::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_bool = !child->result_bool; + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +TransitionLt::TransitionLt() + : BinaryNode(OP_LT) +{ + // Nothing to do here +} + +void TransitionLt::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_float < right->result_float; +} + +void TransitionLt::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + try { + result_bool = left->result_interval < right->result_interval; + } catch (comparison_error& e) { + result_bool = indeterminate; + } + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +TransitionLeq::TransitionLeq() + : BinaryNode(OP_LEQ) +{ + // Nothing to do here +} + +void TransitionLeq::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_float <= right->result_float; +} + +void TransitionLeq::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + try { + result_bool = left->result_interval <= right->result_interval; + } catch (comparison_error& e) { + result_bool = indeterminate; + } + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +TransitionGt::TransitionGt() + : BinaryNode(OP_GT) +{ + // Nothing to do here +} + +void TransitionGt::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_float > right->result_float; +} + +void TransitionGt::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + try { + result_bool = left->result_interval > right->result_interval; + } catch (comparison_error& e) { + result_bool = indeterminate; + } + marked = !indeterminate(result_bool); +} + +//////////////////////////////////////////////////////////////////////////////// + +TransitionGeq::TransitionGeq() + : BinaryNode(OP_GEQ) +{ + // Nothing to do here +} + +void TransitionGeq::eval(const float X, const float Y, const float Z) +{ + result_bool = left->result_float >= right->result_float; +} + +void TransitionGeq::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + try { + result_bool = left->result_interval >= right->result_interval; + } catch (comparison_error& e) { + result_bool = indeterminate; + } + marked = !indeterminate(result_bool); +} \ No newline at end of file diff --git a/src/solver/logic_nodes.hpp b/src/solver/logic_nodes.hpp new file mode 100644 index 0000000..e9fbf87 --- /dev/null +++ b/src/solver/logic_nodes.hpp @@ -0,0 +1,16 @@ +#ifndef LOGIC_NODES_H +#define LOGIC_NODES_H + +#include "node.hpp" +#include "node_macro.hpp" + +NODE(LogicAnd, BinaryNode); +NODE(LogicOr, BinaryNode); +NODE(LogicNeq, BinaryNode); +NODE(LogicNot, UnaryNode); + +NODE(TransitionLt, BinaryNode); +NODE(TransitionLeq, BinaryNode); +NODE(TransitionGt, BinaryNode); +NODE(TransitionGeq, BinaryNode); +#endif \ No newline at end of file diff --git a/src/solver/math_dot.cpp b/src/solver/math_dot.cpp new file mode 100644 index 0000000..772585a --- /dev/null +++ b/src/solver/math_dot.cpp @@ -0,0 +1,35 @@ +#include + +#include "fabvars.hpp" +#include "parser.hpp" +#include "math_tree.hpp" + +using namespace std; + +void print_help() +{ + cout << "command line: math_dot in.math out.dot\n" + << " in.math = input math string file\n" + << " out.dot = output dot file\n"; +} + +int main(int argc, char** argv) +{ + if (argc < 3) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_NONE, argc, argv); + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + tree->export_dot(v.outfile_name); + + delete tree; + return 0; +} \ No newline at end of file diff --git a/src/solver/math_png.cpp b/src/solver/math_png.cpp new file mode 100644 index 0000000..bda8ad8 --- /dev/null +++ b/src/solver/math_png.cpp @@ -0,0 +1,64 @@ +#include +#include + +#include "fabvars.hpp" +#include "imagesolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "parser.hpp" +#include "thread_manager.hpp" + +#include "switches.hpp" + +using namespace std; + + +void print_help() +{ + cout << "command line: math_png in.math out.png [resolution [slices]]\n" + << " in.math = input math string file\n" + << " out.png = output PNG image\n" + << " resolution = pixels per mm (optional, default 10)\n" + << " slices = number of z slices (optional, default full)\n"; +} + + +int main(int argc, char** argv) +{ + if (argc < 3) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_PNG, argc, argv); + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + cout << "Nodes in tree: " << tree->node_count() << endl + << "\t" << tree->constant_count() << " constants\n" + << "Tree depth: " << tree->root->get_weight() << endl + << "Evaluating (region size = " << v.ni << " x " << v.nj + << " x " << v.nk << ")" + << endl; + +#if MULTITHREADED + ThreadManager tm(v); + tm.evaluate(tree); +#else + ImageSolver s(tree, v); + s.evaluate_region(Region(v)); +#endif + + cout << "\n"; + v.write_png(); + +#if MULTITHREADED + delete tree; +#endif + + return 0; +} \ No newline at end of file diff --git a/src/solver/math_ray.cpp b/src/solver/math_ray.cpp new file mode 100644 index 0000000..77f56e3 --- /dev/null +++ b/src/solver/math_ray.cpp @@ -0,0 +1,69 @@ +#include +#include + +#include "fabvars.hpp" +#include "raycaster.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "parser.hpp" +#include "thread_manager.hpp" + +#include "switches.hpp" + +using namespace std; + + +void print_help() +{ + cout << "command line: math_ray in.math out.png [resolution]\n" + << " in.math = input math string file\n" + << " out.png = output PNG image\n" + << " resolution = pixels per mm (optional, default 10)\n"; +} + + +int main(int argc, char** argv) +{ + if (argc < 3) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_PNG, argc, argv); + v.projection = true; + + if (v.mode != SOLVE_REAL) { + cerr << "Error: math_ray only works on Real math strings." << endl; + exit(4); + } + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + cout << "Nodes in tree: " << tree->node_count() << endl + << "\t" << tree->constant_count() << " constants\n" + << "Tree depth: " << tree->root->get_weight() << endl + << "Evaluating (region size = " << v.ni << " x " << v.nj + << " x " << v.nk << ")" + << endl; + +#if MULTITHREADED + ThreadManager tm(v); + tm.evaluate(tree); +#else + Raycaster s(tree, v); + s.evaluate_region(Region(v)); +#endif + + cout << "\n"; + v.write_png(); + +#if MULTITHREADED + delete tree; +#endif + + return 0; +} \ No newline at end of file diff --git a/src/solver/math_stats.cpp b/src/solver/math_stats.cpp new file mode 100644 index 0000000..f0d271e --- /dev/null +++ b/src/solver/math_stats.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "fabvars.hpp" +#include "volsolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "parser.hpp" +#include "thread_manager.hpp" + +#include "switches.hpp" + +using namespace std; + + +void print_help() +{ + cout << "command line: math_stats in.math [resolution]\n" + << " in.math = input math string file\n" + << " resolution = pixels per mm (optional, default 10)\n"; +} + + +int main(int argc, char** argv) +{ + if (argc < 1) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_STATS, argc, argv); + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + cout << "Nodes in tree: " << tree->node_count() << endl + << "\t" << tree->constant_count() << " constants\n" + << "Tree depth: " << tree->root->get_weight() << endl + << "Evaluating (region size = " << v.ni << " x " << v.nj + << " x " << v.nk << ")" + << endl; + +#if MULTITHREADED + ThreadManager tm(v); + tm.evaluate(tree); +#else + VolSolver s(tree, v); + s.evaluate_region(Region(v)); +#endif + + cout << "\n"; + cout << "Filled volume = " << v.volume/pow(v.pixels_per_mm,3) << " mm^3" << endl; + +#if MULTITHREADED + delete tree; +#endif + + return 0; +} \ No newline at end of file diff --git a/src/solver/math_stl.cpp b/src/solver/math_stl.cpp new file mode 100644 index 0000000..fd370b1 --- /dev/null +++ b/src/solver/math_stl.cpp @@ -0,0 +1,64 @@ +#include + +#include "fabvars.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "parser.hpp" +#include "thread_manager.hpp" +#include "trisolver.hpp" + +#include "switches.hpp" + +using namespace std; + + +void print_help() +{ + cout << "command line: math_stl in.math out.stl [resolution [quality]]\n" + << " in.math = input math string file\n" + << " out.png = output PNG image\n" + << " resolution = voxels per mm (optional, default 10)\n" + << " quality = voxel interpolation level (default 8)\n"; +} + + +int main(int argc, char** argv) +{ + if (argc < 3) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_STL, argc, argv); + + if (v.mode != SOLVE_BOOL && v.mode != SOLVE_REAL) { + cerr << "Error: math_stl only works on Boolean or Real math strings." << endl; + exit(4); + } + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + cout << "Nodes in tree: " << tree->node_count() << endl + << "Tree depth: " << tree->root->get_weight() << endl + << "Evaluating (region size = " << v.ni << " x " << v.nj + << " x " << v.nk << ")" + << endl; +#if MULTITHREADED + ThreadManager tm(v); + tm.evaluate(tree); +#else + TriSolver s(tree, v); + s.evaluate_region(Region(v)); + s.save(); +#endif + + cout << "\nWriting STL..." << endl; + v.write_stl(); + + delete tree; + return 0; +} \ No newline at end of file diff --git a/src/solver/math_svg.cpp b/src/solver/math_svg.cpp new file mode 100644 index 0000000..30392f7 --- /dev/null +++ b/src/solver/math_svg.cpp @@ -0,0 +1,66 @@ +#include + +#include "fabvars.hpp" +#include "edgesolver.hpp" +#include "math_tree.hpp" +#include "parser.hpp" +#include "node.hpp" +#include "thread_manager.hpp" + +#include "switches.hpp" + +using namespace std; + +void print_help() +{ + cout << "command line: math_svg in.math out.svg [resolution [slices [error [quality]]]]\n" + << " in.math = input math string file\n" + << " out.png = output PNG image\n" + << " resolution = voxels per mm (default: 10)\n" + << " slices = z slices (defaults: 1 for 2D models, 10 for 3D models)\n" + << " error = maximum decimation error (in mm^2)\n" + << " quality = voxel interpolation level (default: 8)\n" + << "Note: output svgs are at 72 dpi." << endl; +} + + +int main(int argc, char** argv) +{ + if (argc < 3) { + print_help(); + exit(1); + } + + argv++; argc--; // Remove executable name from argv + FabVars v(OUTPUT_SVG, argc, argv); + + if (v.mode != SOLVE_BOOL && v.mode != SOLVE_REAL) { + cerr << "Error: math_svg only works on Boolean or Real math strings." << endl; + exit(4); + } + + Parser p; + MathTree* tree = p.parse(v.math_string, v.mode); + if (!tree) + return 1; + + cout << "Nodes in tree: " << tree->node_count() << endl + << "Tree depth: " << tree->root->get_weight() << endl + << "Evaluating (region size = " << v.ni << " x " << v.nj + << " x " << v.nk << ")" + << endl; +#if MULTITHREADED + ThreadManager tm(v); + tm.evaluate(tree); +#else + EdgeSolver s(tree, v); + s.evaluate_region(Region(v)); + s.save(); +#endif + + cout << "\nWriting SVG." << endl; + v.write_svg(); + + delete tree; + return 0; +} \ No newline at end of file diff --git a/src/solver/math_tree.cpp b/src/solver/math_tree.cpp new file mode 100644 index 0000000..5f57edb --- /dev/null +++ b/src/solver/math_tree.cpp @@ -0,0 +1,243 @@ +#include + +#include "math_tree.hpp" +#include "node.hpp" +#include "switches.hpp" + +using namespace std; + +typedef boost::lock_guard locker; + +MathTree::MathTree() + : root(NULL), levels(NULL), active_nodes(NULL), dNodes(NULL), parent(NULL) +{ + // Nothing to do here +} + +MathTree::~MathTree() +{ + // If this tree is a clone, then notify the parent (because the parent will be + // waiting for this tree to be deleted before it can delete itself). + if (parent) { + locker lock(parent->mutex); + parent->done = true; + parent->condition.notify_one(); + } + + // Make sure that all children have been deleted. + wait_for_clones(); + + // Delete all nodes stored in the tree, from top to bottom (to prevent + // issues due to reference subtraction) + if (levels) + for (int i = num_levels - 1; i >= 0; --i) { + for (int j = 0; j < active_nodes[i]; ++j) + delete levels[i][j]; + delete [] levels[i]; + } + + for (MathTreeIter it = constants.begin(); it != constants.end(); ++it) + delete *it; + + delete [] levels; + delete [] active_nodes; + delete [] dNodes; +} + +MathTree* MathTree::clone() +{ + MathTree* m = new MathTree(); +// cout << "MathTree::clone() is cloning " << this << " to " << m << endl; + m->num_levels = num_levels; + m->levels = new Node**[num_levels]; + m->active_nodes = new int[num_levels]; + m->dNodes = new list[num_levels]; + + // Clone all of the active nodes. + // Since constants aren't changing, we don't need to clone them. + for (int i = 0; i < num_levels; ++i) { + m->active_nodes[i] = active_nodes[i]; + m->levels[i] = new Node*[active_nodes[i]]; + for (int j = 0; j < active_nodes[i]; ++j) + m->levels[i][j] = levels[i][j]->clone(); + } + + // If the entire tree is constant, then point back to this + // original tree's root. + if (num_levels) + m->root = m->levels[num_levels - 1][0]; + else + m->root = root; + + clones.push_back(new ThreadComm()); + m->parent = clones.back(); + + return m; +} + +void MathTree::wait_for_clones() +{ + + // Go through the list, waiting for each of the children. + list::iterator it = clones.begin(); + while (it != clones.end()) + { + { + boost::unique_lock lock((**it).mutex); + while (!(**it).done) + (**it).condition.wait(lock); + } + delete *it; + it = clones.erase(it); + } +} + +void MathTree::add(Node* n) +{ + if (!n) + return; + else if (n->marked) { + constants.push_back(n); + } else { + unsigned int L = n->get_weight(); + if (L + 1 > level_list.size()) + level_list.resize(L + 1); + level_list[L].push_back(n); + } +} + +// Converts the friendly, easy-to use C++ STL data structures into +// fast C-style arrays of pointers. +void MathTree::pack() +{ + num_levels = level_list.size(); + levels = new Node**[num_levels]; + active_nodes = new int[num_levels]; + dNodes = new list[num_levels]; + + for (int i = 0; i < num_levels; ++i) + { + active_nodes[i] = level_list[i].size(); + levels[i] = new Node*[active_nodes[i]]; + int j = 0; + while (level_list[i].size()) { + levels[i][j++] = level_list[i].front(); + level_list[i].pop_front(); + } + } +} + +void MathTree::set_root(Node* r) +{ + root = r; +} + +int MathTree::node_count() const +{ + int total = 0; + for(int i = 0; i < num_levels; ++i) + total += active_nodes[i]; + return total; +} + +int MathTree::constant_count() const +{ + return constants.size(); +} + + +// Evaluate a single point +void MathTree::eval(const float X, + const float Y, + const float Z) +{ + for (int i = 0; i < num_levels; ++i) + for (int j = 0; j < active_nodes[i]; ++j) + levels[i][j]->eval(X, Y, Z); +} + +// Evaluate an interval region +void MathTree::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + for (int i = 0; i < num_levels; ++i) + for (int j = 0; j < active_nodes[i]; ++j) + levels[i][j]->eval(X, Y, Z); +} + +void MathTree::push() +{ + // Pass downwards through the tree. If a node is cached + // (meaning it won't change upon further recursion), then + // tell its children that they are no longer being watched. + + // If all of a node's parents are no longer watching it, then + // remove that node from the tree as well (and inform its children) + + // Keep track of how many nodes were removed from the tree + // in the dNodes[i] stack. + + for (int i = num_levels - 2; i >= 0; --i) { + dNodes[i].push_back(0); + for (int j = 0; j < active_nodes[i]; ++j) { + if (levels[i][j]->cacheable()) + { + levels[i][j]->deactivate(); + swap(levels[i][j--], levels[i][--active_nodes[i]]); + dNodes[i].back()++; + } + } + } +} + +void MathTree::pop() +{ + // Increase the number of active nodes in the arrays so that + // previous cached nodes are now evaluated. + + for (int i = 0; i < num_levels - 1; ++i) { + + // Activate each of the previously disabled nodes. + for (int n = 0; n < dNodes[i].back(); ++n) { + levels[i][active_nodes[i]++]->activate(); + } + dNodes[i].pop_back(); + } +} + +ostream& operator<<(ostream& o, const MathTree& t) +{ + o << "Constants (" << t.constants.size() << " items)\n"; + MathTreeConstIter it; + for (it = t.constants.begin(); it != t.constants.end(); ++it) + o << '\t' << **it << '\n'; + o << endl; + + for (int i = 0; i < t.num_levels; ++i) + { + o << "Level " << i << " (" << t.active_nodes[i] << " items)\n"; + for (int j = 0; j < t.active_nodes[i]; ++j) + o << '\t' << *t.levels[i][j] << '\n'; + o << endl; + } + return o; +} + +void MathTree::export_dot(string filename) const +{ + ofstream out; + out.open(filename.c_str()); + out << "digraph math {\n" + << "node [rank = min, fontsize = 14, fontname = Arial]\n"; + MathTreeConstIter it; + for (it = constants.begin(); it != constants.end(); ++it) + (**it).dot(out); + + for (int i = 0; i < num_levels; ++i) + for (int j = 0; j < active_nodes[i]; ++j) + levels[i][j]->dot(out); + + out << "}\n"; + out.close(); +} diff --git a/src/solver/math_tree.hpp b/src/solver/math_tree.hpp new file mode 100644 index 0000000..422913b --- /dev/null +++ b/src/solver/math_tree.hpp @@ -0,0 +1,177 @@ +#ifndef MATH_TREE_H +#define MATH_TREE_H + +#include +#include +#include + +#include "fab_interval.hpp" +#include "region.hpp" + +// Forward declaration of node. +class Node; + + + +// This class stores a math expression tree. +class MathTree +{ +public: + /* MathTree() + * + * Simple constructor initializes pointers to NULL and nothing else. + */ + MathTree(); + + + /* ~MathTree() + * + * Destructor deletes all stored nodes. + */ + ~MathTree(); + + + /* MathTree* clone() + * + * Clones the MathTree. Constants and cached values are not cloned, + * so anything that references them will point back to this tree. + * + * Creates a ThreadComm object so that the child can notify us on + * destruction. + */ + MathTree* clone(); + + + /* void wait_for_clones() + * + * Waits for all clones to be deleted before returning. + */ + void wait_for_clones(); + + + /* void add(Node* n) + * + * Adds a node to the tree, based on the node's weight. + * The node is added to the list level_list if it is unmarked, + * otherwise it is added to the list constants. + * + * Note that pack() must be called before the tree can be evaluated. + */ + void add(Node* n); + + /* void pack() + * + * Converts the STL lists into C-style arrays for fast access. + */ + void pack(); + + /* void set_root(Node* r) + * + * Sets the root of the tree. + */ + void set_root(Node* r); + + /* int node_count() const + * + * Counts the number of active nodes in the tree. + */ + int node_count() const; + + /* int constant_count() const + * + * Counts the number of constant nodes in the tree. + */ + int constant_count() const; + + + /* int depth() const + * + * Returns the tree's depth. + */ + int depth() const { return num_levels; } + + /* void eval(X, Y, Z) + * + * Evaluates every active node in the tree, from leaves to root. + * After an evaluate, each node will have correct results stored in + * its result_{float,interval,bool,color} variables. Each node may + * also be marked if it can be ignored upon further recursion. + */ + void eval(const float X, + const float Y, + const float Z); + void eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z); + + /* void push() + * + * Traveling downward through the tree, deactivating nodes that are no + * longer relevant (either because they will not change values upon + * deeper recursion, or because no one is referencing them anymore). + * + * Deactivated nodes are moved to the back of their list, and the number + * of active nodes for that level is decreased by one. + * + * This function keeps track of how many nodes have been deactivated on + * each tree level in the variable dNodes. + */ + void push(); + + /* void pop() + * + * Traverse through the tree, re-activating nodes that had been + * deactivated by an earlier push(). + */ + void pop(); + + /* void export_dot(std::string filename) const + * + * Exports the tree to a dot/graphviz file with a given filename. + */ + void export_dot(std::string filename) const; + + // Output helper function + friend std::ostream& operator<<(std::ostream& o, const MathTree& t); + + // Root of the tree (stores the overall tree's results) + Node* root; + +private: + // Nice STL vectors and lists to store nodes while we're building the tree + std::vector< std::list > level_list; + std::list constants; + + // Fast C-style array for when we're actually using the tree. + Node*** levels; + + // Keeps track of how many nodes are active on each level + int* active_nodes; + + // Total number of levels in the tree + int num_levels; + + // Array of stacks storing the number of nodes that have been deactivated + // in each push() operation. Each level has an independent stack + // (implemented as a list) + std::list* dNodes; + + + typedef struct ThreadComm { + ThreadComm() : done(false) {} + bool done; + boost::mutex mutex; + boost::condition_variable condition; + } ThreadData; + + std::list clones; + ThreadComm* parent; + +}; + +// Helpful typedefs +typedef std::list::iterator MathTreeIter; +typedef std::list::const_iterator MathTreeConstIter; + +std::ostream& operator<<(std::ostream& o, const MathTree& t); +#endif \ No newline at end of file diff --git a/src/solver/node.cpp b/src/solver/node.cpp new file mode 100644 index 0000000..e8626e5 --- /dev/null +++ b/src/solver/node.cpp @@ -0,0 +1,307 @@ +#include "node.hpp" +#include "switches.hpp" + +#include "numeric_nodes.hpp" +#include "logic_nodes.hpp" +#include "translator_nodes.hpp" +#include "color_nodes.hpp" + +using namespace std; +using boost::logic::indeterminate; + +Node::Node(opcode operation) + : result_float(0), result_interval(0), + result_bool(indeterminate), result_color(0), + marked(false), operation(operation), + ref_count(0), weight(0), + clone_address(this) +{ + // Nothing to do here. +} + +Node::~Node() +{ + // Nothing to do here +} + +Node* Node::make(opcode operation) +{ + switch (operation) + { + case OP_AND: return new LogicAnd(); + case OP_OR: return new LogicOr(); + case OP_NEQ: return new LogicNeq(); + case OP_NOT: return new LogicNot(); + case OP_LT: return new TransitionLt(); + case OP_LEQ: return new TransitionLeq(); + case OP_GT: return new TransitionGt(); + case OP_GEQ: return new TransitionGeq(); + case OP_ABS: return new NumericAbs(); + case OP_COS: return new NumericCos(); + case OP_SIN: return new NumericSin(); + case OP_ACOS: return new NumericACos(); + case OP_ASIN: return new NumericASin(); + case OP_ATAN: return new NumericATan(); + case OP_SQRT: return new NumericSqrt(); + case OP_NEGATIVE: return new NumericNeg(); + case OP_EXP: return new NumericExp(); + case OP_SGN: return new NumericSgn(); + case OP_PLUS: return new NumericPlus(); + case OP_MINUS: return new NumericMinus(); + case OP_MULT: return new NumericMult(); + case OP_DIV: return new NumericDiv(); + case OP_ATAN2: return new NumericATan2(); + case OP_POW: return new NumericPow(); + case OP_MIN: return new NumericMin(); + case OP_MAX: return new NumericMax(); + case NUM_CONST: return new NumericConst(0); + case VAR_X: return new VarX(); + case VAR_Y: return new VarY(); + case VAR_Z: return new VarZ(); + case COLOR_AND: return new ColorAnd(); + case COLOR_OR: return new ColorOr(); + case COLOR_NOT: return new ColorNot(); + case NUM2BOOL: return new NumToBool(); + case BOOL2NUM: return new BoolToNum(); + case NUM2COLOR: return new NumToColor(); + case BOOL2COLOR: return new BoolToColor(); + default: + cerr << "Unknown clone target " << operation << endl; + exit(1); + } +} + +void Node::deactivate() +{ + // If we clone this node, then we want to be pointing back here + // (not to a previous clone address). + clone_address = this; +} + +void Node::activate() +{ + // Nothing to do here +} + +void Node::dot(ostream& o) const +{ + o << "\"p" << this << "\" [shape = " << dot_shape(operation) + << ", color = " << dot_color(operation) << ", fontsize = 24, label = \"" + << dot_label(operation) << "\""; + if (marked) + o << ", style=\"dotted\""; + o << "]\n"; +} + +ostream& operator<<(ostream& o, const Node& t) +{ + t.print(o); + return o; +} +//////////////////////////////////////////////////////////////////////////////// + +UnaryNode::UnaryNode(opcode operation) + : Node(operation), child(NULL) +{ + // Nothing to do here. +} + +Node* UnaryNode::clone() +{ + clone_address = make(operation); + static_cast(clone_address)-> + set_child(child->get_clone_address()); + return clone_address; +} + + +void UnaryNode::deactivate() +{ + Node::deactivate(); + child->sub_ref(); +} + +void UnaryNode::activate() +{ + child->add_ref(); + Node::activate(); +} + +bool UnaryNode::operator==(const Node& rhs) +{ + if (operation != rhs.op() ) + return false; + return *child == *static_cast(rhs).child; +} + +void UnaryNode::print(ostream& o) const +{ + o << operation; + if (child) { + o << '('; + child->print(o); + o << ')'; + } +} + +void UnaryNode::dot(ostream& o) const +{ + Node::dot(o); + + o << "p" << this << "->p" << child + << " [color = " << dot_arrow(operation) << "]\n"; +} + +void UnaryNode::set_child(Node* child_) +{ + child = child_; + child->add_ref(); + marked = child->marked; + if (marked) { + // Evaluate for both floats and intervals to ensure that + // result_float and result_interval are both populated + eval(0,0,0); + eval(FabInterval(0),FabInterval(0),FabInterval(0)); + } else { + weight = child->get_weight() + 1; + } +} + +bool UnaryNode::null_children() const +{ + return child == NULL; +} + +//////////////////////////////////////////////////////////////////////////////// + +BinaryNode::BinaryNode(opcode operation) + : Node(operation), left(NULL), right(NULL) +{ + // Nothing to do here. +} + +Node* BinaryNode::clone() +{ + clone_address = make(operation); + static_cast(clone_address)-> + set_children(left->get_clone_address(), + right->get_clone_address()); + return clone_address; +} + +void BinaryNode::deactivate() +{ + Node::deactivate(); + left->sub_ref(); + right->sub_ref(); +} + +void BinaryNode::activate() +{ + left->add_ref(); + right->add_ref(); + Node::activate(); +} + +bool BinaryNode::operator==(const Node& rhs) +{ + if (operation != rhs.op() ) + return false; + return *left == *static_cast(rhs).left && + *right == *static_cast(rhs).right; +} + +void BinaryNode::print(ostream& o) const +{ + if (operation == OP_ATAN2 || operation == OP_POW || + operation == OP_MAX || operation == OP_MIN) + o << operation; + if (left){ + o << '('; + left->print(o); + } + + if (operation == OP_ATAN2 || operation == OP_POW || + operation == OP_MAX || operation == OP_MIN) { + if (left && right) + o << ", "; + } + else + o << operation; + + if (right) { + right->print(o); + o << ')'; + } +} + +void BinaryNode::dot(ostream& o) const +{ + Node::dot(o); + + o << "p" << this << "->p" << left + << " [color = " << dot_arrow(operation) << "]\n"; + o << "p" << this << "->p" << right + << " [color = " << dot_arrow(operation) << "]\n"; +} + +void BinaryNode::set_children(Node* left_, Node* right_) +{ + left = left_; + left->add_ref(); + right = right_; + right->add_ref(); + marked = left->marked && right->marked; + if (marked) { + // Evaluate for both floats and intervals to ensure that + // result_float and result_interval are both populated + eval(0,0,0); + eval(FabInterval(0),FabInterval(0),FabInterval(0)); + } else { + weight = max(left->get_weight() + 1, right->get_weight() + 1); + } + +} + +bool BinaryNode::null_children() const +{ + return left == NULL || right == NULL; +} + +//////////////////////////////////////////////////////////////////////////////// + +NonaryNode::NonaryNode(opcode operation) + : Node(operation) +{ + // Nothing to do here. +} + +Node* NonaryNode::clone() +{ + clone_address = make(operation); + return clone_address; +} + +void NonaryNode::deactivate() { + Node::deactivate(); +} + +void NonaryNode::activate() +{ + Node::activate(); +} + +bool NonaryNode::operator==(const Node& rhs) +{ + return operation == rhs.op(); +} + +void NonaryNode::print(ostream& o) const +{ + o << operation; +} + +bool NonaryNode::null_children() const +{ + return false; +} \ No newline at end of file diff --git a/src/solver/node.hpp b/src/solver/node.hpp new file mode 100644 index 0000000..a074a9f --- /dev/null +++ b/src/solver/node.hpp @@ -0,0 +1,221 @@ +#ifndef NODE_H +#define NODE_H + +#include + +#include + +#include "opcodes.hpp" +#include "fab_interval.hpp" +#include "region.hpp" + +class Node +{ +public: + // Constructor and destructor. Nothing unusual here. + Node(opcode operation); + virtual ~Node(); + + /* virtual Node* clone() = 0 + * + * Clones a node (non-recursively). + * Refers to the clone_address member of children, which + * must be populated with a valid value. + */ + virtual Node* clone() = 0; + + + /* static Node* make(opcode op) + * + * Creates a new node with the provided opcode. + * + * Used by clone() to duplicate an existing node. + */ + static Node* make(opcode op); + + + /* virtual void eval(X, Y, Z) = 0 + * + * Evaluates the node, storing results in the local + * result_{float,interval,bool,color} variables (depending on + * node output type and whether we're solving for intervals or + * floats). Nodes may also become marked if they can be ignored + * upon deeper recursion. + */ + virtual void eval(const float X, + const float Y, + const float Z) = 0; + virtual void eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) = 0; + + + /* int add_ref() + * int sub_ref() + * + * Increments and decrements to the node's reference count, returning + * the updated value. + */ + int add_ref() { return ++ref_count; } + int sub_ref() { return --ref_count; } + + + /* virtual void deactivate() + * virtual void activate() + * + * Turns a node on or off. Turning a node off entails: + * Setting 'marked = true' + * Subtracting a reference from all children. + * + * Turning a node on is the opposite. + */ + virtual void deactivate(); + virtual void activate(); + + + /* int get_weight() + * + * Return the node's weight (i.e. distance from the bottom of the + * tree). Constants and variables have weight 0, everything else + * has weight of max(children's weights) + 1. + */ + int get_weight() const { return weight; } + + + /* opcode op() const + * + * Return this node's opcode. + */ + opcode op() const { return operation; } + + + /* bool ignored() const + * + * Returns true if no other nodes are watching this node + * (i.e. ref_count == 0). + */ + bool ignored() const { return ref_count == 0; } + + + /* bool cacheable() const + * + * Returns true if no other nodes are watching this node + * (i.e. ref_count == 0) or if this node is marked. + */ + bool cacheable() const { return marked || ref_count == 0; } + + /* Node* get_clone_address() + * + * Returns the address of this node's youngest clone. + */ + Node* get_clone_address() const { return clone_address; } + + + /* virtual bool operator==(const Node& rhs) = 0 + * + * Recursively compare two nodes, going down the + * tree as far as needed to check equality. + */ + virtual bool operator==(const Node& rhs) = 0; + + + /* virtual void print(std::ostream& o) const + * + * Function defined by derived classes to print a node + * and its children in human-readable (hah!) form. + */ + virtual void print(std::ostream& o) const = 0; + + + /* virtual void dot(std::ostream& o) const + * + * Function defined by derived classes to print a node + * and its children in graphviz format. + */ + virtual void dot(std::ostream& o) const; + + + /* virtual bool null_children const + * + * Returns true if the node's children are null, false otherwise. + */ + virtual bool null_children() const=0; + + // Results are stored locally and then looked up by parents + float result_float; + FabInterval result_interval; + boost::tribool result_bool; + int result_color; + + // Nodes are marked if they should to be moved to the cache (with + // a math_tree push operation). + bool marked; + +protected: + const opcode operation; + int ref_count; + + int weight; + Node* clone_address; +}; + +std::ostream& operator<<(std::ostream& o, const Node& t); + +//////////////////////////////////////////////////////////////////////////////// +class UnaryNode : public Node +{ +public: + UnaryNode(opcode operation); + virtual ~UnaryNode() {/*Nothing to do here*/}; + Node* clone(); + + void deactivate(); + void activate(); + + bool operator==(const Node& rhs); + void print(std::ostream& o) const; + void dot(std::ostream& o) const; + + void set_child(Node* child); + virtual bool null_children() const; +protected: + Node* child; +}; +//////////////////////////////////////////////////////////////////////////////// +class BinaryNode : public Node +{ +public: + BinaryNode(opcode operation); + virtual ~BinaryNode() {/*Nothing to do here*/}; + Node* clone(); + + void deactivate(); + void activate(); + + bool operator==(const Node& rhs); + void print(std::ostream& o) const; + void dot(std::ostream& o) const; + + void set_children(Node* left, Node* right); + virtual bool null_children() const; +protected: + Node* left; + Node* right; +}; +//////////////////////////////////////////////////////////////////////////////// +class NonaryNode : public Node +{ +public: + NonaryNode(opcode operation); + virtual ~NonaryNode() {/*Nothing to do here*/}; + Node* clone(); + + void deactivate(); + void activate(); + + bool operator==(const Node& rhs); + void print(std::ostream& o) const; + virtual bool null_children() const; +}; + +#endif diff --git a/src/solver/node_macro.hpp b/src/solver/node_macro.hpp new file mode 100644 index 0000000..8798a41 --- /dev/null +++ b/src/solver/node_macro.hpp @@ -0,0 +1,34 @@ +#ifndef NODE_MACRO_H +#define NODE_MACRO_H + +// To save text, we use the following macro to define classes in bulk. +#define NODE(NAME, TYPE) \ +class NAME : public TYPE \ +{ \ +public: \ + NAME(); \ + virtual ~NAME() {/*Nothing to do here*/}; \ + void eval(const float X, \ + const float Y, \ + const float Z); \ + void eval(const FabInterval& X, \ + const FabInterval& Y, \ + const FabInterval& Z); \ +} + +#define TRANSLATOR(NAME, TYPE) \ +class NAME : public TYPE \ +{ \ +public: \ + NAME(); \ + NAME(Node* c); \ + virtual ~NAME() {/*Nothing to do here*/}; \ + void eval(const float X, \ + const float Y, \ + const float Z); \ + void eval(const FabInterval& X, \ + const FabInterval& Y, \ + const FabInterval& Z); \ +} + +#endif \ No newline at end of file diff --git a/src/solver/numeric_nodes.cpp b/src/solver/numeric_nodes.cpp new file mode 100644 index 0000000..663f9ea --- /dev/null +++ b/src/solver/numeric_nodes.cpp @@ -0,0 +1,559 @@ +#include "numeric_nodes.hpp" +#include "switches.hpp" + +using namespace std; + +using boost::logic::indeterminate; +using namespace boost::numeric::interval_lib; + +//////////////////////////////////////////////////////////////////////////////// + +NumericAbs::NumericAbs() + : UnaryNode(OP_ABS) +{ + // Nothing to do here. +} + +void NumericAbs::eval(const float X, const float Y, const float Z) +{ + result_float = abs(child->result_float); +} + +void NumericAbs::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = abs(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericCos::NumericCos() + : UnaryNode(OP_COS) +{ + // Nothing to do here. +} + +void NumericCos::eval(const float X, const float Y, const float Z) +{ + result_float = cos(child->result_float); +} + +void NumericCos::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = cos(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericSin::NumericSin() + : UnaryNode(OP_SIN) +{ + // Nothing to do here. +} + +void NumericSin::eval(const float X, const float Y, const float Z) +{ + result_float = sin(child->result_float); +} + +void NumericSin::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = sin(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericACos::NumericACos() + : UnaryNode(OP_ACOS) +{ + // Nothing to do here. +} + +void NumericACos::eval(const float X, const float Y, const float Z) +{ + result_float = acos(child->result_float); +} + +void NumericACos::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = acos(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericASin::NumericASin() + : UnaryNode(OP_ASIN) +{ + // Nothing to do here. +} + +void NumericASin::eval(const float X, const float Y, const float Z) +{ + result_float = asin(child->result_float); +} + +void NumericASin::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = asin(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericATan::NumericATan() + : UnaryNode(OP_ATAN) +{ + // Nothing to do here. +} + +void NumericATan::eval(const float X, const float Y, const float Z) +{ + result_float = atan(child->result_float); +} + +void NumericATan::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = atan(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericSqrt::NumericSqrt() + : UnaryNode(OP_SQRT) +{ + // Nothing to do here. +} + +void NumericSqrt::eval(const float X, const float Y, const float Z) +{ + result_float = sqrt(child->result_float); +} + +void NumericSqrt::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = sqrt(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericNeg::NumericNeg() + : UnaryNode(OP_NEGATIVE) +{ + // Nothing to do here. +} + +void NumericNeg::eval(const float X, const float Y, const float Z) +{ + result_float = -child->result_float; +} + +void NumericNeg::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = -child->result_interval; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericExp::NumericExp() + : UnaryNode(OP_EXP) +{ + // Nothing to do here. +} + +void NumericExp::eval(const float X, const float Y, const float Z) +{ + result_float = exp(child->result_float); +} + +void NumericExp::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = exp(child->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericSgn::NumericSgn() + : UnaryNode(OP_SGN) +{ + // Nothing to do here. +} + +void NumericSgn::eval(const float X, const float Y, const float Z) +{ + if (child->result_float > 0) + result_float = 1; + else if (child->result_float < 0) + result_float = -1; + else + result_float = 0; +} + +void NumericSgn::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = sgn(child->result_interval); +} +//////////////////////////////////////////////////////////////////////////////// + +NumericPlus::NumericPlus() + : BinaryNode(OP_PLUS) +{ + // Nothing to do here. +} + +void NumericPlus::eval(const float X, const float Y, const float Z) +{ + result_float = left->result_float + right->result_float; +} + +void NumericPlus::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = left->result_interval + right->result_interval; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericMinus::NumericMinus() + : BinaryNode(OP_MINUS) +{ + // Nothing to do here. +} + +void NumericMinus::eval(const float X, const float Y, const float Z) +{ + result_float = left->result_float - right->result_float; +} + +void NumericMinus::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = left->result_interval - right->result_interval; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericMult::NumericMult() + : BinaryNode(OP_MULT) +{ + // Nothing to do here. +} + +void NumericMult::eval(const float X, const float Y, const float Z) +{ + result_float = left->result_float * right->result_float; +} + +void NumericMult::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = left->result_interval * right->result_interval; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericDiv::NumericDiv() + : BinaryNode(OP_DIV) +{ + // Nothing to do here. +} + +void NumericDiv::eval(const float X, const float Y, const float Z) +{ + result_float = left->result_float / right->result_float; +} + +void NumericDiv::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = left->result_interval / right->result_interval; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericATan2::NumericATan2() + : BinaryNode(OP_ATAN2) +{ + // Nothing to do here. +} + +void NumericATan2::eval(const float X, const float Y, const float Z) +{ + result_float = atan2(left->result_float, right->result_float); +} + +void NumericATan2::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = atan2(left->result_interval, right->result_interval); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericPow::NumericPow() + : BinaryNode(OP_POW) +{ + // Nothing to do here. +} + +void NumericPow::eval(const float X, const float Y, const float Z) +{ + result_float = pow(left->result_float, right->result_float); +} + +void NumericPow::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = pow(left->result_interval, right->result_interval.lower()); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericMin::NumericMin() + : BinaryNode(OP_MIN), left_cached(false), right_cached(false) +{ + // Nothing to do here. +} + +void NumericMin::eval(const float X, const float Y, const float Z) +{ + result_float = min(left->result_float, right->result_float); +} + +void NumericMin::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = min(left->result_interval, right->result_interval); + +#if MINMAX_PRUNE + if (right->result_interval < left->result_interval) { + if (!left_cached) { + left_cached = true; + left->sub_ref(); + } + + // In case this node gets deactivated out, save a float result + left->result_float = left->result_interval.lower(); + + } else if (left_cached) { + left_cached = false; + left->add_ref(); + } + + if (left->result_interval < right->result_interval) { + if (!right_cached) { + right->sub_ref(); + right_cached = true; + } + + // In case this node gets deactivated, save a float result + right->result_float = right->result_interval.lower(); + + } else if (right_cached) { + right_cached = false; + right->add_ref(); + } +#endif + +} + +void NumericMin::deactivate() +{ + Node::deactivate(); + if (!left_cached) + left->sub_ref(); + if (!right_cached) + right->sub_ref(); +} + +void NumericMin::activate() +{ + if (!left_cached) + left->add_ref(); + if (!right_cached) + right->add_ref(); + Node::activate(); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericMax::NumericMax() + : BinaryNode(OP_MAX), left_cached(false), right_cached(false) +{ + // Nothing to do here. +} + +void NumericMax::eval(const float X, const float Y, const float Z) +{ + result_float = max(left->result_float, right->result_float); +} + +void NumericMax::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = max(left->result_interval, right->result_interval); + +#if MINMAX_PRUNE + if (right->result_interval > left->result_interval) { + if (!left_cached) { + left->sub_ref(); + left_cached = true; + } + + // In case this node gets deactivated out, save a float result + left->result_float = left->result_interval.lower(); + + } else if (left_cached) { + left->add_ref(); + left_cached = false; + } + + if (left->result_interval > right->result_interval) { + if (!right_cached) { + right->sub_ref(); + right_cached = true; + } + + // In case this node gets deactivated, save a float result + right->result_float = right->result_interval.lower(); + + } else if (right_cached) { + right->add_ref(); + right_cached = false; + } +#endif + +} + + +void NumericMax::activate() +{ + if (!left_cached) + left->add_ref(); + if (!right_cached) + right->add_ref(); + Node::activate(); +} + +void NumericMax::deactivate() +{ + Node::deactivate(); + if (!left_cached) + left->sub_ref(); + if (!right_cached) + right->sub_ref(); +} + +//////////////////////////////////////////////////////////////////////////////// +VarX::VarX() + : NonaryNode(VAR_X) +{ + // Nothing to do here. +} + +void VarX::eval(const float X, const float Y, const float Z) +{ + result_float = X; +} + +void VarX::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = X; +} + +//////////////////////////////////////////////////////////////////////////////// + +VarY::VarY() + : NonaryNode(VAR_Y) +{ + // Nothing to do here. +} + +void VarY::eval(const float X, const float Y, const float Z) +{ + result_float = Y; +} + +void VarY::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = Y; +} + +//////////////////////////////////////////////////////////////////////////////// + +VarZ::VarZ() + : NonaryNode(VAR_Z) +{ + // Nothing to do here. +} + +void VarZ::eval(const float X, const float Y, const float Z) +{ + result_float = Z; +} + +void VarZ::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + result_interval = Z; +} + +//////////////////////////////////////////////////////////////////////////////// + +NumericConst::NumericConst(float value) + : NonaryNode(NUM_CONST) +{ + marked = true; + + result_float = value; + result_interval = value; +} + +bool NumericConst::operator==(const Node& rhs) +{ + if (operation != rhs.op()) + return false; + return result_float == rhs.result_float; +} + +void NumericConst::print(ostream& o) const +{ + o << result_float; +} + +void NumericConst::dot(ostream& o) const +{ + o << "\"p" << this << "\" [shape = " << dot_shape(operation) + << ", color = " << dot_color(operation) << ", fontsize = 24, label = \"" + << result_float << "\", style=\"dotted\"]\n"; +} \ No newline at end of file diff --git a/src/solver/numeric_nodes.hpp b/src/solver/numeric_nodes.hpp new file mode 100644 index 0000000..701c243 --- /dev/null +++ b/src/solver/numeric_nodes.hpp @@ -0,0 +1,98 @@ +#ifndef NUMERIC_NODES_H +#define NUMERIC_NODES_H + +#include "node.hpp" +#include "node_macro.hpp" + +// This header file defines nodes with numeric inputs and outputs. + +NODE(NumericAbs, UnaryNode); +NODE(NumericCos, UnaryNode); +NODE(NumericSin, UnaryNode); +NODE(NumericACos, UnaryNode); +NODE(NumericASin, UnaryNode); +NODE(NumericATan, UnaryNode); +NODE(NumericSqrt, UnaryNode); +NODE(NumericNeg, UnaryNode); +NODE(NumericExp, UnaryNode); +NODE(NumericSgn, UnaryNode); + +NODE(NumericPlus, BinaryNode); +NODE(NumericMinus, BinaryNode); +NODE(NumericMult, BinaryNode); +NODE(NumericDiv, BinaryNode); +NODE(NumericATan2, BinaryNode); +NODE(NumericPow, BinaryNode); + + +// These two nodes have special forms with internal variables to keep track of +// selective child deactivation. +class NumericMin : public BinaryNode +{ +public: + NumericMin(); + virtual ~NumericMin() {/*Nothing to do here*/}; + void eval(const float X, + const float Y, + const float Z); + void eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z); + void activate(); + void deactivate(); + + +private: + bool left_cached; + bool right_cached; +}; + + +class NumericMax : public BinaryNode +{ +public: + NumericMax(); + virtual ~NumericMax() {/*Nothing to do here*/}; + void eval(const float X, + const float Y, + const float Z); + void eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z); + + void activate(); + void deactivate(); + +private: + bool left_cached; + bool right_cached; +}; + + + +NODE(VarX, NonaryNode); +NODE(VarY, NonaryNode); +NODE(VarZ, NonaryNode); + +// Numerical constants are a special case, because the constructor +// has a unique signature. +class NumericConst : public NonaryNode +{ +public: + NumericConst(float value); + virtual ~NumericConst() { /* Nothing to do here */ }; + virtual bool operator==(const Node& rhs); + + void eval(const float X, + const float Y, + const float Z) { /* Nothing to do here */ }; + void eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) { /* Nothing to do here */ }; + void eval(const Region& r); + + void print(std::ostream& o) const; + void dot(std::ostream& o) const; +}; + +#endif diff --git a/src/solver/opcodes.cpp b/src/solver/opcodes.cpp new file mode 100644 index 0000000..e07f599 --- /dev/null +++ b/src/solver/opcodes.cpp @@ -0,0 +1,157 @@ +#include +#include + +#include "opcodes.hpp" +#include "parser.hpp" + +using namespace std; + +//////////////////////////////////////////////////////////////////////////////// + +ostream& operator<<(ostream& o, const opcode& op) +{ + switch(op) + { + case OP_AND: + o << " && "; return o; + case OP_OR: + o << " || "; return o; + case OP_NOT: + o << "!"; return o; + case OP_LT: + o << "<"; return o; + case OP_LEQ: + o << "<="; return o; + case OP_GT: + o << ">"; return o; + case OP_GEQ: + o << ">="; return o; + case OP_NEQ: + o << "!="; return o; + case OP_ABS: + o << "abs"; return o; + case OP_COS: + o << "cos"; return o; + case OP_SIN: + o << "sin"; return o; + case OP_ACOS: + o << "acos"; return o; + case OP_ASIN: + o << "asin"; return o; + case OP_ATAN: + o << "atan"; return o; + case OP_SQRT: + o << "sqrt"; return o; + case OP_NEGATIVE: + o << "-"; return o; + case OP_EXP: + o << "exp"; return o; + case OP_SGN: + o << "sgn"; return o; + case OP_PLUS: + o << "+"; return o; + case OP_MINUS: + o << "-"; return o; + case OP_MULT: + o << "*"; return o; + case OP_DIV: + o << "/"; return o; + case OP_ATAN2: + o << "atan2"; return o; + case OP_POW: + o << "pow"; return o; + case OP_MIN: + o << "min"; return o; + case OP_MAX: + o << "max"; return o; + case NUM_CONST: + return o; + case VAR_X: + o << "X"; return o; + case VAR_Y: + o << "Y"; return o; + case VAR_Z: + o << "Z"; return o; + case COLOR_AND: + o << "&"; return o; + case COLOR_OR: + o << "|"; return o; + case COLOR_NOT: + o << "~"; return o; + case BOOL2NUM: + o << "bool2num"; return o; + case NUM2BOOL: + o << "num2bool"; return o; + case BOOL2COLOR: + o << "bool2color"; return o; + case NUM2COLOR: + o << "num2color"; return o; + default: + o << "???"; return o; + } + return o; +} + + +//////////////////////////////////////////////////////////////////////////////// + +string dot_color(opcode op) +{ + if (op == VAR_X || op == VAR_Y || op == VAR_Z) + return "red"; + else if (op == NUM_CONST) + return "orangered"; + + switch (get_output(op)) { + case Parser::IO_NUM: + return "goldenrod"; + case Parser::IO_BOOL: + return get_input(op) == Parser::IO_NUM ? "green" : "dodgerblue"; + case Parser::IO_COLOR: + return "palevioletred2"; + default: + return "black"; + } +} + +string dot_arrow(opcode op) +{ + switch (get_input(op)) { + case Parser::IO_NUM: + return "darkgoldenrod"; + case Parser::IO_BOOL: + return "dodgerblue4"; + case Parser::IO_COLOR: + return "palevioletred4"; + default: + return "grey"; + } +} + +string dot_shape(opcode op) +{ + if (op == NUM_CONST) + return "oval"; + else if (get_token_type(op) == Parser::TOKEN_FUNC) + return "rectangle"; + else + return "square"; +} + +string dot_label(opcode op) +{ + stringstream ss; + + switch (op) { + case OP_NEGATIVE: + case OP_MINUS: + return "−"; + case OP_MULT: + return "×"; + default: + ss << op; + } + + return ss.str(); +} + diff --git a/src/solver/opcodes.hpp b/src/solver/opcodes.hpp new file mode 100644 index 0000000..17b2146 --- /dev/null +++ b/src/solver/opcodes.hpp @@ -0,0 +1,60 @@ +#ifndef OPCODES_H +#define OPCODES_H + +#include +#include + +// opcode defines which operator a node is performing. +enum opcode { + // Logical operations + OP_AND = 0, OP_OR, OP_NEQ, OP_NOT, + + // Transition operations + OP_LT, OP_LEQ, OP_GT, OP_GEQ, + + // Numerical unary operations + OP_ABS, OP_COS, OP_SIN, OP_ACOS, OP_ASIN, OP_ATAN, + OP_SQRT, OP_NEGATIVE, OP_EXP, OP_SGN, + + // Numeric binary operations + OP_PLUS, OP_MINUS, OP_MULT, OP_DIV, OP_ATAN2, OP_POW, + OP_MIN, OP_MAX, + + // Variables and constants + NUM_CONST, VAR_X, VAR_Y, VAR_Z, + + // Color operations + COLOR_AND, COLOR_OR, COLOR_NOT, + + // Translator nodes + BOOL2NUM, NUM2BOOL, BOOL2COLOR, NUM2COLOR, + + NOP_UNKNOWN, + LAST_OP +}; +std::ostream& operator<<(std::ostream& o, const opcode& i); + +// Overarching node types +enum node_type { + NODE_NUM, + NODE_TRANS, + NODE_LOGIC, + NODE_COLOR, + NODE_UNKNOWN +}; + + + +/* std::string dot_color(opcode op) + std::string dot_arrow(opcode op) + std::string dot_shape(opcode op) + std::string dot_label(opcode op) + * + * Returns various format strings for graphviz/dot file output. + */ +std::string dot_color(opcode op); +std::string dot_arrow(opcode op); +std::string dot_shape(opcode op); +std::string dot_label(opcode op); + +#endif \ No newline at end of file diff --git a/src/solver/parser.cpp b/src/solver/parser.cpp new file mode 100644 index 0000000..e2fe441 --- /dev/null +++ b/src/solver/parser.cpp @@ -0,0 +1,1248 @@ +#include +#include +#include + +#include "logic_nodes.hpp" +#include "numeric_nodes.hpp" +#include "translator_nodes.hpp" +#include "color_nodes.hpp" + +#include "parser.hpp" +#include "opcodes.hpp" +#include "switches.hpp" + +using namespace std; + +Parser::parse_token::parse_token() + : n(NULL), num_args(0), precedence(100), + ttype(TOKEN_EMPTY), input(IO_NONE), output(IO_NONE) + { + // Nothing to do here. + } + +Parser::parse_token::parse_token(token_type type) + : n(NULL), num_args(0), precedence(100), + ttype(type), input(IO_NONE), output(IO_NONE) + { + // Nothing to do here. + } + +Parser::parse_token::parse_token(Node* n) + : n(n), + num_args(get_argcount(n->op())), + precedence(get_precedence(n->op())), + ttype(get_token_type(n->op())), + input(get_input(n->op())), + output(get_output(n->op())), + associativity(get_associativity(n->op())) + { + // Nothing to do here. + } + + +ostream& operator<<(ostream& o, const Parser::token_type& t) +{ + switch (t) { + case Parser::TOKEN_NUM: + o << "TOKEN_NUM"; return o; + case Parser::TOKEN_FUNC: + o << "TOKEN_FUNC"; return o; + case Parser::TOKEN_OP: + o << "TOKEN_OP"; return o; + case Parser::TOKEN_LPARENS: + o << "TOKEN_LPARENS"; return o; + case Parser::TOKEN_ARGSEP: + o << "TOKEN_ARGSEP"; return o; + case Parser::TOKEN_RPARENS: + o << "TOKEN_RPARENS"; return o; + case Parser::TOKEN_ERROR: + o << "TOKEN_ERROR"; return o; + case Parser::TOKEN_EMPTY: + default: + o << "TOKEN_EMPTY"; return o; + } +} + +ostream& operator<<(ostream& o, const Parser::io_type& t) +{ + switch (t) { + case Parser::IO_NUM: + o << "IO_NUM"; return o; + case Parser::IO_BOOL: + o << "IO_BOOL"; return o; + case Parser::IO_COLOR: + o << "IO_COLOR"; return o; + case Parser::IO_NONE: + default: + o << "IO_NONE"; return o; + } +} + + +Parser::Parser() + : math_string(NULL), start(NULL), unary_subtraction(true), map_state(0), + newX(NULL), newY(NULL), newZ(NULL) +{ + // Stores plain old X, Y, and Z as the current + // X, Y, and Z coordinates. + currentX.push_front(new VarX()); + cache_node(currentX.front()); + + currentY.push_front(new VarY()); + cache_node(currentY.front()); + + currentZ.push_front(new VarZ()); + cache_node(currentZ.front()); +} + +void Parser::wrap_argument(parse_token& arg, io_type desired) +{ + if (!arg.n || arg.output == desired) + return; + + // Transform numerical nodes into logical nodes. + if (desired == IO_BOOL && arg.output == IO_NUM) { + arg.n = new NumToBool(arg.n); + arg.output = IO_BOOL; + + // Transform booleans into numbers + } else if (desired == IO_NUM && arg.output == IO_BOOL) { + arg.n = new BoolToNum(arg.n); + arg.output = IO_NUM; + + // Transform numbers into colors + } else if (desired == IO_COLOR && arg.output == IO_NUM) { + arg.n = new NumToColor(arg.n); + arg.output = IO_COLOR; + + // Transform booleans into colors + } else if (desired == IO_COLOR && arg.output == IO_BOOL) { + arg.n = new BoolToColor(arg.n); + arg.output = IO_COLOR; + + // If we can't wrap the operator, then return false. + } else { + cerr << "Error: node " << *(arg.n) << " has output of type " + << arg.output << ", which cannot be converted to " + << desired << endl; + exit(1); + } + + cache_node(arg.n); +} + + +void print_list(list L, ostream& o) +{ + list::iterator it; + int limit = 10; + for (it = L.begin(); it != L.end(); ++it) { + if (it->ttype == Parser::TOKEN_LPARENS) + o << "\t(\n"; + else if (it->ttype == Parser::TOKEN_RPARENS) + o << "\t)\n"; + else if (it->ttype == Parser::TOKEN_ARGSEP) + o << "\t,\n"; + else if (it->n) + o << "\t" << *(it->n) << "\n"; + if (--limit == 0) + return; + } +} + + +void print_parse(list output, + list operators, + ostream& o) +{ + for(int i = 0; i < 80; ++i) + o << '-'; + o << endl; + o << "Output stack:\n"; + print_list(output, o); + o << "Operators stack:\n"; + print_list(operators, o); + o << endl; +} + +void print_parse(list output, + list operators) +{ + print_parse(output, operators, cout); +} + + +// Stores a node in the cache, uniquifying if COMBINE_NODES is enabled. +void Parser::cache_node(Node*& node) +{ + // If this is a dummy node of some kind (e.g. parenthesis, + // argument separator), then don't do anything. + if (!node) + return; + + opcode op = node->op(); + unsigned weight = node->get_weight(); + + // If we don't have a cache line for this weight, then expand the cache, + // filling new lines with a vector of node lists. + if (weight+1 > node_cache.size()) + node_cache.resize(weight+1, vector >(LAST_OP)); + +#if COMBINE_NODES + list::iterator it; + Node* match = NULL; + + // Look for matches + for (it = node_cache[weight][op].begin(); + it != node_cache[weight][op].end(); + ++it) { + if (**it == *(node)) { + match = *it; + break; + } + } + + // If we found a match, delete the old node and replace it with + // the matching node. + if (match) { + if (node != match) { + delete node; + node = match; + } + } else { + node_cache[weight][op].push_front(node); + } +#else + node_cache[weight][op].push_front(node); +#endif +} + + +// Go through the node cache and delete nodes with no references +void Parser::remove_ignored() +{ + list::iterator it; + bool keep_going; + + do { + keep_going = false; + + // Iterate through each list in the node cache + for (unsigned weight = 0; weight < node_cache.size(); ++weight) { + for (int op = 0; op < LAST_OP; ++op) { + it = node_cache[weight][op].begin(); + + // Iterate through each node in this cache + while (it != node_cache[weight][op].end()) { + + // If the node has no one watching it, then + // deactivate and delete it + if ((**it).ignored()) { + (**it).deactivate(); + delete *it; + it = node_cache[weight][op].erase(it); + keep_going = true; + } else { + ++it; + } + } + } // end of loop through operators + } // end of loop through weights + + } while (keep_going); +} + + +// Copies the entire cache to a MathTree +MathTree* Parser::cache_to_tree(Node* root) +{ + MathTree* tree = new MathTree(); + list::iterator it; + for (unsigned weight = 0; weight < node_cache.size(); ++weight) + for (int op = 0; op < LAST_OP; ++op) + for (it = node_cache[weight][op].begin(); + it != node_cache[weight][op].end(); ++it) + tree->add(*it); + tree->pack(); + tree->set_root(root); + cout << "Done." << endl; + return tree; +} + + +void Parser::convert_colors(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg) +{ + // If we find a boolean multiplied by a numerical value, then + // we treat it as a color creation. + if (oper.n->op() == OP_MULT && + ((rh_arg.output == IO_NUM && lh_arg.output == IO_BOOL) || + (lh_arg.output == IO_NUM && rh_arg.output == IO_BOOL)) ) + { + delete oper.n; + oper.n = new ColorAnd(); + oper.input = IO_COLOR; + oper.output = IO_COLOR; + } + // Logical OR on colors -> bitwise or + if (oper.n->op() == OP_OR && (rh_arg.output == IO_COLOR || + lh_arg.output == IO_COLOR)) + { + delete oper.n; + oper.n = new ColorOr(); + oper.input = IO_COLOR; + oper.output = IO_COLOR; + } + // Logical AND on colors -> bitwise and + if (oper.n->op() == OP_AND && (rh_arg.output == IO_COLOR || + lh_arg.output == IO_COLOR)) + { + delete oper.n; + oper.n = new ColorAnd(); + oper.input = IO_COLOR; + oper.output = IO_COLOR; + } + // Logical not on colors -> bitwise not + if (oper.n->op() == OP_NOT && rh_arg.output == IO_COLOR) + { + delete oper.n; + oper.n = new ColorNot(); + oper.input = IO_COLOR; + oper.output = IO_COLOR; + } +} + + +bool Parser::simplify(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg) +{ + // We're only going to simplify numeric nodes to keep life easy. + if (oper.input != IO_NUM) + return false; + + opcode op = oper.n->op(); + + if (op == OP_PLUS) { + // 0 + X => X + if (lh_arg.n->marked && lh_arg.n->result_float == 0) { + delete oper.n; + oper.n = rh_arg.n; + return true; + } + // X + 0 => X + if (rh_arg.n->marked && rh_arg.n->result_float == 0) { + delete oper.n; + oper.n = lh_arg.n; + return true; + } + } else if (op == OP_MINUS) { + // X - 0 => X + if (rh_arg.n->marked && rh_arg.n->result_float == 0) { + delete oper.n; + oper.n = lh_arg.n; + return true; + } + } else if (op == OP_MULT) { + // X * 0 => 0 + if (rh_arg.n->marked && rh_arg.n->result_float == 0) { + delete oper.n; + oper.n = rh_arg.n; + return true; + } + // 0 * X => 0 + if (lh_arg.n->marked && lh_arg.n->result_float == 0) { + delete oper.n; + oper.n = lh_arg.n; + return true; + } + // X * 1 => X + if (rh_arg.n->marked && rh_arg.n->result_float == 1) { + delete oper.n; + oper.n = lh_arg.n; + return true; + } + // 1 * X => X + if (lh_arg.n->marked && lh_arg.n->result_float == 1) { + delete oper.n; + oper.n = rh_arg.n; + return true; + } + } + + return false; +} + + +// operator_to_output +// +// Find out how many arguments the operation wants to take from +// the output stack +// Take them off the stack and make them the operator's children +// Put the new operation on the output stack. +void Parser::operator_to_output(parse_token& oper) +{ + if (oper.ttype == TOKEN_LPARENS || oper.ttype == TOKEN_MAP_START) + return; + + // If this node's children have already been populated, then + // we can skip the song and dance about pulling them from the + // stack. + if (oper.n && oper.n->null_children() == false) { + cache_node(oper.n); + output.push_front(oper); + return; + } + + parse_token rh_arg; + parse_token lh_arg; + + // Handle the first argument + if (oper.num_args >= 1) { + if (output.empty()) { + cerr << "Parse failed:\n\t'" << *(oper.n) + << "' failed to acquire its first operand." << endl; + exit(1); + } + rh_arg = output.front(); + output.pop_front(); + } + + // Handle the second argument + if (oper.num_args >= 2) { + if (output.empty()) { + cerr << "Parse failed:\n\t'" << *(oper.n) + << "' failed to acquire its second operand." << endl; + exit(1); + } + lh_arg = output.front(); + output.pop_front(); + } + + // Set of special cases to handle colors correctly. + convert_colors(oper, lh_arg, rh_arg); + + // If the argument outputs are of a different type then + // the operator's inputs, wrap them in a lightweight + // wrapper classes to do the conversion. + wrap_argument(lh_arg, oper.input); + wrap_argument(rh_arg, oper.input); + + // Simplify common arithmetic expressions (e.g. X + 0 => X) + bool simplified = false; +#if SIMPLIFY_TREE + simplified = simplify(oper, lh_arg, rh_arg); +#endif + + // If this node has been simplified, then we don't need to worry + // about assigning children or caching (since the node is already + // cached). + if (!simplified) { + if (oper.num_args == 1) + static_cast(oper.n)->set_child(rh_arg.n); + else if (oper.num_args == 2) + static_cast(oper.n)->set_children(lh_arg.n, + rh_arg.n); + cache_node(oper.n); + } + + output.push_front(oper); +} + + +// operator_to_stack +// +// Add an operator to the operator stack, while checking if precedence +// requires removing other operators from the top of the stack. +void Parser::operator_to_stack(parse_token& o1) +{ + while (!operators.empty()) + { + parse_token o2 = operators.front(); + if ((o1.associativity == 'l' && o1.precedence >= o2.precedence) || + (o1.associativity == 'r' && o1.precedence > o2.precedence)) + { + operators.pop_front(); + operator_to_output(o2); + } else + break; + } + operators.push_front(o1); +} + + +bool str_match(const char* s1, const char* s2) +{ + do + if (!*s1 || *s1++ != *s2++) + return false; + while (*s2); + + return true; +} + +Parser::parse_token Parser::next_token() +{ + bool next_unary_subtraction = true; + + parse_token result; + + if (*start == '(') { + start += 1; + result = TOKEN_LPARENS; + } + else if (str_match(start, "{")) { + start += 1; + result = TOKEN_MAP_START; + } + else if (str_match(start, "X:")) { + start +=2; + result = TOKEN_MAP_DEF; + result.n = currentX.front(); + } + else if (str_match(start, "Y:")) { + start +=2; + result = TOKEN_MAP_DEF; + result.n = currentY.front(); + } + else if (str_match(start, "Z:")) { + start +=2; + result = TOKEN_MAP_DEF; + result.n = currentZ.front(); + } + else if (str_match(start, ";")) { + start += 1; + result = TOKEN_MAP_SEPARATOR; + } + else if (str_match(start, "}")) { + start += 1; + result = TOKEN_MAP_END; + } + else if (*start == ')') { + start += 1; + next_unary_subtraction = false; + result = TOKEN_RPARENS; + } else if (*start == 'X' || *start == 'x') { + start += 1; + next_unary_subtraction = false; + result = currentX.front(); + result.ttype = TOKEN_NUM; + } else if (*start == 'Y' || *start == 'y') { + start += 1; + next_unary_subtraction = false; + result = currentY.front(); + result.ttype = TOKEN_NUM; + } else if (*start == 'Z' || *start == 'z') { + start += 1; + next_unary_subtraction = false; + result = currentZ.front(); + result.ttype = TOKEN_NUM; + } + else if (*start == '-') { + start += 1; + if (unary_subtraction) { + result = new NumericNeg(); + } else { + result = new NumericMinus(); + } + } + else if (*start == ',') { + start += 1; + result = TOKEN_ARGSEP; + } + else if (*start == '*') { + start += 1; + result = new NumericMult(); + } + else if (*start == '+') { + start += 1; + result = new NumericPlus(); + } + else if (*start == '/') { + start += 1; + result = new NumericDiv(); + } + else if (str_match(start, "atan2")) { + start += 5; + result = new NumericATan2(); + } + else if (str_match(start, "pow")) { + start += 3; + result = new NumericPow(); + } + else if (str_match(start, "min")) { + start += 3; + result = new NumericMin(); + } + else if (str_match(start, "max")) { + start += 3; + result = new NumericMax(); + } + else if (str_match(start, "exp")) { + start += 3; + result = new NumericExp(); + } + else if (str_match(start, "sgn")) { + start += 3; + result = new NumericSgn(); + } + else if (str_match(start, "abs")) { + start += 3; + result = new NumericAbs(); + } + else if (str_match(start, "cos")) { + start += 3; + result = new NumericCos(); + } + else if (str_match(start, "sin")) { + start += 3; + result = new NumericSin(); + } + else if (str_match(start, "acos")) { + start += 4; + result = new NumericACos(); + } + else if (str_match(start, "asin")) { + start += 4; + result = new NumericASin(); + } + else if (str_match(start, "atan")) { + start += 4; + result = new NumericATan(); + } + else if (str_match(start, "sqrt")) { + start += 4; + result = new NumericSqrt(); + } + else if (str_match(start, "<=")) { + start += 2; + result = new TransitionLeq(); + } + else if (str_match(start, "<")) { + start += 1; + result = new TransitionLt(); + } + else if (str_match(start, ">=")) { + start += 2; + result = new TransitionGeq(); + } + else if (str_match(start, ">")) { + start += 1; + result = new TransitionGt(); + } + else if (str_match(start, "!=")) { + start += 2; + result = new LogicNeq(); + } + else if (*start == '!' || *start == '~') { + start += 1; + result = new LogicNot(); + } + else if (str_match(start, "&&")) + { + start += 2; + result = new LogicAnd(); + } + else if (*start == '&') + { + start += 1; + result = new LogicAnd(); + } + else if (str_match(start, "||")) + { + start += 2; + result = new LogicOr(); + } + else if (*start == '|') + { + start += 1; + result = new LogicOr(); + } + else if (str_match(start, "pi")) + { + start += 2; + result = new NumericConst(3.14159265358979323846); + } + else if ((*start >= '0' && *start <= '9') || *start == '.') + { + + // Accumulated value + float v = 0; + + // Divided value once we're after the decimal place + double divider = 0; + do { + if (*start == '.') + divider = 10; + else if (divider) { + v += float(*start - '0') / divider; + divider *= 10; + } else { + v = v * 10 + (*start - '0'); + } + + start++; + } while ((*start >= '0' && *start <= '9') || *start == '.'); + + // Check for scientific notation. + if (*start == 'e') { + int e = 0; + bool neg_exp = false; + start++; + if (*start == '-') { + neg_exp = true; + start++; + } else if (*start == '+') { + neg_exp = false; + start++; + } + do { + e = e * 10 + (*start++ - '0'); + } while (*start >= '0' && *start <= '9'); + // Negate the exponent if needed. + e = e * (neg_exp ? -1 : 1); + v = v * pow(10.0, e); + } + + next_unary_subtraction = false; + result = new NumericConst(v); + } + else if (*start != ' ') + { + cerr << "Warning: Unknown token at '"; + if (string(start).size() > 10) + cerr << string(start, start + 10) << "...'" << endl; + else + cerr << string(start) << "'" << endl; + start++; + return parse_token(); + } + + // Zoom along until we're staring at something useful. + while (*start == ' ') + start++; + + unary_subtraction = next_unary_subtraction; + + return result; +} + + +MathTree* Parser::parse(string input, solver_mode& mode) +{ + parse_token current; + + cout << "Parsing... "; + cout.flush(); + + // Convert into a c-style string + math_string = input.c_str(); + start = math_string; + + unary_subtraction = true; + + while (*start) + { + current = next_token(); + + // If there was a parse failure, then return. + if (current.ttype == TOKEN_ERROR) + return NULL; + + // If this token was empty, then continue. + if (current.ttype == TOKEN_EMPTY) + continue; + + if (current.ttype == TOKEN_NUM) + operator_to_output(current); + + else if (current.ttype == TOKEN_FUNC) + operators.push_front(current); + + else if (current.ttype == TOKEN_MAP_START) { + + if (map_state) { + cerr << "Parse error: badly nested map statement." + << endl; + exit(1); + } + + // If they are using curly braces without any map commands, then + // push trivial maps to the stacks. + if (*start && *(start+1) == ':') { + map_state = '?'; + } else { + currentX.push_front(currentX.front()); + currentY.push_front(currentY.front()); + currentZ.push_front(currentZ.front()); + } + + operators.push_front(current); + } + + else if (current.ttype == TOKEN_MAP_DEF) { + // When we get a colon, it better be within in the context of + // a map operation (and it should follow X,Y, or Z) + + if (current.n == currentX.front()) { + if (newX || map_state != '?') { + cerr << "Parse error: Repeated X mapping." << endl; + exit(1); + } + map_state = 'X'; + } else if (current.n == currentY.front()) { + if (newY || map_state != '?') { + cerr << "Parse error: Repeated Y mapping." << endl; + exit(1); + } + map_state = 'Y'; + } else if (current.n == currentZ.front()) { + if (newZ || map_state != '?') { + cerr << "Parse error: Repeated Z mapping." << endl; + exit(1); + } + map_state = 'Z'; + } + } + + + else if (current.ttype == TOKEN_ARGSEP) + { + if (operators.empty()) { + cerr << "Parse error: Misplaced argument separator." + << endl; + exit(1); + } + while (operators.front().ttype != TOKEN_LPARENS) + { + operator_to_output(operators.front()); + operators.pop_front(); + if (operators.empty()) { + cerr << "Parse error: Misplaced argument separator." + << endl; + exit(1); + } + } + } + + + else if (current.ttype == TOKEN_MAP_SEPARATOR) { + + if (!map_state) { + cerr << "Parse error: Misplaced map argument separator." + << endl; + exit(1); + } + + if (operators.empty()) { + cerr << "Parse error: Misplaced map argument separator." + << endl; + exit(1); + } + while (operators.front().ttype != TOKEN_MAP_START) + { + operator_to_output(operators.front()); + operators.pop_front(); + if (operators.empty()) { + cerr << "Parse error: Misplaced map argument separator." + << endl; + exit(1); + } + } + + // If we're in the middle of a map operation, save the + // new mapped value for X, Y, or Z. + if (map_state == 'X') { + newX = output.front().n; + output.pop_front(); + } else if (map_state == 'Y') { + newY = output.front().n; + output.pop_front(); + } else if (map_state == 'Z') { + newZ = output.front().n; + output.pop_front(); + } + + // Check to see if another map operation is coming down the line. + if (*start && *(start+1) == ':') { + map_state = '?'; + } + + // If not, then apply the saved maps for X, Y, and Z. + else { + if (newX) + currentX.push_front(newX); + else + currentX.push_front(currentX.front()); + + if (newY) + currentY.push_front(newY); + else + currentY.push_front(currentY.front()); + + if (newZ) + currentZ.push_front(newZ); + else + currentZ.push_front(currentZ.front()); + + newX = NULL; + newY = NULL; + newZ = NULL; + + map_state = 0; + } + } + + + + else if (current.ttype == TOKEN_OP) + operator_to_stack(current); + + else if (current.ttype == TOKEN_LPARENS) + operators.push_front(current); + + else if (current.ttype == TOKEN_RPARENS) + { + if (operators.empty()) { + cerr << "Parse error: mismatched parentheses." << endl; + exit(1); + } + while (operators.front().ttype != TOKEN_LPARENS) + { + operator_to_output(operators.front()); + operators.pop_front(); + if (operators.empty()) { + cerr << "Parse error: mismatched parentheses." << endl; + exit(1); + } + } + operators.pop_front(); + + // If there's a function on top of the stack, then it belongs + // with the set of parentheses. + if (!operators.empty() && operators.front().ttype == TOKEN_FUNC) { + operator_to_output(operators.front()); + operators.pop_front(); + } + } + + else if (current.ttype == TOKEN_MAP_END) + { + if (operators.empty()) { + cerr << "Parse error: mismatched curly braces." << endl; + exit(1); + } + while (operators.front().ttype != TOKEN_MAP_START) + { + operator_to_output(operators.front()); + operators.pop_front(); + if (operators.empty()) { + cerr << "Parse error: mismatched curly braces." << endl; + exit(1); + } + } + operators.pop_front(); + + currentX.pop_front(); + currentY.pop_front(); + currentZ.pop_front(); + } + } + + // Finish the parse by popping operators off the stack. + while (!operators.empty()) + { + operator_to_output(operators.front()); + operators.pop_front(); + } + + if (!output.size()) + { + cerr << "Parse failed:\n\tEmpty math tree." << endl; + return NULL; + } else if (output.size() > 1) { + cerr << "Parse failed:\n\tInvalid math string." << endl; + return NULL; + } + + // Make sure that the root's output type is correct; otherwise + // return NULL. + if (mode == SOLVE_BOOL) + wrap_argument(output.front(), IO_BOOL); + else if (mode == SOLVE_RGB) + wrap_argument(output.front(), IO_COLOR); + else if (mode == SOLVE_REAL) { + wrap_argument(output.front(), IO_NUM); + } + + // Add a watcher to the top node of the tree (so that it doesn't get + // auto-deleted) + Node* root = output.front().n; + root->add_ref(); + + // Delete any ignored nodes (that were optimized out of the tree) + remove_ignored(); + + // Convert the cache into the tree. + return cache_to_tree(root); +} + +//////////////////////////////////////////////////////////////////////////////// +// Functions below this point are used to extract parsing information from node +// opcodes. +//////////////////////////////////////////////////////////////////////////////// + +int get_precedence(opcode op) +{ + switch (op) + { + case OP_NOT: + case OP_NEGATIVE: + case COLOR_NOT: + return 1; + case OP_MULT: + case OP_DIV: + return 2; + case OP_PLUS: + case OP_MINUS: + return 3; + case OP_LT: + case OP_GT: + case OP_LEQ: + case OP_GEQ: + case OP_NEQ: + return 4; + case OP_AND: + case COLOR_AND: + return 5; + case OP_OR: + case COLOR_OR: + return 6; + default: + return 100; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// get_node_type +// +// From an opcode, infer the type of the node. +// (e.g. cosine implies a numerical node) +node_type get_node_type(opcode op) +{ + switch (op) + { + case OP_ABS: + case OP_COS: + case OP_SIN: + case OP_ACOS: + case OP_ASIN: + case OP_ATAN: + case OP_SQRT: + case OP_NEGATIVE: + case OP_EXP: + case OP_SGN: + case OP_PLUS: + case OP_MINUS: + case OP_MULT: + case OP_DIV: + case OP_ATAN2: + case OP_POW: + case OP_MIN: + case OP_MAX: + case VAR_X: + case VAR_Y: + case VAR_Z: + case NUM_CONST: + return NODE_NUM; + case OP_AND: + case OP_OR: + case OP_NOT: + case OP_NEQ: + return NODE_LOGIC; + case OP_LT: + case OP_LEQ: + case OP_GT: + case OP_GEQ: + return NODE_TRANS; + case COLOR_AND: + case COLOR_OR: + case COLOR_NOT: + return NODE_COLOR; + default: + cerr << "Error: unknown operator " << op << " in get_node_type." << endl; + exit(1); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// get_token_type +// +// From an opcode, infer the type of the token. +// (e.g. cosine implies a function node) +Parser::token_type get_token_type(opcode op) +{ + switch (op) + { + case OP_ABS: + case OP_COS: + case OP_SIN: + case OP_ACOS: + case OP_ASIN: + case OP_ATAN: + case OP_SQRT: + case OP_ATAN2: + case OP_POW: + case OP_MIN: + case OP_MAX: + case OP_EXP: + case OP_SGN: + case NUM2BOOL: + case BOOL2NUM: + case NUM2COLOR: + case BOOL2COLOR: + return Parser::TOKEN_FUNC; + case OP_NEGATIVE: + case OP_PLUS: + case OP_MINUS: + case OP_MULT: + case OP_DIV: + case OP_AND: + case OP_OR: + case OP_NOT: + case OP_LT: + case OP_LEQ: + case OP_GT: + case OP_GEQ: + case OP_NEQ: + case COLOR_OR: + case COLOR_AND: + case COLOR_NOT: + return Parser::TOKEN_OP; + case VAR_X: + case VAR_Y: + case VAR_Z: + case NUM_CONST: + return Parser::TOKEN_NUM; + default: + cerr << "Error: unknown operator " << op << " in get_token_type." << endl; + exit(1); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +Parser::io_type get_output(opcode op) +{ + // Special case for translator nodes + switch (op) { + case BOOL2NUM: + return Parser::IO_NUM; + case NUM2BOOL: + return Parser::IO_BOOL; + case BOOL2COLOR: + case NUM2COLOR: + return Parser::IO_COLOR; + default: + ; // Continue to the rest of the function + } + + node_type ntype = get_node_type(op); + switch (ntype) + { + case NODE_NUM: + return Parser::IO_NUM; + case NODE_TRANS: + case NODE_LOGIC: + return Parser::IO_BOOL; + case NODE_COLOR: + return Parser::IO_COLOR; + default: + return Parser::IO_NONE; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +Parser::io_type get_input(opcode op) +{ + // Special case for translator nodes + switch (op) { + case BOOL2NUM: + case BOOL2COLOR: + return Parser::IO_BOOL; + case NUM2BOOL: + case NUM2COLOR: + return Parser::IO_NUM; + default: + ; // Continue to the rest of the function + } + + node_type ntype = get_node_type(op); + switch (ntype) + { + case NODE_NUM: + case NODE_TRANS: + return Parser::IO_NUM; + case NODE_LOGIC: + return Parser::IO_BOOL; + case NODE_COLOR: + return Parser::IO_COLOR; + default: + return Parser::IO_NONE; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// get_argcount +// +// From an opcode, infer the number of arguments that a node will want +// to take (e.g. cosine wants one, atan2 wants 2) +int get_argcount(opcode op) +{ + switch (op) + { + case NUM_CONST: + case VAR_X: + case VAR_Y: + case VAR_Z: + return 0; + case OP_NEGATIVE: + case OP_EXP: + case OP_SGN: + case OP_ABS: + case OP_COS: + case OP_SIN: + case OP_ACOS: + case OP_ASIN: + case OP_ATAN: + case OP_SQRT: + case OP_NOT: + case COLOR_NOT: + return 1; + default: + return 2; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// get_associativity +// +// From an opcode, return the associativity of the operation. +char get_associativity(opcode op) +{ + switch (op) + { + case OP_NEGATIVE: + case OP_NOT: + case COLOR_NOT: + return 'r'; + default: + return 'l'; + } +} \ No newline at end of file diff --git a/src/solver/parser.hpp b/src/solver/parser.hpp new file mode 100644 index 0000000..60a39c1 --- /dev/null +++ b/src/solver/parser.hpp @@ -0,0 +1,272 @@ +#ifndef PARSE_H +#define PARSE_H + +#include +#include + +#include "opcodes.hpp" +#include "math_tree.hpp" +#include "fabvars.hpp" + +// This class parses a .math file, converting it into a MathTree. +class Parser +{ +public: + Parser(); + + // Tokens are divided into a set of types + enum token_type { + TOKEN_NUM, + TOKEN_FUNC, + TOKEN_OP, + TOKEN_LPARENS, + TOKEN_ARGSEP, + TOKEN_RPARENS, + + TOKEN_MAP_START, + TOKEN_MAP_DEF, TOKEN_MAP_SEPARATOR, + TOKEN_MAP_END, + + TOKEN_EMPTY, + TOKEN_ERROR + }; + + // Input and output types for parse tokens. + enum io_type { + IO_NUM, + IO_BOOL, + IO_COLOR, + IO_NONE + }; + + // Small structure to hold a single parse token + typedef struct parse_token + { + /* parse_token() + * + * Token constructor. Creates an empty token. + */ + parse_token(); + + + /* parse_token(token_type type) + * + * Token constructor. Creates an null token of + * the given type. + */ + parse_token(token_type type); + + /* parse_token(Node* n) + * + * Token constructor. Creates an token based on + * a Node object, using helper functions to look up + * the node's parameters (e.g. number of arguments) + */ + parse_token(Node* n); + + // Every token points to a Node + Node* n; + + // How many arguments will this token want to pull + // off the stack? + int num_args; + + // This token's precedence (lower is more important) + int precedence; + + // The type of this token (function, number, operation, etc) + token_type ttype; + + // Token's input and output data types + io_type input; + io_type output; + + // 'l' or 'r' for left or right associative + char associativity; + + } parse_token; + + + /* MathTree* parse(std::string input, solver_mode& mode) + * + * Takes in a string of math and solver mode, and returns an + * appropriate MathTree. + */ + MathTree* parse(std::string input, solver_mode& mode); + +private: + /* parse_token next_token() + * + * Extracts and returns the next token from the input string. + */ + parse_token next_token(); + + + /* void operator_to_stack(parse_token& o1) + * + * Puts an operator node on the top of the operator stack. + * This may require popping other nodes off the operator stack + * depending on their precedence. + */ + void operator_to_stack(parse_token& o1); + + + /* void operator_to_output(parse_token& oper) + * + * Puts an operator node on the top of the output stack. + * This may involve pulling arguments from the output stack + * and assigning them as the operator's children. + */ + void operator_to_output(parse_token& oper); + + + /* void cache_node(Node*& node) + * + * Stores a node in the cache. If COMBINE_NODES is enabled, then + * this function uniquifies nodes in the cache. + */ + void cache_node(Node*& node); + + + /* void remove_ignored() + * + * Traverses the node cache, deleting any items with no references. + * This is needed if the SIMPLIFY_TREE is turned on, because nodes + * are optimized out of the tree after they are cached. + */ + void remove_ignored(); + + + /* MathTree* cache_to_tree() + * + * Copies the set of cached nodes into a MathTree and + * returns the tree. + */ + MathTree* cache_to_tree(Node* root); + + + /* bool simplify(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg) + * + * Simplifies an expression by replacing an operation with one of its + * operands if appropriate (e.g. X + 0 -> X). + * + * Returns true if the operation was simplified, false otherwise. + */ + bool simplify(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg); + + + /* void convert_colors(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg); + * + * Replaces logical operations with bitwise operations where + * appropriate. This occurs in a few situations: + * boolean * number -> boolean & number, which will be + * wrapped into color(boolean) & color(number) by + * wrap_argument + * color && color -> color & color + * color || color -> color | color + * !color -> ~color + */ + void convert_colors(parse_token& oper, + parse_token& lh_arg, + parse_token& rh_arg); + + + /* void wrap_argument(parse_token& arg, io_type desired) + * + * Coerces the output type of the provided parse token into the + * desired output types, using translator nodes if needed. + */ + void wrap_argument(parse_token& arg, io_type desired); + + // The math string in question + const char* math_string; + + // Our current position in the math string (used in tokenizer) + const char* start; + + // State variable to keep track of whether the next subtraction is + // unary (e.g. 4 * -1 vs. 4 - 1) + bool unary_subtraction; + + // Stack of output tokens + std::list output; + + // Stack of operator tokens + std::list operators; + + // Cached nodes + std::vector > > node_cache; + + // Stacks for X, Y, and Z (to add support from "map" operation) + std::list currentX; + std::list currentY; + std::list currentZ; + + // Store where we are in a map operation. + char map_state; + + // New nodes (for partway through a map operation) + Node* newX; + Node* newY; + Node* newZ; +}; + +// Print operator for token type enum +std::ostream& operator<<(std::ostream& o, const Parser::token_type& t); + +// Print operator for io type enum +std::ostream& operator<<(std::ostream& o, const Parser::io_type& t); + + +/* int get_precedence(opcode op) + * + * Returns the precedence of an operation. Lower values are equivalent + * to a higher precedence. + */ +int get_precedence(opcode op); + + +/* Parser::token_type get_token_type(opcode op) + * + * From an opcode, return a token type for the parser's use. + */ +Parser::token_type get_token_type(opcode op); + + +/* node_type get_node_type(opcode op) + * + * From an opcode, return a node type. + */ +node_type get_node_type(opcode op); + + +/* Parser::io_type get_input(opcode op) + Parser::io_type get_output(opcode op) + * + * Find a node's preferred input and output formats. + */ +Parser::io_type get_input(opcode op); +Parser::io_type get_output(opcode op); + + +/* int get_argcount(opcode op) + * + * Returns the number of arguments required by a node. + */ +int get_argcount(opcode op); + + +/* char get_associativity(opcode op) + * + * Returns 'l' or 'r' for left or right associative operators. + */ +char get_associativity(opcode op); + + +#endif \ No newline at end of file diff --git a/src/solver/progress_bar.cpp b/src/solver/progress_bar.cpp new file mode 100644 index 0000000..786f45a --- /dev/null +++ b/src/solver/progress_bar.cpp @@ -0,0 +1,36 @@ +#include +#include "progress_bar.hpp" + +using namespace std; + +ProgressBar::ProgressBar() + : full(0), progress(0), next_tick(1), bar_length(40) +{ + // Nothing to do here +} + +bool ProgressBar::update(uint64_t delta) +{ + if (!lock.try_lock()) + return false; + progress += delta; + lock.unlock(); + + if (!cout_lock.try_lock()) + return true; + + while (next_tick <= (progress*bar_length) / full) { + cout << "\r ["; + for(unsigned i = 0; i < next_tick; ++i) + cout << '|'; + for(int i = next_tick; i < bar_length; ++i) + cout << ' '; + cout << ']'; + + cout << flush; + + next_tick += 1; + } + cout_lock.unlock(); + return true; +} \ No newline at end of file diff --git a/src/solver/progress_bar.hpp b/src/solver/progress_bar.hpp new file mode 100644 index 0000000..128493b --- /dev/null +++ b/src/solver/progress_bar.hpp @@ -0,0 +1,44 @@ +#ifndef PROGRESS_H +#define PROGRESS_H + +#include +#include + +// This class draws a progress bar on the screen at regular intervals +class ProgressBar +{ +public: + /* ProgressBar() + * + * Simple constructor. + */ + ProgressBar(); + + /* bool update(unsigned long delta) + * + * Informs the progress bar that another delta units have been + * evaluated. The progress bar may or may not redraw at this point. + * + * Returns true if the update was accepted, false otherwise. + */ + bool update(uint64_t delta); + + + // The number of units in the full render + uint64_t full; + + // The number of units that have been solved + uint64_t progress; + + // The next significant redraw point + unsigned next_tick; + + // Total length of the ASCII bar + int bar_length; + + // Mutex to synchronize disparate threads + boost::mutex lock; + boost::mutex cout_lock; +}; + +#endif \ No newline at end of file diff --git a/src/solver/raycaster.cpp b/src/solver/raycaster.cpp new file mode 100644 index 0000000..41f4f79 --- /dev/null +++ b/src/solver/raycaster.cpp @@ -0,0 +1,99 @@ +#include "raycaster.hpp" +#include "math_tree.hpp" +#include "node.hpp" +#include "task_buffer.hpp" + +#include "switches.hpp" + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +Raycaster::Raycaster(FabVars& v) + : Solver(v) +{ + // Nothing to do here. +} + +Raycaster::Raycaster(MathTree* tree, FabVars& v) + : Solver(tree, v) +{ + // Nothing to do here. +} + +/////////////////////////////////////////////////////////////////////////////// + +// Evaluate a single region, either with point-by-point evaluation or +// interval math + recursion. Operates in a single thread and spawns +// no children. +void Raycaster::evaluate_region(Region r) +{ + + FabInterval X = v.x(r.imin, r.imax-1); + FabInterval Y = v.y(r.jmin, r.jmax-1); + FabInterval Z = v.z(r.kmin, r.kmax-1); + + tree->eval(X, Y, Z); + + // If the result was unambiguous, then fill in that part + // of the image, then return. + tribool result = tree->root->result_interval <= FabInterval(0); + + if (result) v.fill(r); + if (!indeterminate(result)) return; + + // Use Newton's method on the distance metric to find + // an upper bound on the front of the object. + + // If we've hit voxel level, use floating-point evaluation + // when evaluating Newton's method. + if (r.ni * r.nj <= 1) { + float x = v.x(r.imin); + float y = v.y(r.jmin); + + float prev_k = r.kmax; + float k = prev_k; + do { + prev_k = k; + + tree->eval(x, y, v.z(k)); + float d1 = tree->root->result_float; + + tree->eval(x, y, v.z(k - 1)); + float d2 = tree->root->result_float; + + float slope = d1 - d2; + k = k - d1 / slope; + + } while (abs(k - prev_k) > 0.5); + + r.kmax = k; + v.fill(r); + + return; + } + + + // Otherwise, use interval evaluation on the xy region. + float prev_k = r.kmax; + float k = prev_k; + do { + prev_k = k; + + tree->eval(X, Y, v.z(k)); + float d1 = tree->root->result_interval.lower(); + + tree->eval(X, Y, v.z(k - 1)); + float d2 = tree->root->result_interval.lower(); + + float slope = d1 - d2; + k = k - d1 / slope; + } while (abs(k - prev_k) > 0.5); + r.kmax = k; + + list subregions = r.split_xy(2); + list::iterator it; + + for (it = subregions.begin(); it != subregions.end(); ++it) + evaluate_region(*it); +} \ No newline at end of file diff --git a/src/solver/raycaster.hpp b/src/solver/raycaster.hpp new file mode 100644 index 0000000..fb9468a --- /dev/null +++ b/src/solver/raycaster.hpp @@ -0,0 +1,34 @@ +#ifndef RAYCASTER_H +#define RAYCASTER_H + +#include + +#include "solver.hpp" + +class Raycaster : public Solver +{ +public: + /* Raycaster(FabVars& v) + * Raycaster(MathTree* tree, FabVars& v) + * + * Constructs an Raycaster instance. + */ + Raycaster(FabVars& v); + Raycaster(MathTree* tree, FabVars& v); + virtual ~Raycaster() { /* Nothing to do here */ } + + /* virtual void evaluate_region(Region R) + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R); + + /* virtual void save() + * + * Nothing needs to happen here, since evaluate_region dumps data + * directly into the image matrix. + */ + void save() { /* Nothing to do here */ } +}; +#endif \ No newline at end of file diff --git a/src/solver/region.cpp b/src/solver/region.cpp new file mode 100644 index 0000000..e800bb8 --- /dev/null +++ b/src/solver/region.cpp @@ -0,0 +1,106 @@ +#include + +#include "region.hpp" +#include "fabvars.hpp" + +using namespace std; + +Region::Region() + : imin(0), jmin(0), kmin(0), + imax(0), jmax(0), kmax(0), + ni(0), nj(0), nk(0), + volume(0) +{ + // Nothing to do here +} + +Region::Region(const FabVars& v) + : imin(0), jmin(0), kmin(0), + imax(v.ni), jmax(v.nj), kmax(v.nk), + ni(v.ni), nj(v.nj), nk(v.nk), + volume(ni * nj * nk) +{ + // Nothing to do here +} + +Region::Region(unsigned int imin, unsigned int jmin, unsigned int kmin, + unsigned int imax, unsigned int jmax, unsigned int kmax) + : imin(imin), jmin(jmin), kmin(kmin), + imax(imax), jmax(jmax), kmax(kmax), + ni(imax - imin), nj(jmax - jmin), nk(kmax - kmin), + volume(ni * nj * nk) +{ + // Nothing to do here. +} + +list Region::split() const +{ + return split(2); +} + +list Region::split(int isplit, int jsplit, int ksplit) const +{ + isplit = isplit > ni ? ni : isplit; + jsplit = jsplit > nj ? nj : jsplit; + ksplit = ksplit > nk ? nk : ksplit; + + list L; + for (int k = ksplit - 1; k >= 0; --k) + for (int i = 0; i < isplit; ++i) + for (int j = 0; j < jsplit; ++j) + L.push_back(Region(imin + (i*ni) / isplit, + jmin + (j*nj) / jsplit, + kmin + (k*nk) / ksplit, + imin + ((i+1)*ni) / isplit, + jmin + ((j+1)*nj) / jsplit, + kmin + ((k+1)*nk) / ksplit)); + return L; +} + +// Split into a given number of segments (must be power of two), +// prioritizing larger dimensions +list Region::split(int count) const +{ + int i_score = 0; + int j_score = 0; + int k_score = 0; + + while ((1 << i_score) * (1 << j_score) * (1 << k_score) < count) { + float di = ni / float(1 << i_score); + float dj = nj / float(1 << j_score); + float dk = nk / float(1 << k_score); + if (di >= dj && di >= dk) + i_score++; + else if (di >= dk) + j_score++; + else + k_score++; + } + + return split(1< Region::split_xy(int count) const +{ + int i_score = 0; + int j_score = 0; + + while ((1 << i_score) * (1 << j_score) < count) { + float di = ni / float(1 << i_score); + float dj = nj / float(1 << j_score); + if (di >= dj) + i_score++; + else + j_score++; + } + + return split(1< +#include + +// Forward declarations +struct FabVars; + +// A note on terminology: +// x, y, z refer to coordinates in space. +// i, j, k refer to pixel discretized coordinates + +// Small structure to hold a 3D lattice region. +typedef struct Region { + + /* Region() + * + * Constructs a empty region. + */ + Region(); + + /* Region(const FabVars& v) + * + * Constructs a region that fills the entire space defined in v. + */ + Region(const FabVars& v); + + + /* Region(unsigned int imin, unsigned int jmin, unsigned int kmin, + unsigned int imax, unsigned int jmax, unsigned int kmax) + + * Constructs a region from the provided bounds. + */ + Region(unsigned int imin, unsigned int jmin, unsigned int kmin, + unsigned int imax, unsigned int jmax, unsigned int kmax); + + + /* std::list split() const + * + * Splits a region in half all three axes, returning a list of + * the resulting subregions. + */ + std::list split() const; + + /* std::list split(int count) const + * + * Splits a region into a provided number of subregions, returning + * a list of the resulting subregions. The split is biased towards + * the larger axes of the initial region. + */ + std::list split(int count) const; + std::list split_xy(int count) const; + + /* std::list split(int isplit, int jsplit, int ksplit) const + * + * Splits a region with a specific number of subregions per axis. + */ + std::list split(int isplit, int jsplit, int ksplit) const; + + // Boundaries of the region + int imin, jmin, kmin, imax, jmax, kmax; + + // Dimensions of the region + int ni, nj, nk; + + // Volume of the region + uint64_t volume; + +} Region; + +/* std::ostream& operator<<(std::ostream& o, const Region& r) + * + * Prints a region. + */ +std::ostream& operator<<(std::ostream& o, const Region& r); + +#endif \ No newline at end of file diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp new file mode 100644 index 0000000..dec6a3b --- /dev/null +++ b/src/solver/solver.cpp @@ -0,0 +1,36 @@ +// This is an implementation file for the solver.hpp + +// It should not be compiled on its own (since a template needs to +// be instantiated with a particular class). + +#include "solver.hpp" + +#include "switches.hpp" +#include "task_buffer.hpp" + + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +void Solver::run() +{ + Task task = task_buffer->next(); + task_buffer->hello(); + + while (task.region.volume != 0) { + if (task.tree) { + delete tree; + tree = task.tree; + } + evaluate_region(task.region); + task = task_buffer->next(); + } + + save(); +} + +void Solver::set_buffer(TaskBuffer* b) +{ + task_buffer = b; +} \ No newline at end of file diff --git a/src/solver/solver.hpp b/src/solver/solver.hpp new file mode 100644 index 0000000..da67a84 --- /dev/null +++ b/src/solver/solver.hpp @@ -0,0 +1,75 @@ +#ifndef SOLVER_H +#define SOLVER_H + +#include + +#include "fabvars.hpp" +#include "region.hpp" +#include "math_tree.hpp" + +// Forward declaration +class TaskBuffer; + +// Generic solver class. +class Solver +{ +public: + + /* Solver(MathTree* tree, FabVars& v) + * Solver(FabVars& v) + + * Constructs a solver with a given tree (or NULL) and reference to the + * global FabVars instance. + */ + Solver(MathTree* tree, FabVars& v) + : tree(tree), task_buffer(NULL), v(v) {} + Solver(FabVars& v) + : tree(NULL), task_buffer(NULL), v(v) {} + + + virtual ~Solver() { delete tree; } + + + /* virtual void evaluate_region(Region R) = 0 + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R) = 0; + + + /* virtual void save() + * + * Saves the results of a solver instance's calculation. + * Typically, this will involve copying locally saved results into + * the solver's FabVars variable. + */ + virtual void save() = 0; + + + /* void run() + * + * Runs an instance of the solver from the task buffer. + */ + void run(); + + + /* void set_buffer(TaskBuffer* b) + * + * Sets the queue from which the solver will operate. + */ + void set_buffer(TaskBuffer* b); + +protected: + // The instance of the MathTree associated with this solver. + MathTree* tree; + + // For a thread-pool style solver, this object gives us tasks. + TaskBuffer* task_buffer; + + // A reference to the system's FabVars, where results are stored. + FabVars& v; +}; + +#endif + \ No newline at end of file diff --git a/src/solver/switches.hpp b/src/solver/switches.hpp new file mode 100644 index 0000000..9ae1aa2 --- /dev/null +++ b/src/solver/switches.hpp @@ -0,0 +1,15 @@ +#ifndef SWITCHES_H +#define SWITCHES_H + +// This header defines compile-time switches that turn on +// or off various optimizations. Optimizations are on when +// a switch is 1 and off when a switch is 0. + +#define COMBINE_NODES 1 +#define PRUNE_TREE 1 +#define MINMAX_PRUNE 1 +#define MULTITHREADED 1 +#define SIMPLIFY_TREE 1 +#define CULL_Z 1 + +#endif \ No newline at end of file diff --git a/src/solver/task_buffer.cpp b/src/solver/task_buffer.cpp new file mode 100644 index 0000000..3ec3526 --- /dev/null +++ b/src/solver/task_buffer.cpp @@ -0,0 +1,158 @@ +#include "math_tree.hpp" +#include "task_buffer.hpp" + +#include +using namespace std; + +typedef boost::lock_guard locker; + +Task::Task() + : tree(NULL) +{ + // Nothing to do here +} + +Task::Task(Region region) + : region(region), tree(NULL) +{ + // Nothing to do here. +} + +Task::Task(Region region, MathTree* tree) + : region(region), tree(tree) +{ + // Nothing to do here +} + +TaskSlot::TaskSlot() + : ready(false) +{ + // Nothing to do here +} + + +TaskBuffer::TaskBuffer(unsigned size) + : size(size), add_position(0), read_position(0), + active_threads(0), unassigned_tasks(0), barrier(size) +{ + tasks = new TaskSlot[size]; +} + + +TaskBuffer::~TaskBuffer() +{ + delete [] tasks; +} + + +bool TaskBuffer::full() const +{ + return (unassigned_tasks >= size - active_threads); +} + +// Add a task to the buffer and notify the corresponding thread. +bool TaskBuffer::add(Region region) +{ + return add(region, NULL); +} + +bool TaskBuffer::add(Region region, MathTree* tree) +{ + + { // Check to see if a thread is available for this + // new unassigned task. + locker lock(master_mutex); + if (unassigned_tasks >= size - active_threads) + return false; + unassigned_tasks++; + } + + + unsigned pos; + { // Figure out which task slot we're about to fill + locker lock(add_mutex); + pos = add_position; + + // Increment the add position in the buffer + add_position = (add_position + 1) % size; + } + + { // Fill the task slot + locker lock(tasks[pos].mutex); + if (tree) + tasks[pos].task = Task(region, tree->clone()); + else + tasks[pos].task = Task(region); + tasks[pos].ready = true; +// cout << "Added new task with region " << region << ' ' << tasks[pos].task.tree << endl; + } + // Notify anyone that has been waiting on this slot. + tasks[pos].condition.notify_one(); + + return true; +} + + +// Each thread should call this function once before taking +// data from the task buffer. +void TaskBuffer::hello() +{ + { + locker lock(master_mutex); + active_threads++; + } + barrier.wait(); +} + + +// Acquire the next task from the buffer. If there is nothing left, then +// fill the buffer with null tasks to halt execution. +Task TaskBuffer::next() +{ + unsigned pos; + { // Figure out the slot from which we'll read + locker lock(read_mutex); + pos = read_position; + read_position = (read_position + 1) % size; + } + + { // Mark that this thread is inactive + locker lock(master_mutex); + active_threads--; + + // If all threads are inactive and there are no unassigned + // tasks, then we're done with evaluation. finish() fills the buffer + // with null tasks to signal the end of execution. + if (active_threads == 0 && unassigned_tasks == 0) + finish(); + } + + Task t; + { // Wait until this task slot is filled, then claim the task. + boost::unique_lock lock(tasks[pos].mutex); + while (!tasks[pos].ready) + tasks[pos].condition.wait(lock); + t = tasks[pos].task; + tasks[pos].ready = false; + } + + { // Note that this thread is now active. + locker lock(master_mutex); + unassigned_tasks--; + active_threads++; + } + + return t; +} + + +// Populate the task buffer with null tasks, to signal the end of the program. +void TaskBuffer::finish() +{ + for (unsigned i = 0; i < size; ++i) { + locker lock(tasks[i].mutex); + tasks[i].task = Task(); + tasks[i].ready = true; + tasks[i].condition.notify_one(); + } +} diff --git a/src/solver/task_buffer.hpp b/src/solver/task_buffer.hpp new file mode 100644 index 0000000..af42674 --- /dev/null +++ b/src/solver/task_buffer.hpp @@ -0,0 +1,109 @@ +#ifndef TASK_BUFFER_H +#define TASK_BUFFER_H + +#include + +#include "region.hpp" + +class MathTree; + +// Simple structure containing a task to be solved. +typedef struct Task { + Task(); + Task(Region region); + Task(Region region, MathTree* tree); + + Region region; + MathTree* tree; +} Task; + + +// Slot to store a task and associated metadata in the ring buffer. +typedef struct TaskSlot { + TaskSlot(); + + Task task; + bool ready; + boost::mutex mutex; + boost::condition_variable condition; +} TaskSlot; + + +class TaskBuffer +{ +public: + /* TaskBuffer(unsigned size) + * + * Create a ring buffer of the appropriate size. + */ + TaskBuffer(unsigned size); + + + /* ~TaskBuffer() + * + * Destructor for the task buffer. + */ + ~TaskBuffer(); + + + /* bool full() const + * + * Checks to see if the task buffer is full in a thread-unsafe + * way. A further check should be run in a thread-safe manner. + */ + bool full() const; + + /* bool add(Region region, MathTree* tree) + * + * Adds a task to the latest available slot, with the provided + * region and a clone of the provided tree. Increments + * add_position and unassigned_tasks. + * + * If all slots are full, returns false; otherwise returns true. + */ + bool add(Region region); + bool add(Region region, MathTree* tree); + + + /* void hello() + * + * Each active thread should call this function once so that the + * task buffer has a count of how many active threads are running. + */ + void hello(); + + /* Task next() + * + * Acquires the next task from the list. If there are no tasks + * and no active threads, fill the buffer with null tasks to halt + * the process + * + * On start, decrements active_threads; when a task is acquired, + * increment active_threads and decrement unassigned_tasks. + * + * Increments read_position. + */ + Task next(); + + const unsigned size; + +private: + + void finish(); + + boost::mutex add_mutex; + unsigned add_position; + + boost::mutex read_mutex; + unsigned read_position; + + TaskSlot* tasks; + + boost::mutex master_mutex; + unsigned active_threads; + unsigned unassigned_tasks; + + boost::barrier barrier; +}; + +#endif \ No newline at end of file diff --git a/src/solver/thread_manager.cpp b/src/solver/thread_manager.cpp new file mode 100644 index 0000000..33ced7a --- /dev/null +++ b/src/solver/thread_manager.cpp @@ -0,0 +1,87 @@ +// This is an implementation file for the ThreadManager + +#include "math_tree.hpp" +#include "switches.hpp" +#include "thread_manager.hpp" +#include "solver.hpp" + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +/////////////////////////////////////////////////////////////////////////////// + +template +ThreadManager::ThreadManager(FabVars& v) + : v(v), task_buffer(thread::hardware_concurrency()) +{ + // Nothing to do here. +} + +/////////////////////////////////////////////////////////////////////////////// + +// Evaluates an entire math tree on the full spatial region. +template +void ThreadManager::evaluate(MathTree* tree) +{ + list regions; + if (v.projection) + regions = Region(v).split_xy(task_buffer.size); + else + regions = Region(v).split(task_buffer.size); + + // Create a task for each region + list::iterator it; + for (it = regions.begin(); it != regions.end(); ++it) { +// cout << "Added region " << *it << endl; + if (!task_buffer.add(*it, tree)) { + cout << "Failed to add initial task to task buffer!" << endl; + exit(1); + } + } + + // Create a new thread for all but one of the tasks + for (unsigned i = 1; i < task_buffer.size; ++i) + make_new_thread(); + + // This thread gets a task as well. + SOLVER_TYPE* s = new SOLVER_TYPE(v); + s->set_buffer(&task_buffer); + s->run(); + delete s; + + wait_for_threads(); +} + +/////////////////////////////////////////////////////////////////////////////// + +template +void ThreadManager::make_new_thread() +{ + SOLVER_TYPE* s = new SOLVER_TYPE(v); + s->set_buffer(&task_buffer); + thread* newThread = new thread(&Solver::run, s); + + threads.push_back(make_pair(newThread, s)); +} + +/////////////////////////////////////////////////////////////////////////////// + +template +void ThreadManager::wait_for_threads() +{ + while (!threads.empty()) + { + typename ThreadList::iterator it = threads.begin(); + while(it != threads.end()) + if (it->first->timed_join(boost::system_time())) + { + delete it->first; + delete it->second; + + it = threads.erase(it); + } else { + ++it; + } + } +} \ No newline at end of file diff --git a/src/solver/thread_manager.hpp b/src/solver/thread_manager.hpp new file mode 100644 index 0000000..20d0d78 --- /dev/null +++ b/src/solver/thread_manager.hpp @@ -0,0 +1,53 @@ +#ifndef THREAD_MANAGER_H +#define THREAD_MANAGER_H + +#include "task_buffer.hpp" + +template +class ThreadManager +{ +public: + + /* ThreadManager(FabVars& v) + * + * Constructor for ThreadManager. + */ + ThreadManager(FabVars& v); + + + /* void evaluate(MathTree* tree, FabVars& v) + * + * This function evaluates the math tree on the full region defined in v, writing + * solver-dependent output to v. + */ + void evaluate(MathTree* tree); + + + /* static void make_new_thread() + * + * This function creates a new thread, in which a solver instance calls + * Solver::run() + */ + void make_new_thread(); + + + /* void wait_for_threads() + * + * Waits until all of the threads are finished. As each thread finishes, + * this function instructs it to saves its results, then deletes it. + */ + void wait_for_threads(); + +private: + FabVars& v; + + typedef std::list > ThreadList; + ThreadList threads; + + TaskBuffer task_buffer; +}; + +// Templated implementation file +#include "thread_manager.cpp" + +#endif \ No newline at end of file diff --git a/src/solver/translator_nodes.cpp b/src/solver/translator_nodes.cpp new file mode 100644 index 0000000..70aa93b --- /dev/null +++ b/src/solver/translator_nodes.cpp @@ -0,0 +1,139 @@ +#include + +#include "translator_nodes.hpp" + +using namespace std; +using boost::logic::indeterminate; + +BoolToNum::BoolToNum() + : UnaryNode(BOOL2NUM) +{ + // Nothing to do here. +} + + +BoolToNum::BoolToNum(Node* c) + : UnaryNode(BOOL2NUM) +{ + set_child(c); +} + +void BoolToNum::eval(const float X, const float Y, const float Z) +{ + if (child->result_bool) + result_float = 1; + else + result_float = 0; +} + +void BoolToNum::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + if (child->result_bool) + result_interval = 1; + else if (!child->result_bool) + result_interval = 0; + else + result_interval = FabInterval(0, 1); +} + +//////////////////////////////////////////////////////////////////////////////// + +NumToBool::NumToBool() + : UnaryNode(NUM2BOOL) +{ + // Nothing to do here. +} + + +NumToBool::NumToBool(Node* c) + : UnaryNode(NUM2BOOL) +{ + set_child(c); +} + +void NumToBool::eval(const float X, const float Y, const float Z) +{ + if (child->result_float) + result_bool = true; + else + result_bool = false; +} + +void NumToBool::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + if (child->result_interval.lower() == 0 && + child->result_interval.upper() == 0) + result_bool = false; + else if (child->result_interval.upper() < 0 || + child->result_interval.lower() > 0) + result_bool = true; + else + result_bool = indeterminate; +} + +/////////////////////////////////////////////////////////////////////////////// + +BoolToColor::BoolToColor() + : UnaryNode(BOOL2COLOR) +{ + // Nothing to do here. +} + +BoolToColor::BoolToColor(Node* c) + : UnaryNode(BOOL2COLOR) +{ + set_child(c); +} + +void BoolToColor::eval(const float X, const float Y, const float Z) +{ + if (child->result_bool) + result_color = 255 + (255 << 8) + (255 << 16); + else + result_color = 0; +} + +void BoolToColor::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + if (child->result_bool) + result_color = 255 + (255 << 8) + (255 << 16); + else if (!child->result_bool) + result_color = 0; + else + result_color = -1; +} + +/////////////////////////////////////////////////////////////////////////////// + +NumToColor::NumToColor() + : UnaryNode(NUM2COLOR) +{ + // Nothing to do here. +} + +NumToColor::NumToColor(Node* c) + : UnaryNode(NUM2COLOR) +{ + set_child(c); +} + +void NumToColor::eval(const float X, const float Y, const float Z) +{ + result_color = int(child->result_float); +} + +void NumToColor::eval(const FabInterval& X, + const FabInterval& Y, + const FabInterval& Z) +{ + if (child->result_interval.lower() == child->result_interval.upper()) + result_color = int(child->result_interval.lower()); + else + result_color = -1; +} \ No newline at end of file diff --git a/src/solver/translator_nodes.hpp b/src/solver/translator_nodes.hpp new file mode 100644 index 0000000..72c18d6 --- /dev/null +++ b/src/solver/translator_nodes.hpp @@ -0,0 +1,14 @@ +#ifndef TRANSLATOR_NODES +#define TRANSLATOR_NODES + +#include "node.hpp" +#include "node_macro.hpp" + +// This header file defines nodes that take in inputs of +// one type and return outputs of another type. +TRANSLATOR(BoolToNum, UnaryNode); +TRANSLATOR(NumToBool, UnaryNode); +TRANSLATOR(BoolToColor, UnaryNode); +TRANSLATOR(NumToColor, UnaryNode); + +#endif \ No newline at end of file diff --git a/src/solver/trisolver.cpp b/src/solver/trisolver.cpp new file mode 100644 index 0000000..b648127 --- /dev/null +++ b/src/solver/trisolver.cpp @@ -0,0 +1,202 @@ +#include "trisolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" + +#include "switches.hpp" + +#include +#include + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +const Vec3f VERTEX_LOOP[] = { + Vec3f(1, 1, 0), Vec3f(1, 0, 0), Vec3f(1, 0, 1), + Vec3f(0, 0, 1), Vec3f(0, 1, 1), Vec3f(0, 1, 0), + Vec3f(1, 1, 0) +}; + +// Based on which vertices are filled, this map tells you which +// edges to interpolate between when forming zero, one, or two +// triangles. +// (filled vertex is first in the pair) +const int EDGE_MAP[16][2][3][2] = { + {{{-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // ---- + {{{ 0, 2}, { 0, 1}, { 0, 3}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // ---0 + {{{ 1, 0}, { 1, 2}, { 1, 3}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // --1- + {{{ 1, 2}, { 1, 3}, { 0, 3}}, {{ 0, 3}, { 0, 2}, { 1, 2}}}, // --10 + {{{ 2, 0}, { 2, 3}, { 2, 1}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // -2-- + {{{ 0, 3}, { 2, 3}, { 2, 1}}, {{ 2, 1}, { 0, 1}, { 0, 3}}}, // -2-0 + {{{ 1, 0}, { 2, 0}, { 2, 3}}, {{ 2, 3}, { 1, 3}, { 1, 0}}}, // -21- + {{{ 2, 3}, { 1, 3}, { 0, 3}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // -210 + + {{{ 3, 0}, { 3, 1}, { 3, 2}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // 3--- + {{{ 3, 2}, { 0, 2}, { 0, 1}}, {{ 0, 1}, { 3, 1}, { 3, 2}}}, // 3--0 + {{{ 1, 2}, { 3, 2}, { 3, 0}}, {{ 3, 0}, { 1, 0}, { 1, 2}}}, // 3-1- + {{{ 1, 2}, { 3, 2}, { 0, 2}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // 3-10 + {{{ 3, 0}, { 3, 1}, { 2, 1}}, {{ 2, 1}, { 2, 0}, { 3, 0}}}, // 32-- + {{{ 3, 1}, { 2, 1}, { 0, 1}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // 32-0 + {{{ 3, 0}, { 1, 0}, { 2, 0}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // 321- + {{{-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}}}, // 3210 +}; + + +/////////////////////////////////////////////////////////////////////////////// + +TriSolver::TriSolver(FabVars& v) + : Solver(v) +{ + // Nothing to do here. +} + +TriSolver::TriSolver(MathTree* tree, FabVars& v) + : Solver(tree, v) +{ + // Nothing to do here. +} + +void TriSolver::save() +{ + v.add_triangles(triangles); +} + +// Evaluate a single region, either with point-by-point evaluation or +// interval math + recursion. Operates in a single thread and spawns +// no children. +void TriSolver::evaluate_region(Region r) +{ + // For sufficiently small fractions of the space, do a + // point-by-point evaluation rather than recursing. + if (r.volume == 1) { + evaluate_voxel(r); + v.pb.update(r.volume); + return; + } + + // Convert from pixel regions to intervals + FabInterval X = v.x(r.imin, r.imax); + FabInterval Y = v.y(r.jmin, r.jmax); + FabInterval Z = v.z(r.kmin, r.kmax); + + tree->eval(X, Y, Z); + + // If the result was unambiguous, then fill in that part + // of the image, then return. + tribool result; + if (v.mode == SOLVE_BOOL) + result = tree->root->result_bool; + else if (v.mode == SOLVE_REAL) + result = tree->root->result_interval < FabInterval(0,0); + + if (!indeterminate(result)) { + v.pb.update(r.volume); + return; + } + + // Split the region and recurse + list subregions = r.split(); + +#if PRUNE_TREE + tree->push(); +#endif + + list::iterator it; + for (it = subregions.begin(); it != subregions.end(); ++it) + evaluate_region(*it); + +#if PRUNE_TREE + tree->pop(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void TriSolver::evaluate_voxel(Region r) +{ + Vec3f corner(r.imin, r.jmin, r.kmin); + Vec3f v1, v2, v3; // triangle vertices + + for (int t = 0; t < 6; ++t) { + // Look up the vertex locations for this tetrahedron + Vec3f vertices[] = {corner, corner + Vec3f(1, 1, 1), + corner + VERTEX_LOOP[t], corner + VERTEX_LOOP[t+1]}; + + // Check which vertices are filled to see how we need to triangulate. + unsigned char lookup = 0; + for (int vertex = 3; vertex >= 0; --vertex) { + lookup <<= 1; + Vec3f pos = vertices[vertex]; + + std::map::iterator it = point_cache.find(pos); + if (it == point_cache.end()) { + tree->eval(v.x(pos.x), v.y(pos.y), v.z(pos.z)); + + if (v.mode == SOLVE_BOOL) + point_cache[pos] = tree->root->result_bool; + else if (v.mode == SOLVE_REAL) + point_cache[pos] = tree->root->result_float < 0; + + if (point_cache[pos]) + lookup++; + } else if (it->second) + lookup++; + } + + // If the triangle map is empty, continue. + if (EDGE_MAP[lookup][0][0][0] == -1) + continue; + + v1 = interpolate(vertices[EDGE_MAP[lookup][0][0][0]], + vertices[EDGE_MAP[lookup][0][0][1]]); + v2 = interpolate(vertices[EDGE_MAP[lookup][0][1][0]], + vertices[EDGE_MAP[lookup][0][1][1]]); + v3 = interpolate(vertices[EDGE_MAP[lookup][0][2][0]], + vertices[EDGE_MAP[lookup][0][2][1]]); + triangles.push_back(Triangle(v1, v2, v3)); + + + // If there was only one triangle, skip the second face + if (EDGE_MAP[lookup][1][0][0] == -1) + continue; + + v1 = interpolate(vertices[EDGE_MAP[lookup][1][0][0]], + vertices[EDGE_MAP[lookup][1][0][1]]); + v2 = interpolate(vertices[EDGE_MAP[lookup][1][1][0]], + vertices[EDGE_MAP[lookup][1][1][1]]); + v3 = interpolate(vertices[EDGE_MAP[lookup][1][2][0]], + vertices[EDGE_MAP[lookup][1][2][1]]); + + triangles.push_back(Triangle(v1, v2, v3)); + } + +} + +// Interpolate between a filled and empty point using binary search +// (after checking in a cache). +Vec3f TriSolver::interpolate(Vec3f filled, Vec3f empty) +{ + std::map::iterator it; + it = edge_cache.find(Edge(filled, empty)); + if (it != edge_cache.end()) + return it->second; + + float step_size = 0.25; + float interp = 0.5; + Vec3f offset = empty - filled; + + for (int i = 0; i < v.quality; ++i) { + Vec3f pos = filled + offset * interp; + + tree->eval(v.x(pos.x), v.y(pos.y), v.z(pos.z)); + if ((v.mode == SOLVE_BOOL && tree->root->result_bool) || + (v.mode == SOLVE_REAL && tree->root->result_float < 0)) + interp += step_size; + else + interp -= step_size; + step_size /= 2; + } + edge_cache[Edge(filled, empty)] = filled + offset * interp; + + return filled + offset * interp; +} \ No newline at end of file diff --git a/src/solver/trisolver.hpp b/src/solver/trisolver.hpp new file mode 100644 index 0000000..566ad6a --- /dev/null +++ b/src/solver/trisolver.hpp @@ -0,0 +1,64 @@ +#ifndef TRISOLVER_H +#define TRISOLVER_H + +#include +#include + +#include "solver.hpp" +#include "geometry.hpp" + +class TriSolver : public Solver +{ +public: + /* TriSolver(FabVars& v) + * TriSolver(MathTree* tree, FabVars& v) + * + * Constructs an TriSolver instance. + */ + TriSolver(FabVars& v); + TriSolver(MathTree* tree, FabVars& v); + virtual ~TriSolver() { /* Nothing to do here */ } + + /* virtual void evaluate_region(Region R) + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R); + + + /* void evaluate_voxel(Region R) + * + * Evaluate a single unit cube. + */ + void evaluate_voxel(Region R); + + + /* virtual void save() + * + * Saves the results of our calculation by copying paths into our + * reference to FabVars v. + */ + virtual void save(); + + + /* Vec3f interpolate(Vec3f filled, Vec3f empty) + * + * Interpolates between a filled and an empty point using binary search. + * Values are saved in a cache, and the cache is checked before the + * search is run. + */ + Vec3f interpolate(Vec3f filled, Vec3f empty); + +private: + // MathTree evaluation cached values + std::map point_cache; + + // Saved edges interpolation values + std::map edge_cache; + + // Saved triangles + std::list triangles; + +}; +#endif \ No newline at end of file diff --git a/src/solver/volsolver.cpp b/src/solver/volsolver.cpp new file mode 100644 index 0000000..28617fa --- /dev/null +++ b/src/solver/volsolver.cpp @@ -0,0 +1,115 @@ +#include "volsolver.hpp" +#include "math_tree.hpp" +#include "node.hpp" + +#include "switches.hpp" + +#include +#include + +using namespace std; +using boost::logic::tribool; +using boost::thread; + +/////////////////////////////////////////////////////////////////////////////// + +VolSolver::VolSolver(FabVars& v) + : Solver(v) +{ + // Nothing to do here. +} + +VolSolver::VolSolver(MathTree* tree, FabVars& v) + : Solver(tree, v) +{ + // Nothing to do here. +} + +void VolSolver::save() +{ + v.add_volume(volume); +} + +// Evaluate a single region, either with point-by-point evaluation or +// interval math + recursion. Operates in a single thread and spawns +// no children. +void VolSolver::evaluate_region(Region r) +{ + // For sufficiently small fractions of the space, do a + // point-by-point evaluation rather than recursing. + if (r.volume <= v.min_volume) { + evaluate_points(r); + v.pb.update(r.volume); + return; + } + + // Convert from pixel regions to intervals + FabInterval X = v.x(r.imin, r.imax); + FabInterval Y = v.y(r.jmin, r.jmax); + FabInterval Z = v.z(r.kmin, r.kmax); + + tree->eval(X, Y, Z); + + // If the result was unambiguous, then fill in that part + // of the image, then return. + tribool result; + if (v.mode == SOLVE_BOOL) + result = tree->root->result_bool; + else if (v.mode == SOLVE_REAL) + result = tree->root->result_interval < FabInterval(0,0); + + if (result) + volume += r.volume; + + if (!indeterminate(result)) { + v.pb.update(r.volume); + return; + } + + // Split the region and recurse + list subregions = r.split(); + +#if PRUNE_TREE + tree->push(); +#endif + + list::iterator it; + for (it = subregions.begin(); it != subregions.end(); ++it) + evaluate_region(*it); + +#if PRUNE_TREE + tree->pop(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +void VolSolver::evaluate_points(Region r) +{ + for (int k = r.kmax - 1; k >= r.kmin; --k) + { + + // Calculate Z coordinate and height-map scaling. + float Z = v.z(k); + + for (int i = r.imin; i < r.imax; ++i) + { // X loop + float X = v.x(i); + + for (int j = r.jmin; j < r.jmax; ++j) + { // Y loop + float Y = v.y(j); + + // Evaluate tree + tree->eval(X, Y, Z); + + // Fill in greyscale image + if ((v.mode == SOLVE_BOOL && tree->root->result_bool) || + (v.mode == SOLVE_REAL && tree->root->result_float <= 0)) + { + volume++; + } + + } // Y loop + } // X loop + } // Z loop +} \ No newline at end of file diff --git a/src/solver/volsolver.hpp b/src/solver/volsolver.hpp new file mode 100644 index 0000000..cad3985 --- /dev/null +++ b/src/solver/volsolver.hpp @@ -0,0 +1,51 @@ +#ifndef VolSolver_H +#define VolSolver_H + +#include +#include +#include + +#include "solver.hpp" +#include "geometry.hpp" + +class VolSolver : public Solver +{ +public: + /* VolSolver(FabVars& v) + * VolSolver(MathTree* tree, FabVars& v) + * + * Constructs an VolSolver instance. + */ + VolSolver(FabVars& v); + VolSolver(MathTree* tree, FabVars& v); + virtual ~VolSolver() { /* Nothing to do here */ } + + /* virtual void evaluate_region(Region R) + * + * Evaluate a given region recursively, saving results wherever is + * appropriate. + */ + virtual void evaluate_region(Region R); + + + /* void evaluate_points(Region R) + * + * Evaluate a set of points in a region + */ + void evaluate_points(Region r); + + + /* virtual void save() + * + * Saves the results of our calculation by copying paths into our + * reference to FabVars v. + */ + virtual void save(); + + +private: + // Saved volume + uint64_t volume; + +}; +#endif \ No newline at end of file