pax_global_header00006660000000000000000000000064123153173320014512gustar00rootroot0000000000000052 comment=bca4028b176daa4ed54c2b07214d7627c7ff2815 repsnapper-2.3.2a5/000077500000000000000000000000001231531733200141235ustar00rootroot00000000000000repsnapper-2.3.2a5/.gitignore000066400000000000000000000007031231531733200161130ustar00rootroot00000000000000ChangeLog src/RepSnapper.log /*.patch *.o *.lo *.la *.a *~ \#* /*.tar.gz /*.tar.bz2 *.rej *.orig TAGS .deps /Makefile Makefile.in config.* aclocal.m4 autogen.lastrun autom4te.cache/ m4/ repsnapper.desktop compile configure depcomp install-sh libtool ltmain.sh missing po/Makefile po/Makefile.in.in po/POTFILES po/stamp-it po/.intltool-merge-cache stamp-h1 .pc .dirstamp po/*.gmo repsnapper debian intltool-*.in src/gitversion.h repsnapper.appdata.xml repsnapper-2.3.2a5/BUILD_OSX.txt000066400000000000000000000047231231531733200162620ustar00rootroot00000000000000THIS DOCUMENT IS A WORK IN PROGRESS - SEE also : https://github.com/timschmidt/repsnapper/issues/38 get a few dependancies first: lf you don't already have homebrew installed from http://mxcl.github.com/homebrew/, do it: #EITHER: # this puts it in /usr/local ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)" # OR: # this puts it in /opt/homebrew cd /opt ; sudo mkdir homebrew && curl -L https://github.com/mxcl/homebrew/tarball/master | sudo tar xz --strip 1 -C homebrew make sure the 'brew' command is in your path, also put /usr/local there too, for autoconf/libtool/make as per below: set PATH=/opt/homebrew/bin:/usr/local/bin:$PATH # now we have brew, install as many of these as you can get to work, you may need to remove pkg-config and/or libiconv from this list if its broken when you try it? brew install gtkmm gtk+ gtkglext cmake glib glade pkg-config pcre pkg-config intltool gettext libiconv you'll also need to manually download , compile and install the latest versions of libtool, autoconf and make: these above tools are ( by default) installed into /usr/local, so you need to have /usr/local/bin in your PATH variable, before /usr/bin etc: ( extract each of these to a folder, cd to it, type: ./configure ; make ; sudo make install ) cd ~ wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.68.tar.gz tar -zxvpf autoconf-2.68.tar.gz cd autoconf-2.68 ./configure ; make sudo make install cd ~ wget http://ftp.gnu.org/gnu/libtool/libtool-2.4.tar.gz cd libtool-2.4 ./configure ; make sudo make install cd ~ wget http://ftp.gnu.org/gnu/make/make-3.82.tar.gz cd make-3.82 ./configure ; make sudo make install cd ~ # if libiconv from brew is still broken when you try this, then do this instead: cd ~ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz tar -zxvpg libiconv-1.14.tar.gz cd libiconv-1.14 #( this builds both 32 and 64 bit archithecture , if you are building for just one architecture, remove one of the -arch XXX types ) MACOSX_DEPLOYMENT_TARGET=10.6 \ CFLAGS='-O3 -fno-common -arch i386 -arch x86_64' \ LDFLAGS='-O3 -arch i386 -arch x86_64' \ CXXFLAGS='-O3 -fno-common -arch i386 -arch x86_64' \ ./configure --prefix=/usr/local # make sure you have the latest repsnapper sources from GIT , as OSX features are recent cd ~ git clone git@github.com:timschmidt/repsnapper.git cd repsnapper # make /usr/local/aclocal aware of the homebrew installed stuff: cat > /usr/local/share/aclocal/dirlist << EOF /opt/homebrew/share/aclocal/ EOF ./autogen.sh make repsnapper-2.3.2a5/HACKING000066400000000000000000000002671231531733200151170ustar00rootroot00000000000000Checkout the latest version like this: git clone git://github.com/timschmidt/repsnapper.git and use github to send your patch in, and/or hang out on #repsnapper on irc.freenode.net.repsnapper-2.3.2a5/Makefile.am000066400000000000000000000025401231531733200161600ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign subdir-objects ACLOCAL_AMFLAGS = -I m4 CLEANFILES = repsnapper.desktop DISTCLEANFILES = tools/gitversion.sh BUILT_SOURCES = tools/gitversion.sh EXTRA_DIST = \ README.asciidoc \ HACKING \ repsnapper.desktop.in \ README.win32 \ licenses/BSL-1.0.txt \ licenses/GPL-2.0.txt \ licenses/LGPL-2.0.txt \ licenses/MIT.txt \ licenses/vmmlib-license.txt Applicationsdir = $(datadir)/applications/ Applications_in_files = repsnapper.desktop.in Applications_DATA = repsnapper.desktop if WIN32_BUILD WIN32_FILES = README.win32 licenses/GPL-2.0.txt else WIN32_FILES = endif win32extrasdir = $(prefix) win32extras_DATA = $(WIN32_FILES) @INTLTOOL_DESKTOP_RULE@ # AppData support @INTLTOOL_XML_RULE@ appdatadir = $(datadir)/appdata appdata_DATA = $(appdata_in_files:.xml.in=.xml) appdata_in_files = repsnapper.appdata.xml.in EXTRA_DIST += $(appdata_in_files) CLEANFILES += $(appdata_DATA) -include $(top_srcdir)/git.mk noinst_LTLIBRARIES = include libraries/Makefile.am include src/Makefile.am # po doesn't use automake, so it can't be included. SUBDIRS = po JUNK = .deps .pc Makefile.in aclocal.m4 compile \ config.guess config.h.in config.sub configure \ depcomp install-sh ltmain.sh m4 missing autoclean: maintainer-clean ifneq ($(wildcard ${JUNK}),) rm -r $(wildcard ${JUNK}) endif repsnapper-2.3.2a5/NEWS000066400000000000000000000000001231531733200146100ustar00rootroot00000000000000repsnapper-2.3.2a5/README.asciidoc000066400000000000000000000033221231531733200165600ustar00rootroot00000000000000RepSnapper is an alternative host software for controlling the RepRap (http://reprap.org) open source 3D printer. == Getting it == * newest source to compile on unix/linux/mac: git clone https://github.com/timschmidt/repsnapper.git ** get newest patches later by git pull * source tarball of latest tag: https://github.com/timschmidt/repsnapper/tags * windows builds: see here: http://reprap.org/wiki/RepSnapper_Manual:Introduction#Downloading or here: https://sourceforge.net/projects/repsnapper/files/ == Compilation == To build and run repsnapper do: ./autogen.sh make ./repsnapper For more details on prerequisites see the manual: https://github.com/timschmidt/repsnapper/blob/master/doc/manual.asciidoc == Documentation == For latest documentation, see: * https://github.com/timschmidt/repsnapper/blob/master/doc/manual.asciidoc RepSnapper v2 Manual For version 1.1.x, see: * https://github.com/timschmidt/repsnapper/blob/repsnapper-1.1.x/doc/manual.asciidoc RepSnapper v1 Manual == Contact Info == * Irc channel: #repsnapper at irc://chat.freenode.net === RepSnapper v2 === Current development of Repsnapper is happening in Timothy Schmidt's repository at the following URLs. * Code: https://github.com/timschmidt/repsnapper * Bug tracker: https://github.com/timschmidt/repsnapper/issues === Kulitorum version === For historical reasons we leave here the links to the old svn version that developed by Kulitorum, this version is now unmaintained and commits go into the Timothy Schmidt version (as of ~ October 5th, 2010) * Code: http://svn.kulitorum.com/RepSnapper * SVN history: http://cia.vc/stats/project/RepSnapper * Bug tracker: http://bugs.kulitorum.com repsnapper-2.3.2a5/README.win32000066400000000000000000000024131231531733200157440ustar00rootroot00000000000000RepSnapper is an alternative host software for controlling the RepRap (http://reprap.org) open source 3D printer. = Notes = Please note that printer communications are not yet functional on Windows with Repsnapper 1.9.x/2.0. It is possible to use Repsnapper to slice and export GCode for printing with another piece of software, such as the old Kulitorum version, or Pronterface. = Documentation = For latest documentation, see: * https://github.com/timschmidt/repsnapper/blob/master/doc/manual.asciidoc - RepSnapper v2 Manual = Contact Info = * Irc channel: #repsnapper at irc://chat.freenode.net === RepSnapper v2 === Current development of Repsnapper is happening in Timothy Schmidt's repository at the following URLs: * Code: https://github.com/timschmidt/repsnapper * Bug tracker: https://github.com/timschmidt/repsnapper/issues === Old Kulitorum version === For historical reasons here are the links to the old svn version that was developed by Kulitorum. This version is now unmaintained, and all development is in the Timothy Schmidt version (as of ~ October 5th, 2010) * Code: http://svn.kulitorum.com/RepSnapper * SVN history: http://cia.vc/stats/project/RepSnapper * Bug tracker: http://bugs.kulitorum.com repsnapper-2.3.2a5/TODO000066400000000000000000000035351231531733200146210ustar00rootroot00000000000000 -- BUGS -- * match offset of fill patterns across all layers * fix rest amounts of antiooze * make 2D mode usable + lost circles at SVG input + gcode generation * layer detection at GCode cursor position * double entries in serial speed * win32 + GL window size on Win7 64bit -- IMPROVEMENTS -- * make model have a list of selected shapes instead of treeview-path? -- FEATURES -- * machine specific GCode? + Create a wizard to select a default machine to base settings on ... + load a Settings object ... + have a directory-list of settings.xml + drop one in there ... + add a 'Name' field ... + add an 'Icon' field ... + Make multiple machine settings pleasantly configurable and selectable ... * 360° arcs / arcs least squares fit (probably) * thin polygons infill line (centreline) * win32 + serial --- the plan --- * add a git hook to forbid DOS line endings [!] ... * Add low prio idle handler for error dialogs: can't connect to device eg. * show heat on in a better way ... * Bin the two 'load' menu items - just one 'open' menu ... + with a gcode and stl filter drop-down ? * Add a right-click menu to the back-drop, so we can change display / object settings there. + cd. render.cpp - on_button_release_event // click only * Multi-model selector ... + leave the single mode's "settings" object + detect changes, and show those in the existing UI + load and save new settings as we switch + prompt to save changes on selection ... * Serial + add a test serial connection ... + error dialogs - "failed to connect ?" + /dev/ttyUSB0 - EACCES + group / permissions problem. + you need to tweak permissions, or add yourself to XYZ group, and re-login ... + connection button + should require confirmation before going off-line during a print ... [ and/or 'pause printing' ] --- older stuff --- repsnapper-2.3.2a5/WIN32_CROSS_COMPILE.txt000066400000000000000000000041461231531733200176140ustar00rootroot00000000000000Instructions for building for win32 using cross-compilation Tested on Debian Sarge 1) Install jhbuild, unzip, libglib2.0-dev (for glib-genmarshal), mingw32-binutils, mingw32-runtime and nsis packages via APT jhbuild needs to be at least version 2.30.2 for .tar.xz file support. 2) Mingw32 compiler You need the right version of mingw32, which supports shared libgcc, or else exceptions don't work and everything breaks. There are 2 packages in Debian distributions: mingw32, and gcc-mingw32. In the past gcc-mingw32 in Ubuntu Natty and Debian (at least) was built with --disable-shared, which breaks C++ exception handling. See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=625778). As of the middle of 2012, this is no longer the case. Basically, check that the version of mingw32 you have installs a libgcc_s.a and provides libgcc_sjlj_1.dll. Also possible is to rebuild mingw32 to use DWARF style exception handling, as well as shared libgcc (in which case, you'll have libgcc_dw2_1.dll instead of libgcc_sjlj_1.dll. This provides a slightly larger but faster library, and can be done because we build all our dependencies and can be sure we'll never throw an exception across a foreign library (which doesn't work with DWARF style exceptions). -- OpenMP support -- As of Feb 2013, neither the mingw32 nor gcc-mingw32 packages provide OpenMP support. mingw32 because it's too old, gcc-mingw32 apparently because the pthreads library isn't stable enough for them (see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=625779) 3) make distclean in the toplevel directory to unconfigure it, if you've been building there already. It needs to be unconfigured for the cross compile done by the script in the next step. 4) cd into win32 and run either cross-build-repsnapper-rls (Release version) or cross-build-repsnapper-dbg (Debug) Hopefully, it all runs succesfully - at which point there should be a usable tree in win32/checkout.rls (or checkout.dbg) The result executable should be in win32/target.dbg/bin/repsnapper.exe In case of the release build, an installer exe (repsnapper-$VERSION.exe) will be built in the win32 directory. repsnapper-2.3.2a5/autogen.sh000077500000000000000000000075041231531733200161320ustar00rootroot00000000000000: eval 'exec perl -S $0 ${1+"$@"}' if 0; use strict; sub clean() { system ("rm -Rf autom4te.cache"); system ("rm -f missing install-sh mkinstalldirs libtool ltmain.sh"); print "cleaned the build tree\n"; } my $aclocal; # check we have various vital tools sub sanity_checks($) { my $system = shift; my @path = split (':', $ENV{'PATH'}); my %required = ( 'pkg-config' => "pkg-config is required to be installed", 'autoconf' => "autoconf is required", $aclocal => "$aclocal is required", ); for my $elem (@path) { for my $app (keys %required) { if (-f "$elem/$app") { delete $required{$app}; } } } if ((keys %required) > 0) { print ("Various low-level dependencies are missing, please install them:\n"); for my $app (keys %required) { print "\t $app: " . $required{$app} . "\n"; } exit (1); } } # one argument per line sub read_args($) { my $file = shift; my $fh; my @lst; open ($fh, $file) || die "can't open file: $file"; while (<$fh>) { chomp(); # migrate from the old system if ( substr($_, 0, 1) eq "'" ) { print "Migrating options from the old autogen.lastrun format, using:\n"; my @opts; @opts = split(/'/); foreach my $opt (@opts) { if ( substr($opt, 0, 1) eq "-" ) { push @lst, $opt; print " $opt\n"; } } } elsif ( substr($_, 0, 1) eq "#" ) { # comment } else { push @lst, $_; } } close ($fh); # print "read args from file '$file': @lst\n"; return @lst; } my @cmdline_args = (); if (!@ARGV) { my $lastrun = "autogen.lastrun"; @cmdline_args = read_args ($lastrun) if (-f $lastrun); } else { @cmdline_args = @ARGV; } my @args; for my $arg (@cmdline_args) { if ($arg eq '--clean') { clean(); } else { push @args, $arg; } } for my $arg (@args) { if ($arg =~ /^([A-Z]+)=(.*)/) { $ENV{$1} = $2; } } # Alloc $ACLOCAL to specify which aclocal to use $aclocal = $ENV{ACLOCAL} ? $ENV{ACLOCAL} : 'aclocal'; my $system = `uname -s`; chomp $system; sanity_checks ($system);# unless($system eq 'Darwin'); my $aclocal_flags = $ENV{ACLOCAL_FLAGS}; if (($aclocal_flags eq "") && ($system eq 'Darwin')) { if (-d '/opt/homebrew/share/aclocal') { $aclocal_flags = "-I ./m4 -I /opt/homebrew/share/aclocal -I /usr/local"; } else { $aclocal_flags = "-I ./m4 -I /usr/local"; } } print "aclocal_flags : $aclocal_flags \n"; $ENV{AUTOMAKE_EXTRA_FLAGS} = '--warnings=no-portability' if (!($system eq 'Darwin')); system ("$aclocal $aclocal_flags") && die "Failed to run aclocal"; unlink ("configure"); system ("autoreconf -i -f") && die "Failed to run autoconf"; die "failed to generate configure" if (! -x "configure"); system ("intltoolize --copy --force --automake") && die "Failed to intltoolize"; if (defined $ENV{NOCONFIGURE}) { print "Skipping configure process."; } else { # Save autogen.lastrun only if we did get some arguments on the command-line if (@ARGV) { if ($#cmdline_args > 0) { # print "writing args to autogen.lastrun\n"; my $fh; open ($fh, ">autogen.lastrun") || die "can't open autogen.lastrun: $!"; for my $arg (@cmdline_args) { print $fh "$arg\n"; } close ($fh); } } print "running ./configure with '" . join ("' '", @args), "'\n"; system ("./configure", @args) && die "Error running configure"; } # Local Variables: # mode: perl # cperl-indent-level: 4 # tab-width: 4 # indent-tabs-mode: nil # End: # vim:set ft=perl shiftwidth=4 softtabstop=4 expandtab: # repsnapper-2.3.2a5/configure.ac000066400000000000000000000074561231531733200164250ustar00rootroot00000000000000AC_PREREQ(2.63) AC_INIT([repsnapper],[2.3.2],[https://github.com/timschmidt/repsnapper], [repsnapper], [https://github.com/timschmidt/repsnapper]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/repsnapper.cpp]) AC_CONFIG_MACRO_DIR([m4]) dnl AC_CONFIG_AUX_DIR([config]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) # Checks for programs. AC_PROG_CC AC_PROG_CXX # Needed for per-target cflags, like in gnomeshell-taskpanel AM_PROG_CC_C_O # Initialize libtool LT_PREREQ([2.2.6]) LT_INIT([disable-static]) GETTEXT_PACKAGE=repsnapper AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",[The prefix for our gettext translation domains.]) case "$host_os" in freebsd*) # Using clang: (no OpenMP) CC=cc CPP=cpp CXX=c++ # or gcc46: # CC=gcc46 # CPP=cpp46 # CXX=g++46 dnl FreeBSD specific hack to search for libintl.h in /usr/local/include CPPFLAGS="$CPPFLAGS -I/usr/local/include" ;; esac IT_PROG_INTLTOOL(0.26) AM_GLIB_GNU_GETTEXT PKG_PROG_PKG_CONFIG([0.22]) AC_LANG_CPLUSPLUS dnl check for installed clipperlib newer than 5.1.0 (has PolyNode) AC_DEFINE([HAVE_CLIPPERLIB],[0],[Have external clipper]) CLIPPER_LIBS="libclipper.la" AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [ClipperLib::PolyNode cnode])], [AC_DEFINE([HAVE_CLIPPERLIB],[1]) CLIPPER_LIBS="-lpolyclipping"], [AC_MSG_WARN([libclipper is not installed. Using internal copy.])]) AC_SUBST(CLIPPER_LIBS) dnl If your script errors here on OSX, see this URL http://myitcorner.com/blog/?p=207 PKG_CHECK_MODULES(GTKMM, [gobject-2.0 glib-2.0 gtkmm-2.4 gtkglextmm-1.2 gtk+-2.0 cairomm-1.0 glibmm-2.4 >= 2.27]) dnl Set a define if we need to include gdkkeysyms-compat.h PKG_CHECK_MODULES(GTK_NEW_KEYSYMS, [gtk+-2.0 >= 2.21.8], [AC_DEFINE([HAVE_GTK_NEW_KEYSYMS], [1], [Need to include gdkkeysyms-compat.h]) ], [HAVE_GTK_NEW_KEYSYMS=no]) dnl m4_include([ax_boost_base.m4]) dnl AX_BOOST_BASE([1.45], dnl [PKG_CHECK_MODULES([OPENVRML], [openvrml], dnl [AC_DEFINE([HAVE_OPENVRML], [1], [Use OpenVRML])], dnl [AC_DEFINE([NO_VRML], [1], [Without OpenVRML])])], dnl ) PKG_CHECK_MODULES(XMLPP, libxml++-2.6 >= 2.10.0) # AC_SUBST(XMLPP_CFLAGS) # AC_SUBST(XMLPP_LIBS) # PKG_CHECK_MODULES(GTS, gts >= 0.7.6) AC_OPENMP() PKG_CHECK_MODULES(LIBZIP, libzip >= 0.10) case "$host_os" in mingw*) GL_LIBS="-lopengl32" # -lglu32 -lglut32" EXTRA_LDFLAGS="-Wl,-subsystem,windows -shared-libgcc" EXTRA_CFLAGS="-fexceptions -mthreads" # AC_CHECK_HEADER(GL/glut.h, , AC_MSG_ERROR([cannot find headers for freeglut])) WIN32_BUILD=yes ;; freebsd*) GL_LIBS="-L/usr/local/lib" # -lGLU -lGL -lglut" EXTRA_LDFLAGS="-L/usr/local/lib" CFLAGS="$CFLAGS -I/usr/local/include" CXXFLAGS="$CXXFLAGS -I/usr/local/include" CPPFLAGS="$CPPFLAGS -I/usr/local/include" # AC_CHECK_HEADER(GL/glut.h, , AC_MSG_ERROR([cannot find headers for freeglut])) ;; Darwin*) GL_LIBS="-L/usr/local/lib" # -lGLU -lOpenGL -lGLUT -lglut" EXTRA_LDFLAGS="-L/usr/local/lib -L/opt/homebrew/lib" CFLAGS="$CFLAGS -I/usr/local/include -I/opt/homebrew/include" CXXFLAGS="$CXXFLAGS -I/usr/local/include -I/opt/homebrew/include" CPPFLAGS="$CPPFLAGS -I/usr/local/include -I/opt/homebrew/include" # AC_CHECK_HEADER(GLUT/glut.h, , AC_MSG_ERROR([cannot find headers for freeglut])) ;; *) GL_LIBS="-L/usr/lib" # -lGLU -lGL -lglut" EXTRA_LDFLAGS= EXTRA_CFLAGS= # AC_CHECK_HEADER(GL/glut.h, , AC_MSG_ERROR([cannot find headers for freeglut])) ;; esac AM_CONDITIONAL(WIN32_BUILD, test "x$WIN32_BUILD" = "xyes") AC_SUBST(GL_LIBS) AC_SUBST(EXTRA_LDFLAGS) AC_SUBST(EXTRA_CFLAGS) dnl Convert install path to use \\ for substitution in the win32 nsi script prefix_win=`echo $prefix | sed -e 's|/|\\\\|g'` AC_SUBST(prefix_win) AC_CONFIG_FILES([ Makefile po/Makefile.in win32/repsnapper.nsi tools/gitversion.sh]) AC_OUTPUT repsnapper-2.3.2a5/doc/000077500000000000000000000000001231531733200146705ustar00rootroot00000000000000repsnapper-2.3.2a5/doc/credits.txt000066400000000000000000000013151231531733200170660ustar00rootroot00000000000000 This is at least a partial credits-file of people that have contributed to repsnapper. It is sorted by name, and formatted in a format that allows for easy grepping and beautification by scripts. The fields are: name (N), email (E), web-address (W), PGP key ID and fingerprint (P), description (D) and snail-mail address (S). Thanks, Tim ---------- N: Evan Clinton E: nave.notnilc@gmail.com D: Palomides N: Francis Crick D: fcrick N: Giles Bathgate E: gilesbathgate@gmail.com W: http://www.gilesbathgate.com/ N: joaz N: logick N: Michael Holm D: kulitorum N: Micheal Meeks D: mmeeks N: MrAlvin W: http://reprap.org/wiki/User:MrAlvin N: The Other Rob N: Timothy Schmidt E: timschmidt@gmail.com repsnapper-2.3.2a5/doc/gcode generation.txt000066400000000000000000000145751231531733200206420ustar00rootroot00000000000000This is a decription of how gcode is currently generated by RepSnapper (June 2010) I'm write for pedagogical and design purposes. * Overview By fcrick Slicing Slicing is where we cut the original 3d model with a horizontal plane at a particular height. The toolpath is the result of processing each slice of the original model, starting at the bottom, and moving upwards. Each layer is separated by the vertical thickness of the extruded material. Currently, each slice is processed entirely independently, and the only information used from the previous slice when generating the toolpath is just where the extrusion head ended up at the end of the previous slice. Models The model ( is made up of discrete triangles, hopefully all sharing edges so that they make a full mesh without any holes in it. Currently, repsnapper (and many 3d programs) use the orientation of a triangle to determine which side of the triangle represents the inside of the object we're creating, and which side borders empty space. So, for example, if you find the cross product of two edges of a triangle (say edge 1 cross edge 2), the resulting normal vector will point into empty space, not into the object. I'm not sure which way it goes but it's consistent. This concept of vertex order dictating orientation is pretty important and is used throughout the program. One slice - 3d model to vertices on a plane When a slice is made at some height, currently we just check every triangle in the 3d model to see if it intersects that plane. Usually, if a triangle intersect ths plane, two of the vectors of the triangle will have one end above the plane, and one end below - we simple calculate where those vectors intersect the plane, and those vertices become part of our output. Since the two vertices come from the same triangle, they are linked. If the plane happens to have the exact height as one or more of the vertices of the triangle, you can hit a few edge cases. Vertex pairs to polygons The previous step gives us many pairs of vertices - each pair came from a triangle, but at this point, we just have vertex pairs, when what we want is the outline of polygons that make up the slice. Polygons represent either holes or fills, and a hole polygon _should_ exist entirely within a fill polygon. Again, we use the order of the vertices to designate which are holes and which are fills - one clockwise, one counter-clockwise. Currently, we use an algorithm that identifies the vertices closest to each other, and those vertices are merged. After a pass of this, either we have complete polygons or we don't, and if we don't, we retry the slice at a slightly different height. It seems like this algorithm could use some improvement :/ A slice as polygons At this point, we have polygons that really represent the goal of this particular layer. Since the extruder has a thickness, and we can't just arbitrarily fill in this geometry with a perfect layer of extrusion material, we can almost never fill in the layer exactly. Instead, our goal is to generate a path that gives us the best possible fill that fits this set of polygons best. Also, typically we don't bother filling the inside of a model with solid material, since this just uses more material, and creates a heavier object that isn't actually any more useful or strong that one with a lot of empty space inside. Shrinking - why we shrink the polygons If we had the extruder just follow the outer edge of our polygon, half the material would end up outside the polygon, and we'd end up with an object larger than the model. To compensate for the width of the extruded material, we shrink the polygons, so that we end up with another polygon that is slightly smaller than our target. If the extruder follows _that_ polygon, than the outer edge of the extruded material will match the edge of our original target polygon, and we'll create an object of the correct size. This tracing of the outside of the polygon is called a shell. If we want multiple shell layers, we shrink the polygons again, this time by the full thickness of the extruded material, instead of half, and the extruder can follow that polygon for an additional shell. Shrinking - how we shrink The 'fast' shrinking algorithm basically takes each vertex of the polygon, and moves it inward. We use the two adjacent vertices to decide where the point should be moved. If the vertex is one pointing out of the polygon, you need to move the point inward more than that amount you're shrinking, and you use the angle of the adjoining edges to find that point. Also, the 'fill' polygons get shrunk, and the 'hole' polygons get grown. After all the vertices get moved, we have to reconcile the edges that have crossed over eachother, and the holes that have grown to overlap the fill polygons they were inside of before the shrinking. Right now we use some external library for this step (gpc polygon something). There is also a slower, better shrinking algorithm, and Logick is working on another shrinking algorithm - I don't know how those work. Infill polygons After we generate all the shell polygons - the polygons that we intend to just follow the edge of with the extruder, we create the infill polygons. RepSnapper does infill in an extremely simple way. Basically, we fill the whole plane with parallel lines, and then extrude along any of the those lines that are within the infill polygons. In a particular layer, the lines are always the same distance apart (the 'infill distance'), and the direction of the lines changed by a fixed angle between each layer. Path generation I haven't really gone through this code yet, but the gist here is we have to generate a path that includes all the shells, and all the infills. There is some logic in there that sorts all these path segments so that the extruder isn't always traversing large empty gaps to get from one segment to the next, but I'm not really familiar with it yet. * Relating this to the code: Much of the code for this flow lives in stl.h / stl.cpp, while the code moves rapidly, the overall design is fairly constant. Slicing: STL::CalcCuttingPlane + generates a CuttingPlane object as output. + we call 'RegisterPoint' on each new point + this tries to identify unique points. + we AddLine a new 'Segment' which has indexes into these points repsnapper-2.3.2a5/doc/manual.asciidoc000066400000000000000000000572551231531733200176630ustar00rootroot00000000000000== Repsnapper Users Manual == Welcome to the RepSnapper Manual, although currently a work in progress this guide aims to help you install and use your RepSnapper software. Contact Info * Irc channel: #repsnapper at irc://irc.freenode.net Timothy Schmidt Version Current development of Repsnapper is happening in Timothy Schmidt's repository at the following URLs. * Code: https://github.com/timschmidt/repsnapper * Bug tracker: https://github.com/timschmidt/repsnapper/issues Kulitorum version For historical reasons we leave here the links to the old svn version that developed by Kulitorum, this version is now unmaintained and commits go into the Timothy Schmidt version (as of ~ October 5th, 2010) * Code: http://svn.kulitorum.com/RepSnapper * SVN history: http://cia.vc/stats/project/RepSnapper * Bug tracker: http://bugs.kulitorum.com == Installation from binaries == === FreeBSD === -------------------------- pkg_add -r repsnapper -------------------------- === Linux === There are currently no Repsnapper binaries pre-built for Linux. However, installation from source is relatively simple. If you'd like to package Repsnapper for your Linux distribution, please let us know! === Windows === There are beta versions for Windows, see the https://github.com/timschmidt/repsnapper/downloads[Downloads section on github]. The Windows version cannot communicate with a printer and can only calculate on a single CPU. Historians only: the v1 of Repsnapper for Windows is here: http://www.kulitorum.com/RepSnapperBeta.rar (Kulitorums version). This is even older, but should work with tonokip and FiveD: http://svn.kulitorum.com/RepSnapper/MSVC9/Release/RepSnapper.exe[here]. === OS X === Old v1 (historians again): David Buzz has posted binaries for OS X https://sites.google.com/site/davidbuzz/repsnapper-for-osx-binaries[here]. == Installation from source == [NOTE] ===== Since the switch to using gtk, only the docs for (some) Ubuntu are uptodate, and even those are untested. Although RepSnapper is not generally tested outside of windows/linux/mac you may be able to get it running on other OSs. To do so you will need the following: * gcc * make * autotools * intltool * OpenGL * git * libgtkmm-2.4-dev * libgktglext1-dev * libxml++-2.6 * libzip ===== === FreeBSD === -------------------------- cd /usr/ports/cad/repsnapper && make install clean -------------------------- or -------------------------- portinstall repsnapper -------------------------- or similar. Or use the port to install dependecies and then checkout the git code. === Linux === ==== Arch Linux ==== There is an AUR package: -------------------------- yaourt -Sy repsnapper -------------------------- or -------------------------- yaourt -Sy repsnapper-git -------------------------- ==== Ubuntu ==== ===== Install dependencies ===== -------------------------- sudo apt-get install git-core build-essential intltool libtool libgtkglextmm-x11-1.2 libgtkmm-2.4-dev gtk2-engines-pixbuf libxml++ libcairomm-1.0 libzip-dev -------------------------- ===== Acquire source and compile ===== git clone git://github.com/timschmidt/repsnapper.git cd repsnapper ./autogen.sh make Executable (repsnapper) will be left in the top folder. Install with "sudo make install-strip" ==== Fedora ==== ====== Fedora 17 and above ====== Repsnapper is in official Fedora 17 and above repositories, so you can just simply run: yum install repsnapper Sometimes you can get a fresher version (but not very tested) by enabling testing updates: yum install repsnapper --enablerepo updates-testing After the installation you should see Repsnapper in Applications (Graphics), or you can run the `repsnapper` command. ====== Older Fedora versions ====== (most probably extremely outdated) Repsnapper was packaged by jebba for Fedora 14 at this repository: http://repos.fedorapeople.org/repos/jebba/reprap/ su wget -P /etc/yum.repos.d/ http://repos.fedorapeople.org/repos/jebba/reprap/fedora-reprap.repo yum install repsnapper-gtk2 exit repsnapper ===== Installing from sources ===== Install dependencies: TODO only tested with Fedora 14 -------------------------- yum install git gtk2-devel gcc-c++ gcc binutils make cmake gtkglextmm gtkglextmm-devel gtkmm* -------------------------- For Fedora 15 (tested on x86_64) -------------------------- yum install git gtk2-devel gcc-c++ gcc binutils make cmake gtkglextmm gtkglextmm-devel libusb1-devel intltool gtkmm* -------------------------- Install repsnapper: git clone git://github.com/timschmidt/repsnapper.git cd repsnapper su echo "/usr/local/lib" > /etc/ld.so.conf.d/local.conf ldconfig exit ./autogen.sh make -j3 Run the program: ./repsnapper Install and run: sudo make install-strip repsnapper ==== OpenSuse 11.2 / SLED 11 SP1 ==== sudo zypper install TODO ==== Generic installation instructions ==== git clone git://github.com/timschmidt/repsnapper.git cd repsnapper ./autogen.sh make -j3 Executable (repsnapper) will be left in the top folder. Install with "sudo make install-strip" === Windows === Currently black magic. Nightly builds coming... === OS X === Install http://developer.apple.com/technologies/xcode.html[XCode]. Install http://www.macports.org/[MacPorts]. Run from a terminal window: sudo port install intltool gtkmm gtkglextmm Acquire source and compile: git clone git://github.com/timschmidt/repsnapper.git cd repsnapper ./autogen.sh make -j3 Executable (repsnapper) will be left in the top folder. Currently there is no install rule. == Printrun/pronterface integration as pure slicer == As the serial communications section of repsnapper is not really state-of-the-art and may be only working in particular circumstances, you could try using pronterface for the printing part. In pronterface, set the option "slicecommand" to "repsnapper -o $o $s" and you will get a window where you can manipulate and slice your model and then send the GCode back to pronterface for printing. == Configuration == Not uptodate, but still useful: === Simple tab === Connect to printer:: Establishes communications between the PC and the main board. Port:: Manually selects the serial communication port that you want to talk across. Speed:: The serial communications baud rate. Typically 115200 - must however match the setting in your firmware. Load STL:: Loads an STL file Convert to GCode:: Converts the STL to GCode Load GCode:: Loads previously generated GCode file Print:: Starts printing Calibrate:: Not yet implemented === Input File tab === Load STL:: Loads an STL file Save STL:: Saves all objects in their current position to a single STL file. You will actually save the complete printing plate to a single STL file without combining the single objects. After loading the file you can manipulate them individually. These multiple-object STL files can also be read and merged by meshlab. Save Settings:: Saves all configuration settings. The configuration settings are stored in a file called repsnapper.conf. [TIP] Save Settings As:: Saves configuration settings in a file of your choice. Load Settings:: Loads configuration settings from a file. Delete:: Deletes the selected STL from the current working area. Duplicate:: Creates a copy of the selected object. Useful for printing several items of the same object. Translate, Rotate and Scale:: If an STL object is first selected in the browser, this will alter the part for creating gcode. Object Name, File location, File type and file material Name a file system and document the contents. Object rotation:: Selects the plane to rotate the object about. GCode generation is affected by final object placement. Also useful when loading several STL files. === Print Options tab === Shell Only - no infill:: Generates path information for only the outermost layer of an object. When printed, the object will be hollow. Shell Count:: Number of passes around the perimeter of an object, before starting infill. Rotation:: Degrees to rotate the first infill layer. Infill Rotation per Layer:: Degrees to rotate each successive infill layer. Infill Distance:: Distance between each filament of infill - measured in extruded material widths. Alternate Infill Layers:: Raft Enable:: Select this option to print a "raft" on the build surface before printing your desired object. May help alleviate problems with uneven build surfaces. Optimization:: Polygon curves are straightened up to the given offset (to get faster prints) === Raft Settings Window === Larger than objects:: Number of millimeters by which the raft should be larger than the base of the printed object. Number of base/interface layers:: Base layers adhere to the build surface and reduce the effect of surface irregularities. Interface layers come in contact with the printed object and should be easy to break off after printing. Material per distance ratio:: The amount of plastic to extrude for this layer is determined by multiplying the normal extrusion speed by this value. Rotation:: Rotation in degrees between layers. Distance between lines:: Distance, in extruded material widths, between lines. Thickness Ratio:: unknown Temperature ratio:: The normal printing temperature is multiplied by this ratio to determine the temperature used while printing the raft. === Printer Settings Window === Build volume:: Maximum build envelope of the printer. Print margin:: Offset to move from the printer's starting position before beginning print. Use incremental ecode:: Enable this option when using "5D" firmware. Use 3D Gcode:: Enable this option when using Makerbot firmware (or if you use the M101/M103 commands for tool control) Extruded material width ratio:: Width of the extrude material in proportion to layer thickness. Extrusion multiplier:: Allows calibration of the extruder without having to adjust E_STEPS_PER_MM in the firmware. Layer thickness:: Distance between printed layers, in millimeters. Min print speed XY:: Minimum print speed for the X and Y axes, in millimeters per minute. Max print speed XY:: Maximum print speed for the X and Y axes, in millimeters per minute. Min print speed Z:: Minimum print speed for the Z axis, in millimeters per minute. Max print speed Z:: Maximum print speed for the Z axis, in millimeters per minute. Enable antiooze retraction:: Enable this option to retract filament by a set amount before each move, reducing unwanted extrusion. Distance to retract filament:: Distance to retract filament -- measured in millimeters of extrusion, not millimeters of filament. Speed to retract filament:: Speed to retract filament, measured in millimeters per minute. Enable Acceleration:: Enable this option to begin each movement at Min print speed XY, and slowly accellerate up to Max print speed XY. Distance used to read full speed:: Distance to accelerate over, measured in millimeters. Port:: Manually selects the serial communication port that you want to talk across. Speed:: The serial communications baud rate. Typically 19200 - must however match the setting in your firmware. For example in the latest svn firmware the baud is 57600 by default in configuration.h the value in repsnapper must match this value. === GCode tab === Here you can create, save, load and/or edit the GCode. Using the tabs, you can manually enter some GCode, that will be "injected" into the resulting GCode, when you press the Convert to GCode button. Convert to GCode:: Slices the object(s) in the current working area, and generates the necessary GCode to print that object. Load Gcode:: Loads a previously generated Gcode file. Save GCode:: Saves generated GCode to a file. You can generate quite useful and very printable GCode using the default settings of RepSnapper. There are however also a host of user changeable settings that will alter/adjust the generation of GCode. On this page you should get introduced to some of these options. ==== Start tab ==== code options to set at the beginning of the print process, like 0-position, default print temperature and more You will almost certainly want to change the value on the line that sets temperature, or remove it if you set the temperature before starting your print. When you first open RepSnapper this is what is in the tab: -------------------------- ; GCode generated by RepSnapper by Kulitorum G21 ;metric is good! G90 ;absolute positioning T0 ;select first extruder G28 ;go home G92 E0 ;set extruder home M104 S200.0 ;set temperature to 200.0 G1 X20 Y20 F500 ;Move away from 0.0, so we use the same reset (in the layer code) for each layer -------------------------- In Labitat.dk the Workhorse Mendel uses this in the Start tab -------------------------- ; GCode generated by RepSnapper by Kulitorum G21 ;metric is good! G90 ;absolute positioning T0 ;select new extruder ;G28 ;go home - does not work with current version of Tonokip Firmwar e (oct 2010) G92 X0 Y0 Z0 E0 ;set home to current location of the nozzle M104 S215 ;set temperature (heating units - NOT actual degree centigrade) G1 X20 Y20 F500 ;Move away from 0.0, so we use the same reset (in the layer code) for each layer -------------------------- ==== Next layer tab ==== something to do in between printing the next layer ==== End code tab ==== something to do at the end of a print, like turning the heater off When you first open RepSnapper this is what is in the tab: -------------------------- G1 X0 Y0 F2000.0 ;feed for start of next move M104 S0.0 ;Heater off -------------------------- ==== Result tab ==== shows you the final complete GCode generated. === Display options tab === === Print tab === Connect to printer:: Initiates communication between Repsnapper and the printer. If already connected, pressing this button will reset the printer. Power on:: Print:: Starts sending the GCode from the "Result" tab under the "GCode" tab to the printer. Pause:: Pauses communication with the printer. Fan on:: Sends the M106 / M107 codes to the printer to toggle the fan on / off respectively. Voltage:: unknown Errors:: Toggles the logging of communications errors. Info:: unknown Echo:: Toggles echoing of all commands sent to the printer. GCode send:: Text entry field allowing user to manually send individual commands to the printer. ==== Interactive control tab ==== Jog pannel:: A matrix of buttons allowing the user to manually jog the printer set distances along each of it's axes. The topmost row controls the X axis, followed by the Y axis, with the bottom most row controlling the Z axis. Temperature update interval:: Number of seconds between sending the M105 command to the printer to check the extruder temperature. Switch heat on:: Sends M104 command to the printer, with Target Temp as the argument. Current temp:: Current extruder temperature, as reported by the M105 command. Target temp:: Target extruder temperature, in degrees Celcius, sent to the printer when "Switch heat on" button is pressed. Run extruder:: Jogs extruder in the direction set by the Reverse toggle button, distance set by the Length slider, at the speed set by the Speed slider. Reverse:: Toggles extruder direction. Speed:: Speed to jog extruder, in millimeters / minute of extruded material. Length:: Length to jog extruder, in millimeters of extruded material Downstream speed multiplier:: unknown Downstream extrusion multiplier:: unknown Custom buttons:: These buttons do nothing by default, but can be assigned custom strings of GCode to be sent to the printer when clicked. ==== Communication logs tab ==== Communication log:: Errors / warnings:: Echo:: Auto scroll:: Log Files:: Clear logs when print starts:: Clear logs now:: Clears the log window immediately ==== Custom buttons tab ==== Button to edit:: Select which button to edit. Button Label:: User-editable text label for the selected custom button. Save:: Assigns current GCode to the selected button. Test:: Sends the current GCode to the printer. == Use == === Launching === To run repsnapper on windows:: double click the repsnapper.exe file. linux/OSX/xBSD:: type ./repsnapper into the console window or install it by 'make install-strip', then you should have repsnapper on your path. After launching the repsnapper application you are presented with the main window of the application On the left is the 3D view and on the right is the configuration and control panel. Loading an STL To load an STL into the 3D view * click on the tab labeled Input file and * press the Load STL button. In revision prior to ??? you are presented with a Fluid file browsing dialog. In later versions you will be presented with your standard operating systems file browse dialog. Choose the STL that you wish to load and click OK. The 3D view should now display your STL. Use this button to pull in a facet file to process into Gcode. [TIP] If repsnapper crashes at this point you might have an STL file that is "Bad Input" try converting it to binary using meshlab or similar. === Viewing the STL === ==== Viewing STL in repsnapper ==== Once an STL is loaded you can rotate, translate and/or scale the view in the 3D viewer so as to see what the object looks like, doing so will not effect the print its mearly for viewing purposes. * To rotate the view of the STL hold down the left mouse button and drag. * To translate the view the STL hold down the right mouse button and drag. * To scale the view the STL hold down the middle mouse button and drag, or turn the wheel on your mouse. Note: the grid shows your build platform / printing area Working with STL Once an STL is loaded, you can move it to further onto the build platform, rotate it and scale it. You can also duplicate it and load additional STL files onto the build platform. * To move around individual objects or a group of objects use Shift and the left mouse button. * Or tab to the translate box and enter absolute values into the X and Y fields. * If the object is not on the Platform, you can also try rotating it about the Z axis to automatically make it touch the Z=0 plane. * Everything below the Z=0 plane will not be sliced, so you will not get negative Z values in your GCode. * Duplicate adds another copy of the STL beside the first. === Convert to GCode === Repsnapper displaying GCode Converting to GCode is a simple process: * Press the Convert to GCode button. You can generate quite useful and very printable GCode using the default settings of RepSnapper. There are however also a host of user changeable settings that will alter/adjust the generation of GCode, see RepSnapper Manual: Setting GCode options for details. === Print === To send the GCode to a FiveD GCode compatible printer: * click the Connect to printer button. (you set com-port and speed in "Settings") * Check the Communication Log tab to make sure the printer has connected and is receiving temperature signals from the Extruder Controller. * Set the extruder target temperature, by editing the "Target Temp" field, and * click "Switch Heat on" to turn on the extruder heater. * once the target temp has been met, you may want to try to extrude a bit, to make sure the extruder is fully loaded and ready to print. To start printing * click the Print button. This starts sending commands to the printer for execution. Below the author describes the things he had to do to get repsnapper (V333, dated 14-08-2010) working to the point where he could finish a print of a test block. Firmware used was Tonokip's firmware running on an Arduino Mega with Pololu stepper drivers. Firmware * Make sure your Arduino config file is accurate. Test movement lengths with a ruler to be sure. * you can do this from repsnapper. (See appendix A to see how to manually control your bot from repsnapper) Printer definition * Make sure 'extruded material width' matches the extruded filament diameter. * Extrusion multiplyer determines how fast your extruder goes at a given print speed... This parameter is the one to fiddle, to set your stretch. * Max printspeed is the speed that repsnapper will command the axes to move. Too fast and you will strip your filament or stall your extruder. * Turn acceleration off. Make sure Use Incremental ecode is on Print options * infill Distance was set quite small, I changed it up to 1.8mm Raft * Turned off Raft for the test blocks. Gcode * Start tab * Cleared the text out of the other tabs, knowing that the steppers are skipping steps is a good thing at the beginning. == Appendix A. == Everything happens from the Print tab when you want to manually control your bot. * To get working for the first time, you must make a connection.. make sure the USB is plugged into the arduino, and that the arduino software is not using the virtual serial port. * make sure you have the correct serial port selected in the Printer Definition tab, and the speeds set to a reasonable number. * Select 'Connect to printer' (should be lit) * You can check your connection by selecting the communication log tab on the 'Print' page. From 'Communication Log', select 'Communication Log, again and see that commands are being acknowledged... * you can eventually skip this step by making sure that your temperature is being updated. Go back to the 'interactive control' tab. * You can execute a line of gcode by putting the cursor into the 'GCode' box and pressing enter, or the 'send' button. * You can jog all three of your axes by hitting one of the numbered buttons.. -100 on the top line will move the X axis 100 mm (or inches! if you are set up for inches) in the home direction... * (you may want to re-visit your arduino config file and reverse an axis or two if things move in the wrong direction). * middle line is Y axis, Bottom line is Z axis... * Pressing home will cause that axis to run in the minus direction until it reaches an endstop. 'Home All' is not supported in Tonokip's firmware. * Clicking 'Switch Heat On' will cause your extruder to start to heat up. It will try to get to the set 'Target temp'. If you change the target temp, you must deselect switch heat off, then on again for it to register. * To run the extruder, once at temperature, set the speed slider (in mm/minute ?), the length (in mm ?) and click the 'Run extruder' button. It will run for the distance specified in 'Length'. to run it again, you click 'Run Extruder' again, it will de-select, but the motor will run anyways. == Development == === Comms debugging === Even if you have a working machine, it can be useful to emulate a serial connection to see what the firmware would see. Using socat (install from your distro repos as usual). For the simplest case, issue "socat -d -d pty,raw,echo=0 readline" in a terminal. It reports the address to to connect RepSnapper to, (something like /dev/pts/N). You should disable connection validation int the printer settings dialog. If you happen to have a working firmware in a simulator (please share if you do :), then you can use "socat -d -d pty,raw,echo=0 pty,raw,echo=0", which gives two addresses, so you can connect anything to RepSnapper. You could also use another serial terminal app this way. repsnapper-2.3.2a5/libraries/000077500000000000000000000000001231531733200160775ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/Makefile.am000066400000000000000000000002701231531733200201320ustar00rootroot00000000000000include libraries/lmfit/Makefile.am include libraries/vmmlib/Makefile.am include libraries/clipper/Makefile.am include libraries/poly2tri/Makefile.am include libraries/amf/Makefile.am repsnapper-2.3.2a5/libraries/amf/000077500000000000000000000000001231531733200166425ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/Makefile.am000066400000000000000000000111701231531733200206760ustar00rootroot00000000000000noinst_LTLIBRARIES += libamf.la libamf_la_CPPFLAGS = \ -I$(srcdir) \ -I$(top_srcdir)/libraries/amf/amftools-code/include/ \ -I$(top_srcdir)/libraries/amf/amftools-code/include/muparser \ $(LIBZIP_CFLAGS) \ $(EXTRA_CFLAGS) libamf_la_SOURCES = \ libraries/amf/amftools-code/include/Amf.h \ libraries/amf/amftools-code/src/Amf.cpp \ libraries/amf/amftools-code/include/nObject.h \ libraries/amf/amftools-code/include/stb_image \ libraries/amf/amftools-code/include/stb_image/stb_image.h \ libraries/amf/amftools-code/include/nTexmap.h \ libraries/amf/amftools-code/include/nMesh.h \ libraries/amf/amftools-code/include/Amf.h \ libraries/amf/amftools-code/include/nCoordinates.h \ libraries/amf/amftools-code/include/SimpleImage.h \ libraries/amf/amftools-code/include/Vec3D.h \ libraries/amf/amftools-code/include/nComposite.h \ libraries/amf/amftools-code/include/nNormal.h \ libraries/amf/amftools-code/include/X3D_File.h \ libraries/amf/amftools-code/include/nVertex.h \ libraries/amf/amftools-code/include/XmlCompress.h \ libraries/amf/amftools-code/include/nMaterial.h \ libraries/amf/amftools-code/include/muparser/muParser.h \ libraries/amf/amftools-code/include/muparser/muParserCallback.h \ libraries/amf/amftools-code/include/muparser/muParserBytecode.h \ libraries/amf/amftools-code/include/muparser/muParserBase.h \ libraries/amf/amftools-code/include/muparser/muParserError.h \ libraries/amf/amftools-code/include/muparser/muParserTokenReader.h \ libraries/amf/amftools-code/include/muparser/muParserStack.h \ libraries/amf/amftools-code/include/muparser/muParserDef.h \ libraries/amf/amftools-code/include/muparser/muParserToken.h \ libraries/amf/amftools-code/include/muparser/muParserFixes.h \ libraries/amf/amftools-code/include/nTriangle.h \ libraries/amf/amftools-code/include/nVertices.h \ libraries/amf/amftools-code/include/nInstance.h \ libraries/amf/amftools-code/include/Mesh.h \ libraries/amf/amftools-code/include/rapidxml/rapidxml_print.h \ libraries/amf/amftools-code/include/rapidxml/rapidxml.h \ libraries/amf/amftools-code/include/STL_File.h \ libraries/amf/amftools-code/include/nConstellation.h \ libraries/amf/amftools-code/include/nColor.h \ libraries/amf/amftools-code/include/Equation.h \ libraries/amf/amftools-code/include/nMetadata.h \ libraries/amf/amftools-code/include/AMF_File.h \ libraries/amf/amftools-code/include/nAmf.h \ libraries/amf/amftools-code/include/nTexture.h \ libraries/amf/amftools-code/include/nEdge.h \ libraries/amf/amftools-code/include/MeshSlice.h \ libraries/amf/amftools-code/include/XmlStream.h \ libraries/amf/amftools-code/include/zip \ libraries/amf/amftools-code/include/zip/zip.h \ libraries/amf/amftools-code/include/zip/unzip.h \ libraries/amf/amftools-code/include/nVolume.h \ libraries/amf/amftools-code/src/zip/zip.cpp \ libraries/amf/amftools-code/src/zip/unzip.cpp \ libraries/amf/amftools-code/src/nMetadata.cpp \ libraries/amf/amftools-code/src/nTriangle.cpp \ libraries/amf/amftools-code/src/nTexmap.cpp \ libraries/amf/amftools-code/src/nTexture.cpp \ libraries/amf/amftools-code/src/Equation.cpp \ libraries/amf/amftools-code/src/nObject.cpp \ libraries/amf/amftools-code/src/nVertex.cpp \ libraries/amf/amftools-code/src/nComposite.cpp \ libraries/amf/amftools-code/src/AMF_File.cpp \ libraries/amf/amftools-code/src/nInstance.cpp \ libraries/amf/amftools-code/src/nCoordinates.cpp \ libraries/amf/amftools-code/src/nAmf.cpp \ libraries/amf/amftools-code/src/XmlCompress.cpp \ libraries/amf/amftools-code/src/nMesh.cpp \ libraries/amf/amftools-code/src/nVertices.cpp \ libraries/amf/amftools-code/src/nNormal.cpp \ libraries/amf/amftools-code/src/nColor.cpp \ libraries/amf/amftools-code/src/STL_File.cpp \ libraries/amf/amftools-code/src/nVolume.cpp \ libraries/amf/amftools-code/src/nEdge.cpp \ libraries/amf/amftools-code/src/SimpleImage.cpp \ libraries/amf/amftools-code/src/nConstellation.cpp \ libraries/amf/amftools-code/src/XmlStream.cpp \ libraries/amf/amftools-code/src/stb_image/stb_image.cpp \ libraries/amf/amftools-code/src/nMaterial.cpp \ libraries/amf/amftools-code/src/Mesh.cpp \ libraries/amf/amftools-code/src/X3D_File.cpp \ libraries/amf/amftools-code/src/MeshSlice.cpp \ libraries/amf/amftools-code/src/muparser/muParserError.cpp \ libraries/amf/amftools-code/src/muparser/muParserBase.cpp \ libraries/amf/amftools-code/src/muparser/muParser.cpp \ libraries/amf/amftools-code/src/muparser/muParserTokenReader.cpp \ libraries/amf/amftools-code/src/muparser/muParserCallback.cpp \ libraries/amf/amftools-code/src/muparser/muParserBytecode.cpp repsnapper-2.3.2a5/libraries/amf/amftools-code/000077500000000000000000000000001231531733200213765ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/000077500000000000000000000000001231531733200230215ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/AMF_File.h000066400000000000000000000356301231531733200245430ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef AMFFILE_H #define AMFFILE_H #include "nAmf.h" #include "Vec3D.h" #include "MeshSlice.h" //for file imports #include "STL_File.h" #include "X3D_File.h" /*DEPRECATED*/ enum EnvelopeData {ENVL_XMIN, ENVL_YMIN, ENVL_ZMIN, ENVL_XMAX, ENVL_YMAX, ENVL_ZMAX, ENVL_XSIZE, ENVL_YSIZE, ENVL_ZSIZE}; enum InstanceParamD {INST_DX, INST_DY, INST_DZ, INST_RX, INST_RY, INST_RZ}; enum ColorView {CV_ALL, CV_VERT, CV_TRI, CV_TRICOLOR, CV_TRITEX, CV_VOL, CV_OBJ, CV_MAT}; //what colors to draw the vertex enum ViewMode {VM_SOLID, VM_WIREFRAME, VM_SOLIDPLUSWIRE}; class nObjectExt; class AmfFile : protected nAmf { public: AmfFile(void); ~AmfFile(void); AmfFile(const AmfFile& In); AmfFile& operator=(const AmfFile& In); //Amf I/O bool Save(std::string AmfFilePath, bool Compressed = true); //LastError bool Load(std::string AmfFilePath, bool StrictLoad = true); //LastError bool ImportAmf(std::string AmfFilePath, bool StrictLoad = true); //merges this AMF with the current AMF void ClearAll(); //importing meshes bool ImportMesh(std::string MeshFilePath, int AmfObjectIndex=0, int AmfMeshIndex=0); //LastError //imports a mesh into a mesh node specified (stl or x3d only) bool LoadStl(std::string StlFilePath); //LastError //imports an stl into a mesh node specified bool GetStlMeshSize(double* XSize, double* YSize, double* ZSize); //LastError bool ImportStl(int AmfObjectIndex=0, int AmfMeshIndex=0); //LastError //imports an stl into a mesh node specified bool LoadX3d(std::string X3dFilePath, std::string ImagePath="", std::string* ImgPathErrorReturn = NULL); //LastError //imports an x3d into a mesh node specified bool GetX3dMeshSize(double* XSize, double* YSize, double* ZSize); //LastError bool ImportX3d(int AmfObjectIndex=0, int AmfMeshIndex=0); //LastError //imports an x3d into a mesh node specified //exporting meshes bool ExportSTL(std::string StlFilePath); //Units void SetImportUnits(UnitSystem Units); UnitSystem GetUnits(void) {return aUnit;} std::string GetUnitsString(void){return GetUnitsString(aUnit);} std::string GetUnitsString(UnitSystem SysIn); void SetUnits(UnitSystem UnitSystemIn) {aUnit = UnitSystemIn; UnitsExist = true;} double ConvertUnits(double Value, UnitSystem OriginalUnits, UnitSystem DesiredUnits); double ToCurrentUnits(double Value, UnitSystem OriginalUnits){return ConvertUnits(Value, OriginalUnits, aUnit);} double FromCurrentUnits(double Value, UnitSystem DesiredUnits){return ConvertUnits(Value, aUnit, DesiredUnits);} //Size of Amf double GetEnvelopeData(EnvelopeData Data); //DEPRECATED //TODO: rethink these bool GetEnvlMin(double* pXMinOut, double* pYMinOut, double* pZMinOut, int RenderIndex=-1); bool GetEnvlMax(double* pXMaxOut, double* pYMaxOut, double* pZMaxOut, int RenderIndex=-1); bool GetEnvlSize(double* pXSizeOut, double* pYSizeOut, double* pZSizeOut, int RenderIndex=-1); bool GetEnvlRotQuat(double* pWRotOut, double* pXRotOut, double* pYRotOut, double* pZRotOut, int RenderIndex=-1); bool GetEnvlRotAngleAxis(double* pAngleRadOut, double* pNXOut, double* pNYOut, double* pNZOut, int RenderIndex=-1); bool GetEnvlOrigin(double* pXOriginOut, double* pYOriginOut, double* pZOriginOut, int RenderIndex=-1); bool GetEnvlDims(double* pIDimOut, double* pJDimOut, double* pKDimOut, int RenderIndex=-1); bool Scale(double ScaleFactor, bool ScaleConstellations=true, bool ScaleEquations = false) {return Scale(ScaleFactor, ScaleFactor, ScaleFactor, ScaleConstellations, ScaleEquations);} bool Scale(double ScaleFactorX, double ScaleFactorY, double ScaleFactorZ, bool ScaleConstellations=true, bool ScaleEquations = false); //Amf Objects: int GetObjectCount(void) {return GetNumObjects();} std::string GetObjectName(int ObjectIndex); void RenameObject(int ObjectIndex, std::string NewName); int AddObject(std::string Name = "") {AppendObject(Name); return Objects.size()-1;} void RemoveObject(int ObjectIndex); void TranslateObject(int ObjectIndex, double dx, double dy, double dz); void RotateObject(int ObjectIndex, double rx, double ry, double rz); //Amf Meshes int GetMeshCount(int ObjectIndex); //Amf Volumes int GetVolumeCount(int ObjectIndex, int MeshIndex); std::string GetVolumeName(int ObjectIndex, int MeshIndex, int VolumeIndex); void RenameVolume(int ObjectIndex, int MeshIndex, int VolumeIndex, std::string NewName); int GetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex); bool SetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex, int MaterialIndex); //Amf Constellations: int GetConstellationCount(void) {return GetNumConstellations();} std::string GetConstellationName(int ConstellationIndex); void RenameConstellation(int ConstellationIndex, std::string NewName); int AddConstellation(std::string Name = "") {AppendConstellation(Name); return Constellations.size()-1;} void RemoveConstellation(int ConstellationIndex); bool IsConstellationReferencedBy(int ConstellationIndex, int ConstellationIndexToCheck); //Amf Instances int GetInstanceCount(int ConstellationIndex); int AddInstance(int ConstellationIndex); void RemoveInstance(int ConstellationIndex, int InstanceIndex); bool SetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex, int InstanceObjectIndex); bool SetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex, int InstanceConstellationIndex); int GetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex); int GetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex); bool SetInstanceParam(int ConstellationIndex, int InstanceIndex, InstanceParamD ParamD, double Value); double GetInstanceParam(int ConstellationIndex, int InstanceIndex, InstanceParamD ParamD); //Amf Materials: int GetMaterialCount(void) {return GetNumMaterials();} std::string GetMaterialName(int MaterialIndex); void RenameMaterial(int MaterialIndex, std::string NewName); int AddMaterial(std::string Name = "") {AppendMaterial(Name); return Materials.size()-1;} int AddMaterial(std::string Name, int Red, int Green, int Blue) {int MatIndex=AddMaterial(Name); SetMaterialColorI(MatIndex, Red, Green, Blue); return MatIndex;} int AddMaterial(std::string Name, double Red, double Green, double Blue) {int MatIndex=AddMaterial(Name); SetMaterialColorD(MatIndex, Red, Green, Blue); return MatIndex;} void RemoveMaterial(int MaterialIndex); bool IsMaterialReferencedBy(int MaterialIndex, int MaterialIndexToCheck); bool SetMaterialColorD(int MaterialIndex, double Red, double Green, double Blue); bool SetMaterialColorI(int MaterialIndex, int Red, int Green, int Blue){return SetMaterialColorD(MaterialIndex, Red/255.0, Green/255.0, Blue/255.0);} bool GetMaterialColorD(int MaterialIndex, double *Red, double *Green, double *Blue); bool GetMaterialColorI(int MaterialIndex, int *Red, int *Green, int *Blue); //Amf Composites int GetCompositeCount(int MaterialIndex); void ClearComposites(int MaterialIndex); int AddComposite(int MaterialIndex, int MaterialIndexToComposite = 0); void RemoveComposite(int MaterialIndex, int CompositeIndex); bool SetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex, int CompositeMaterialIndex); //1-based (because 0 always VOID material int GetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex); //1-based (because 0 always VOID material std::string GetCompositeEquation(int MaterialIndex, int CompositeIndex); //use! ToAmfString() bool SetCompositeEquation(int MaterialIndex, int CompositeIndex, std::string Equation); //Amf Textures: int GetTextureCount(void) {return GetNumTextures();} //Output utilities bool SetSubdivisionLevel(int Level=4); void DrawGL(); //draw everything! /// int GetRenderedMeshCount(void); //number of meshes drawn on the screen unsigned char* GetSliceBitmapRGBA(double PixelSizeX, double PixelSizeY, double SliceHeightZ, int* XSizeOut, int* YSizeOut, double SurfaceDepth = 0.0); int* GetSliceSegmentsXY(double ZHeight, int* NumSegmentsOut); //Errors and information std::string GetInfoString(bool MeshInfo = true); std::string* pLastErrorMsg() {return &LastError;} std::string GetLastErrorMsg() {return LastError;} //Real time status info on long i/o operations bool* pCancelIO() {return &CancelIO;} int* pCurTick(){return &CurTick;} int* pMaxTick(){return &MaxTick;} std::string* pStatusMsg(){return &CurrentMessage;} std::vector RenderedObjs; //todo: this should be protected... protected: //Amf I/O utilities //bool CheckValid(bool Strict=true, std::string* pMessage = 0); //Import meshes Utilities/members CSTL_File StlFile; CX3D_File X3dFile; enum Channel{CR, CG, CB, CA}; int AddTexture(CSimpleImage* pImageIn, Channel ChannelToGet, bool TiledIn = true); //adds texture, returns the ID it was added with. If the volume already has a texture on this channel, it resizes the texture to add this one and adjusts all texmap coordinates accordingly void ToOneTexturePerVolume(void); //if a volume references more than one texture void X3dFillImportInfo(nMesh* pMesh, std::vector* pVolumes, std::vector* pCoordsBeginIndex); //resizes pVolume to the number of x3d shapes and fills with a pointer to the volume (creating new volumes) each should be loaded in to. alse fills pCoordsBeginIndex with what vertex index in the AMF mesh vertex list these coordinates start... //Units utilities UnitSystem CurImportUnits; //units system of the current importing mesh... double GetImportScaleFactor(void); //gets scaling factor based on CurImportUnits and current Amf Units. Sets amf units to CurImportUnits if first mesh to be imported. //Amf Size Utilities/members bool ComputeBoundingBox(); void GetMinMax(double& xMinOut, double& yMinOut, double& zMinOut, double& xMaxOut, double& yMaxOut, double& zMaxOut); void GetSize(double& xOut, double& yOut, double& zOut); double MinX, MaxX, MinY, MaxY, MinZ, MaxZ; //Amf node Utilities nObject* GetObject(int ObjectIndex, bool CanCreate = false); nMesh* GetMesh(int ObjectIndex, int MeshIndex, bool CanCreate = false); nVolume* GetVolume(int ObjectIndex, int MeshIndex, int VolumeIndex, bool CanCreate = false); nConstellation* GetConstellation(int ConstellationIndex, bool CanCreate = false); nMaterial* GetMaterial(int MaterialIndex, bool CanCreate = false); nInstance* GetInstance(int ConstellationIndex, int InstanceIndex, bool CanCreate = false); nComposite* GetComposite(int MaterialIndex, int CompositeIndex, bool CanCreate = false); // int MaterialIDToIndex(int MaterialID); int MaterialIndexToID(int MaterialIndex) {nMaterial* pMat = GetMaterial(MaterialIndex); if(pMat) return pMat->aID; else return -1;} //Real Time status info utilities bool CancelIO; //!< Cancels any input/output operations int CurTick; //!< Current progress (with respect to MaxTick) of the current input/output operation. int MaxTick; //!< Total possible progress of the current input/output operation. std::string CurrentMessage; //!< Status of the current input/output operation. //Rendering utilities bool NeedRender; //Flag set to true whenever anything pertaining to the visuals of the amf is changed... bool Render(); //generates RenderedObjs, calls RenderMeshes() if flag set; int SubDivLevel; //how many times do we want to subdivide curved triangles? ColorView CurColorView; ViewMode CurViewMode; bool RenderConstellation(nConstellation* pConst, std::vector* pIndexStack, Vec3D CurOff, CQuat CurRot, ColorView CurColorView, ViewMode CurViewMode, int SubDivLevel); //for recursion bool RenderObject(nObject* pObj, std::vector* pIndexStack, Vec3D CurOff, CQuat CurRot, ColorView CurColorView, ViewMode CurViewMode, int SubDivLevel); //actually adds an object to RenderedObjs nObjectExt* GetRenderObject(int RenderIndex); CMeshSlice* GetRenderMesh(int RenderIndex); //Slicing Utilitoes bool GenerateLayer(double PixelSizeX, double PixelSizeY, double SliceHeightZ, double SurfaceDepthIn = 0.0, std::string* pMessage = NULL); void ImposeBitmap(CSimpleImage* pBase, CSimpleImage* pImposed, int BaseXOrigin, int BaseYOrigin, int XOrigin, int YOrigin); //X, Y origin is the location within pBase that pImposed should be added. CSimpleImage CurSlice; //Errors and information utilities std::string LastError; void ClearError() {LastError = "";} }; #define d2r 2*3.1415926/360.0 class nObjectExt{ //class to "unwind" an nObject to from its constellations (and render/slice mesh to in absolute coordinates!) public: nObjectExt(nAmf* pAmfIn, nObject* ObjIn, std::vector* pIndexStack, Vec3D& OffsetIn, CQuat& RotIn, ColorView& CurColorViewIn, ViewMode& CurViewModeIn, int& SubDivLevelIn) {RenderMesh(pAmfIn, ObjIn, pIndexStack, OffsetIn, RotIn, CurColorViewIn, CurViewModeIn, SubDivLevelIn);} nObjectExt(const nObjectExt& O) {*this = O;} //copy constructor nObjectExt& operator=(const nObjectExt& O) {pAmf = O.pAmf; /*Offset = O.Offset; Rot = O.Rot; */Meshes = O.Meshes; MaterialIDs = O.MaterialIDs; return *this; }; //overload equals std::vector Meshes; //one for each VOLUME of each mesh... std::vector MaterialIDs; //store material ID for each mesh static CColor nColor2CColor(nColor& ColorIn, Vec3D* pLoc = NULL); // CQuat GetRot(void) {return Rot;} // Vec3D GetOffset(void) {return Offset;} // Vec3D OriginalLoc(Vec3D& vIn){return (vIn-Offset).Rot(Rot.Inverse());} //returns the location of vIn in the original coordinate system of the object // static void GetColorCallback(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut, int aObjectID); //function to get color based on location // static std::vector aThis; //keep a static array of pointers to all our objects so we can have a static callback function to get colors. protected: nAmf* pAmf; bool RenderMesh(nAmf* pAmfIn, nObject* pObj, std::vector* pIndexStack, Vec3D& OffsetIn, CQuat& RotIn, ColorView& CurColorView, ViewMode& CurViewMode, int& SubDivLevel); //call on bool AddTriangle(bool SubDivide, int CurSubDivLevel); //TODO // Vec3D Offset; // CQuat Rot; }; #endif //AMFFILE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/Amf.h000066400000000000000000001162301231531733200237000ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef AMF_H #define AMF_H #include //inlude for std::string parameters #if defined(_WIN32) || defined(_WIN64) /*Windows*/ #ifdef DLL_EXPORT #define LIBSPEC __declspec(dllexport) #elif defined(DLL_IMPORT) #define LIBSPEC __declspec(dllimport) #else #define LIBSPEC #endif #else /*non-windows*/ #define LIBSPEC /*TODO: Allow this header file to generate (and be distributed) with non-windows shared objects*/ #endif class AmfFile; //!The Amf class encapsulates all the functionality of an AMF file, including the ability to load, save, import other mesh types, and output 3D openGL drawings and 2D color slices. Windows users have the option of #defining LIBSPEC as either (1) DLL_EXPORT to generate a dll using this header or (2) DLL_IMPORT to use this header in conjunction with a compiled dll. class LIBSPEC Amf /*LIBSPEC macro allows windows users the option of using this class in DLL form */ { public: Amf(); ~Amf(); Amf(const Amf& In); Amf& operator=(const Amf& In); //!Defines a unit system enum aUnitSystem { aUNIT_MM, //! for license details. *******************************************************************************/ #ifndef EQUATION_H #define EQUATION_H #include "muparser/muParser.h" class nAmf; class CEquation { public: CEquation(void); ~CEquation(void); CEquation(const CEquation& In) {*this = In;} //copy constructor CEquation& operator=(const CEquation& In); //overload Equals void Clear(void); //clear everything out to blank equation bool IsConst(void){return IsConstant;} void FromConstant(double Value); //set the equation to a constant, non-varying value void FromAmfString(std::string& EqIn, nAmf* pAmfIn); std::string ToAmfString(void) const; std::string Amf2MuParser(std::string& Equation); //translates from AMF syntax to MuParser syntax std::string MuParser2Amf(std::string& Equation); //translates from MuParser syntax to AMF syntax bool CheckParse(std::string* pMessage = 0); //tries an evaluation to see if equation is valid... double Eval(double x=0, double y=0, double z=0, bool UnitRange = false); //Evaluates at specified location. UnitRange truncates to between 0 and 1. UnitRange flag clamps result to between 0 and 1 void Scale(double ScaleFactor); //list of textures to be able to evaluate tex() function calls in equations. This must be set whenever nAmf* pAmf; private: bool IsConstant; double ConstantValue; std::string* pEqCache; //remember the last equation we imported mu::Parser* pP; void IniParser(); double XVar, YVar, ZVar; //these are mapped out directly to x, y, and z in MuParser void inline findAndReplace(std::string& source, const std::string& find, const std::string& replace) { const int fLen = (int)find.size(); const int rLen = (int)replace.size(); for (int pos = 0; (pos = source.find(find, pos)) != (int)std::string::npos; pos += rLen) { source.replace(pos, fLen, replace); } } typedef struct {unsigned long int s1, s2, s3;} taus_state; static unsigned long int rand_seed(unsigned long int x); static unsigned long int taus_get(taus_state* state); static double prsm(double x, double y, double z=0, int k=0); //read and write strings to AMF file with CDATA, etc... static nAmf* pAmfStatic; //unfortunately this must be static for MuParser to be able to use it... Set it to pTexList within the class whenever we call eval... static double texture(int textureID, double uIn, double vIn, double wIn = 0); //additional functions and operators for MuParser to use for AMF equations static mu::value_type Mod(mu::value_type Base, mu::value_type Div) {return fmod(Base, Div);} static mu::value_type AND(mu::value_type v1, mu::value_type v2) {return v1 != 0 && v2 != 0;} static mu::value_type OR(mu::value_type v1, mu::value_type v2) {return v1 != 0 || v2 != 0;} static mu::value_type XOR(mu::value_type v1, mu::value_type v2) {return (v1==0 && v2!=0) || (v1 !=0 && v2==0);} static mu::value_type NOT(mu::value_type v) { return v==0; } static mu::value_type Floor(mu::value_type In) {return In>=0 ? (double)((int)In) : (double)((int)In-1);} static mu::value_type Ceil(mu::value_type In) {return In>=0 ? (double)((int)In+1) : (double)((int)In);} static mu::value_type Abs(mu::value_type In) {return fabs(In);} static mu::value_type Rand(const mu::value_type* ArgIn, int NumArg) {switch (NumArg){case 0: return prsm(0,0); break; case 1: return prsm(ArgIn[0],0); break; case 2: return prsm(ArgIn[0],ArgIn[1]); break; case 3: return prsm(ArgIn[0],ArgIn[1],ArgIn[2]); break; default: return prsm(ArgIn[0],ArgIn[1],ArgIn[2],(int)(ArgIn[3]+0.5)); break; }} static mu::value_type Tex(const mu::value_type* ArgIn, int NumArg) {switch (NumArg){case 3: return texture((int)(ArgIn[0]+0.5), ArgIn[1], ArgIn[2]); break; case 4: return texture((int)(ArgIn[0]+0.5), ArgIn[1], ArgIn[2], ArgIn[3]); break; default: return 0; break; }} }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/Mesh.h000066400000000000000000000274451231531733200241020ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef MESH_H #define MESH_H #include #include #include "Vec3D.h" #include "XmlStream.h" //basic RGB color container struct CColor { //copied from GL_Utils.h CColor(){r=-1; g=-1; b=-1;a=-1;}; CColor (const CColor& C) {*this = C;} CColor(double rIn, double gIn, double bIn){r=rIn; g=gIn; b=bIn; a=1.0;} CColor(double rIn, double gIn, double bIn, double aIn){r=rIn; g=gIn; b=bIn; a=aIn;} inline CColor& operator=(const CColor& C) {r = C.r; g = C.g; b = C.b; a = C.a; return *this; }; //overload equals double r, g, b, a; bool isValid(void) const {if(r>=0.0 && r <=1.0 && g>=0.0 && g <=1.0 && b>=0.0 && b <=1.0 && a>=0.0 && a <=1.0) return true; else return false;}; }; //structure to hold each vertex struct CVertex { CVertex() {Clear();} CVertex(const Vec3D& av) {Clear(); v = av;} CVertex(const Vec3D& an, const Vec3D& av) {Clear(); n = an; HasNormal=true; v = av;} CVertex(const Vec3D& av, const CColor& ac) {Clear(); v = av; HasColor = true; VColor = ac;} inline CVertex& operator=(const CVertex& V) {v=V.v; HasNormal=V.HasNormal; n=V.n;HasColor=V.HasColor; VColor = V.VColor; /*DrawOffset = V.DrawOffset;*/ return *this;}; //overload equals CVertex(const CVertex& V) {*this = V;} // DrawAxis = V.DrawAxis; DrawAngle = V.DrawAngle;} inline void Clear(){v = Vec3D(0,0,0); HasNormal = false; n = Vec3D(0,0,0); HasColor = false; VColor = CColor(1,1,1,1); /*DrawOffset = Vec3D(0,0,0);*/} void WriteXML(CXmlStreamWrite* pXML); bool ReadXML(CXmlStreamRead* pXML); Vec3D v; //Vertex location bool HasNormal; Vec3D n; //normal bool HasColor; CColor VColor; }; struct TexMap { TexMap() {}; // TexMap(const double U1In, const double U2In, const double U3In, const double V1In, const double V2In, const double V3In, const bool TexTileIn = false) {uc[0]=U1In; uc[1]=U2In; uc[2]=U3In; vc[0]=V1In; vc[1]=V2In; vc[2]=V3In; TexTile=TexTileIn;} TexMap(const int TexIndexIn, const double U1In, const double U2In, const double U3In, const double V1In, const double V2In, const double V3In, const bool TexTileIn = false) {TexIndex=TexIndexIn; uc[0]=U1In; uc[1]=U2In; uc[2]=U3In; vc[0]=V1In; vc[1]=V2In; vc[2]=V3In; TexTile=TexTileIn;} // inline TexMap& operator=(const TexMap& t) {uc[0]=t.uc[0]; uc[1]=t.uc[1]; uc[2]=t.uc[2]; vc[0]=t.vc[0]; vc[1]=t.vc[1]; vc[2]=t.vc[2]; TexTile = t.TexTile; return *this;}; //overload equals inline TexMap& operator=(const TexMap& t) {TexIndex=t.TexIndex; uc[0]=t.uc[0]; uc[1]=t.uc[1]; uc[2]=t.uc[2]; vc[0]=t.vc[0]; vc[1]=t.vc[1]; vc[2]=t.vc[2]; TexTile = t.TexTile; return *this;}; //overload equals TexMap(const TexMap& t) {*this = t;} int TexIndex; double uc[3]; //u texture coordinates double vc[3]; //v texture coordinates bool TexTile; }; //structure to hold each facet struct CFacet { CFacet() {Clear();} CFacet(const int& av1, const int& av2, const int& av3) {Clear(); vi[0] = av1; vi[1] = av2; vi[2] = av3;} CFacet(const Vec3D& an, const int& av1, const int& av2, const int& av3) {Clear(); n = an; vi[0] = av1; vi[1] = av2; vi[2] = av3;} CFacet(const Vec3D& an, const int& av1, const int& av2, const int& av3, const int& NIn) {Clear(); n = an; vi[0] = av1; vi[1] = av2; vi[2] = av3; Name = NIn;} CFacet(const Vec3D& an, const int& av1, const int& av2, const int& av3, const CColor& ac) {Clear(); n = an; vi[0] = av1; vi[1] = av2; vi[2] = av3; FColor = ac;} inline CFacet& operator=(const CFacet& p) { vi[0]=p.vi[0]; vi[1]=p.vi[1]; vi[2]=p.vi[2]; n=p.n; FColor = p.FColor; HasEdge[0]=p.HasEdge[0]; HasEdge[1]=p.HasEdge[1]; HasEdge[2]=p.HasEdge[2]; ei[0]=p.ei[0]; ei[1]=p.ei[1]; ei[2]=p.ei[2]; HasName=p.HasName; Name = p.Name; HasTexture = p.HasTexture; Map = p.Map; return *this;}; //overload equals CFacet(const CFacet& p) {*this = p;} void Clear() {n=Vec3D(0,0,0); FColor = CColor(1,1,1,1); vi[0] = 0; vi[1] = 0; vi[2] = 0; HasEdge[0] = false; HasEdge[1] = false; HasEdge[2] = false; ei[0]=0; ei[1]=0; ei[2]=0; HasTexture = false; HasName = false; Name = -1;} int vi[3]; //vertex indices bool HasEdge[3]; //correspond to indices in ei[] int ei[3]; //edge indices ei[0] = vi[0] -> vi[1], ei[1] = vi[1] -> vi[2], ei[2] = vi[2] -> vi[0] bool HasName; int Name; //my name (for GL picking) bool HasTexture; //do we want to draw a texture instead of a color for this facet? TexMap Map; //mapping to a texture bool HasColor; CColor FColor; Vec3D n; //normal (computed from vertex locations }; struct CLine { CLine() {Clear();} CLine(const int& av1, const int& av2) {Clear(); vi[0] = av1; vi[1] = av2;} CLine(const int& av1, const int& av2, Vec3D vt1, Vec3D vt2) {Clear(); vi[0] = av1; vi[1] = av2; vt[0]=vt1; vt[1]=vt2; HasTangent[0]=true; HasTangent[1]=true;} inline CLine& operator=(const CLine& l) { vi[0]=l.vi[0]; vi[1]=l.vi[1]; HasTangent[0]=l.HasTangent[0]; HasTangent[1]=l.HasTangent[1]; vt[0]=l.vt[0]; vt[1]=l.vt[1]; return *this;}; //overload equals CLine(const CLine& l) {*this = l;} friend bool operator<(const CLine& L1, const CLine& L2) { if (L1.vi[0] == L2.vi[0]) return L1.vi[1] < L2.vi[1]; else return L1.vi[0] < L2.vi[0];} //for sorting friend bool operator==(const CLine& L1, const CLine& L2) {return ((L1.vi[0]==L2.vi[0] && L1.vi[1]==L2.vi[1]));} // || (vi[0]==O.vi[1] && vi[1]==O.vi[0]));} //Is equal void Clear(void) {vi[0]=-1; vi[1]=-1; HasTangent[0]=false; HasTangent[1]=false; vt[0]=Vec3D(0,0,0); vt[1]=Vec3D(0,0,0);} int vi[2]; //vertex indices bool HasTangent[2]; //is this edge curved or not? (if so vt is ignored) Vec3D vt[2]; //vertex tangents - always must go ccw (same direction as vertices!)) }; class CTexture { public: CTexture() {Clear();} ~CTexture() {} CTexture& operator=(const CTexture& t) {Width = t.Width; Height = t.Height; RGBAImage = t.RGBAImage; Tiled = t.Tiled; GlTexInitialized=t.GlTexInitialized; GlTexName=t.GlTexName; return *this;}; //overload equals CTexture(const CTexture& t) {*this = t;} void Clear(){Tiled=false; Width=0; Height=0; GlTexInitialized=false; GlTexName=-1;} bool Tiled; //show tiled or transparent past edges? int Width, Height; //, ActWidth, ActHeight; // double XScale, YScale; void LoadData(int WidthIn, int HeightIn, unsigned char* RGBAdata, bool TiledIn = true); void LoadData(int WidthIn, int HeightIn, unsigned char* Rdata, unsigned char* Gdata, unsigned char* Bdata, unsigned char* Adata, bool TiledIn = true); void LoadData(int WidthIn, int HeightIn, unsigned char* Rdata, unsigned char* Gdata, unsigned char* Bdata, bool TiledIn = true); std::vector RGBAImage; bool GlTexInitialized; unsigned int GlTexName; unsigned int TexName(void); //returns the openGL texture name, or initializes it in ogl if it hasn't already bool SetGlBorderColor(float r, float g, float b, float a); //private: // void ResizeToMult2(void); //resizes the internal image to a multiple of 2, stores the factors. }; class CMesh { public: CMesh(void); ~CMesh(void); CMesh(CMesh& s); CMesh& operator=(const CMesh& s); void Clear(); void WriteXML(CXmlStreamWrite* pXML, bool MeshOnly = false); //meshonly only store stl-equiavalent info (no color, normals, etc...) bool ReadXML(CXmlStreamRead* pXML); bool Exists(void) {if (Facets.size() != 0) return true; else return false;} void SetBBColor(double r, double g, double b){BoundBoxColor = CColor(r, g, b);} const CFacet* GetpFacet(int FacetIndex) const {return &Facets[FacetIndex];} const CVertex* GetpVertex(int VertexIndex) const {return &Vertices[VertexIndex];} const CLine* GetpLine(int LineIndex) const {return &Lines[LineIndex];} CFacet* GetpFacet(int FacetIndex) {return &Facets[FacetIndex];} CVertex* GetpVertex(int VertexIndex) {return &Vertices[VertexIndex];} CLine* GetpLine(int LineIndex) {return &Lines[LineIndex];} int GetFacetCount(){return (int)Facets.size();} int GetVertexCount(){return (int)Vertices.size();} int GetLineCount(){return (int)Lines.size();} // file i/o bool LoadSTL(std::string filename); bool SaveSTL(std::string filename, bool Binary = true) const; void CalcFaceNormals(); //called to update the face normals... void CalcVertNormals(); //called once for each new geometry (or after deformed...) (depends on face normals!!!) //bool TexturesChanged; #ifdef USE_OPEN_GL void Draw(bool DrawBoundingBox = false); //requires OpenGL libs #endif virtual void MeshChanged(void) {}; //add a facet CFacet* AddFacet(const Vec3D& v1, const Vec3D& v2, const Vec3D& v3, bool QuickAdd = false); //adds a facet, checks vertex list for existing vertices... (should be called with vertices in CCW for proper normal calculation! CFacet* AddFacet(const Vec3D& v1, const Vec3D& v2, const Vec3D& v3, const CColor& Col1, const CColor& Col2, const CColor& Col3, bool QuickAdd = false); //adds a facet... with color info CFacet* AddFacet(const Vec3D& v1, const Vec3D& v2, const Vec3D& v3, const TexMap& MapIn); //adds a facet... with color info CFacet* AddFacet(const CVertex& v1, const CVertex& v2, const CVertex& v3); CFacet* AddFacet(const CVertex& v1, const CVertex& v2, const CVertex& v3, const TexMap& MapIn); //adds a facet... with texture map void AddQuadFacet(const Vec3D& v1, const Vec3D& v2, const Vec3D& v3, const Vec3D& v4) {AddFacet(v1, v2, v3); AddFacet(v3, v4, v1);}; //Vertices should be CCW from outside CLine* AddLine(const CLine& l1){Lines.push_back(l1); return &Lines.back();} //Add a texture CTexture* AddTexture(const CTexture& t1){Textures.push_back(t1); return &Textures.back();} int GetTextureCount(void) {return Textures.size();} Vec3D GetBBMin(void) {if (NeedBBCalc) UpdateBoundingBox(); return _CurBBMin;} Vec3D GetBBMax(void) {if (NeedBBCalc) UpdateBoundingBox(); return _CurBBMax;} Vec3D GetBBSize(void) {if (NeedBBCalc) UpdateBoundingBox(); return _CurBBMax - _CurBBMin;} //manipulation... void Scale(Vec3D d); void Translate(Vec3D d); void Rotate(Vec3D ax, double a); void Rotate(CQuat QRot); //rotation by quaternion void RotX(double a); void RotY(double a); void RotZ(double a); void WeldClose(float Distance); //welds vertices that are nearby (within Distance). Removes deleted triangles... void RemoveDupLines(void); std::vector GlNameIndexStack; //for OpenGL picking void SubdivideMe(void); //tmp protected: bool NeedBBCalc; // void ComputeBoundingBox(Vec3D& pmin, Vec3D& pmax); void UpdateBoundingBox(void); bool LoadBinarySTL(std::string filename); bool LoadAsciiSTL(std::string filename); bool DrawNormals, DrawTextures, DrawEdges, DrawShaded, DrawSmooth, IgnoreNames; CColor BodyColor; //base color to use in absence of face/vertex colors CColor BoundBoxColor; //color when drawing bounding box std::vector Facets; std::vector Vertices; std::vector Lines; std::vector Textures; Vec3D _CurBBMin, _CurBBMax; //cached bounding box values... (UpdateBoundingBox to update()) //curved triangle stuff: void HermiteInterpolation(Vec3D v0, Vec3D n0, Vec3D t0, Vec3D v1, Vec3D n1, Vec3D t1, double s, Vec3D& vs, Vec3D& ts, Vec3D& ns); }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/MeshSlice.h000066400000000000000000000154471231531733200250610ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef MESHSLICE_H #define MESHSLICE_H #include "Mesh.h" #include //#include class CSimpleImage; class nMaterial; //TODO: get rid of AMF dependence. class nObjectExt; class nAmf; enum IntersectionType {IT_INSIDE, IT_OUTSIDE, IT_EDGE}; //structure to hold envelope of each triangle struct TriEnvelope { TriEnvelope(const CMesh& m, const int& FacetIndex) {TriIndex=FacetIndex; const CFacet* pTmpFacet = m.GetpFacet(FacetIndex); Vec3D v0 = m.GetpVertex(pTmpFacet->vi[0])->v; Vec3D v1 = m.GetpVertex(pTmpFacet->vi[1])->v; Vec3D v2 = m.GetpVertex(pTmpFacet->vi[2])->v; MinX=v0.xv1.x?v0.x:v1.x; MaxX=MaxX>v2.x?MaxX:v2.x; MaxY=v0.y>v1.y?v0.y:v1.y; MaxY=MaxY>v2.y?MaxY:v2.y; MaxZ=v0.z>v1.z?v0.z:v1.z; MaxZ=MaxZ>v2.z?MaxZ:v2.z; } inline TriEnvelope& operator=(const TriEnvelope& t) {MinX=t.MinX; MinY=t.MinY; MinZ=t.MinZ; MaxX=t.MaxX; MaxY=t.MaxY; MaxZ=t.MaxZ; TriIndex=t.TriIndex; return *this;}; //overload equals TriEnvelope(const TriEnvelope& T) {*this = T;} // DrawAxis = V.DrawAxis; DrawAngle = V.DrawAngle;} double MinX, MinY, MinZ, MaxX, MaxY, MaxZ; int TriIndex; static const bool MinXLessThan(const TriEnvelope& TriE1, const TriEnvelope& TriE2) {return TriE1.MinXCMesh::operator=(M); Initialized = false; pAmf=M.pAmf; pGetColor=M.pGetColor; pMaterial=M.pMaterial; Offset=M.Offset; Rot=M.Rot; OrigDim=M.OrigDim; /*OrigBBMin=M.OrigBBMin; pObjExt=M.pObjExt; */return *this;} //overload equals // CMeshSlice& operator=(const CMeshSlice& M) {this->CMesh::operator=(M); pGetColor=M.pGetColor; return *this;} //overload equals //voxelizing stuff! void MeshChanged(void); //invalidates all cached voxelizing info! bool IsInside(Vec3D* Point, double TexDepth = 0, CColor* pColor = NULL); std::list CurTriLayer; //list of all triangle indices that cross the current z height (with paddings) std::list CurTriLine; //array of all intersection points at the current z height at the current Y value std::list CurTriPoint; //array of all intersection points at the current z height at the current Y value within range of the current X point! std::vector CurTriPoints; //array of all intersection points at the current z height at the current Y value double _TriLayerZ, _TriLineY, _TriLayerPZ, _TriLinePY, _TriPointPX; //height we calculated TriHeight, CurTriLine at double _ZActual, _YActual, _XActual; //actual values of Y and Z, may be offset by epsilon from nominal o avoid hitting vertices dead on... double _IsCurInside; //as we're iterating through X, are we currently inside or outside the part? void FillTriLayer(double z, double ZPad = 0); //fills in CurTriLayer with all triangles that bridge this plane +-Pad bool FillTriLine(double y, double z, double YPad = 0, double ZPad = 0); //fills in CurTriLine with all triangle the bridge the line in the layer bool FillTriPoints(void); //fills points based on _YActual _ZActual, and the tris in TriLine returns false increments _YActual (to re-do FillTriLine with) and try again. //TODO: FillTriPoints should somehow happen within FillTriLine I think. deal with epsilon offsets and returning quickly... bool Initialized; void Initialize(void); //does all precomputing std::vector Envelopes; std::vector::iterator ZEnvMaxIterator; //iterator left at the Maximum minZ value of last layer computation std::list::iterator YEnvMaxIterator, XEnvMaxIterator; std::vector::iterator XPtIter; double GetClosestFreeZ(double ZIn); //returns the next Z value that does not intersect any vertices // int GetXIntersections(double z, double y, double* pIntersections, int NumtoCheck, int* pToCheck); //returns the number of intersections, stored in pIntersections IntersectionType IntersectXRay(CFacet* pFacet, double y, double z, double& XIntersect); bool GetTriDist(CFacet* pFacetCheck, Vec3D* pPointIn, double& UOut, double& VOut, double& Dist2Out); //gets distance of provided point to closest UV coordinate of within the triangle. returns true if sensible distance, otherwise false // static bool InsideTri(Vec3D& p, Vec3D& v0, Vec3D& v1, Vec3D& v2); // static double Det(Vec3D& v0, Vec3D& v1, Vec3D& v2); // IntersectionType IntersectXRay(CFacet* pFacet, double y, double z, Vec3D& p, double& pu, double& pv); //TODO: Figure out a way to get volume color info into this class based on position!! pFuncGetColor pGetColor; nMaterial* pMaterial; nAmf* pAmf; // nObjectExt* pObjExt; //to get transforamtion for material Vec3D Offset; CQuat Rot; Vec3D OrigDim; // Original size BEFORE any rotation! (helpful for bounding boxes showing up rotated) // Vec3D OrigBBMin; //Original minimum corner of the bounding box CQuat GetRot(void) {return Rot;} Vec3D GetOffset(void) {return Offset;} Vec3D GetOrigDim(void) {return OrigDim;} // Vec3D GetOrigBBMin(void) {return OrigBBMin;} Vec3D OriginalLoc(Vec3D& vIn); //returns the location of vIn in the original coordinate system of the object bool GetSlice(CSimpleImage* pImgOut, double ZHeight, double SurfDepth, double XMin, double XMax, double YMin, double YMax, int XPix, int YPix, int aObjectID=-1, std::string* pMessage = NULL); }; #endif //MESHSLICE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/STL_File.h000066400000000000000000000067141231531733200246030ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef STL_FILE_H #define STL_FILE_H #include #include #include #include "Vec3D.h" //structure to hold each facet struct CSTLFacet { CSTLFacet() {} // CSTLFacet(const CVec& an, const CVec& av1, const CVec& av2, const CVec& av3) : n(an), v1(av1), v2(av2), v3(av3) {} CSTLFacet(const Vec3D& an, const Vec3D& av1, const Vec3D& av2, const Vec3D& av3) { n = an; v[0] = av1; v[1] = av2; v[2] = av3;} CSTLFacet(const CSTLFacet& p) { v[0]=p.v[0]; v[1]=p.v[1]; v[2]=p.v[2]; n=p.n;} Vec3D n; //normal Vec3D v[3]; //vertices }; class CSTL_File { public: CSTL_File(void); ~CSTL_File(void); CSTL_File(CSTL_File& s); CSTL_File& operator=(const CSTL_File& s); std::string ObjectName; bool IsLoaded; bool Load(std::string filename); bool Save(std::string filename, bool Binary = true) const; void ComputeBoundingBox(Vec3D& pmin, Vec3D& pmax); Vec3D GetSize(); std::vector Facets; void Clear() { Facets.clear(); ObjectName = "Default"; IsLoaded=false;} // clear/reset the list of trianges int Size() const { return (int)Facets.size(); } void AddFacet(const Vec3D& n, const Vec3D& v1, const Vec3D& v2, const Vec3D& v3) {Facets.push_back(CSTLFacet(n,v1,v2,v3)); } void AddFacet(float nx, float ny, float nz, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z){ AddFacet(Vec3D(nx, ny, nz), Vec3D(v1x,v1y,v1z), Vec3D(v2x,v2y,v2z), Vec3D(v3x,v3y,v3z)); } protected: // file i/o bool LoadBinary(std::string filename); bool LoadAscii(std::string filename); void Draw(bool bModelhNormals, bool bShaded); //add a facet //manipulation... // void Rotate(CVec ax, double a); // void RotX(double a); // void RotY(double a); // void RotZ(double a); // void Scale(CVec d); // void Translate(CVec d); }; class aWeldVertex { public: aWeldVertex(Vec3D LocIn, int MyInd) {v = LocIn; OrigIndex = MyInd;} //constructor aWeldVertex(const aWeldVertex& Vert) {*this = Vert;} //copy constructor inline aWeldVertex& operator=(const aWeldVertex& vIn) {v = vIn.v; OrigIndex = vIn.OrigIndex; return *this; }; //overload equals // aVertex v; Vec3D v; int OrigIndex; static inline bool IsSoftLessThan(const aWeldVertex& v1, const aWeldVertex& v2){if(abs(v1.v.z - v2.v.z) <= WeldThresh){ if(abs(v1.v.y - v2.v.y) <= WeldThresh){ return v1.v.x < v2.v.x-WeldThresh;}else return (v1.v.y < v2.v.y-WeldThresh);} else return (v1.v.z < v2.v.z-WeldThresh); } //Is less then (generates a "hash" for sorting vertices by z for set static double WeldThresh; //weld threshold for importing from STL }; #endif //STL_FILE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/SimpleImage.h000066400000000000000000000035321231531733200253710ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef SIMPLEIMAGE_H #define SIMPLEIMAGE_H #include //enum IndexMode {IM_VBW}; class CSimpleImage { public: CSimpleImage(void); ~CSimpleImage(void); CSimpleImage(const CSimpleImage& In) {*this = In;} CSimpleImage& operator=(const CSimpleImage& In); bool LoadImage(std::string FilePath); int Width(void) {return DataWidth;} int Height(void) {return DataHeight;} bool AllocateRGBA(int WidthIn, int HeightIn); // bool IndexFromRGBA(IndexMode IndexModeIn); // bool IndexExists() {if (pDataIndex) return true; else return false;} bool HasAlphaChannel() {return AlphaPresent;} unsigned char* GetRGBABits(void) {return pDataRGBA;} // int* GetIndexBits(void) {return pDataIndex;} void Fill(unsigned char R, unsigned char G, unsigned char B, unsigned char A = 255); private: // IndexMode CurIndexMode; bool AlphaPresent; unsigned char* pDataRGBA; int DataWidth, DataHeight; // int* pDataIndex; // int PixelDataIndexWidth, PixelDataIndexHeight; }; #endif //SIMPLEIMAGE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/Vec3D.h000066400000000000000000000244711231531733200241060ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef _VEC3D_H #define _VEC3D_H //Possible Linux portability issues: min, max #define __isnand(x) std::isnan(x) #include #include class CQuat; class Vec3D { public: //Constructors Vec3D() {x = 0; y = 0; z = 0;} //Vec3D(const Vec3D& s) {x = s.x; y = s.y; z = s.z;} Vec3D(const Vec3D& Vec) {*this = Vec;} //copy constructor Vec3D(double dx, double dy, double dz) {x = dx; y = dy; z = dz;} inline Vec3D& operator=(const Vec3D& s) {x = s.x; y = s.y; z = s.z; return *this; }; //overload equals #ifdef WIN32 bool IsValid() const {return !_isnan(x) && _finite(x) && !_isnan(y) && _finite(y) && !_isnan(z) && _finite(z);} //is a valid vector? (funky windows _ versions...) #else bool IsValid() const {return !__isnand(x) && finite(x) && !__isnand(y) && finite(y) && !__isnand(z) && finite(z);} //is a valid vector? #endif bool IsNear(Vec3D& s, double thresh) {return Dist2(s) 0) {x /= l;y /= l;z /= l;} return l;} //normalizes this vector inline Vec3D Rot(Vec3D u, double a) {double ca = cos(a); double sa = sin(a); double t = 1-ca; return Vec3D((u.x*u.x*t + ca) * x + (u.x*u.y*t - u.z*sa) * y + (u.z*u.x*t + u.y*sa) * z, (u.x*u.y*t + u.z*sa) * x + (u.y*u.y*t+ca) * y + (u.y*u.z*t - u.x*sa) * z, (u.z*u.x*t - u.y*sa) * x + (u.y*u.z*t + u.x*sa) * y + (u.z*u.z*t + ca) * z);} //rotates by arbitrary vector arbitrary amount (http://www.cprogramming.com/tutorial/3d/rotation.html (Errors! LH one is actually RH one)) inline Vec3D Rot(CQuat& Q); //below CQuat for linking sake... void RotZ(double a) {double xt = x*cos(a) - y*sin(a); double yt = x*sin(a) + y*cos(a); x = xt; y = yt;} //rotates about Z axis "a" radians void RotY(double a) {double xt = x*cos(a) + z*sin(a); double zt = -x*sin(a) + z*cos(a); x = xt; z = zt;} //rotates about Y axis "a" radians void RotX(double a) {double yt = y*cos(a) + z*sin(a); double zt = -y*sin(a) + z*cos(a); y = yt; z = zt;} //rotates about X axis "a" radians //Vector operations (don't change this object!) inline Vec3D Cross(Vec3D& v) {return Vec3D(y*v.z-z*v.y,z*v.x-x*v.z,x*v.y-y*v.x);} //Cross product inline double Dot(Vec3D& v) {return (x * v.x + y * v.y + z * v.z);} //Dot product inline Vec3D Abs() {return Vec3D(fabs(x),fabs(y),fabs(z));} //Absolute value inline Vec3D Normalized() { double l = sqrt(x*x+y*y+z*z); return (l>0?(*this)/l:(*this));} //returns normalized vec inline Vec3D ProjXY() { return Vec3D(x,y,0);} //projection into the xy plane inline double Length() {return sqrt(x*x+y*y+z*z);} //length of the vector inline double Length2() {return (x*x+y*y+z*z);} //length squared of the vector inline Vec3D Min(const Vec3D& s) {return Vec3D(xs.x ? x:s.x, y>s.y ? y:s.y, z>s.z ? z:s.z);} //max vector of the two inline double Min() {double Min1 = (xy ? x:y); return (z>Max1 ? z:Max1);} //max element of this vector inline Vec3D Scale(const Vec3D& v) {return Vec3D(x*v.x, y*v.y, z*v.z);} //scales by another vector inline Vec3D ScaleInv(const Vec3D& v) {return Vec3D(x/v.x, y/v.y, z/v.z);} //scales by inverse of another vector inline double Dist(const Vec3D& v) {return sqrt(Dist2(v));} //distance from another vector inline double Dist2(const Vec3D& v) {return (v.x-x)*(v.x-x)+(v.y-y)*(v.y-y)+(v.z-z)*(v.z-z);} //distance from another vector inline double AlignWith(Vec3D target, Vec3D& rotax) {Vec3D thisvec = Normalized(); Vec3D targvec = target.Normalized(); Vec3D rotaxis = thisvec.Cross(targvec); if (rotaxis.Length2() == 0) {rotaxis=target.ArbitraryNormal();} rotax = rotaxis.Normalized(); return acos(thisvec.Dot(targvec));} //returns vector (rotax) and amount (return val) to align this vector with target vector inline Vec3D ArbitraryNormal() {Vec3D n = Normalized(); if (fabs(n.x) <= fabs(n.y) && fabs(n.x) <= fabs(n.z)){n.x = 1;} else if (fabs(n.y) <= fabs(n.x) && fabs(n.y) <= fabs(n.z)){n.y = 1;} else {n.z = 1;} return Cross(n).Normalized();} //generate arbitrary normal }; class CQuat // : public Vec3D //extending Vec3D saves us reimplementing some stuff, I think? this is not a comprehensive quaternion class at this point... { public: CQuat(void) {Clear();} ~CQuat(void){}; CQuat(double dw, double dx, double dy, double dz) {w=dw; x=dx; y=dy; z=dz;} //constructor CQuat(const CQuat& Quat) {*this = Quat;} //copy constructor CQuat(const Vec3D& VecIn) {w = 0; x = VecIn.x; y = VecIn.y; z = VecIn.z;} CQuat(double angle, const Vec3D &axis){Clear(); const double a = angle * 0.5f; const double s = sin(a); const double c = cos(a); w = c; x = axis.x * s; y = axis.y * s; z = axis.z * s;}; inline CQuat& operator=(const CQuat& s) {w = s.w; x = s.x; y = s.y; z = s.z; return *this; }; //overload equals inline void Clear() {w=1; x=0; y=0; z=0;} // for (int i=0; i<3; i++){for (int j=0; j<3; j++){M[i][j] = 0;iM[i][j] = 0;}}}; inline Vec3D ToVec(void) {return Vec3D(x, y, z);} //shouldnt be necessaty... should be able to just set equal... friend CQuat operator+(const CQuat& s1, const CQuat& s2) {return CQuat(s1.w+s2.w, s1.x+s2.x, s1.y+s2.y, s1.z+s2.z);} //Plus CQuat& operator+=(const CQuat& s) {w += s.w; x += s.x; y += s.y; z += s.z; return *this;} //add and set friend CQuat operator-(const CQuat& s1, const CQuat& s2) {return CQuat(s1.w-s2.w, s1.x-s2.x, s1.y-s2.y, s1.z-s2.z);} //Minus CQuat& operator-=(const CQuat& s) {w -= s.w; x -= s.x; y -= s.y; z -= s.z; return *this;} //subract and set inline CQuat operator*(double f) {return CQuat(w*f, x*f, y*f, z*f);}; //scalar multiplication friend CQuat operator*(double f, CQuat v) {return CQuat(v.w*f, v.x*f, v.y*f, v.z*f);}; inline CQuat operator*(const CQuat& f) {return CQuat(w*f.w - x*f.x - y*f.y - z*f.z, w*f.x + x*f.w + y*f.z - z*f.y, w*f.y - x*f.z + y*f.w + z*f.x, w*f.z + x*f.y - y*f.x + z*f.w);}; //overload Quaternion multiplication! operator Vec3D() {return Vec3D(x, y, z);}; inline double Length() {return sqrt(Length2());} //length of the vector inline double Length2() {return (w*w+x*x+y*y+z*z);} //length squared of the vector double Normalize(void) {double l = Length(); if (l == 0){w = 1; x = 0; y = 0; z = 0;} else if (l > 0) {w /= l; x /= l; y /= l; z /= l;} return l;}; CQuat Inverse(void) {double n = w*w + x*x + y*y + z*z; return CQuat(w/n, -x/n, -y/n, -z/n); }; CQuat Conjugate(void) {return CQuat(w, -x, -y, -z);}; double w, x, y, z; double M [3][3]; double iM [3][3]; void CalcMatrix(void) {M[0][0] = 1.0f-2.0f*(y*y+z*z); M[0][1] = 2.0f*(y*x-z*w); M[0][2] = 2.0f*(z*x+y*w); M[1][1] = 1.0f-2.0f*(x*x+z*z); M[1][2] = 2.0f*(z*y-x*w); M[2][2] = 1.0f-2.0f*(x*x+y*y); M[1][0] = M[0][1]; M[2][1] = M[1][2]; M[2][0] = M[0][2];}; void CalciMatrix(void) {double determinant = -M[0][2]*M[1][1]*M[2][0] + M[0][1]*M[1][2]*M[2][0] + M[0][2]*M[1][0]*M[2][1] - M[0][0]*M[1][2]*M[2][1] - M[0][1]*M[1][0]*M[2][2] + M[0][0]*M[1][1]*M[2][2]; double k = 1.0 / determinant; iM[0][0] = (M[1][1]*M[2][2] - M[2][1]*M[1][2])*k; iM[0][1] = (M[2][1]*M[0][2] - M[0][1]*M[2][2])*k; iM[0][2] = (M[0][1]*M[1][2] - M[1][1]*M[0][2])*k; iM[1][0] = (M[1][2]*M[2][0] - M[2][2]*M[1][0])*k; iM[1][1] = (M[2][2]*M[0][0] - M[0][2]*M[2][0])*k; iM[1][2] = (M[0][2]*M[1][0] - M[1][2]*M[0][0])*k; iM[2][0] = (M[1][0]*M[2][1] - M[2][0]*M[1][1])*k; iM[2][1] = (M[2][0]*M[0][1] - M[0][0]*M[2][1])*k; iM[2][2] = (M[0][0]*M[1][1] - M[1][0]*M[0][1])*k;}; void AngleAxis(double &angle, Vec3D &axis) {if (w>1.0) w = 1.0; double squareLength = x*x + y*y + z*z; if (squareLength>0.0000000000001){angle = 2.0f * (double) acos(w); double inverseLength = 1.0f / (double) pow(squareLength, 0.5); axis.x = x * inverseLength; axis.y = y * inverseLength; axis.z = z * inverseLength;} else{angle = 0.0f; axis.x = 1.0f; axis.y = 0.0f; axis.z = 0.0f;}}; }; inline Vec3D Vec3D::Rot(CQuat& Q){return (Q*CQuat(*this)*Q.Conjugate()).ToVec();} #endif //_VEC3D_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/X3D_File.h000066400000000000000000000127351231531733200245370ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef CX3D_FILE_H #define CX3D_FILE_H #include #include #include "SimpleImage.h" //#include //#include class CXmlStreamRead; class CX3D_File; enum X3dLoadResult {XLR_SUCCESS, XLR_BADFILEPATH, XLR_NOSHAPE, XLR_BADIMAGEPATH}; class xAppearanceNode { public: xAppearanceNode(void){Clear();} ~xAppearanceNode(void){}; xAppearanceNode& operator=(const xAppearanceNode& x) {ImageTexture=x.ImageTexture; MatColorRed=x.MatColorRed; MatColorGreen=x.MatColorGreen; MatColorBlue=x.MatColorBlue; repeatS=x.repeatS; repeatT=x.repeatT; return *this;} //overload equals xAppearanceNode(const xAppearanceNode& x) {*this = x;} void Clear() {repeatS = true; repeatT = true; MatColorRed = -1; MatColorGreen = -1; MatColorBlue = -1;} X3dLoadResult ReadXML(CXmlStreamRead* pXML, CX3D_File* pX3dFile, std::string* pRetMessage = NULL); CSimpleImage ImageTexture; // QImage ImageTexture; bool repeatS, repeatT; double MatColorRed; double MatColorGreen; double MatColorBlue; }; enum ColChan {CC_R=0, CC_G=1, CC_B=2, CC_A=3}; enum TexCoordAxis {TCA_S=0, TCA_T=1}; enum XYZAxis {AX_X=0, AX_Y=1, AX_Z=2}; class xIndexedFaceSetNode { public: xIndexedFaceSetNode(void){Clear();} ~xIndexedFaceSetNode(void){}; xIndexedFaceSetNode& operator=(const xIndexedFaceSetNode& x); //overload equals xIndexedFaceSetNode(const xIndexedFaceSetNode& x) {*this = x;} void Clear(); X3dLoadResult ReadXML(CXmlStreamRead* pXML, std::string* pRetMessage = NULL); std::string CoordDef; //the name of this particular coordinate set std::string CoordUse; //another coordinate set to use std::vector coordIndex; std::vector Coordinate; std::vector texCoordIndex; std::vector TextureCoordinate; bool colorPerVertex; std::vector colorIndex; std::vector Color; std::vector ColorRGBA; //information to load x3d! bool FillDerivedInfo(); //fills in these calculated other parameters for easy access later. int NumVertPerFacet; //triangles or quads? bool Colors; bool ColByIndex; bool HasAlpha; bool HasTexture; int GetNumTriangles(); //returns 2x number of quads if x3d has quads... int GetNumCoords(){return Coordinate.size()/3;} //return number of points (coords) int GetCoordInd(int TriNum, int VertNum); //VertNum is 0, 1, or 2 inline double GetCoord(int CoordNum, XYZAxis Axis) {return Coordinate[CoordNum*3+(int)Axis];} double GetColorFace(int TriNum, ColChan Chan); //triangle color (make sure Color && !colorPerVertex and HasAlpha if requesting alpha) double GetColorVert(int CoordNum, ColChan Chan); //vertex color (make sure Color && colorPerVertex and HasAlpha if requesting alpha) double GetColorVert(int TriNum, int VertNum, ColChan Chan); //vertex color (make sure Color && colorPerVertex and Hasplpha if requesting alpha) int GetTexCoordInd(int TriNum, int VertNum); inline double GetTexCoord(int TriNum, int VertNum, TexCoordAxis Axis){ return TextureCoordinate[GetTexCoordInd(TriNum, VertNum)*2+(int)Axis];} }; class xShapeNode { public: xShapeNode(void) {Clear();}; ~xShapeNode(void) {}; xShapeNode& operator=(const xShapeNode& x) {xAppearance=x.xAppearance; xIndexedFaceSet=x.xIndexedFaceSet; return *this;} //overload equals xShapeNode(const xShapeNode& x) {*this = x;} void Clear() {xAppearance.Clear(); xIndexedFaceSet.Clear();} X3dLoadResult ReadXML(CXmlStreamRead* pXML, CX3D_File* pX3dFile, std::string* pRetMessage = NULL); xAppearanceNode xAppearance; xIndexedFaceSetNode xIndexedFaceSet; bool IsIndexedFaceSet(void) {return !(xIndexedFaceSet.Coordinate.size() == 0 && xIndexedFaceSet.coordIndex.size() == 0);} }; class CX3D_File { public: CX3D_File(void); ~CX3D_File(void); CX3D_File& operator=(const CX3D_File& x) {xShapes=x.xShapes; filePath=x.filePath; ImagePath=x.ImagePath; errors=x.errors; return *this;} //overload equals CX3D_File(const CX3D_File& x) {*this = x;} void Clear() {xShapes.clear(); filePath=""; ImagePath=""; errors=""; IsLoaded=false;} std::vector xShapes; std::string filePath, ImagePath, errors; bool IsLoaded; X3dLoadResult Load(std::string filename, std::string ImgPathIn = ""); void GetMinMax(double& minX, double& minY, double& minZ, double& maxX, double& maxY, double& maxZ); void GetSize(double& sizeX, double& sizeY, double& sizeZ); static void Str2Data(std::string* pS, std::vector* pD); // {std::stringstream ss(*pS); int i; while (ss >> i){pD->push_back(i);}} static void Str2Data(std::string* pS, std::vector* pD); // {std::stringstream ss(*pS); double i; while (ss >> i){pD->push_back(i);}} }; #endif //CX3D_FILE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/XmlCompress.h000066400000000000000000000033551231531733200254540ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef CXMLCOMPRESS_H #define CXMLCOMPRESS_H #include #include //enum CompressType{COMP_ZIP}; bool CompressFile(std::string ZipName, std::string FilePath, std::string* pError = NULL); //filepath string to zip into location of ZipName (also a filepath) bool CompressFiles(std::string ZipName, std::vector* pFilePaths, std::string* pError = NULL); //pointer to a vector of filepath strings to zip into location of ZipName (also a filepath) bool GetCompressedFile(std::string ZipName, std::string FileName, std::vector *data, std::string* pError = NULL); bool GetCompressedFiles(std::string ZipName, std::vector* pFileNames, std::vector >* data, std::string* pError = NULL); bool UncompressAllFiles(std::string ZipName, std::vector* pFileNames, std::vector >* data, std::string* pError = NULL); #endif //CXMLCOMPRESS_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/XmlStream.h000066400000000000000000000216041231531733200251110ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef CXMLSTREAM_H #define CXMLSTREAM_H #include "rapidxml/rapidxml.h" #include #include #include static const char Ind[49] = " "; //maximum indent: 24 levels of nesting... //for quick run-through xml encoding //Code by Jonathan Hiller. jdh74@cornell.edu //turn off case-sensitivity...? //CDATA handling for all read strings... class CXmlStreamRead { public: CXmlStreamRead(); //std::string FilePathToRead); ~CXmlStreamRead(void); //for loading rapidxml::xml_document<> doc; std::vector *> ElStack; std::vector StrStack; //used on loading to keep track of which tags were last looked for std::vector data; //buffer for reading/writing that won't go out of scope. // std::string filename; std::string tmp; //temporary string (to avoid creating a bunch of these...) rapidxml::xml_attribute<>* pTmpAtt; rapidxml::xml_node<>* pTmpNode; bool LoadFile(std::string filename); std::string LastError; //last error encountered in the loading process... std::string LastTagSearched; //keep track of which tag we last looks for. if new query same as last, look for siblings. bool OpenElement(std::string tag, bool RepeatingTag = false); //Find a child node. Subsequent calls will find children of this node with the same name. if RepeatingTag=true, calling repeatedly until it returns false will automatically close the last element it found. void CloseElement(void); //call to return to parent element level //looks for and (if finds) loads entire element with the provided tag bool GetElementS(std::string tag, std::string* pStringReturn, bool RepeatingTag = false); inline bool GetElementD(std::string tag, double* pDoubleReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pDoubleReturn = atof(tmp.c_str()); return true;} return false;} inline bool GetElementF(std::string tag, float* pFloatReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pFloatReturn = (float)atof(tmp.c_str()); return true;}return false;} inline bool GetElementI(std::string tag, int* pIntReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pIntReturn = atoi(tmp.c_str()); return true;} return false;} inline bool GetElementB(std::string tag, bool* pBoolReturn, bool RepeatingTag = false) {int tmpInt; if (!GetElementI(tag, &tmpInt, RepeatingTag)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;} //looks for and (if finds) loads attributes of the open element //CDATA!!! bool GetElAttS(std::string Att, std::string* pStringReturn);/* { *pStringReturn = std::string(ElStack.back()->first_attribute(Att.c_str(), 0, false)->value()); return ("" == (*pStringReturn))?false:true; }*/ inline bool GetElAttD(std::string Att, double* pDoubleReturn) {if (!GetElAttS(Att, &tmp)) return false; *pDoubleReturn = atof(tmp.c_str()); return true;} inline bool GetElAttF(std::string Att, float* pFloatReturn) {if (!GetElAttS(Att, &tmp)) return false; *pFloatReturn = (float)atof(tmp.c_str()); return true;} inline bool GetElAttI(std::string Att, int* pIntReturn) {if(!GetElAttS(Att, &tmp)) return false; *pIntReturn = atoi(tmp.c_str()); return true;} inline bool GetElAttB(std::string Att, bool* pBoolReturn) {int tmpInt; if (!GetElAttI(Att, &tmpInt)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;} //looks for and (if finds) loads attributes of the open element bool GetElDataS(std::string* pStringReturn); // {*pStringReturn = std::string(ElStack.back()->first_node()->value()); return (*pStringReturn == "")?false:true;} inline bool GetElDataD(double* pDoubleReturn) {if (!GetElDataS(&tmp)) return false; *pDoubleReturn = atof(tmp.c_str()); return true;} inline bool GetElDataF(float* pFloatReturn) {if (!GetElDataS(&tmp)) return false; *pFloatReturn = (float)atof(tmp.c_str()); return true;} inline bool GetElDataI(int* pIntReturn) {if(!GetElDataS(&tmp)) return false; *pIntReturn = atoi(tmp.c_str()); return true;} inline bool GetElDataB(bool* pBoolReturn) {int tmpInt; if (!GetElDataI(&tmpInt)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;} }; class CXmlStreamWrite { //todo: enforce open/closing of tags at CloseElement() and Save() //seperate opening of file to kick back error if no file was created... //anytowrite can be changes to "needendtag/line, string removed... public: CXmlStreamWrite(); //opens the file for writing ~CXmlStreamWrite(void) {}; bool BeginXmlFile(std::string FilePathToWrite, bool Compressed = false); bool EndXmlFile(); int CurIndent; //for formatting... FILE* fp; std::string filename; std::string LastError; //last error encountered in the loading process... bool AnyToWrite; bool IndentNextClose; std::string ToWrite; //Buffer to hold closing parts of tags until next tag opened (mostly to allow for writting of attributes) std::vector StrStack; //used on loading to keep track of which tags were last looked for void OpenElement(std::string tag); void CloseElement(void); //should be only called directly after OpenElement()! inline void SetElAttS(std::string Att, std::string Value) {if(fp) fprintf(fp," %s=\"%s\"", Att.c_str(), Value.c_str());} //adds an attribute to the current element in the stack inline void SetElAttD(std::string Att, double Value) {if(fp) fprintf(fp," %s=\"%g\"", Att.c_str(), Value);} inline void SetElAttF(std::string Att, float Value) {if(fp) fprintf(fp," %s=\"%g\"", Att.c_str(), Value);} inline void SetElAttI(std::string Att, int Value) {if(fp) fprintf(fp," %s=\"%d\"", Att.c_str(), Value);} inline void SetElAttB(std::string Att, bool Value) { if(fp) { if(Value) fprintf(fp," %s=\"1\"", Att.c_str()); else fprintf(fp," %s=\"0\"", Att.c_str()); } } //should be only called directly after OpenElement() and any SetElAttribute()'s! Must be followed directly by CloseElement()! inline void SetElDataS(std::string Value, bool CDATA = false) {if(fp){if (CDATA) fprintf(fp,">", Value.c_str()); else fprintf(fp,">%s", Value.c_str()); AnyToWrite = false; IndentNextClose = false;}} inline void SetElDataD(double Value) {if(fp){ fprintf(fp,">%g", Value); AnyToWrite = false; IndentNextClose = false;}} inline void SetElDataF(float Value) {if(fp){ fprintf(fp,">%g", Value);AnyToWrite = false; IndentNextClose = false;}} inline void SetElDataI(int Value) {if(fp){ fprintf(fp,">%d", Value); AnyToWrite = false; IndentNextClose = false;}} inline void SetElDataB(bool Value) {if(fp){if(Value) fprintf(fp,">1"); else fprintf(fp,">0"); AnyToWrite = false; IndentNextClose = false;}} //writes a complete Data element inline void SetElementS(std::string tag, std::string Value, bool CDATA = false) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); if (CDATA) fprintf(fp,"<%s>\n", tag.c_str(), Value.c_str(), tag.c_str()); else fprintf(fp,"<%s>%s\n", tag.c_str(), Value.c_str(), tag.c_str()); AnyToWrite = false;}} inline void SetElementD(std::string tag, double Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%g\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}} inline void SetElementF(std::string tag, float Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%g\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}} inline void SetElementI(std::string tag, int Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%d\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}} inline void SetElementB(std::string tag, bool Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); if (Value) fprintf(fp,"<%s>1\n", tag.c_str(), tag.c_str()); else fprintf(fp,"<%s>0\n", tag.c_str(), tag.c_str()); AnyToWrite = false;}} protected: bool WantCompressed; }; #endif //CXMLSTREAM_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/000077500000000000000000000000001231531733200246575ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParser.h000066400000000000000000000102621231531733200266270ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_H #define MU_PARSER_H //--- Standard includes ------------------------------------------------------------------------ #include //--- Parser includes -------------------------------------------------------------------------- #include "muParserBase.h" /** \file \brief Definition of the standard floating point parser. */ namespace mu { /** \brief Mathematical expressions parser. Standard implementation of the mathematical expressions parser. Can be used as a reference implementation for subclassing the parser. (C) 2011 Ingo Berg
muparser(at)gmx.de
*/ class Parser : public ParserBase { public: Parser(); virtual void InitCharSets(); virtual void InitFun(); virtual void InitConst(); virtual void InitOprt(); virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); value_type Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const; protected: // Trigonometric functions static value_type Sin(value_type); static value_type Cos(value_type); static value_type Tan(value_type); // arcus functions static value_type ASin(value_type); static value_type ACos(value_type); static value_type ATan(value_type); // hyperbolic functions static value_type Sinh(value_type); static value_type Cosh(value_type); static value_type Tanh(value_type); // arcus hyperbolic functions static value_type ASinh(value_type); static value_type ACosh(value_type); static value_type ATanh(value_type); // Logarithm functions static value_type Log2(value_type); // Logarithm Base 2 static value_type Log10(value_type); // Logarithm Base 10 static value_type Ln(value_type); // Logarithm Base e (natural logarithm) // misc static value_type Exp(value_type); static value_type Abs(value_type); static value_type Sqrt(value_type); static value_type Rint(value_type); static value_type Sign(value_type); // Prefix operators // !!! Unary Minus is a MUST if you want to use negative signs !!! static value_type UnaryMinus(value_type); // Functions with variable number of arguments static value_type Sum(const value_type*, int); // sum static value_type Avg(const value_type*, int); // mean value static value_type Min(const value_type*, int); // minimum static value_type Max(const value_type*, int); // maximum static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal); }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserBase.h000066400000000000000000000300121231531733200274150ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BASE_H #define MU_PARSER_BASE_H //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include //--- Parser includes -------------------------------------------------------------------------- #include "muParserDef.h" #include "muParserStack.h" #include "muParserTokenReader.h" #include "muParserBytecode.h" #include "muParserError.h" namespace mu { /** \file \brief This file contains the class definition of the muparser engine. */ //-------------------------------------------------------------------------------------------------- /** \brief Mathematical expressions parser (base parser engine). \author (C) 2011 Ingo Berg This is the implementation of a bytecode based mathematical expressions parser. The formula will be parsed from string and converted into a bytecode. Future calculations will be done with the bytecode instead the formula string resulting in a significant performance increase. Complementary to a set of internally implemented functions the parser is able to handle user defined functions and variables. */ class ParserBase { friend class ParserTokenReader; private: /** \brief Typedef for the parse functions. The parse function do the actual work. The parser exchanges the function pointer to the parser function depending on which state it is in. (i.e. bytecode parser vs. string parser) */ typedef value_type (ParserBase::*ParseFunction)() const; /** \brief Type used for storing an array of values. */ typedef std::vector valbuf_type; /** \brief Type for a vector of strings. */ typedef std::vector stringbuf_type; /** \brief Typedef for the token reader. */ typedef ParserTokenReader token_reader_type; /** \brief Type used for parser tokens. */ typedef ParserToken token_type; /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ static const int s_MaxNumOpenMPThreads = 4; public: /** \brief Type of the error class. Included for backwards compatibility. */ typedef ParserError exception_type; static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); ParserBase(); ParserBase(const ParserBase &a_Parser); ParserBase& operator=(const ParserBase &a_Parser); virtual ~ParserBase(); value_type Eval() const; value_type* Eval(int &nStackSize) const; void Eval(value_type *results, int nBulkSize); int GetNumResults() const; void SetExpr(const string_type &a_sExpr); void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); void SetDecSep(char_type cDecSep); void SetThousandsSep(char_type cThousandsSep = 0); void ResetLocale(); void EnableOptimizer(bool a_bIsOn=true); void EnableBuiltInOprt(bool a_bIsOn=true); bool HasBuiltInOprt() const; void AddValIdent(identfun_type a_pCallback); /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) \brief Define a parser function without arguments. \param a_strName Name of the function \param a_pFun Pointer to the callback function \param a_bAllowOpt A flag indicating this function may be optimized */ template void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true) { AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() ); } void DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); void DefineConst(const string_type &a_sName, value_type a_fVal); void DefineStrConst(const string_type &a_sName, const string_type &a_strVal); void DefineVar(const string_type &a_sName, value_type *a_fVar); void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true); // Clear user defined variables, constants or functions void ClearVar(); void ClearFun(); void ClearConst(); void ClearInfixOprt(); void ClearPostfixOprt(); void ClearOprt(); void RemoveVar(const string_type &a_strVarName); const varmap_type& GetUsedVar() const; const varmap_type& GetVar() const; const valmap_type& GetConst() const; const string_type& GetExpr() const; const funmap_type& GetFunDef() const; string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; const char_type ** GetOprtDef() const; void DefineNameChars(const char_type *a_szCharset); void DefineOprtChars(const char_type *a_szCharset); void DefineInfixOprtChars(const char_type *a_szCharset); const char_type* ValidNameChars() const; const char_type* ValidOprtChars() const; const char_type* ValidInfixOprtChars() const; void SetArgSep(char_type cArgSep); char_type GetArgSep() const; void Error(EErrorCodes a_iErrc, int a_iPos = (int)mu::string_type::npos, const string_type &a_strTok = string_type() ) const; protected: void Init(); virtual void InitCharSets() = 0; virtual void InitFun() = 0; virtual void InitConst() = 0; virtual void InitOprt() = 0; virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); static const char_type *c_DefaultOprt[]; static std::locale s_locale; ///< The locale used by the parser static bool g_DbgDumpCmdCode; static bool g_DbgDumpStack; /** \brief A facet class used to change decimal and thousands separator. */ template class change_dec_sep : public std::numpunct { public: explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() ,m_cDecPoint(cDecSep) ,m_cThousandsSep(cThousandsSep) ,m_nGroup(nGroup) {} protected: virtual char_type do_decimal_point() const { return m_cDecPoint; } virtual char_type do_thousands_sep() const { return m_cThousandsSep; } virtual std::string do_grouping() const { return std::string(1, m_nGroup); } private: int m_nGroup; char_type m_cDecPoint; char_type m_cThousandsSep; }; private: static value_type Pow(value_type v1, value_type v2); void Assign(const ParserBase &a_Parser); void InitTokenReader(); void ReInit() const; void AddCallback( const string_type &a_strName, const ParserCallback &a_Callback, funmap_type &a_Storage, const char_type *a_szCharSet ); void ApplyRemainingOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyBinOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyIfElse(ParserStack &a_stOpt, ParserStack &a_stVal) const; void ApplyFunc(ParserStack &a_stOpt, ParserStack &a_stVal, int iArgCount) const; token_type ApplyNumFunc(const token_type &a_FunTok, const std::vector &a_vArg) const; token_type ApplyBulkFunc(const token_type &a_FunTok, const std::vector &a_vArg) const; token_type ApplyStrFunc(const token_type &a_FunTok, const std::vector &a_vArg) const; int GetOprtPrecedence(const token_type &a_Tok) const; EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; void CreateRPN() const; value_type ParseString() const; value_type ParseCmdCode() const; value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const; void CheckName(const string_type &a_strName, const string_type &a_CharSet) const; void CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback, const string_type &a_szCharSet) const; void StackDump(const ParserStack &a_stVal, const ParserStack &a_stOprt) const; /** \brief Pointer to the parser function. Eval() calls the function whose address is stored there. */ mutable ParseFunction m_pParseFormula; mutable const SToken *m_pRPN; mutable ParserByteCode m_vRPN; ///< The Bytecode class. mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments stringbuf_type m_vStringVarBuf; std::auto_ptr m_pTokenReader; ///< Managed pointer to the token reader object. funmap_type m_FunDef; ///< Map of function names and pointers. funmap_type m_PostOprtDef; ///< Postfix operator callbacks funmap_type m_InfixOprtDef; ///< unary infix operator. funmap_type m_OprtDef; ///< Binary operator callbacks valmap_type m_ConstDef; ///< user constants. strmap_type m_StrVarDef; ///< user defined string constants varmap_type m_VarDef; ///< user defind variables. bool m_bOptimize; ///< Flag that indicates if the optimizer is on or off. bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off string_type m_sNameChars; ///< Charset for names string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens string_type m_sInfixOprtChars; ///< Charset for infix operator tokens mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses // items merely used for caching state information mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine mutable int m_nFinalResultIdx; }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserBytecode.h000066400000000000000000000077441231531733200303210ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_BYTECODE_H #define MU_PARSER_BYTECODE_H #include #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" /** \file \brief Definition of the parser bytecode class. */ namespace mu { struct SToken { ECmdCode Cmd; int StackPos; union { union //SValData { value_type *ptr; value_type data; } Val; struct //SFunData { void* ptr; int argc; int idx; } Fun; struct //SOprtData { value_type *ptr; int offset; } Oprt; }; }; /** \brief Bytecode implementation of the Math Parser. The bytecode contains the formula converted to revers polish notation stored in a continious memory area. Associated with this data are operator codes, variable pointers, constant values and function pointers. Those are necessary in order to calculate the result. All those data items will be casted to the underlying datatype of the bytecode. \author (C) 2004-2011 Ingo Berg */ class ParserByteCode { private: /** \brief Token type for internal use only. */ typedef ParserToken token_type; /** \brief Token vector for storing the RPN. */ typedef std::vector rpn_type; /** \brief Position in the Calculation array. */ unsigned m_iStackPos; /** \brief Maximum size needed for the stack. */ std::size_t m_iMaxStackSize; /** \brief The actual rpn storage. */ rpn_type m_vRPN; public: ParserByteCode(); ParserByteCode(const ParserByteCode &a_ByteCode); ParserByteCode& operator=(const ParserByteCode &a_ByteCode); void Assign(const ParserByteCode &a_ByteCode); void AddVar(value_type *a_pVar); void AddVal(value_type a_fVal); void AddOp(ECmdCode a_Oprt); void AddIfElse(ECmdCode a_Oprt); void AddAssignOp(value_type *a_pVar); void AddFun(void *a_pFun, int a_iArgc); void AddBulkFun(void *a_pFun, int a_iArgc); void AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx); void Finalize(); void clear(); std::size_t GetMaxStackSize() const; const SToken* GetBase() const; //rpn_type Clone() const //{ // return rpn_type(m_vRPN); //} void RemoveValEntries(unsigned a_iNumber); void AsciiDump(); }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserCallback.h000066400000000000000000000122561231531733200302510ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_CALLBACK_H #define MU_PARSER_CALLBACK_H #include "muParserDef.h" /** \file \brief Definition of the parser callback class. */ namespace mu { /** \brief Encapsulation of prototypes for a numerical parser function. Encapsulates the prototyp for numerical parser functions. The class stores the number of arguments for parser functions as well as additional flags indication the function is non optimizeable. The pointer to the callback function pointer is stored as void* and needs to be casted according to the argument count. Negative argument counts indicate a parser function with a variable number of arguments. \author (C) 2004-2011 Ingo Berg */ class ParserCallback { public: ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti); ParserCallback(multfun_type a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); ParserCallback(); ParserCallback(const ParserCallback &a_Fun); ParserCallback* Clone() const; bool IsOptimizable() const; void* GetAddr() const; ECmdCode GetCode() const; ETypeCode GetType() const; int GetPri() const; EOprtAssociativity GetAssociativity() const; int GetArgc() const; private: void *m_pFun; ///< Pointer to the callback function, casted to void /** \brief Number of numeric function arguments This number is negative for functions with variable number of arguments. in this cases they represent the actual number of arguments found. */ int m_iArgc; int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators ECmdCode m_iCode; ETypeCode m_iType; bool m_bAllowOpti; ///< Flag indication optimizeability }; //------------------------------------------------------------------------------ /** \brief Container for Callback objects. */ typedef std::map funmap_type; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserDef.h000066400000000000000000000340011231531733200272430ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MUP_DEF_H #define MUP_DEF_H #include #include #include #include #include "muParserFixes.h" /** \file \brief This file contains standard definitions used by the parser. */ #define MUP_VERSION _T("2.0.0") #define MUP_VERSION_DATE _T("20110803; SF-SVN") #define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") /** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */ //#define MUP_MATH_EXCEPTIONS /** \brief Define the base datatype for values. This datatype must be a built in value type. You can not use custom classes. It has been tested with float, double and long double types, int should work as well. */ #define MUP_BASETYPE double /** \brief Activate this option in order to compile with OpenMP support. OpenMP is used only in the bulk mode it may increase the performance a bit. */ //#define MUP_USE_OPENMP #if defined(_UNICODE) /** \brief Definition of the basic parser string type. */ #define MUP_STRING_TYPE std::wstring #if !defined(_T) #define _T(x) L##x #endif // not defined _T #else #ifndef _T #define _T(x) x #endif /** \brief Definition of the basic parser string type. */ #define MUP_STRING_TYPE std::string #endif #if defined(_DEBUG) /** \brief Debug macro to force an abortion of the programm with a certain message. */ #define MUP_FAIL(MSG) \ bool MSG=false; \ assert(MSG); /** \brief An assertion that does not kill the program. This macro is neutralised in UNICODE builds. It's too difficult to translate. */ #define MUP_ASSERT(COND) \ if (!(COND)) \ { \ stringstream_type ss; \ ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ << __FILE__ << _T(" line ") \ << __LINE__ << _T("."); \ throw ParserError( ss.str() ); \ } #else #define MUP_FAIL(MSG) #define MUP_ASSERT(COND) #endif namespace mu { #if defined(_UNICODE) //------------------------------------------------------------------------------ /** \brief Encapsulate wcout. */ inline std::wostream& console() { return std::wcout; } /** \brief Encapsulate cin. */ inline std::wistream& console_in() { return std::wcin; } #else /** \brief Encapsulate cout. Used for supporting UNICODE more easily. */ inline std::ostream& console() { return std::cout; } /** \brief Encapsulate cin. Used for supporting UNICODE more easily. */ inline std::istream& console_in() { return std::cin; } #endif //------------------------------------------------------------------------------ /** \brief Bytecode values. \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! */ enum ECmdCode { // The following are codes for built in binary operators // apart from built in operators the user has the opportunity to // add user defined operators. cmLE = 0, ///< Operator item: less or equal cmGE = 1, ///< Operator item: greater or equal cmNEQ = 2, ///< Operator item: not equal cmEQ = 3, ///< Operator item: equals cmLT = 4, ///< Operator item: less than cmGT = 5, ///< Operator item: greater than cmADD = 6, ///< Operator item: add cmSUB = 7, ///< Operator item: subtract cmMUL = 8, ///< Operator item: multiply cmDIV = 9, ///< Operator item: division cmPOW = 10, ///< Operator item: y to the power of ... cmLAND = 11, cmLOR = 12, cmASSIGN = 13, ///< Operator item: Assignment operator cmBO = 14, ///< Operator item: opening bracket cmBC = 15, ///< Operator item: closing bracket cmIF = 16, ///< For use in the ternary if-then-else operator cmELSE = 17, ///< For use in the ternary if-then-else operator cmENDIF = 18, ///< For use in the ternary if-then-else operator cmARG_SEP, ///< function argument separator cmVAR, ///< variable item cmVAL, ///< value item cmFUNC, ///< Code for a function item cmFUNC_STR, ///< Code for a function with a string parameter cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index cmSTRING, ///< Code for a string token cmOPRT_BIN, ///< user defined binary operator cmOPRT_POSTFIX, ///< code for postfix operators cmOPRT_INFIX, ///< code for infix operators cmEND, ///< end of formula cmUNKNOWN ///< uninitialized item }; //------------------------------------------------------------------------------ /** \brief Types internally used by the parser. */ enum ETypeCode { tpSTR = 0, ///< String type (Function arguments and constants only, no string variables) tpDBL = 1, ///< Floating point variables tpVOID = 2 ///< Undefined type. }; //------------------------------------------------------------------------------ enum EParserVersionInfo { pviBRIEF, pviFULL }; //------------------------------------------------------------------------------ /** \brief Parser operator precedence values. */ enum EOprtAssociativity { oaLEFT = 0, oaRIGHT = 1, oaNONE = 2 }; //------------------------------------------------------------------------------ /** \brief Parser operator precedence values. */ enum EOprtPrecedence { // binary operators prLOR = 1, prLAND = 2, prLOGIC = 3, ///< logic operators prCMP = 4, ///< comparsion operators prADD_SUB = 5, ///< addition prMUL_DIV = 6, ///< multiplication/division prPOW = 7, ///< power operator priority (highest) // infix operators prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator prPOSTFIX = 6 ///< Postfix operator priority (currently unused) }; //------------------------------------------------------------------------------ // basic types /** \brief The numeric datatype used by the parser. Normally this is a floating point type either single or double precision. */ typedef MUP_BASETYPE value_type; /** \brief The stringtype used by the parser. Depends on wether UNICODE is used or not. */ typedef MUP_STRING_TYPE string_type; /** \brief The character type used by the parser. Depends on wether UNICODE is used or not. */ typedef string_type::value_type char_type; /** \brief Typedef for easily using stringstream that respect the parser stringtype. */ typedef std::basic_stringstream, std::allocator > stringstream_type; // Data container types /** \brief Type used for storing variables. */ typedef std::map varmap_type; /** \brief Type used for storing constants. */ typedef std::map valmap_type; /** \brief Type for assigning a string name to an index in the internal string table. */ typedef std::map strmap_type; // Parser callbacks /** \brief Callback type used for functions without arguments. */ typedef value_type (*fun_type0)(); /** \brief Callback type used for functions with a single arguments. */ typedef value_type (*fun_type1)(value_type); /** \brief Callback type used for functions with two arguments. */ typedef value_type (*fun_type2)(value_type, value_type); /** \brief Callback type used for functions with three arguments. */ typedef value_type (*fun_type3)(value_type, value_type, value_type); /** \brief Callback type used for functions with four arguments. */ typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions without arguments. */ typedef value_type (*bulkfun_type0)(int, int); /** \brief Callback type used for functions with a single arguments. */ typedef value_type (*bulkfun_type1)(int, int, value_type); /** \brief Callback type used for functions with two arguments. */ typedef value_type (*bulkfun_type2)(int, int, value_type, value_type); /** \brief Callback type used for functions with three arguments. */ typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type); /** \brief Callback type used for functions with four arguments. */ typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with a variable argument list. */ typedef value_type (*multfun_type)(const value_type*, int); /** \brief Callback type used for functions taking a string as an argument. */ typedef value_type (*strfun_type1)(const char_type*); /** \brief Callback type used for functions taking a string and a value as arguments. */ typedef value_type (*strfun_type2)(const char_type*, value_type); /** \brief Callback type used for functions taking a string and two values as arguments. */ typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); /** \brief Callback used for functions that identify values in a string. */ typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal); /** \brief Callback used for variable creation factory functions. */ typedef value_type* (*facfun_type)(const char_type*, void*); } // end fo namespace #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserError.h000066400000000000000000000164301231531733200276440ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_ERROR_H #define MU_PARSER_ERROR_H #include #include #include #include #include #include #include "muParserDef.h" /** \file \brief This file defines the error class used by the parser. */ namespace mu { /** \brief Error codes. */ enum EErrorCodes { // Formula syntax errors ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") ecTOO_MANY_PARAMS = 14, ///< Too many function parameters ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type ecSTR_RESULT = 17, ///< result is a string // Invalid Parser input Parameters ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer ecEMPTY_EXPRESSION = 25, ///< The Expression is empty ecNAME_CONFLICT = 26, ///< Name conflict ecOPT_PRI = 27, ///< Invalid operator priority // ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) ecGENERIC = 30, ///< Generic error ecLOCALE = 31, ///< Conflict with current locale ecUNEXPECTED_CONDITIONAL = 32, ecMISSING_ELSE_CLAUSE = 33, ecMISPLACED_COLON = 34, // internal errors ecINTERNAL_ERROR = 35, ///< Internal error of any kind. // The last two are special entries ecCOUNT, ///< This is no error code, It just stores just the total number of error codes ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages }; //--------------------------------------------------------------------------- /** \brief A class that handles the error messages. */ class ParserErrorMsg { public: typedef ParserErrorMsg self_type; ParserErrorMsg& operator=(const ParserErrorMsg &); ParserErrorMsg(const ParserErrorMsg&); ParserErrorMsg(); ~ParserErrorMsg(); static const ParserErrorMsg& Instance(); string_type operator[](unsigned a_iIdx) const; private: std::vector m_vErrMsg; ///< A vector with the predefined error messages static const self_type m_Instance; ///< The instance pointer }; //--------------------------------------------------------------------------- /** \brief Error class of the parser. \author Ingo Berg Part of the math parser package. */ class ParserError { private: /** \brief Replace all ocuurences of a substring with another string. */ void ReplaceSubString( string_type &strSource, const string_type &strFind, const string_type &strReplaceWith); void Reset(); public: ParserError(); explicit ParserError(EErrorCodes a_iErrc); explicit ParserError(const string_type &sMsg); ParserError( EErrorCodes a_iErrc, const string_type &sTok, const string_type &sFormula = string_type(_T("(formula is not available)")), int a_iPos = -1); ParserError( EErrorCodes a_iErrc, int a_iPos, const string_type &sTok); ParserError( const char_type *a_szMsg, int a_iPos = -1, const string_type &sTok = string_type()); ParserError(const ParserError &a_Obj); ParserError& operator=(const ParserError &a_Obj); ~ParserError(); void SetFormula(const string_type &a_strFormula); const string_type& GetExpr() const; const string_type& GetMsg() const; std::size_t GetPos() const; const string_type& GetToken() const; EErrorCodes GetCode() const; private: string_type m_strMsg; ///< The message string string_type m_strFormula; ///< Formula string string_type m_strTok; ///< Token related with the error int m_iPos; ///< Formula position related to the error EErrorCodes m_iErrc; ///< Error code const ParserErrorMsg &m_ErrMsg; }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserFixes.h000066400000000000000000000143711231531733200276330ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_FIXES_H #define MU_PARSER_FIXES_H /** \file \brief This file contains compatibility fixes for some platforms. */ // // Compatibility fixes // //--------------------------------------------------------------------------- // // Intel Compiler // //--------------------------------------------------------------------------- #ifdef __INTEL_COMPILER // remark #981: operands are evaluated in unspecified order // disabled -> completely pointless if the functions do not have side effects // #pragma warning(disable:981) // remark #383: value copied to temporary, reference to temporary used #pragma warning(disable:383) // remark #1572: floating-point equality and inequality comparisons are unreliable // disabled -> everyone knows it, the parser passes this problem // deliberately to the user #pragma warning(disable:1572) #endif //--------------------------------------------------------------------------- // // MSVC6 // //--------------------------------------------------------------------------- #if defined(_MSC_VER) && _MSC_VER==1200 /** \brief Macro to replace the MSVC6 auto_ptr with the _my_auto_ptr class. Hijack auto_ptr and replace it with a version that actually does what an auto_ptr normally does. If you use std::auto_ptr in your other code might either explode or work much better. The original crap created by Microsoft, called auto_ptr and bundled with MSVC6 is not standard compliant. */ #define auto_ptr _my_auto_ptr // This is another stupidity that needs to be undone in order to de-pollute // the global namespace! #undef min #undef max namespace std { typedef ::size_t size_t; //--------------------------------------------------------------------------- /** \brief MSVC6 fix: Dummy function to put rand into namespace std. This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided inlining is enabled. Necessary because I will not pollute or change my code in order to adopt it to MSVC6 interpretation of how C++ should look like! */ inline int rand(void) { return ::rand(); } //--------------------------------------------------------------------------- /** \brief MSVC6 fix: Dummy function to put strlen into namespace std. This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided inlining is enabled. Necessary because I will not pollute or change my code in order to adopt it to MSVC6 interpretation of how C++ should look like! */ inline size_t strlen(const char *szMsg) { return ::strlen(szMsg); } //--------------------------------------------------------------------------- /** \brief MSVC6 fix: Dummy function to put strncmp into namespace std. This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided inlining is enabled. Necessary because I will not pollute or change my code in order to adopt it to MSVC6 interpretation of how C++ should look like! */ inline int strncmp(const char *a, const char *b, size_t len) { return ::strncmp(a,b,len); } //--------------------------------------------------------------------------- template T max(T a, T b) { return (a>b) ? a : b; } //--------------------------------------------------------------------------- template T min(T a, T b) { return (a class _my_auto_ptr { public: typedef _Ty element_type; explicit _my_auto_ptr(_Ty *_Ptr = 0) :_Myptr(_Ptr) {} _my_auto_ptr(_my_auto_ptr<_Ty>& _Right) :_Myptr(_Right.release()) {} template operator _my_auto_ptr<_Other>() { return (_my_auto_ptr<_Other>(*this)); } template _my_auto_ptr<_Ty>& operator=(_my_auto_ptr<_Other>& _Right) { reset(_Right.release()); return (*this); } ~auto_ptr() { delete _Myptr; } _Ty& operator*() const { return (*_Myptr); } _Ty *operator->() const { return (&**this); } _Ty *get() const { return (_Myptr); } _Ty *release() { _Ty *_Tmp = _Myptr; _Myptr = 0; return (_Tmp); } void reset(_Ty* _Ptr = 0) { if (_Ptr != _Myptr) delete _Myptr; _Myptr = _Ptr; } private: _Ty *_Myptr; }; // class _my_auto_ptr } // namespace std #endif // Microsoft Visual Studio Version 6.0 #endif // include guard repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserStack.h000066400000000000000000000100141231531733200276100ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_STACK_H #define MU_PARSER_STACK_H #include #include #include #include #include "muParserError.h" #include "muParserToken.h" /** \file \brief This file defines the stack used by muparser. */ namespace mu { /** \brief Parser stack implementation. Stack implementation based on a std::stack. The behaviour of pop() had been slightly changed in order to get an error code if the stack is empty. The stack is used within the Parser both as a value stack and as an operator stack. \author (C) 2004-2011 Ingo Berg */ template class ParserStack { private: /** \brief Type of the underlying stack implementation. */ typedef std::stack > impl_type; impl_type m_Stack; ///< This is the actual stack. public: //--------------------------------------------------------------------------- ParserStack() :m_Stack() {} //--------------------------------------------------------------------------- virtual ~ParserStack() {} //--------------------------------------------------------------------------- /** \brief Pop a value from the stack. Unlike the standard implementation this function will return the value that is going to be taken from the stack. \throw ParserException in case the stack is empty. \sa pop(int &a_iErrc) */ TValueType pop() { if (empty()) throw ParserError( _T("stack is empty.") ); TValueType el = top(); m_Stack.pop(); return el; } /** \brief Push an object into the stack. \param a_Val object to push into the stack. \throw nothrow */ void push(const TValueType& a_Val) { m_Stack.push(a_Val); } /** \brief Return the number of stored elements. */ unsigned size() const { return (unsigned)m_Stack.size(); } /** \brief Returns true if stack is empty false otherwise. */ bool empty() const { return m_Stack.size()==0; } /** \brief Return reference to the top object in the stack. The top object is the one pushed most recently. */ TValueType& top() { return m_Stack.top(); } }; } // namespace MathUtils #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserToken.h000066400000000000000000000343341231531733200276360ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_H #define MU_PARSER_TOKEN_H #include #include #include #include #include #include "muParserError.h" #include "muParserCallback.h" /** \file \brief This file contains the parser token definition. */ namespace mu { /** \brief Encapsulation of the data for a single formula token. Formula token implementation. Part of the Math Parser Package. Formula tokens can be either one of the following:
  • value
  • variable
  • function with numerical arguments
  • functions with a string as argument
  • prefix operators
  • infix operators
  • binary operator
\author (C) 2004-2011 Ingo Berg */ template class ParserToken { public: /** \brief Additional token flags. */ enum ETokFlags { flVOLATILE = 1 ///< Mark a token that depends on a variable or a function that is not conservative }; private: ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. ETypeCode m_iType; void *m_pTok; ///< Stores Token pointer; not applicable for all tokens int m_iFlags; ///< Additional flags for the token. int m_iIdx; ///< An otional index to an external buffer storing the token data TString m_strTok; ///< Token string TString m_strVal; ///< Value for string variables value_type m_fVal; ///< the value std::auto_ptr m_pCallback; public: //--------------------------------------------------------------------------- /** \brief Constructor (default). Sets token to an neutral state of type cmUNKNOWN. \throw nothrow \sa ECmdCode */ ParserToken() :m_iCode(cmUNKNOWN) ,m_iType(tpVOID) ,m_pTok(0) ,m_iFlags(0) ,m_iIdx(-1) ,m_strTok() ,m_pCallback() {} //------------------------------------------------------------------------------ /** \brief Create token from another one. Implemented by calling Assign(...) \throw nothrow \post m_iType==cmUNKNOWN \sa #Assign */ ParserToken(const ParserToken &a_Tok) { Assign(a_Tok); } //------------------------------------------------------------------------------ /** \brief Assignement operator. Copy token state from another token and return this. Implemented by calling Assign(...). \throw nothrow */ ParserToken& operator=(const ParserToken &a_Tok) { Assign(a_Tok); return *this; } //------------------------------------------------------------------------------ /** \brief Copy token information from argument. \throw nothrow */ void Assign(const ParserToken &a_Tok) { m_iCode = a_Tok.m_iCode; m_pTok = a_Tok.m_pTok; m_iFlags = a_Tok.m_iFlags; m_strTok = a_Tok.m_strTok; m_iIdx = a_Tok.m_iIdx; m_strVal = a_Tok.m_strVal; m_iType = a_Tok.m_iType; m_fVal = a_Tok.m_fVal; // create new callback object if a_Tok has one m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0); } //------------------------------------------------------------------------------ /** \brief Add additional flags to the token. Flags are currently used to mark volatile (non optimizeable) functions. \sa m_iFlags, ETokFlags */ void AddFlags(int a_iFlags) { m_iFlags |= a_iFlags; } //------------------------------------------------------------------------------ /** \brief Check if a certain flag ist set. \throw nothrow */ bool IsFlagSet(int a_iFlags) const { #if defined(_MSC_VER) #pragma warning( disable : 4800 ) #endif return (bool)(m_iFlags & a_iFlags); #if defined(_MSC_VER) #pragma warning( default : 4800 ) // int: Variable set to boolean value (may degrade performance) #endif } //------------------------------------------------------------------------------ /** \brief Assign a token type. Token may not be of type value, variable or function. Those have seperate set functions. \pre [assert] a_iType!=cmVAR \pre [assert] a_iType!=cmVAL \pre [assert] a_iType!=cmFUNC \post m_fVal = 0 \post m_pTok = 0 */ ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) { // The following types cant be set this way, they have special Set functions assert(a_iType!=cmVAR); assert(a_iType!=cmVAL); assert(a_iType!=cmFUNC); m_iCode = a_iType; m_iType = tpVOID; m_pTok = 0; m_iFlags = 0; m_strTok = a_strTok; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** \brief Set Callback type. */ ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok) { assert(a_pCallback.GetAddr()); m_iCode = a_pCallback.GetCode(); m_iType = tpVOID; m_strTok = a_sTok; m_pCallback.reset(new ParserCallback(a_pCallback)); m_pTok = 0; m_iFlags = 0; m_iIdx = -1; if (!m_pCallback->IsOptimizable()) AddFlags(flVOLATILE); return *this; } //------------------------------------------------------------------------------ /** \brief Make this token a value token. Member variables not necessary for value tokens will be invalidated. \throw nothrow */ ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) { m_iCode = cmVAL; m_iType = tpDBL; m_fVal = a_fVal; m_iFlags = 0; m_strTok = a_strTok; m_iIdx = -1; m_pTok = 0; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** \brief make this token a variable token. Member variables not necessary for variable tokens will be invalidated. \throw nothrow */ ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) { m_iCode = cmVAR; m_iType = tpDBL; m_iFlags = 0; m_strTok = a_strTok; m_iIdx = -1; m_pTok = (void*)a_pVar; m_pCallback.reset(0); AddFlags(ParserToken::flVOLATILE); return *this; } //------------------------------------------------------------------------------ /** \brief Make this token a variable token. Member variables not necessary for variable tokens will be invalidated. \throw nothrow */ ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) { m_iCode = cmSTRING; m_iType = tpSTR; m_iFlags = 0; m_strTok = a_strTok; m_iIdx = static_cast(a_iSize); m_pTok = 0; m_pCallback.reset(0); AddFlags(ParserToken::flVOLATILE); return *this; } //------------------------------------------------------------------------------ /** \brief Set an index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. \param a_iIdx The index the string function result will take in the bytecode parser. \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING */ void SetIdx(int a_iIdx) { if (m_iCode!=cmSTRING || a_iIdx<0) throw ParserError(ecINTERNAL_ERROR); m_iIdx = a_iIdx; } //------------------------------------------------------------------------------ /** \brief Return Index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING \return The index the result will take in the Bytecode calculatin array (#m_iIdx). */ int GetIdx() const { if (m_iIdx<0 || m_iCode!=cmSTRING ) throw ParserError(ecINTERNAL_ERROR); return m_iIdx; } //------------------------------------------------------------------------------ /** \brief Return the token type. \return #m_iType \throw nothrow */ ECmdCode GetCode() const { if (m_pCallback.get()) { return m_pCallback->GetCode(); } else { return m_iCode; } } //------------------------------------------------------------------------------ ETypeCode GetType() const { if (m_pCallback.get()) { return m_pCallback->GetType(); } else { return m_iType; } } //------------------------------------------------------------------------------ int GetPri() const { if ( !m_pCallback.get()) throw ParserError(ecINTERNAL_ERROR); if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetPri(); } //------------------------------------------------------------------------------ EOprtAssociativity GetAssociativity() const { if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetAssociativity(); } //------------------------------------------------------------------------------ /** \brief Return the address of the callback function assoziated with function and operator tokens. \return The pointer stored in #m_pTok. \throw exception_type if token type is non of:
  • cmFUNC
  • cmSTRFUNC
  • cmPOSTOP
  • cmINFIXOP
  • cmOPRT_BIN
\sa ECmdCode */ void* GetFuncAddr() const { return (m_pCallback.get()) ? m_pCallback->GetAddr() : 0; } //------------------------------------------------------------------------------ /** \biref Get value of the token. Only applicable to variable and value tokens. \throw exception_type if token is no value/variable token. */ TBase GetVal() const { switch (m_iCode) { case cmVAL: return m_fVal; case cmVAR: return *((TBase*)m_pTok); default: throw ParserError(ecVAL_EXPECTED); } } //------------------------------------------------------------------------------ /** \brief Get address of a variable token. Valid only if m_iType==CmdVar. \throw exception_type if token is no variable token. */ TBase* GetVar() const { if (m_iCode!=cmVAR) throw ParserError(ecINTERNAL_ERROR); return (TBase*)m_pTok; } //------------------------------------------------------------------------------ /** \brief Return the number of function arguments. Valid only if m_iType==CmdFUNC. */ int GetArgCount() const { assert(m_pCallback.get()); if (!m_pCallback->GetAddr()) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetArgc(); } //------------------------------------------------------------------------------ /** \brief Return the token identifier. If #m_iType is cmSTRING the token identifier is the value of the string argument for a string function. \return #m_strTok \throw nothrow \sa m_strTok */ const TString& GetAsString() const { return m_strTok; } }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/muparser/muParserTokenReader.h000066400000000000000000000137751231531733200307670ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MU_PARSER_TOKEN_READER_H #define MU_PARSER_TOKEN_READER_H #include #include #include #include #include #include #include #include "muParserDef.h" #include "muParserToken.h" /** \file \brief This file contains the parser token reader definition. */ namespace mu { // Forward declaration class ParserBase; /** \brief Token reader for the ParserBase class. */ class ParserTokenReader { private: typedef ParserToken token_type; public: ParserTokenReader(ParserBase *a_pParent); ParserTokenReader* Clone(ParserBase *a_pParent) const; void AddValIdent(identfun_type a_pCallback); void SetVarCreator(facfun_type a_pFactory, void *pUserData); void SetFormula(const string_type &a_strFormula); void SetArgSep(char_type cArgSep); int GetPos() const; const string_type& GetExpr() const; varmap_type& GetUsedVar(); char_type GetArgSep() const; void IgnoreUndefVar(bool bIgnore); void ReInit(); token_type ReadNextToken(); private: /** \brief Syntax codes. The syntax codes control the syntax check done during the first time parsing of the expression string. They are flags that indicate which tokens are allowed next if certain tokens are identified. */ enum ESynCodes { noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" noOPT = 1 << 6, ///< to avoid i.e. "(+)" noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" noEND = 1 << 9, ///< to avoid unexpected end of formula noSTR = 1 << 10, ///< to block numeric arguments on string functions noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" noIF = 1 << 12, noELSE = 1 << 13, sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, noANY = ~0 ///< All of he above flags set }; ParserTokenReader(const ParserTokenReader &a_Reader); ParserTokenReader& operator=(const ParserTokenReader &a_Reader); void Assign(const ParserTokenReader &a_Reader); void SetParent(ParserBase *a_pParent); int ExtractToken(const char_type *a_szCharSet, string_type &a_strTok, int a_iPos) const; int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const; bool IsBuiltIn(token_type &a_Tok); bool IsArgSep(token_type &a_Tok); bool IsEOF(token_type &a_Tok); bool IsInfixOpTok(token_type &a_Tok); bool IsFunTok(token_type &a_Tok); bool IsPostOpTok(token_type &a_Tok); bool IsOprt(token_type &a_Tok); bool IsValTok(token_type &a_Tok); bool IsVarTok(token_type &a_Tok); bool IsStrVarTok(token_type &a_Tok); bool IsUndefVarTok(token_type &a_Tok); bool IsString(token_type &a_Tok); void Error(EErrorCodes a_iErrc, int a_iPos = -1, const string_type &a_sTok = string_type() ) const; token_type& SaveBeforeReturn(const token_type &tok); ParserBase *m_pParser; string_type m_strFormula; int m_iPos; int m_iSynFlags; bool m_bIgnoreUndefVar; const funmap_type *m_pFunDef; const funmap_type *m_pPostOprtDef; const funmap_type *m_pInfixOprtDef; const funmap_type *m_pOprtDef; const valmap_type *m_pConstDef; const strmap_type *m_pStrVarDef; varmap_type *m_pVarDef; ///< The only non const pointer to parser internals facfun_type m_pFactory; void *m_pFactoryData; std::vector m_vIdentFun; ///< Value token identification function varmap_type m_UsedVar; value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables int m_iBrackets; token_type m_lastTok; char_type m_cArgSep; ///< The character used for separating function arguments }; } // namespace mu #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nAmf.h000066400000000000000000000076211231531733200240610ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NAMF_H #define NAMF_H #include #include #include "nMetadata.h" #include "nObject.h" #include "nConstellation.h" #include "nTexture.h" #include "nMaterial.h" class CXmlStreamWrite; class CXmlStreamRead; enum UnitSystem {UNIT_MM, UNIT_M, UNIT_IN, UNIT_FT, UNIT_UM}; class nAmf { public: nAmf(void); ~nAmf(void); nAmf(const nAmf& In) {*this = In;} //copy constructor nAmf& operator=(const nAmf& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0, bool* pCancelFlag = 0); bool ReadXML(CXmlStreamRead* pXML, bool StrictLoad=true, std::string* pMessage = 0, bool* pCancelFlag = 0); bool CheckValid(bool FixNode=true, std::string* pMessage = 0); //required attributes //optional attributes bool UnitsExist; UnitSystem aUnit; bool VersionExists; double aVersion; //required children std::vector Objects; //optional children std::vector Metadata; std::vector Constellations; std::vector Textures; std::vector Materials; //Utilities int GetNumObjects(void) {return (int)Objects.size();} int GetNumConstellations(void) {return (int)Constellations.size();} int GetNumMaterials(void) {return (int)Materials.size();} int GetNumTextures(void) {return (int)Textures.size();} int GetUsedGeoID(void); int GetUnusedGeoID(void); int GetUnusedTexID(void); int GetUnusedMatID(void); bool IsDuplicateGeoID(int IdToCheck); //returns true if two or more of this ID exist bool IsDuplicateTexID(int IdToCheck); //returns true if two or more of this ID exist bool IsDuplicateMatID(int IdToCheck); //returns true if two or more of this ID exist std::string GetGeoNameFromID(int GeometryID); //finds the name of the object or constellation with this internal ID std::string GetMatNameFromID(int MaterialID); //returns name string for a material if it exists nObject* GetObjectByID(int GeometryID); //returns pointer to a constellation that has this ID, or NULL if non exists. nConstellation* GetConstellationByID(int GeometryID); //returns pointer to a constellation that has this ID, or NULL if non exists. nMaterial* GetMaterialByID(int MaterialID); //returns a TEMPORARY pointer to the first material with the specified ID, or NULL if not found nTexture* GetTextureByID(int TextureID); //returns a TEMPORARY pointer to the first texture with the specified ID, or NULL if not found int AppendObject(std::string Name = ""); int AppendConstellation(std::string Name = ""); int AppendMaterial(std::string Name = ""); void DeleteGeometry(int GeometryID); //Deletes by the internal object ID, not index in the vector!! Removes all instances to this object or constellation, too! void DeleteMaterial(int MaterialID); bool IsTopLevelGeo(int GeometryID); //returns true if not referenced by any constellations // std::string GetMatName(nVolume* pVolume); //returns name string for material of this volume if it has one. }; #endif //NAMF_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nColor.h000066400000000000000000000062141231531733200244310ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NCOLOR_H #define NCOLOR_H #include #include "Equation.h" class CXmlStreamWrite; class CXmlStreamRead; class nAmf; //enum Profile {sRGB, AdobeRGB, Wide_Gamut_RGB, CIERGB, CIELAB, CIEXYZ}; class nColor { public: nColor(); ~nColor(void); nColor(double RIn, double GIn, double BIn) {Clear(); R.FromConstant(RIn); G.FromConstant(GIn); B.FromConstant(BIn);} nColor(double RIn, double GIn, double BIn, double AIn) {Clear(); R.FromConstant(RIn); G.FromConstant(GIn); B.FromConstant(BIn); A.FromConstant(AIn); AExists = true;} nColor(const nColor& In) {*this = In;} //copy constructor nColor& operator=(const nColor& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //optional attributes // Profile aProfile; //color space profile //required children CEquation R; //if these equation pointers are constant, caching is used CEquation G; CEquation B; //optional children bool AExists; //flag for if there is alpha data in the file CEquation A; //utilities void GetColor(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut = NULL) {*rOut = GetR(xIn, yIn, zIn); *gOut = GetG(xIn, yIn, zIn); *bOut = GetB(xIn, yIn, zIn); if(aOut){if (AExists){ *aOut = GetA(xIn, yIn, zIn);} else {*aOut = 1.0;}}} double GetR(double XLoc = 0, double YLoc = 0, double ZLoc = 0) {return R.Eval(XLoc, YLoc, ZLoc, true);} //returns range form 0 to 1; double GetG(double XLoc = 0, double YLoc = 0, double ZLoc = 0) {return G.Eval(XLoc, YLoc, ZLoc, true);} //returns range form 0 to 1; double GetB(double XLoc = 0, double YLoc = 0, double ZLoc = 0) {return B.Eval(XLoc, YLoc, ZLoc, true);} //returns range form 0 to 1; double GetA(double XLoc = 0, double YLoc = 0, double ZLoc = 0) {if (AExists) return A.Eval(XLoc, YLoc, ZLoc, true); else return 1.0;} //returns range form 0 to 1; void SetConstColor(double RIn, double GIn, double BIn, double AIn = 1.0){R.FromConstant(RIn); G.FromConstant(GIn); B.FromConstant(BIn); if(AIn == 1.0) AExists = false; else {A.FromConstant(AIn); AExists = true;}} }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nComposite.h000066400000000000000000000042661231531733200253220ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NCOMPOSITE_H #define NCOMPOSITE_H #include #include "Equation.h" class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nComposite { public: nComposite(void); ~nComposite(void); // nComposite(int MaterialIDIn) {Clear(); MaterialID = MaterialIDIn;} nComposite(const nComposite& In) {*this = In;} //copy constructor nComposite& operator=(const nComposite& In); //overload Equals void Clear(void); //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attributes int aMaterialID; //the material that this equation governs the percent of //required data CEquation MatEquation; //Utilities bool SetEquation(std::string AmfEquationIn, nAmf* pAmf, std::string* pMessage = 0); bool CheckEquation(std::string* pMessage = 0) {return MatEquation.CheckParse(pMessage);} std::string GetEquation(void) {return MatEquation.ToAmfString();} double EvalEquation(double x, double y, double z){return MatEquation.Eval(x, y, z);} bool ScaleEquation(double ScaleFactor, std::string* pMessage = 0); //Scale factor is the factor we're changing the Amf (2.0 = doubling the object size) }; #endif //NCOMPOSITE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nConstellation.h000066400000000000000000000043611231531733200261720ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NCONSTELLATION_H #define NCONSTELLATION_H #include #include #include "nInstance.h" #include "nMetadata.h" class CXmlStreamWrite; class CXmlStreamRead; class nConstellation { public: nConstellation(nAmf* pnAmfIn); ~nConstellation(void); nConstellation(const nConstellation& In) {*this = In;} //copy constructor nConstellation& operator=(const nConstellation& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags std::vector Instances; //required attributes int aID; //optional tags std::vector Metadata; //Utilities void SetName(std::string NewName); std::string GetName(void); void AddInstance(int aObjectID = -1) {Instances.push_back(nInstance(aObjectID));} void DeleteInstance(int VectorIndex) {Instances.erase(Instances.begin()+VectorIndex);} int GetNumInstances(void) {return (int)Instances.size();} bool IsReferencedBy(nConstellation* pConstellationCheck); //returns true if pUsesCheck references pCheck anywhere in its tree. nAmf* pnAmf; //need to keep pointer to AMF to recurse in constellation tags... }; #endif //NCONSTELLATION_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nCoordinates.h000066400000000000000000000031201231531733200256160ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NCOORDINATES_H #define NCOORDINATES_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nCoordinates { public: nCoordinates(void); ~nCoordinates(void); nCoordinates(const double Xin, const double Yin, const double Zin); nCoordinates(const nCoordinates& In) {*this = In;} //copy constructor nCoordinates& operator=(const nCoordinates& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required children double X, Y, Z; }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nEdge.h000066400000000000000000000032161231531733200242160ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NEDGE_H #define NEDGE_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nEdge { public: nEdge(void); ~nEdge(void); nEdge(const nEdge& In) {*this = In;} //copy constructor nEdge& operator=(const nEdge& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); int v1, v2; double dx1, dy1, dz1, dx2, dy2, dz2; void SetDirectionVectors(double Dx1In, double Dy1In, double Dz1In, double Dx2In, double Dy2In, double Dz2In){dx1=Dx1In; dy1=Dy1In; dz1=Dz1In; dx2=Dx2In; dy2=Dy2In; dz2=Dz2In;} }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nInstance.h000066400000000000000000000032561231531733200251220ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NINSTANCE_H #define NINSTANCE_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nInstance { public: nInstance(void); ~nInstance(void); nInstance(int ObjectIDIn) {Clear(); aObjectID = ObjectIDIn;} nInstance(const nInstance& In) {*this = In;} //copy constructor nInstance& operator=(const nInstance& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attibutes int aObjectID; //optional tags (although without one this would be useless...) double DeltaX, DeltaY, DeltaZ, rX, rY, rZ; }; #endif //NINSTANCE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nMaterial.h000066400000000000000000000054661231531733200251210ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NMATERIAL_H #define NMATERIAL_H #include #include #include "nColor.h" #include "nComposite.h" #include "nMetadata.h" class CXmlStreamWrite; class CXmlStreamRead; class nMaterial { public: nMaterial(nAmf* pnAmfIn); ~nMaterial(void); nMaterial(const nMaterial& In) {*this = In;} //copy constructor nMaterial& operator=(const nMaterial& In); //overload Equals void Clear(void); //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attributes int aID; //required tags std::vector Composites; //optional tags bool ColorExists; nColor Color; std::vector Metadata; //utilities int GetNumComposites() {return (int) Composites.size();} void SetName(std::string NewName); std::string GetName(void); void SetConstColor(double RIn, double GIn, double BIn, double AIn = 1.0) {if (aID!=0){Color.SetConstColor(RIn, GIn, BIn, AIn); ColorExists = true;}} void GetConstColor(double* rOut, double* gOut, double* bOut) {GetColorAt(0,0,0, rOut, gOut, bOut);} void GetColorAt(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut = NULL); //add and delete composite function are in the top level nAmf class to allow us to enforce no recursion //composite is only ever a sub of material, but needs functions here to check against recursion... int AddCompositeInstance(int InstanceMaterialID = 0, std::string AmfEquationIn = "1", std::string* pMessage = 0); //returns the index. void DeleteCompositeInstance(int CompositeIndex); bool IsReferencedBy(nMaterial* pMaterialCheck); //returns true if pUsesCheck references this material anywhere in its tree. nAmf* pnAmf; //need to keep pointer to AMF to recurse in composite tags... }; #endif //NMATERIAL_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nMesh.h000066400000000000000000000043651231531733200242540ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NMESH_H #define NMESH_H #include #include #include "nVertices.h" #include "nVolume.h" class CXmlStreamWrite; class CXmlStreamRead; //class nVolume; class nMesh { public: nMesh(void); ~nMesh(void); nMesh(const nMesh& In) {*this = In;} //copy constructor nMesh& operator=(const nMesh& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0, bool* pCancelFlag = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0, bool* pCancelFlag = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags nVertices Vertices; std::vector Volumes; //utilities int GetNumVertices(void){return Vertices.GetNumVertices();} int GetNumEdges(void){return Vertices.GetNumEdges();} int AddVertex(nVertex& Vin) {return Vertices.AddVertex(Vin);} int AddEdge(nEdge& Ein) {return Vertices.AddEdge(Ein);} void Translate(double dx, double dy, double dz) {Vertices.Translate(dx, dy, dz);} void Rotate(double rx, double ry, double rz) {Vertices.Rotate(rx, ry, rz);} nVolume* NewVolume(std::string Name) {Volumes.push_back(nVolume(Name)); return &Volumes.back();} bool Bounds(double* MinX, double* MaxX, double* MinY, double* MaxY, double* MinZ, double* MaxZ); //returns false if no vertices }; #endif //NMESH_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nMetadata.h000066400000000000000000000034551231531733200250770ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NMETADATA_H #define NMETADATA_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; enum MetaDataType {MD_INVALID, MD_NAME, MD_DESCRIPTION, MD_URL, MD_AUTHOR, MD_COMPANY, MD_CAD, MD_REVISION, MD_TOLERANCE, MD_VOLUME, MD_ELASTICMOD, MD_POISSONRATIO}; class nMetadata { public: nMetadata(void); ~nMetadata(void); nMetadata(MetaDataType TypeIn, std::string DataIn){Type = TypeIn; Data = DataIn;} nMetadata(const nMetadata& In) {*this = In;} //copy constructor nMetadata& operator=(const nMetadata& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attributes MetaDataType Type; //required data std::string Data; }; #endif //NMETADATA_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nNormal.h000066400000000000000000000027441231531733200246070ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NNORMAL_H #define NNORMAL_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nNormal { public: nNormal(void); ~nNormal(void); nNormal(const nNormal& In) {*this = In;} //copy constructor nNormal& operator=(const nNormal& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required children double nX, nY, nZ; }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nObject.h000066400000000000000000000045761231531733200245720ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NOBJECT_H #define NOBJECT_H #include #include #include "nColor.h" #include "nMesh.h" class CXmlStreamWrite; class CXmlStreamRead; class nMetadata; //class nAmf; class nObject { public: nObject(nAmf* pnAmfIn); ~nObject(void); nObject(const nObject& In) {*this = In;} //copy constructor nObject& operator=(const nObject& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0, bool* pCancelFlag = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0, bool* pCancelFlag = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags std::vector Meshes; //optional tags bool ColorExists; nColor Color; std::vector Metadata; //required attributes int aID; //Utilities void SetName(std::string NewName); std::string GetName(void); int GetNumMeshes(void) {return (int)Meshes.size();} void SetColor(nColor& ColorIn) {Color = ColorIn; ColorExists = true;} void RemoveColor(void) {ColorExists = false;} void GetColorAt(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut) {if (ColorExists){Color.GetColor(xIn, yIn, zIn, rOut, gOut, bOut, aOut);} else{*rOut=0; *gOut=0; *bOut=0; *aOut=1.0;}} void Translate(double dx, double dy, double dz); void Rotate(double rx, double ry, double rz); nAmf* pnAmf; //need to keep pointer to parent AMF }; #endif //NOBJECT_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nTexmap.h000066400000000000000000000037161231531733200246150ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NMAP_H #define NMAP_H #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; class nTexmap { public: nTexmap(void); ~nTexmap(void); nTexmap(int RTexIdIn, int GTexIdIn, int BTexIdIn, double U1In, double U2In, double U3In, double V1In, double V2In, double V3In) {Clear(); RTexID = RTexIdIn; GTexID = GTexIdIn; BTexID = BTexIdIn; uTex1 = U1In; uTex2 = U2In; uTex3 = U3In; vTex1 = V1In; vTex2 = V2In; vTex3 = V3In;} nTexmap(const nTexmap& In) {*this = In;} //copy constructor nTexmap& operator=(const nTexmap& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attibutes int RTexID, GTexID, BTexID; //optional attributes int ATexID; bool ATexIDExists; //required tags double uTex1, uTex2, uTex3, vTex1, vTex2, vTex3; //optional tags double wTex1, wTex2, wTex3; bool WExists; }; #endif //NMAP_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nTexture.h000066400000000000000000000050601231531733200250110ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NTEXTURE_H #define NTEXTURE_H #include #include class CXmlStreamWrite; class CXmlStreamRead; class nAmf; enum TexType {TT_GRAYSCALE}; static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; class nTexture { public: nTexture(nAmf* pnAmfIn); ~nTexture(); nTexture(const nTexture& In) {*this = In;} //copy constructor nTexture& operator=(const nTexture& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required attributes int aID, aWidth, aHeight, aDepth; TexType Type; bool aTiled; //required data std::vector BinaryData; //this must be converted to base 64 before writing to xml. //utility functions std::string DataToBase64(void) {return ToBase64(BinaryData.data(), BinaryData.size());} //converts data to base 64 for writing to XML bool Base64ToData(std::string inputBase64); //converts base 64 to data. returns false if not valid B64 data void GetSize(int* WidthOut, int* HeightOut, int* DepthOut = NULL) {*WidthOut = aWidth; *HeightOut = aHeight; if (DepthOut) *DepthOut = aDepth;} static inline bool is_base64(unsigned char c) {return (isalnum(c) || (c == '+') || (c == '/'));} std::string ToBase64(unsigned char const* , unsigned int len); std::string FromBase64(std::string const& s); double GetValue(double uIn, double vIn, double wIn = 0); nAmf* pnAmf; //need to keep pointer to parent AMF }; #endif //NTEXTURE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nTriangle.h000066400000000000000000000040561231531733200251220ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NTRIANGLE_H #define NTRIANGLE_H #include #include "nColor.h" #include "nTexmap.h" class CXmlStreamWrite; class CXmlStreamRead; class nTriangle { public: nTriangle(void); ~nTriangle(void); nTriangle(const int v1In, const int v2In, const int v3In) {Clear(); v1 = v1In; v2 = v2In; v3 = v3In;} nTriangle(const int v1In, const int v2In, const int v3In, const nColor& ColorIn) {Clear(); v1 = v1In; v2 = v2In; v3 = v3In; ColorExists = true; Color = ColorIn;} nTriangle(const nTriangle& In) {*this = In;} //copy constructor nTriangle& operator=(const nTriangle& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags int v1, v2, v3; //optional tags; bool ColorExists; nColor Color; bool TexMapExists; nTexmap TexMap; public: void SetTexMap(const nTexmap& TexMapIn) {TexMap = TexMapIn; TexMapExists = true;} nTexmap* GetpTexMap(void) {return &TexMap;} // std::vector MapList; }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nVertex.h000066400000000000000000000043501231531733200246270ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NVERTEX_H #define NVERTEX_H #include "nCoordinates.h" #include "nNormal.h" #include "nColor.h" class CXmlStreamWrite; class CXmlStreamRead; class nVertex { public: nVertex(void); ~nVertex(void); nVertex(const double X, const double Y, const double Z); nVertex(const double X, const double Y, const double Z, const nColor& ColorIn); nVertex(const nVertex& In){*this = In;} //copy constructor nVertex& operator=(const nVertex& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags nCoordinates Coordinates; //optional tags bool NormalExists; nNormal Normal; bool ColorExists; nColor Color; //utilities: double GetX(void) {return Coordinates.X;} double GetY(void) {return Coordinates.Y;} double GetZ(void) {return Coordinates.Z;} double GetNX(void) {return Normal.nX;} double GetNY(void) {return Normal.nY;} double GetNZ(void) {return Normal.nZ;} void SetCoordinates(double XIn, double YIn, double ZIn){Coordinates.X=XIn; Coordinates.Y=YIn;Coordinates.Z=ZIn;} void SetNormal(double nXIn, double nYIn, double nZIn){Normal.nX=nXIn; Normal.nY=nYIn;Normal.nZ=nZIn;} }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nVertices.h000066400000000000000000000042331231531733200251360ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NVERTICES_H #define NVERTICES_H #include #include #include "nVertex.h" #include "nEdge.h" //class nVertex; ///class nEdge; class CXmlStreamWrite; class CXmlStreamRead; class nVertices { public: nVertices(void); ~nVertices(void); nVertices(const nVertices& In) {*this = In;} //copy constructor nVertices& operator=(const nVertices& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0, bool* pCancelFlag = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0, bool* pCancelFlag = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //required tags std::vector VertexList; //optional tags std::vector EdgeList; //utilities int GetNumVertices(void){return VertexList.size();} int GetNumEdges(void){return EdgeList.size();} int AddVertex(nVertex& VIn){VertexList.push_back(VIn); return VertexList.size()-1;} //returns index int AddEdge(nEdge& EIn){EdgeList.push_back(EIn); return EdgeList.size()-1;} //returns index void Translate(double dx, double dy, double dz); void Rotate(double rx, double ry, double rz); //rotates about origin //RotateQuat //RotateAngleAxis }; #endif //NVERTICES_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/nVolume.h000066400000000000000000000047741231531733200246330ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #ifndef NVOLUME_H #define NVOLUME_H #include #include #include "nColor.h" #include "nMetadata.h" #include "nTriangle.h" class CXmlStreamWrite; class CXmlStreamRead; enum VolType {VT_OBJECT, VT_SUPPORT}; class nVolume { public: nVolume(void); ~nVolume(void); nVolume(std::string Name); nVolume(const nVolume& In) {*this = In;} //copy constructor nVolume& operator=(const nVolume& In); //overload Equals void Clear(void); //clears all data //XML read/write bool WriteXML(CXmlStreamWrite* pXML, std::string* pMessage = 0, bool* pCancelFlag = 0); bool ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad=true, std::string* pMessage = 0, bool* pCancelFlag = 0); bool CheckValid(nAmf* pAmf, bool FixNode=true, std::string* pMessage = 0); //optional attributes bool MaterialIDExists; int aMaterialID; // bool TypeExists; // VolType Type; //required tags std::vector Triangles; //optional tags bool ColorExists; nColor Color; std::vector Metadata; //Utilities void SetName(std::string NewName); std::string GetName(void); void SetMaterialID(int NewMatId); bool GetMaterialID(int* pMatIdRet); nTriangle* AddTriangle(nTriangle& TriIn) {Triangles.push_back(TriIn); return &Triangles.back();} //returns temporary pointer to this triangle void SetColor(nColor& ColorIn) {Color = ColorIn; ColorExists = true;} void EraseColor(void) {ColorExists = false;} void GetColorAt(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut) {if (ColorExists){Color.GetColor(xIn, yIn, zIn, rOut, gOut, bOut, aOut);} else{*rOut=0; *gOut=0; *bOut=0; *aOut=1.0;}} }; #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/rapidxml/000077500000000000000000000000001231531733200246415ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/rapidxml/rapidxml.h000066400000000000000000003541511231531733200266430ustar00rootroot00000000000000#ifndef RAPIDXML_HPP_INCLUDED #define RAPIDXML_HPP_INCLUDED // Copyright (C) 2006, 2009 Marcin Kalicinski // Version 1.13 // Revision $DateTime: 2009/05/13 01:46:17 $ //! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation // If standard library is disabled, user must provide implementations of required functions and typedefs #if !defined(RAPIDXML_NO_STDLIB) #include // For std::size_t #include // For assert #include // For placement new #endif // On MSVC, disable "conditional expression is constant" warning (level 4). // This warning is almost impossible to avoid with certain types of templated code #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) // Conditional expression is constant #endif /////////////////////////////////////////////////////////////////////////// // RAPIDXML_PARSE_ERROR #if defined(RAPIDXML_NO_EXCEPTIONS) #define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } namespace rapidxml { //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, //! this function is called to notify user about the error. //! It must be defined by the user. //!

//! This function cannot return. If it does, the results are undefined. //!

//! A very simple definition might look like that: //!
    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
    //! {
    //!     std::cout << "Parse error: " << what << "\n";
    //!     std::abort();
    //! }
    //! 
//! \param what Human readable description of the error. //! \param where Pointer to character data where error was detected. void parse_error_handler(const char *what, void *where); } #else #include // For std::exception #define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) namespace rapidxml { //! Parse error exception. //! This exception is thrown by the parser when an error occurs. //! Use what() function to get human-readable error message. //! Use where() function to get a pointer to position within source text where error was detected. //!

//! If throwing exceptions by the parser is undesirable, //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. //! This function must be defined by the user. //!

//! This class derives from std::exception class. class parse_error: public std::exception { public: //! Constructs parse error parse_error(const char *what, void *where) : m_what(what) , m_where(where) { } //! Gets human readable description of error. //! \return Pointer to null terminated description of the error. virtual const char *what() const throw() { return m_what; } //! Gets pointer to character data where error happened. //! Ch should be the same as char type of xml_document that produced the error. //! \return Pointer to location within the parsed string where error occured. template Ch *where() const { return reinterpret_cast(m_where); } private: const char *m_what; void *m_where; }; } #endif /////////////////////////////////////////////////////////////////////////// // Pool sizes #ifndef RAPIDXML_STATIC_POOL_SIZE // Size of static memory block of memory_pool. // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) #endif #ifndef RAPIDXML_DYNAMIC_POOL_SIZE // Size of dynamic memory block of memory_pool. // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) #endif #ifndef RAPIDXML_ALIGNMENT // Memory allocation alignment. // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. // All memory allocations for nodes, attributes and strings will be aligned to this value. // This must be a power of 2 and at least 1, otherwise memory_pool will not work. #define RAPIDXML_ALIGNMENT sizeof(void *) #endif namespace rapidxml { // Forward declarations template class xml_node; template class xml_attribute; template class xml_document; //! Enumeration listing all node types produced by the parser. //! Use xml_node::type() function to query node type. enum node_type { node_document, //!< A document node. Name and value are empty. node_element, //!< An element node. Name contains element name. Value contains text of first data node. node_data, //!< A data node. Name is empty. Value contains data text. node_cdata, //!< A CDATA node. Name is empty. Value contains data text. node_comment, //!< A comment node. Name is empty. Value contains comment text. node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. node_pi //!< A PI node. Name contains target. Value contains instructions. }; /////////////////////////////////////////////////////////////////////// // Parsing flags //! Parse flag instructing the parser to not create data nodes. //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_no_data_nodes = 0x1; //! Parse flag instructing the parser to not use text of first data node as a value of parent element. //! Can be combined with other flags by use of | operator. //! Note that child data nodes of element node take precendence over its value when printing. //! That is, if element has one or more child data nodes and a value, the value will be ignored. //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. //!

//! See xml_document::parse() function. const int parse_no_element_values = 0x2; //! Parse flag instructing the parser to not place zero terminators after strings in the source text. //! By default zero terminators are placed, modifying source text. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_no_string_terminators = 0x4; //! Parse flag instructing the parser to not translate entities in the source text. //! By default entities are translated, modifying source text. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_no_entity_translation = 0x8; //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. //! By default, UTF-8 handling is enabled. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_no_utf8 = 0x10; //! Parse flag instructing the parser to create XML declaration node. //! By default, declaration node is not created. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_declaration_node = 0x20; //! Parse flag instructing the parser to create comments nodes. //! By default, comment nodes are not created. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_comment_nodes = 0x40; //! Parse flag instructing the parser to create DOCTYPE node. //! By default, doctype node is not created. //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_doctype_node = 0x80; //! Parse flag instructing the parser to create PI nodes. //! By default, PI nodes are not created. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_pi_nodes = 0x100; //! Parse flag instructing the parser to validate closing tag names. //! If not set, name inside closing tag is irrelevant to the parser. //! By default, closing tags are not validated. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_validate_closing_tags = 0x200; //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. //! By default, whitespace is not trimmed. //! This flag does not cause the parser to modify source text. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_trim_whitespace = 0x400; //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. //! By default, whitespace is not normalized. //! If this flag is specified, source text will be modified. //! Can be combined with other flags by use of | operator. //!

//! See xml_document::parse() function. const int parse_normalize_whitespace = 0x800; // Compound flags //! Parse flags which represent default behaviour of the parser. //! This is always equal to 0, so that all other flags can be simply ored together. //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. //! This also means that meaning of each flag is a negation of the default setting. //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, //! and using the flag will disable it. //!

//! See xml_document::parse() function. const int parse_default = 0; //! A combination of parse flags that forbids any modifications of the source text. //! This also results in faster parsing. However, note that the following will occur: //!
    //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • //!
  • entities will not be translated
  • //!
  • whitespace will not be normalized
  • //!
//! See xml_document::parse() function. const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. //!

//! See xml_document::parse() function. const int parse_fastest = parse_non_destructive | parse_no_data_nodes; //! A combination of parse flags resulting in largest amount of data being extracted. //! This usually results in slowest parsing. //!

//! See xml_document::parse() function. const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; /////////////////////////////////////////////////////////////////////// // Internals //! \cond internal namespace internal { // Struct that contains lookup tables for the parser // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). template struct lookup_tables { static const unsigned char lookup_whitespace[256]; // Whitespace table static const unsigned char lookup_node_name[256]; // Node name table static const unsigned char lookup_text[256]; // Text table static const unsigned char lookup_text_pure_no_ws[256]; // Text table static const unsigned char lookup_text_pure_with_ws[256]; // Text table static const unsigned char lookup_attribute_name[256]; // Attribute name table static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes static const unsigned char lookup_digits[256]; // Digits static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters }; // Find length of the string template inline std::size_t measure(const Ch *p) { const Ch *tmp = p; while (*tmp) ++tmp; return tmp - p; } // Compare strings for equality template inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) { if (size1 != size2) return false; if (case_sensitive) { for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) if (*p1 != *p2) return false; } else { for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) return false; } return true; } } //! \endcond /////////////////////////////////////////////////////////////////////// // Memory pool //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. //! In most cases, you will not need to use this class directly. //! However, if you need to create nodes manually or modify names/values of nodes, //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. //! Not only is this faster than allocating them by using new operator, //! but also their lifetime will be tied to the lifetime of document, //! possibly simplyfing memory management. //!

//! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. //! You can also call allocate_string() function to allocate strings. //! Such strings can then be used as names or values of nodes without worrying about their lifetime. //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, //! or when the pool is destroyed. //!

//! It is also possible to create a standalone memory_pool, and use it //! to allocate nodes, whose lifetime will not be tied to any document. //!

//! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. //! Until static memory is exhausted, no dynamic memory allocations are done. //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, //! by using global new[] and delete[] operators. //! This behaviour can be changed by setting custom allocation routines. //! Use set_allocator() function to set them. //!

//! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. //! This value defaults to the size of pointer on target architecture. //!

//! To obtain absolutely top performance from the parser, //! it is important that all nodes are allocated from a single, contiguous block of memory. //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT //! to obtain best wasted memory to performance compromise. //! To do it, define their values before rapidxml.hpp file is included. //! \param Ch Character type of created nodes. template class memory_pool { public: //! \cond internal typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory typedef void (free_func)(void *); // Type of user-defined function used to free memory //! \endcond //! Constructs empty pool with default allocator functions. memory_pool() : m_alloc_func(0) , m_free_func(0) { init(); } //! Destroys pool and frees all the memory. //! This causes memory occupied by nodes allocated by the pool to be freed. //! Nodes allocated from the pool are no longer valid. ~memory_pool() { clear(); } //! Allocates a new node from the pool, and optionally assigns name and value to it. //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param type Type of node to create. //! \param name Name to assign to the node, or 0 to assign no name. //! \param value Value to assign to the node, or 0 to assign no value. //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. //! \return Pointer to allocated node. This pointer will never be NULL. xml_node *allocate_node(node_type type, const Ch *name = 0, const Ch *value = 0, std::size_t name_size = 0, std::size_t value_size = 0) { void *memory = allocate_aligned(sizeof(xml_node)); xml_node *node = new(memory) xml_node(type); if (name) { if (name_size > 0) node->name(name, name_size); else node->name(name); } if (value) { if (value_size > 0) node->value(value, value_size); else node->value(value); } return node; } //! Allocates a new attribute from the pool, and optionally assigns name and value to it. //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param name Name to assign to the attribute, or 0 to assign no name. //! \param value Value to assign to the attribute, or 0 to assign no value. //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. //! \return Pointer to allocated attribute. This pointer will never be NULL. xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, std::size_t name_size = 0, std::size_t value_size = 0) { void *memory = allocate_aligned(sizeof(xml_attribute)); xml_attribute *attribute = new(memory) xml_attribute; if (name) { if (name_size > 0) attribute->name(name, name_size); else attribute->name(name); } if (value) { if (value_size > 0) attribute->value(value, value_size); else attribute->value(value); } return attribute; } //! Allocates a char array of given size from the pool, and optionally copies a given string to it. //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param source String to initialize the allocated memory with, or 0 to not initialize it. //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. //! \return Pointer to allocated char array. This pointer will never be NULL. Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) { assert(source || size); // Either source or size (or both) must be specified if (size == 0) size = internal::measure(source) + 1; Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); if (source) for (std::size_t i = 0; i < size; ++i) result[i] = source[i]; return result; } //! Clones an xml_node and its hierarchy of child nodes and attributes. //! Nodes and attributes are allocated from this memory pool. //! Names and values are not cloned, they are shared between the clone and the source. //! Result node can be optionally specified as a second parameter, //! in which case its contents will be replaced with cloned source node. //! This is useful when you want to clone entire document. //! \param source Node to clone. //! \param result Node to put results in, or 0 to automatically allocate result node //! \return Pointer to cloned node. This pointer will never be NULL. xml_node *clone_node(const xml_node *source, xml_node *result = 0) { // Prepare result node if (result) { result->remove_all_attributes(); result->remove_all_nodes(); result->type(source->type()); } else result = allocate_node(source->type()); // Clone name and value result->name(source->name(), source->name_size()); result->value(source->value(), source->value_size()); // Clone child nodes and attributes for (xml_node *child = source->first_node(); child; child = child->next_sibling()) result->append_node(clone_node(child)); for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); return result; } //! Clears the pool. //! This causes memory occupied by nodes allocated by the pool to be freed. //! Any nodes or strings allocated from the pool will no longer be valid. void clear() { while (m_begin != m_static_memory) { char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; if (m_free_func) m_free_func(m_begin); else delete[] m_begin; m_begin = previous_begin; } init(); } //! Sets or resets the user-defined memory allocation functions for the pool. //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. //! Allocation function must not return invalid pointer on failure. It should either throw, //! stop the program, or use longjmp() function to pass control to other place of program. //! If it returns invalid pointer, results are undefined. //!

//! User defined allocation functions must have the following forms: //!
//!
void *allocate(std::size_t size); //!
void free(void *pointer); //!

//! \param af Allocation function, or 0 to restore default function //! \param ff Free function, or 0 to restore default function void set_allocator(alloc_func *af, free_func *ff) { assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet m_alloc_func = af; m_free_func = ff; } private: struct header { char *previous_begin; }; void init() { m_begin = m_static_memory; m_ptr = align(m_begin); m_end = m_static_memory + sizeof(m_static_memory); } char *align(char *ptr) { std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); return ptr + alignment; } char *allocate_raw(std::size_t size) { // Allocate void *memory; if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] { memory = m_alloc_func(size); assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp } else { memory = new char[size]; #ifdef RAPIDXML_NO_EXCEPTIONS if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc RAPIDXML_PARSE_ERROR("out of memory", 0); #endif } return static_cast(memory); } void *allocate_aligned(std::size_t size) { // Calculate aligned pointer char *result = align(m_ptr); // If not enough memory left in current pool, allocate a new pool if (result + size > m_end) { // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; if (pool_size < size) pool_size = size; // Allocate std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation char *raw_memory = allocate_raw(alloc_size); // Setup new pool in allocated memory char *pool = align(raw_memory); header *new_header = reinterpret_cast
(pool); new_header->previous_begin = m_begin; m_begin = raw_memory; m_ptr = pool + sizeof(header); m_end = raw_memory + alloc_size; // Calculate aligned pointer again using new pool result = align(m_ptr); } // Update pool and return aligned pointer m_ptr = result + size; return result; } char *m_begin; // Start of raw memory making up current pool char *m_ptr; // First free byte in current pool char *m_end; // One past last available byte in current pool char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used free_func *m_free_func; // Free function, or 0 if default is to be used }; /////////////////////////////////////////////////////////////////////////// // XML base //! Base class for xml_node and xml_attribute implementing common functions: //! name(), name_size(), value(), value_size() and parent(). //! \param Ch Character type to use template class xml_base { public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction // Construct a base with empty name, value and parent xml_base() : m_name(0) , m_value(0) , m_parent(0) { } /////////////////////////////////////////////////////////////////////////// // Node data access //! Gets name of the node. //! Interpretation of name depends on type of node. //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. //!

//! Use name_size() function to determine length of the name. //! \return Name of node, or empty string if node has no name. Ch *name() const { return m_name ? m_name : nullstr(); } //! Gets size of node name, not including terminator character. //! This function works correctly irrespective of whether name is or is not zero terminated. //! \return Size of node name, in characters. std::size_t name_size() const { return m_name ? m_name_size : 0; } //! Gets value of node. //! Interpretation of value depends on type of node. //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. //!

//! Use value_size() function to determine length of the value. //! \return Value of node, or empty string if node has no value. Ch *value() const { return m_value ? m_value : nullstr(); } //! Gets size of node value, not including terminator character. //! This function works correctly irrespective of whether value is or is not zero terminated. //! \return Size of node value, in characters. std::size_t value_size() const { return m_value ? m_value_size : 0; } /////////////////////////////////////////////////////////////////////////// // Node modification //! Sets name of node to a non zero-terminated string. //! See \ref ownership_of_strings. //!

//! Note that node does not own its name or value, it only stores a pointer to it. //! It will not delete or otherwise free the pointer on destruction. //! It is reponsibility of the user to properly manage lifetime of the string. //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - //! on destruction of the document the string will be automatically freed. //!

//! Size of name must be specified separately, because name does not have to be zero terminated. //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). //! \param name Name of node to set. Does not have to be zero terminated. //! \param size Size of name, in characters. This does not include zero terminator, if one is present. void name(const Ch *name, std::size_t size) { m_name = const_cast(name); m_name_size = size; } //! Sets name of node to a zero-terminated string. //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). //! \param name Name of node to set. Must be zero terminated. void name(const Ch *name) { this->name(name, internal::measure(name)); } //! Sets value of node to a non zero-terminated string. //! See \ref ownership_of_strings. //!

//! Note that node does not own its name or value, it only stores a pointer to it. //! It will not delete or otherwise free the pointer on destruction. //! It is reponsibility of the user to properly manage lifetime of the string. //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - //! on destruction of the document the string will be automatically freed. //!

//! Size of value must be specified separately, because it does not have to be zero terminated. //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). //!

//! If an element has a child node of type node_data, it will take precedence over element value when printing. //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. //! \param value value of node to set. Does not have to be zero terminated. //! \param size Size of value, in characters. This does not include zero terminator, if one is present. void value(const Ch *value, std::size_t size) { m_value = const_cast(value); m_value_size = size; } //! Sets value of node to a zero-terminated string. //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). //! \param value Vame of node to set. Must be zero terminated. void value(const Ch *value) { this->value(value, internal::measure(value)); } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets node parent. //! \return Pointer to parent node, or 0 if there is no parent. xml_node *parent() const { return m_parent; } protected: // Return empty string static Ch *nullstr() { static Ch zero = Ch('\0'); return &zero; } Ch *m_name; // Name of node, or 0 if no name Ch *m_value; // Value of node, or 0 if no value std::size_t m_name_size; // Length of node name, or undefined of no name std::size_t m_value_size; // Length of node value, or undefined if no value xml_node *m_parent; // Pointer to parent node, or 0 if none }; //! Class representing attribute node of XML document. //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. //! Thus, this text must persist in memory for the lifetime of attribute. //! \param Ch Character type to use. template class xml_attribute: public xml_base { friend class xml_node; public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction //! Constructs an empty attribute with the specified type. //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. xml_attribute() { } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets document of which attribute is a child. //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. xml_document *document() const { if (xml_node *node = this->parent()) { while (node->parent()) node = node->parent(); return node->type() == node_document ? static_cast *>(node) : 0; } else return 0; } //! Gets previous attribute, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return this->m_parent ? m_prev_attribute : 0; } //! Gets next attribute, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return this->m_parent ? m_next_attribute : 0; } private: xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero }; /////////////////////////////////////////////////////////////////////////// // XML node //! Class representing a node of XML document. //! Each node may have associated name and value strings, which are available through name() and value() functions. //! Interpretation of name and value depends on type of the node. //! Type of node can be determined by using type() function. //!

//! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. //! Thus, this text must persist in the memory for the lifetime of node. //! \param Ch Character type to use. template class xml_node: public xml_base { public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction //! Constructs an empty node with the specified type. //! Consider using memory_pool of appropriate document to allocate nodes manually. //! \param type Type of node to construct. xml_node(node_type type) : m_type(type) , m_first_node(0) , m_first_attribute(0) { } /////////////////////////////////////////////////////////////////////////// // Node data access //! Gets type of node. //! \return Type of node. node_type type() const { return m_type; } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets document of which node is a child. //! \return Pointer to document that contains this node, or 0 if there is no parent document. xml_document *document() const { xml_node *node = const_cast *>(this); while (node->parent()) node = node->parent(); return node->type() == node_document ? static_cast *>(node) : 0; } //! Gets first child node, optionally matching node name. //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found child, or 0 if not found. xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node *child = m_first_node; child; child = child->next_sibling()) if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) return child; return 0; } else return m_first_node; } //! Gets last child node, optionally matching node name. //! Behaviour is undefined if node has no children. //! Use first_node() to test if node has children. //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found child, or 0 if not found. xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(m_first_node); // Cannot query for last child if node has no children if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node *child = m_last_node; child; child = child->previous_sibling()) if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) return child; return 0; } else return m_last_node; } //! Gets previous sibling node, optionally matching node name. //! Behaviour is undefined if node has no parent. //! Use parent() to test if node has a parent. //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found sibling, or 0 if not found. xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(this->m_parent); // Cannot query for siblings if node has no parent if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) return sibling; return 0; } else return m_prev_sibling; } //! Gets next sibling node, optionally matching node name. //! Behaviour is undefined if node has no parent. //! Use parent() to test if node has a parent. //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found sibling, or 0 if not found. xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(this->m_parent); // Cannot query for siblings if node has no parent if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) return sibling; return 0; } else return m_next_sibling; } //! Gets first attribute of node, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return m_first_attribute; } //! Gets last attribute of node, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return m_first_attribute ? m_last_attribute : 0; } /////////////////////////////////////////////////////////////////////////// // Node modification //! Sets type of node. //! \param type Type of node to set. void type(node_type type) { m_type = type; } /////////////////////////////////////////////////////////////////////////// // Node manipulation //! Prepends a new child node. //! The prepended child becomes the first child, and all existing children are moved one position back. //! \param child Node to prepend. void prepend_node(xml_node *child) { assert(child && !child->parent() && child->type() != node_document); if (first_node()) { child->m_next_sibling = m_first_node; m_first_node->m_prev_sibling = child; } else { child->m_next_sibling = 0; m_last_node = child; } m_first_node = child; child->m_parent = this; child->m_prev_sibling = 0; } //! Appends a new child node. //! The appended child becomes the last child. //! \param child Node to append. void append_node(xml_node *child) { assert(child && !child->parent() && child->type() != node_document); if (first_node()) { child->m_prev_sibling = m_last_node; m_last_node->m_next_sibling = child; } else { child->m_prev_sibling = 0; m_first_node = child; } m_last_node = child; child->m_parent = this; child->m_next_sibling = 0; } //! Inserts a new child node at specified place inside the node. //! All children after and including the specified node are moved one position back. //! \param where Place where to insert the child, or 0 to insert at the back. //! \param child Node to insert. void insert_node(xml_node *where, xml_node *child) { assert(!where || where->parent() == this); assert(child && !child->parent() && child->type() != node_document); if (where == m_first_node) prepend_node(child); else if (where == 0) append_node(child); else { child->m_prev_sibling = where->m_prev_sibling; child->m_next_sibling = where; where->m_prev_sibling->m_next_sibling = child; where->m_prev_sibling = child; child->m_parent = this; } } //! Removes first child node. //! If node has no children, behaviour is undefined. //! Use first_node() to test if node has children. void remove_first_node() { assert(first_node()); xml_node *child = m_first_node; m_first_node = child->m_next_sibling; if (child->m_next_sibling) child->m_next_sibling->m_prev_sibling = 0; else m_last_node = 0; child->m_parent = 0; } //! Removes last child of the node. //! If node has no children, behaviour is undefined. //! Use first_node() to test if node has children. void remove_last_node() { assert(first_node()); xml_node *child = m_last_node; if (child->m_prev_sibling) { m_last_node = child->m_prev_sibling; child->m_prev_sibling->m_next_sibling = 0; } else m_first_node = 0; child->m_parent = 0; } //! Removes specified child from the node // \param where Pointer to child to be removed. void remove_node(xml_node *where) { assert(where && where->parent() == this); assert(first_node()); if (where == m_first_node) remove_first_node(); else if (where == m_last_node) remove_last_node(); else { where->m_prev_sibling->m_next_sibling = where->m_next_sibling; where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; where->m_parent = 0; } } //! Removes all child nodes (but not attributes). void remove_all_nodes() { for (xml_node *node = first_node(); node; node = node->m_next_sibling) node->m_parent = 0; m_first_node = 0; } //! Prepends a new attribute to the node. //! \param attribute Attribute to prepend. void prepend_attribute(xml_attribute *attribute) { assert(attribute && !attribute->parent()); if (first_attribute()) { attribute->m_next_attribute = m_first_attribute; m_first_attribute->m_prev_attribute = attribute; } else { attribute->m_next_attribute = 0; m_last_attribute = attribute; } m_first_attribute = attribute; attribute->m_parent = this; attribute->m_prev_attribute = 0; } //! Appends a new attribute to the node. //! \param attribute Attribute to append. void append_attribute(xml_attribute *attribute) { assert(attribute && !attribute->parent()); if (first_attribute()) { attribute->m_prev_attribute = m_last_attribute; m_last_attribute->m_next_attribute = attribute; } else { attribute->m_prev_attribute = 0; m_first_attribute = attribute; } m_last_attribute = attribute; attribute->m_parent = this; attribute->m_next_attribute = 0; } //! Inserts a new attribute at specified place inside the node. //! All attributes after and including the specified attribute are moved one position back. //! \param where Place where to insert the attribute, or 0 to insert at the back. //! \param attribute Attribute to insert. void insert_attribute(xml_attribute *where, xml_attribute *attribute) { assert(!where || where->parent() == this); assert(attribute && !attribute->parent()); if (where == m_first_attribute) prepend_attribute(attribute); else if (where == 0) append_attribute(attribute); else { attribute->m_prev_attribute = where->m_prev_attribute; attribute->m_next_attribute = where; where->m_prev_attribute->m_next_attribute = attribute; where->m_prev_attribute = attribute; attribute->m_parent = this; } } //! Removes first attribute of the node. //! If node has no attributes, behaviour is undefined. //! Use first_attribute() to test if node has attributes. void remove_first_attribute() { assert(first_attribute()); xml_attribute *attribute = m_first_attribute; if (attribute->m_next_attribute) { attribute->m_next_attribute->m_prev_attribute = 0; } else m_last_attribute = 0; attribute->m_parent = 0; m_first_attribute = attribute->m_next_attribute; } //! Removes last attribute of the node. //! If node has no attributes, behaviour is undefined. //! Use first_attribute() to test if node has attributes. void remove_last_attribute() { assert(first_attribute()); xml_attribute *attribute = m_last_attribute; if (attribute->m_prev_attribute) { attribute->m_prev_attribute->m_next_attribute = 0; m_last_attribute = attribute->m_prev_attribute; } else m_first_attribute = 0; attribute->m_parent = 0; } //! Removes specified attribute from node. //! \param where Pointer to attribute to be removed. void remove_attribute(xml_attribute *where) { assert(first_attribute() && where->parent() == this); if (where == m_first_attribute) remove_first_attribute(); else if (where == m_last_attribute) remove_last_attribute(); else { where->m_prev_attribute->m_next_attribute = where->m_next_attribute; where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; where->m_parent = 0; } } //! Removes all attributes of node. void remove_all_attributes() { for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) attribute->m_parent = 0; m_first_attribute = 0; } private: /////////////////////////////////////////////////////////////////////////// // Restrictions // No copying xml_node(const xml_node &); void operator =(const xml_node &); /////////////////////////////////////////////////////////////////////////// // Data members // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. // This is required for maximum performance, as it allows the parser to omit initialization of // unneded/redundant values. // // The rules are as follows: // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage node_type m_type; // Type of node; always valid xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero }; /////////////////////////////////////////////////////////////////////////// // XML document //! This class represents root of the DOM hierarchy. //! It is also an xml_node and a memory_pool through public inheritance. //! Use parse() function to build a DOM tree from a zero-terminated XML text string. //! parse() function allocates memory for nodes and attributes by using functions of xml_document, //! which are inherited from memory_pool. //! To access root node of the document, use the document itself, as if it was an xml_node. //! \param Ch Character type to use. template class xml_document: public xml_node, public memory_pool { public: //! Constructs empty XML document xml_document() : xml_node(node_document) { } //! Parses zero-terminated XML string according to given flags. //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. //! The string must persist for the lifetime of the document. //! In case of error, rapidxml::parse_error exception will be thrown. //!

//! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. //! Make sure that data is zero-terminated. //!

//! Document can be parsed into multiple times. //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. template void parse(Ch *text) { assert(text); // Remove current contents this->remove_all_nodes(); this->remove_all_attributes(); // Parse BOM, if any parse_bom(text); // Parse children while (1) { // Skip whitespace before node skip(text); if (*text == 0) break; // Parse and append new child if (*text == Ch('<')) { ++text; // Skip '<' if (xml_node *node = parse_node(text)) this->append_node(node); } else RAPIDXML_PARSE_ERROR("expected <", text); } } //! Clears the document by deleting all nodes and clearing the memory pool. //! All nodes owned by document pool are destroyed. void clear() { this->remove_all_nodes(); this->remove_all_attributes(); memory_pool::clear(); } private: /////////////////////////////////////////////////////////////////////// // Internal character utility functions // Detect whitespace character struct whitespace_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; } }; // Detect node name character struct node_name_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; } }; // Detect attribute name character struct attribute_name_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; } }; // Detect text character (PCDATA) struct text_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; } }; // Detect text character (PCDATA) that does not require processing struct text_pure_no_ws_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; } }; // Detect text character (PCDATA) that does not require processing struct text_pure_with_ws_pred { static unsigned char test(Ch ch) { return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; } }; // Detect attribute value character template struct attribute_value_pred { static unsigned char test(Ch ch) { if (Quote == Ch('\'')) return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; if (Quote == Ch('\"')) return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; return 0; // Should never be executed, to avoid warnings on Comeau } }; // Detect attribute value character template struct attribute_value_pure_pred { static unsigned char test(Ch ch) { if (Quote == Ch('\'')) return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; if (Quote == Ch('\"')) return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; return 0; // Should never be executed, to avoid warnings on Comeau } }; // Insert coded character, using UTF8 or 8-bit ASCII template static void insert_coded_character(Ch *&text, unsigned long code) { if (Flags & parse_no_utf8) { // Insert 8-bit ASCII character // Todo: possibly verify that code is less than 256 and use replacement char otherwise? text[0] = static_cast(code); text += 1; } else { // Insert UTF8 sequence if (code < 0x80) // 1 byte sequence { text[0] = static_cast(code); text += 1; } else if (code < 0x800) // 2 byte sequence { text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[0] = static_cast(code | 0xC0); text += 2; } else if (code < 0x10000) // 3 byte sequence { text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[0] = static_cast(code | 0xE0); text += 3; } else if (code < 0x110000) // 4 byte sequence { text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; text[0] = static_cast(code | 0xF0); text += 4; } else // Invalid, only codes up to 0x10FFFF are allowed in Unicode { RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); } } } // Skip characters until predicate evaluates to true template static void skip(Ch *&text) { Ch *tmp = text; while (StopPred::test(*tmp)) ++tmp; text = tmp; } // Skip characters until predicate evaluates to true while doing the following: // - replacing XML character entity references with proper characters (' & " < > &#...;) // - condensing whitespace sequences to single space character template static Ch *skip_and_expand_character_refs(Ch *&text) { // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip if (Flags & parse_no_entity_translation && !(Flags & parse_normalize_whitespace) && !(Flags & parse_trim_whitespace)) { skip(text); return text; } // Use simple skip until first modification is detected skip(text); // Use translation skip Ch *src = text; Ch *dest = src; while (StopPred::test(*src)) { // If entity translation is enabled if (!(Flags & parse_no_entity_translation)) { // Test if replacement is needed if (src[0] == Ch('&')) { switch (src[1]) { // & ' case Ch('a'): if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) { *dest = Ch('&'); ++dest; src += 5; continue; } if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) { *dest = Ch('\''); ++dest; src += 6; continue; } break; // " case Ch('q'): if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) { *dest = Ch('"'); ++dest; src += 6; continue; } break; // > case Ch('g'): if (src[2] == Ch('t') && src[3] == Ch(';')) { *dest = Ch('>'); ++dest; src += 4; continue; } break; // < case Ch('l'): if (src[2] == Ch('t') && src[3] == Ch(';')) { *dest = Ch('<'); ++dest; src += 4; continue; } break; // &#...; - assumes ASCII case Ch('#'): if (src[2] == Ch('x')) { unsigned long code = 0; src += 3; // Skip &#x while (1) { unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; if (digit == 0xFF) break; code = code * 16 + digit; ++src; } insert_coded_character(dest, code); // Put character in output } else { unsigned long code = 0; src += 2; // Skip &# while (1) { unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; if (digit == 0xFF) break; code = code * 10 + digit; ++src; } insert_coded_character(dest, code); // Put character in output } if (*src == Ch(';')) ++src; else RAPIDXML_PARSE_ERROR("expected ;", src); continue; // Something else default: // Ignore, just copy '&' verbatim break; } } } // If whitespace condensing is enabled if (Flags & parse_normalize_whitespace) { // Test if condensing is needed if (whitespace_pred::test(*src)) { *dest = Ch(' '); ++dest; // Put single space in dest ++src; // Skip first whitespace char // Skip remaining whitespace chars while (whitespace_pred::test(*src)) ++src; continue; } } // No replacement, only copy character *dest++ = *src++; } // Return new end text = src; return dest; } /////////////////////////////////////////////////////////////////////// // Internal parsing functions // Parse BOM, if any template void parse_bom(Ch *&text) { // UTF-8? if (static_cast(text[0]) == 0xEF && static_cast(text[1]) == 0xBB && static_cast(text[2]) == 0xBF) { text += 3; // Skup utf-8 bom } } // Parse XML declaration ( xml_node *parse_xml_declaration(Ch *&text) { // If parsing of declaration is disabled if (!(Flags & parse_declaration_node)) { // Skip until end of declaration while (text[0] != Ch('?') || text[1] != Ch('>')) { if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } text += 2; // Skip '?>' return 0; } // Create declaration xml_node *declaration = this->allocate_node(node_declaration); // Skip whitespace before attributes or ?> skip(text); // Parse declaration attributes parse_node_attributes(text, declaration); // Skip ?> if (text[0] != Ch('?') || text[1] != Ch('>')) RAPIDXML_PARSE_ERROR("expected ?>", text); text += 2; return declaration; } // Parse XML comment (' return 0; // Do not produce comment node } // Remember value start Ch *value = text; // Skip until end of comment while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) { if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } // Create comment node xml_node *comment = this->allocate_node(node_comment); comment->value(value, text - value); // Place zero terminator after comment value if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); text += 3; // Skip '-->' return comment; } // Parse DOCTYPE template xml_node *parse_doctype(Ch *&text) { // Remember value start Ch *value = text; // Skip to > while (*text != Ch('>')) { // Determine character type switch (*text) { // If '[' encountered, scan for matching ending ']' using naive algorithm with depth // This works for all W3C test files except for 2 most wicked case Ch('['): { ++text; // Skip '[' int depth = 1; while (depth > 0) { switch (*text) { case Ch('['): ++depth; break; case Ch(']'): --depth; break; case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); } ++text; } break; } // Error on end of text case Ch('\0'): RAPIDXML_PARSE_ERROR("unexpected end of data", text); // Other character, skip it default: ++text; } } // If DOCTYPE nodes enabled if (Flags & parse_doctype_node) { // Create a new doctype node xml_node *doctype = this->allocate_node(node_doctype); doctype->value(value, text - value); // Place zero terminator after value if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); text += 1; // skip '>' return doctype; } else { text += 1; // skip '>' return 0; } } // Parse PI template xml_node *parse_pi(Ch *&text) { // If creation of PI nodes is enabled if (Flags & parse_pi_nodes) { // Create pi node xml_node *pi = this->allocate_node(node_pi); // Extract PI target name Ch *name = text; skip(text); if (text == name) RAPIDXML_PARSE_ERROR("expected PI target", text); pi->name(name, text - name); // Skip whitespace between pi target and pi skip(text); // Remember start of pi Ch *value = text; // Skip to '?>' while (text[0] != Ch('?') || text[1] != Ch('>')) { if (*text == Ch('\0')) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } // Set pi value (verbatim, no entity expansion or whitespace normalization) pi->value(value, text - value); // Place zero terminator after name and value if (!(Flags & parse_no_string_terminators)) { pi->name()[pi->name_size()] = Ch('\0'); pi->value()[pi->value_size()] = Ch('\0'); } text += 2; // Skip '?>' return pi; } else { // Skip to '?>' while (text[0] != Ch('?') || text[1] != Ch('>')) { if (*text == Ch('\0')) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } text += 2; // Skip '?>' return 0; } } // Parse and append data // Return character that ends data. // This is necessary because this character might have been overwritten by a terminating 0 template Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) { // Backup to contents start if whitespace trimming is disabled if (!(Flags & parse_trim_whitespace)) text = contents_start; // Skip until end of data Ch *value = text, *end; if (Flags & parse_normalize_whitespace) end = skip_and_expand_character_refs(text); else end = skip_and_expand_character_refs(text); // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > if (Flags & parse_trim_whitespace) { if (Flags & parse_normalize_whitespace) { // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end if (*(end - 1) == Ch(' ')) --end; } else { // Backup until non-whitespace character is found while (whitespace_pred::test(*(end - 1))) --end; } } // If characters are still left between end and value (this test is only necessary if normalization is enabled) // Create new data node if (!(Flags & parse_no_data_nodes)) { xml_node *data = this->allocate_node(node_data); data->value(value, end - value); node->append_node(data); } // Add data to parent node if no data exists yet if (!(Flags & parse_no_element_values)) if (*node->value() == Ch('\0')) node->value(value, end - value); // Place zero terminator after value if (!(Flags & parse_no_string_terminators)) { Ch ch = *text; *end = Ch('\0'); return ch; // Return character that ends data; this is required because zero terminator overwritten it } // Return character that ends data return *text; } // Parse CDATA template xml_node *parse_cdata(Ch *&text) { // If CDATA is disabled if (Flags & parse_no_data_nodes) { // Skip until end of cdata while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) { if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } text += 3; // Skip ]]> return 0; // Do not produce CDATA node } // Skip until end of cdata Ch *value = text; while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) { if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } // Create new cdata node xml_node *cdata = this->allocate_node(node_cdata); cdata->value(value, text - value); // Place zero terminator after value if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); text += 3; // Skip ]]> return cdata; } // Parse element node template xml_node *parse_element(Ch *&text) { // Create element node xml_node *element = this->allocate_node(node_element); // Extract element name Ch *name = text; skip(text); if (text == name) RAPIDXML_PARSE_ERROR("expected element name", text); element->name(name, text - name); // Skip whitespace between element name and attributes or > skip(text); // Parse attributes, if any parse_node_attributes(text, element); // Determine ending type if (*text == Ch('>')) { ++text; parse_node_contents(text, element); } else if (*text == Ch('/')) { ++text; if (*text != Ch('>')) RAPIDXML_PARSE_ERROR("expected >", text); ++text; } else RAPIDXML_PARSE_ERROR("expected >", text); // Place zero terminator after name if (!(Flags & parse_no_string_terminators)) element->name()[element->name_size()] = Ch('\0'); // Return parsed element return element; } // Determine node type, and parse it template xml_node *parse_node(Ch *&text) { // Parse proper node type switch (text[0]) { // <... default: // Parse and append element node return parse_element(text); // (text); } else { // Parse PI return parse_pi(text); } // (text); } break; // (text); } break; // (text); } } // switch // Attempt to skip other, unrecognized node types starting with ')) { if (*text == 0) RAPIDXML_PARSE_ERROR("unexpected end of data", text); ++text; } ++text; // Skip '>' return 0; // No node recognized } } // Parse contents of the node - children, data etc. template void parse_node_contents(Ch *&text, xml_node *node) { // For all children and text while (1) { // Skip whitespace between > and node contents Ch *contents_start = text; // Store start of node contents before whitespace is skipped skip(text); Ch next_char = *text; // After data nodes, instead of continuing the loop, control jumps here. // This is because zero termination inside parse_and_append_data() function // would wreak havoc with the above code. // Also, skipping whitespace after data nodes is unnecessary. after_data_node: // Determine what comes next: node closing, child node, data node, or 0? switch (next_char) { // Node closing or child node case Ch('<'): if (text[1] == Ch('/')) { // Node closing text += 2; // Skip '(text); if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) RAPIDXML_PARSE_ERROR("invalid closing tag name", text); } else { // No validation, just skip name skip(text); } // Skip remaining whitespace after node name skip(text); if (*text != Ch('>')) RAPIDXML_PARSE_ERROR("expected >", text); ++text; // Skip '>' return; // Node closed, finished parsing contents } else { // Child node ++text; // Skip '<' if (xml_node *child = parse_node(text)) node->append_node(child); } break; // End of data - error case Ch('\0'): RAPIDXML_PARSE_ERROR("unexpected end of data", text); // Data node default: next_char = parse_and_append_data(node, text, contents_start); goto after_data_node; // Bypass regular processing after data nodes } } } // Parse XML attributes of the node template void parse_node_attributes(Ch *&text, xml_node *node) { // For all attributes while (attribute_name_pred::test(*text)) { // Extract attribute name Ch *name = text; ++text; // Skip first character of attribute name skip(text); if (text == name) RAPIDXML_PARSE_ERROR("expected attribute name", name); // Create new attribute xml_attribute *attribute = this->allocate_attribute(); attribute->name(name, text - name); node->append_attribute(attribute); // Skip whitespace after attribute name skip(text); // Skip = if (*text != Ch('=')) RAPIDXML_PARSE_ERROR("expected =", text); ++text; // Add terminating zero after name if (!(Flags & parse_no_string_terminators)) attribute->name()[attribute->name_size()] = 0; // Skip whitespace after = skip(text); // Skip quote and remember if it was ' or " Ch quote = *text; if (quote != Ch('\'') && quote != Ch('"')) RAPIDXML_PARSE_ERROR("expected ' or \"", text); ++text; // Extract attribute value and expand char refs in it Ch *value = text, *end; const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes if (quote == Ch('\'')) end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); else end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); // Set attribute value attribute->value(value, end - value); // Make sure that end quote is present if (*text != quote) RAPIDXML_PARSE_ERROR("expected ' or \"", text); ++text; // Skip quote // Add terminating zero after value if (!(Flags & parse_no_string_terminators)) attribute->value()[attribute->value_size()] = 0; // Skip whitespace after attribute value skip(text); } } }; //! \cond internal namespace internal { // Whitespace (space \n \r \t) template const unsigned char lookup_tables::lookup_whitespace[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F }; // Node name (anything but space \n \r \t / > ? \0) template const unsigned char lookup_tables::lookup_node_name[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Text (i.e. PCDATA) (anything but < \0) template const unsigned char lookup_tables::lookup_text[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled // (anything but < \0 &) template const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled // (anything but < \0 & space \n \r \t) template const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Attribute name (anything but space \n \r \t / < > = ? ! \0) template const unsigned char lookup_tables::lookup_attribute_name[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Attribute data with single quote (anything but ' \0) template const unsigned char lookup_tables::lookup_attribute_data_1[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Attribute data with single quote that does not require processing (anything but ' \0 &) template const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Attribute data with double quote (anything but " \0) template const unsigned char lookup_tables::lookup_attribute_data_2[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Attribute data with double quote that does not require processing (anything but " \0 &) template const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F }; // Digits (dec and hex, 255 denotes end of numeric character reference) template const unsigned char lookup_tables::lookup_digits[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F }; // Upper case conversion template const unsigned char lookup_tables::lookup_upcase[256] = { // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F }; } //! \endcond } // Undefine internal macros #undef RAPIDXML_PARSE_ERROR // On MSVC, restore warnings state #ifdef _MSC_VER #pragma warning(pop) #endif #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/rapidxml/rapidxml_print.h000066400000000000000000000377171231531733200300650ustar00rootroot00000000000000#ifndef RAPIDXML_PRINT_HPP_INCLUDED #define RAPIDXML_PRINT_HPP_INCLUDED // Copyright (C) 2006, 2009 Marcin Kalicinski // Version 1.13 // Revision $DateTime: 2009/05/13 01:46:17 $ //! \file rapidxml_print.hpp This file contains rapidxml printer implementation #include "rapidxml.h" // Only include streams if not disabled #ifndef RAPIDXML_NO_STREAMS #include #include #endif #define NUMINDENT 2 namespace rapidxml { /////////////////////////////////////////////////////////////////////// // Printing flags const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. /////////////////////////////////////////////////////////////////////// // Internal //! \cond internal namespace internal { /////////////////////////////////////////////////////////////////////////// // Internal character operations // Copy characters from given range to given output iterator template inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) { while (begin != end) *out++ = *begin++; return out; } // Copy characters from given range to given output iterator and expand // characters into references (< > ' " &) template inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) { while (begin != end) { if (*begin == noexpand) { *out++ = *begin; // No expansion, copy character } else { switch (*begin) { case Ch('<'): *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); break; case Ch('>'): *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); break; case Ch('\''): *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); break; case Ch('"'): *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); break; case Ch('&'): *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); break; default: *out++ = *begin; // No expansion, copy character } } ++begin; // Step to next character } return out; } // Fill given output iterator with repetitions of the same character template inline OutIt fill_chars(OutIt out, int n, Ch ch) { for (int i = 0; i < n; ++i) *out++ = ch; return out; } // Find character template inline bool find_char(const Ch *begin, const Ch *end) { while (begin != end) if (*begin++ == ch) return true; return false; } /////////////////////////////////////////////////////////////////////////// // Internal printing operations // Print node template inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) { // Print proper node type switch (node->type()) { // Document case node_document: out = print_children(out, node, flags, indent); break; // Element case node_element: out = print_element_node(out, node, flags, indent); break; // Data case node_data: out = print_data_node(out, node, flags, indent); break; // CDATA case node_cdata: out = print_cdata_node(out, node, flags, indent); break; // Declaration case node_declaration: out = print_declaration_node(out, node, flags, indent); break; // Comment case node_comment: out = print_comment_node(out, node, flags, indent); break; // Doctype case node_doctype: out = print_doctype_node(out, node, flags, indent); break; // Pi case node_pi: out = print_pi_node(out, node, flags, indent); break; // Unknown default: assert(0); break; } // If indenting not disabled, add line break after node if (!(flags & print_no_indenting)){ #ifdef WIN32 *out = Ch('\r'), ++out; #endif *out = Ch('\n'), ++out; } // Return modified iterator return out; } // Print children of the node template inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) { for (xml_node *child = node->first_node(); child; child = child->next_sibling()) out = print_node(out, child, flags, indent); return out; } // Print attributes of the node template inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) { for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) { if (attribute->name() && attribute->value()) { // Print attribute name *out = Ch(' '), ++out; out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); *out = Ch('='), ++out; // Print attribute value using appropriate quote type if (find_char(attribute->value(), attribute->value() + attribute->value_size())) { *out = Ch('\''), ++out; out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); *out = Ch('\''), ++out; } else { *out = Ch('"'), ++out; out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); *out = Ch('"'), ++out; } } } return out; } // Print data node template inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_data); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); return out; } // Print data node template inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_cdata); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'); ++out; *out = Ch('!'); ++out; *out = Ch('['); ++out; *out = Ch('C'); ++out; *out = Ch('D'); ++out; *out = Ch('A'); ++out; *out = Ch('T'); ++out; *out = Ch('A'); ++out; *out = Ch('['); ++out; out = copy_chars(node->value(), node->value() + node->value_size(), out); *out = Ch(']'); ++out; *out = Ch(']'); ++out; *out = Ch('>'); ++out; return out; } // Print element node template inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_element); // Print element name and attributes, if any if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'), ++out; out = copy_chars(node->name(), node->name() + node->name_size(), out); out = print_attributes(out, node, flags); // If node is childless if (node->value_size() == 0 && !node->first_node()) { // Print childless node tag ending *out = Ch('/'), ++out; *out = Ch('>'), ++out; } else { // Print normal node tag ending *out = Ch('>'), ++out; // Test if node contains a single data node only (and no other nodes) xml_node *child = node->first_node(); if (!child) { // If node has no children, only print its value without indenting out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); } else if (child->next_sibling() == 0 && child->type() == node_data) { // If node has a sole data child, only print its value without indenting out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); } else { // Print all children with full indenting if (!(flags & print_no_indenting)){ #ifdef WIN32 *out = Ch('\r'), ++out; //for windows only... #endif *out = Ch('\n'), ++out; } out = print_children(out, node, flags, indent + 1); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); } // Print node end *out = Ch('<'), ++out; *out = Ch('/'), ++out; out = copy_chars(node->name(), node->name() + node->name_size(), out); *out = Ch('>'), ++out; } return out; } // Print declaration node template inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) { // Print declaration start if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'), ++out; *out = Ch('?'), ++out; *out = Ch('x'), ++out; *out = Ch('m'), ++out; *out = Ch('l'), ++out; // Print attributes out = print_attributes(out, node, flags); // Print declaration end *out = Ch('?'), ++out; *out = Ch('>'), ++out; return out; } // Print comment node template inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_comment); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'), ++out; *out = Ch('!'), ++out; *out = Ch('-'), ++out; *out = Ch('-'), ++out; out = copy_chars(node->value(), node->value() + node->value_size(), out); *out = Ch('-'), ++out; *out = Ch('-'), ++out; *out = Ch('>'), ++out; return out; } // Print doctype node template inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_doctype); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'), ++out; *out = Ch('!'), ++out; *out = Ch('D'), ++out; *out = Ch('O'), ++out; *out = Ch('C'), ++out; *out = Ch('T'), ++out; *out = Ch('Y'), ++out; *out = Ch('P'), ++out; *out = Ch('E'), ++out; *out = Ch(' '), ++out; out = copy_chars(node->value(), node->value() + node->value_size(), out); *out = Ch('>'), ++out; return out; } // Print pi node template inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) { assert(node->type() == node_pi); if (!(flags & print_no_indenting)) out = fill_chars(out, NUMINDENT*indent, Ch(' ')); *out = Ch('<'), ++out; *out = Ch('?'), ++out; out = copy_chars(node->name(), node->name() + node->name_size(), out); *out = Ch(' '), ++out; out = copy_chars(node->value(), node->value() + node->value_size(), out); *out = Ch('?'), ++out; *out = Ch('>'), ++out; return out; } } //! \endcond /////////////////////////////////////////////////////////////////////////// // Printing //! Prints XML to given output iterator. //! \param out Output iterator to print to. //! \param node Node to be printed. Pass xml_document to print entire document. //! \param flags Flags controlling how XML is printed. //! \return Output iterator pointing to position immediately after last character of printed text. template inline OutIt print(OutIt out, const xml_node &node, int flags = 0) { return internal::print_node(out, &node, flags, 0); } #ifndef RAPIDXML_NO_STREAMS //! Prints XML to given output stream. //! \param out Output stream to print to. //! \param node Node to be printed. Pass xml_document to print entire document. //! \param flags Flags controlling how XML is printed. //! \return Output stream. template inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) { print(std::ostream_iterator(out), node, flags); return out; } //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. //! \param out Output stream to print to. //! \param node Node to be printed. //! \return Output stream. template inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) { return print(out, node); } #endif } #endif repsnapper-2.3.2a5/libraries/amf/amftools-code/include/stb_image/000077500000000000000000000000001231531733200247535ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/stb_image/stb_image.h000066400000000000000000000337101231531733200270620ustar00rootroot00000000000000/* stbi-1.33 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c when you control the images you're loading no warranty implied; use at your own risk QUICK NOTES: Primarily of interest to game developers and other people who can avoid problematic images and only need the trivial interface JPEG baseline (no JPEG progressive) PNG 8-bit only TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE PSD (composited view only, no extra channels) GIF (*comp always reports as 4-channel) HDR (radiance rgbE format) PIC (Softimage PIC) - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - decode from arbitrary I/O callbacks - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) Latest revisions: 1.33 (2011-07-14) minor fixes suggested by Dave Moore 1.32 (2011-07-13) info support for all filetypes (SpartanJ) 1.31 (2011-06-19) a few more leak fixes, bug in PNG handling (SpartanJ) 1.30 (2011-06-11) added ability to load files via io callbacks (Ben Wenger) 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) cast-to-uint8 to fix warnings (Laurent Gomila) allow trailing 0s at end of image data (Laurent Gomila) 1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ See end of file for full revision history. TODO: stbi_info support for BMP,PSD,HDR,PIC ============================ Contributors ========================= Image formats Optimizations & bugfixes Sean Barrett (jpeg, png, bmp) Fabian "ryg" Giesen Nicolas Schulz (hdr, psd) Jonathan Dummer (tga) Bug fixes & warning fixes Jean-Marc Lienher (gif) Marc LeBlanc Tom Seddon (pic) Christpher Lloyd Thatcher Ulrich (psd) Dave Moore Won Chun the Horde3D community Extensions, features Janez Zemva Jetro Lauha (stbi_info) Jonathan Blow James "moose2000" Brown (iPhone PNG) Laurent Gomila Ben "Disch" Wenger (io callbacks) Aruelien Pocheville Martin "SpartanJ" Golini Ryamond Barbiero David Woo If your name should be here but isn't, let Sean know. */ #ifndef STBI_INCLUDE_STB_IMAGE_H #define STBI_INCLUDE_STB_IMAGE_H // To get a header file for this, either cut and paste the header, // or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and // then include stb_image.c from it. //// begin header file //////////////////////////////////////////////////// // // Limitations: // - no jpeg progressive support // - non-HDR formats support 8-bit samples only (jpeg, png) // - no delayed line count (jpeg) -- IJG doesn't support either // - no 1-bit BMP // - GIF always returns *comp=4 // // Basic usage (see HDR discussion below): // int x,y,n; // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); // // ... process data if not NULL ... // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 // stbi_image_free(data) // // Standard parameters: // int *x -- outputs image width in pixels // int *y -- outputs image height in pixels // int *comp -- outputs # of image components in image file // int req_comp -- if non-zero, # of image components requested in result // // The return value from an image loader is an 'unsigned char *' which points // to the pixel data. The pixel data consists of *y scanlines of *x pixels, // with each pixel consisting of N interleaved 8-bit components; the first // pixel pointed to is top-left-most in the image. There is no padding between // image scanlines or between pixels, regardless of format. The number of // components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. // If req_comp is non-zero, *comp has the number of components that _would_ // have been output otherwise. E.g. if you set req_comp to 4, you will always // get RGBA output, but you can check *comp to easily see if it's opaque. // // An output image with N components has the following components interleaved // in this order in each pixel: // // N=#comp components // 1 grey // 2 grey, alpha // 3 red, green, blue // 4 red, green, blue, alpha // // If image loading fails for any reason, the return value will be NULL, // and *x, *y, *comp will be unchanged. The function stbi_failure_reason() // can be queried for an extremely brief, end-user unfriendly explanation // of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid // compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly // more user-friendly ones. // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // // =========================================================================== // // iPhone PNG support: // // By default we convert iphone-formatted PNGs back to RGB; nominally they // would silently load as BGR, except the existing code should have just // failed on such iPhone PNGs. But you can disable this conversion by // by calling stbi_convert_iphone_png_to_rgb(0), in which case // you will always just get the native iphone "format" through. // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly // says there's premultiplied data (currently only happens in iPhone images, // and only if iPhone convert-to-rgb processing is on). // // =========================================================================== // // HDR image support (disable by defining STBI_NO_HDR) // // stb_image now supports loading HDR images in general, and currently // the Radiance .HDR file format, although the support is provided // generically. You can still load any file through the existing interface; // if you attempt to load an HDR file, it will be automatically remapped to // LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; // both of these constants can be reconfigured through this interface: // // stbi_hdr_to_ldr_gamma(2.2f); // stbi_hdr_to_ldr_scale(1.0f); // // (note, do not use _inverse_ constants; stbi_image will invert them // appropriately). // // Additionally, there is a new, parallel interface for loading files as // (linear) floats to preserve the full dynamic range: // // float *data = stbi_loadf(filename, &x, &y, &n, 0); // // If you load LDR images through this interface, those images will // be promoted to floating point values, run through the inverse of // constants corresponding to the above: // // stbi_ldr_to_hdr_scale(1.0f); // stbi_ldr_to_hdr_gamma(2.2f); // // Finally, given a filename (or an open file or memory block--see header // file for details) containing image data, you can query for the "most // appropriate" interface to use (that is, whether the image is HDR or // not), using: // // stbi_is_hdr(char *filename); // // =========================================================================== // // I/O callbacks // // I/O callbacks allow you to read from arbitrary sources, like packaged // files or some other source. Data read from callbacks are processed // through a small internal buffer (currently 128 bytes) to try to reduce // overhead. // // The three functions you must define are "read" (reads some bytes of data), // "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). #ifndef STBI_NO_STDIO #if defined(_MSC_VER) && _MSC_VER >= 0x1400 #define _CRT_SECURE_NO_WARNINGS // suppress bogus warnings about fopen() #endif #include #endif #define STBI_VERSION 1 enum { STBI_default = 0, // only used for req_comp STBI_grey = 1, STBI_grey_alpha = 2, STBI_rgb = 3, STBI_rgb_alpha = 4 }; typedef unsigned char stbi_uc; #ifdef __cplusplus extern "C" { #endif ////////////////////////////////////////////////////////////////////////////// // // PRIMARY API - works on images of any type // // // load image by filename, open file, or memory buffer // extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif typedef struct { int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read void (*skip) (void *user,unsigned n); // skip the next 'n' bytes int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; extern stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_HDR extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif extern float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); extern void stbi_hdr_to_ldr_gamma(float gamma); extern void stbi_hdr_to_ldr_scale(float scale); extern void stbi_ldr_to_hdr_gamma(float gamma); extern void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_HDR // stbi_is_hdr is always defined extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO extern int stbi_is_hdr (char const *filename); extern int stbi_is_hdr_from_file(FILE *f); #endif // STBI_NO_STDIO // get a VERY brief reason for failure // NOT THREADSAFE extern const char *stbi_failure_reason (void); // free the loaded image -- this is just free() extern void stbi_image_free (void *retval_from_stbi_load); // get image dimensions & components without fully decoding extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); extern int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); #ifndef STBI_NO_STDIO extern int stbi_info (char const *filename, int *x, int *y, int *comp); extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); #endif // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); // indicate whether we should process iphone images back to canonical format, // or just pass them through "as-is" extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // ZLIB client - used by PNG, available for other purposes extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); // define faster low-level operations (typically SIMD support) #ifdef STBI_SIMD typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize); // compute an integer IDCT on "input" // input[x] = data[x] * dequantize[x] // write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' // CLAMP results to 0..255 typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step); // compute a conversion from YCbCr to RGB // 'count' pixels // write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B // y: Y input channel // cb: Cb input channel; scale/biased to be 0..255 // cr: Cr input channel; scale/biased to be 0..255 extern void stbi_install_idct(stbi_idct_8x8 func); extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); #endif // STBI_SIMD #ifdef __cplusplus } #endif // // //// end header file ///////////////////////////////////////////////////// #endif // STBI_INCLUDE_STB_IMAGE_H repsnapper-2.3.2a5/libraries/amf/amftools-code/include/zip/000077500000000000000000000000001231531733200236235ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/include/zip/unzip.h000066400000000000000000000236521231531733200251510ustar00rootroot00000000000000#ifdef WIN32 #ifndef _unzip_H #define _unzip_H // UNZIPPING functions -- for unzipping. // This file is a repackaged form of extracts from the zlib code available // at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original // copyright notice may be found in unzip.cpp. The repackaging was done // by Lucian Wischik to simplify and extend its use in Windows/C++. Also // encryption and unicode filenames have been added. #ifndef _zip_H DECLARE_HANDLE(HZIP); #endif // An HZIP identifies a zip file that has been opened typedef DWORD ZRESULT; // return codes from any of the zip functions. Listed later. typedef struct { int index; // index of this file within the zip TCHAR name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRY; HZIP OpenZip(const TCHAR *fn, const char *password); HZIP OpenZip(void *z,unsigned int len, const char *password); HZIP OpenZipHandle(HANDLE h, const char *password); // OpenZip - opens a zip file and returns a handle with which you can // subsequently examine its contents. You can open a zip file from: // from a pipe: OpenZipHandle(hpipe_read,0); // from a file (by handle): OpenZipHandle(hfile,0); // from a file (by name): OpenZip("c:\\test.zip","password"); // from a memory block: OpenZip(bufstart, buflen,0); // If the file is opened through a pipe, then items may only be // accessed in increasing order, and an item may only be unzipped once, // although GetZipItem can be called immediately before and after unzipping // it. If it's opened in any other way, then full random access is possible. // Note: pipe input is not yet implemented. // Note: zip passwords are ascii, not unicode. // Note: for windows-ce, you cannot close the handle until after CloseZip. // but for real windows, the zip makes its own copy of your handle, so you // can close yours anytime. ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze); // GetZipItem - call this to get information about an item in the zip. // If index is -1 and the file wasn't opened through a pipe, // then it returns information about the whole zipfile // (and in particular ze.index returns the number of index items). // Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) // See below for notes on what happens when you unzip such an item. // Note: if you are opening the zip through a pipe, then random access // is not possible and GetZipItem(-1) fails and you can't discover the number // of items except by calling GetZipItem on each one of them in turn, // starting at 0, until eventually the call fails. Also, in the event that // you are opening through a pipe and the zip was itself created into a pipe, // then then comp_size and sometimes unc_size as well may not be known until // after the item has been unzipped. ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); // FindZipItem - finds an item by name. ic means 'insensitive to case'. // It returns the index of the item, and returns information about it. // If nothing was found, then index is set to -1 and the function returns // an error code. ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn); ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len); ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h); // UnzipItem - given an index to an item, unzips it. You can unzip to: // to a pipe: UnzipItemHandle(hz,i, hpipe_write); // to a file (by handle): UnzipItemHandle(hz,i, hfile); // to a file (by name): UnzipItem(hz,i, ze.name); // to a memory block: UnzipItem(hz,i, buf,buflen); // In the final case, if the buffer isn't large enough to hold it all, // then the return code indicates that more is yet to come. If it was // large enough, and you want to know precisely how big, GetZipItem. // Note: zip files are normally stored with relative pathnames. If you // unzip with ZIP_FILENAME a relative pathname then the item gets created // relative to the current directory - it first ensures that all necessary // subdirectories have been created. Also, the item may itself be a directory. // If you unzip a directory with ZIP_FILENAME, then the directory gets created. // If you unzip it to a handle or a memory block, then nothing gets created // and it emits 0 bytes. ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir); // if unzipping to a filename, and it's a relative filename, then it will be relative to here. // (defaults to current-directory). ZRESULT CloseZip(HZIP hz); // CloseZip - the zip handle must be closed with this function. unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); // FormatZipMessage - given an error code, formats it as a string. // It returns the length of the error message. If buf/len points // to a real buffer, then it also writes as much as possible into there. // These are the result codes: #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. // The following come from general system stuff (e.g. files not openable) #define ZR_GENMASK 0x0000FF00 #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle #define ZR_NOFILE 0x00000200 // couldn't create/open the file #define ZR_NOALLOC 0x00000300 // failed to allocate some resource #define ZR_WRITE 0x00000400 // a general error writing to the file #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip #define ZR_MORE 0x00000600 // there's still more data to be unzipped #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile #define ZR_READ 0x00000800 // a general error reading the file #define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file // The following come from mistakes on the part of the caller #define ZR_CALLERMASK 0x00FF0000 #define ZR_ARGS 0x00010000 // general mistake with the arguments #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't #define ZR_MEMSIZE 0x00030000 // the memory size is too small #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function #define ZR_ENDED 0x00050000 // the zip creation has already been closed #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip // The following come from bugs within the zip library itself #define ZR_BUGMASK 0xFF000000 #define ZR_NOTINITED 0x01000000 // initialisation didn't work #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code // e.g. // // SetCurrentDirectory("c:\\docs\\stuff"); // HZIP hz = OpenZip("c:\\stuff.zip",0); // ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; // for (int i=0; i // ZIP functions -- for creating zip files // This file is a repackaged form of the Info-Zip source code available // at www.info-zip.org. The original copyright notice may be found in // zip.cpp. The repackaging was done by Lucian Wischik to simplify and // extend its use in Windows/C++. Also to add encryption and unicode. #ifndef _unzip_H DECLARE_HANDLE(HZIP); #endif // An HZIP identifies a zip file that is being created typedef DWORD ZRESULT; // return codes from any of the zip functions. Listed later. HZIP CreateZip(const TCHAR *fn, const char *password); HZIP CreateZip(void *buf,unsigned int len, const char *password); HZIP CreateZipHandle(HANDLE h, const char *password); // CreateZip - call this to start the creation of a zip file. // As the zip is being created, it will be stored somewhere: // to a pipe: CreateZipHandle(hpipe_write); // in a file (by handle): CreateZipHandle(hfile); // in a file (by name): CreateZip("c:\\test.zip"); // in memory: CreateZip(buf, len); // or in pagefile memory: CreateZip(0, len); // The final case stores it in memory backed by the system paging file, // where the zip may not exceed len bytes. This is a bit friendlier than // allocating memory with new[]: it won't lead to fragmentation, and the // memory won't be touched unless needed. That means you can give very // large estimates of the maximum-size without too much worry. // As for the password, it lets you encrypt every file in the archive. // (This api doesn't support per-file encryption.) // Note: because pipes don't allow random access, the structure of a zipfile // created into a pipe is slightly different from that created into a file // or memory. In particular, the compressed-size of the item cannot be // stored in the zipfile until after the item itself. (Also, for an item added // itself via a pipe, the uncompressed-size might not either be known until // after.) This is not normally a problem. But if you try to unzip via a pipe // as well, then the unzipper will not know these things about the item until // after it has been unzipped. Therefore: for unzippers which don't just write // each item to disk or to a pipe, but instead pre-allocate memory space into // which to unzip them, then either you have to create the zip not to a pipe, // or you have to add items not from a pipe, or at least when adding items // from a pipe you have to specify the length. // Note: for windows-ce, you cannot close the handle until after CloseZip. // but for real windows, the zip makes its own copy of your handle, so you // can close yours anytime. ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn); ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len); ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h); ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len); ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn); // ZipAdd - call this for each file to be added to the zip. // dstzn is the name that the file will be stored as in the zip file. // The file to be added to the zip can come // from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read); // from a file: ZipAddHandle(hz,"file.dat", hfile); // from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat"); // from memory: ZipAdd(hz,"subdir\\file.dat", buf,len); // (folder): ZipAddFolder(hz,"subdir"); // Note: if adding an item from a pipe, and if also creating the zip file itself // to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle // function. This will let the zipfile store the item's size ahead of the // compressed item itself, which in turn makes it easier when unzipping the // zipfile from a pipe. ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len); // ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len), // then this function will return information about that memory block. // buf will receive a pointer to its start, and len its length. // Note: you can't add any more after calling this. ZRESULT CloseZip(HZIP hz); // CloseZip - the zip handle must be closed with this function. unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); // FormatZipMessage - given an error code, formats it as a string. // It returns the length of the error message. If buf/len points // to a real buffer, then it also writes as much as possible into there. // These are the result codes: #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. // The following come from general system stuff (e.g. files not openable) #define ZR_GENMASK 0x0000FF00 #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle #define ZR_NOFILE 0x00000200 // couldn't create/open the file #define ZR_NOALLOC 0x00000300 // failed to allocate some resource #define ZR_WRITE 0x00000400 // a general error writing to the file #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip #define ZR_MORE 0x00000600 // there's still more data to be unzipped #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile #define ZR_READ 0x00000800 // a general error reading the file // The following come from mistakes on the part of the caller #define ZR_CALLERMASK 0x00FF0000 #define ZR_ARGS 0x00010000 // general mistake with the arguments #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't #define ZR_MEMSIZE 0x00030000 // the memory size is too small #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function #define ZR_ENDED 0x00050000 // the zip creation has already been closed #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip // The following come from bugs within the zip library itself #define ZR_BUGMASK 0xFF000000 #define ZR_NOTINITED 0x01000000 // initialisation didn't work #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code // e.g. // // (1) Traditional use, creating a zipfile from existing files // HZIP hz = CreateZip("c:\\simple1.zip",0); // ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp"); // ZipAdd(hz,"znsimple.txt", "c:\\simple.txt"); // CloseZip(hz); // // (2) Memory use, creating an auto-allocated mem-based zip file from various sources // HZIP hz = CreateZip(0,100000, 0); // // adding a conventional file... // ZipAdd(hz,"src1.txt", "c:\\src1.txt"); // // adding something from memory... // char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F); // ZipAdd(hz,"file.dat", buf,1000); // // adding something from a pipe... // HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0); // HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0); // ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional. // WaitForSingleObject(hthread,INFINITE); // CloseHandle(hthread); CloseHandle(hread); // ... meanwhile DWORD WINAPI ThreadFunc(void *dat) // { HANDLE hwrite = (HANDLE)dat; // char buf[1000]={17}; // DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL); // CloseHandle(hwrite); // return 0; // } // // and now that the zip is created, let's do something with it: // void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen); // HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); // DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL); // CloseHandle(hfz); // CloseZip(hz); // // (3) Handle use, for file handles and pipes // HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0); // HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0); // HZIP hz = CreateZipHandle(hzwrite,0); // // ... add to it // CloseZip(hz); // CloseHandle(hzwrite); // WaitForSingleObject(hthread,INFINITE); // CloseHandle(hthread); // ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat) // { HANDLE hread = (HANDLE)dat; // char buf[1000]; // while (true) // { DWORD red; ReadFile(hread,buf,1000,&red,NULL); // // ... and do something with this zip data we're receiving // if (red==0) break; // } // CloseHandle(hread); // return 0; // } // Now we indulge in a little skullduggery so that the code works whether // the user has included just zip or both zip and unzip. // Idea: if header files for both zip and unzip are present, then presumably // the cpp files for zip and unzip are both present, so we will call // one or the other of them based on a dynamic choice. If the header file // for only one is present, then we will bind to that particular one. ZRESULT CloseZipZ(HZIP hz); unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len); bool IsZipHandleZ(HZIP hz); #ifdef _unzip_H #undef CloseZip #define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz)) #else #define CloseZip CloseZipZ #define FormatZipMessage FormatZipMessageZ #endif #endif #endif //WIN32 repsnapper-2.3.2a5/libraries/amf/amftools-code/src/000077500000000000000000000000001231531733200221655ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/src/AMF_File.cpp000066400000000000000000002246021231531733200242410ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "AMF_File.h" #include "XmlStream.h" #include "nTexture.h" //for sort, etc. #include AmfFile::AmfFile(void)// : Slicer(this) { ClearAll(); } AmfFile::~AmfFile(void) { //if (pPixelDataRGBA) delete [] pPixelDataRGBA; //if (pPixelDataIndex) delete [] pPixelDataIndex; } AmfFile::AmfFile(const AmfFile& In)// : Slicer(this) { *this = In; } AmfFile& AmfFile::operator=(const AmfFile& In) { RenderedObjs = In.RenderedObjs; CancelIO = In.CancelIO; CurTick = In.CurTick; MaxTick = In.MaxTick; CurrentMessage = In.CurrentMessage; MinX = In.MinX; MaxX = In.MaxX; MinY = In.MinY; MaxY = In.MaxY; MinZ = In.MinZ; MaxZ = In.MaxZ; StlFile = In.StlFile; X3dFile = In.X3dFile; NeedRender = In.NeedRender; SubDivLevel = In.SubDivLevel; CurColorView = In.CurColorView; CurViewMode = In.CurViewMode; CurSlice = In.CurSlice; CurImportUnits = In.CurImportUnits; LastError = In.LastError; return *this; } //************************************************************************ //Amf I/O //************************************************************************ bool AmfFile::Save(std::string AmfFilePath, bool Compressed) { CancelIO = false; ClearError(); CurTick = 0; MaxTick = 2; CXmlStreamWrite XmlWrite; std::string LocalError; CurrentMessage = "Beginning Xml file..."; if (!XmlWrite.BeginXmlFile(AmfFilePath, Compressed)){LastError = XmlWrite.LastError; return false;} if (CancelIO) return false; CurrentMessage = "Writing Xml..."; if (!WriteXML(&XmlWrite, &LocalError, &CancelIO)){LastError = LocalError; return false;} if (CancelIO) return false; CurTick = 1; CurrentMessage = "Compressing and saving AMF..."; if (!XmlWrite.EndXmlFile()){LastError = XmlWrite.LastError; return false;} return true; } bool AmfFile::Load(std::string AmfFilePath, bool StrictLoad) { Clear(); ClearError(); CancelIO = false; // ClearError(); CurTick = 0; MaxTick = 0; CXmlStreamRead XmlRead; std::string LocalError; CurrentMessage = "Uncompressing/Parsing Xml...\n"; if (!XmlRead.LoadFile(AmfFilePath)){LastError = XmlRead.LastError; return false;} CurrentMessage = "Reading Xml...\n"; if (!ReadXML(&XmlRead, StrictLoad, &LocalError, &CancelIO)) {Clear(); LastError = LocalError; return false;} LastError = LocalError; NeedRender = true; return true; //CheckValid(StrictLoad, &LocalError); } bool AmfFile::ImportAmf(std::string AmfFilePath, bool StrictLoad) //merges this AMF with the current AMF { ClearError(); //TODO: deal with Color: scaling, AmfPointers within color equations. //load the file... AmfFile AmfMerge; if (!AmfMerge.Load(AmfFilePath, StrictLoad)) return false; double ScaleFactor = ToCurrentUnits(1.0, AmfMerge.GetUnits()); //ImprtAmf*ScaleFactor = This Amf //Textures std::vector PrevTexIDs, NewTexIDs; for (std::vector::iterator it = AmfMerge.Textures.begin(); it != AmfMerge.Textures.end(); it++){ int NewID = GetUnusedTexID(); PrevTexIDs.push_back(it->aID); NewTexIDs.push_back(NewID); it->pnAmf = this; it->aID = NewID; Textures.push_back(*it); } //Materials int NumPrevMats = Materials.size(); std::vector PrevMatIDs, NewMatIDs; //set newIDs for (std::vector::iterator it = AmfMerge.Materials.begin()+1; it != AmfMerge.Materials.end(); it++){ //+1 to avoid the obligatory void material int NewID = GetUnusedMatID(); PrevMatIDs.push_back(it->aID); NewMatIDs.push_back(NewID); it->aID = NewID; it->pnAmf = this; it->SetName("Imported-" + it->GetName()); Materials.push_back(*it); } //set composite material ID references for (std::vector::iterator it = Materials.begin()+NumPrevMats; it != Materials.end(); it++){ for (std::vector::iterator jt = it->Composites.begin(); jt != it->Composites.end(); jt++){ for (int i=0; i<(int)PrevMatIDs.size(); i++){ if (jt->aMaterialID == PrevMatIDs[i]){jt->aMaterialID = NewMatIDs[i]; break;} } //A composite that has a reference to a nonexistant material ID should have been caught on load, so not handled here if (!jt->MatEquation.IsConst()){ jt->ScaleEquation(ScaleFactor); jt->MatEquation.pAmf = this; } } } //Objects and Constellations std::vector PrevGeoIDs, NewGeoIDs; //order: all objects, then all constellations for (std::vector::iterator it = AmfMerge.Objects.begin(); it != AmfMerge.Objects.end(); it++){ int NewID = GetUnusedGeoID(); //keep track of IDs PrevGeoIDs.push_back(it->aID); NewGeoIDs.push_back(NewID); it->pnAmf = this; it->SetName("Imported-" + it->GetName()); it->aID=NewID; //set this new ID for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ for (std::vector::iterator kt = jt->Volumes.begin(); kt != jt->Volumes.end(); kt++){ //materialID of nVolumes for (int i=0; i<(int)PrevMatIDs.size(); i++){ if (kt->aMaterialID == PrevMatIDs[i]){kt->aMaterialID = NewMatIDs[i]; break;} } int NumPrevTexIDs = (int)PrevTexIDs.size(); for (std::vector::iterator lt = kt->Triangles.begin(); lt != kt->Triangles.end(); lt++){ if (lt->TexMapExists){ //texID of nTexMap for (int i=0; iTexMap.RTexID == PrevTexIDs[i]){lt->TexMap.RTexID = NewTexIDs[i];} if (lt->TexMap.GTexID == PrevTexIDs[i]){lt->TexMap.GTexID = NewTexIDs[i];} if (lt->TexMap.BTexID == PrevTexIDs[i]){lt->TexMap.BTexID = NewTexIDs[i];} if (lt->TexMap.ATexIDExists && lt->TexMap.ATexID == PrevTexIDs[i]){lt->TexMap.ATexID = NewTexIDs[i];} } } } } if (ScaleFactor != 1.0){ //update vertex positions based on relative units for (std::vector::iterator kt = jt->Vertices.VertexList.begin(); kt != jt->Vertices.VertexList.end(); kt++){ kt->Coordinates.X *= ScaleFactor; kt->Coordinates.Y *= ScaleFactor; kt->Coordinates.Z *= ScaleFactor; } } } Objects.push_back(*it); } //set newIDs int NumPrevConsts = Constellations.size(); for (std::vector::iterator it = AmfMerge.Constellations.begin(); it != AmfMerge.Constellations.end(); it++){ int NewID = GetUnusedGeoID(); PrevMatIDs.push_back(it->aID); NewMatIDs.push_back(NewID); it->aID = NewID; it->SetName("Imported-" + it->GetName()); it->pnAmf = this; Constellations.push_back(*it); } //set instance geometry ID references for (std::vector::iterator it = Constellations.begin()+NumPrevConsts; it != Constellations.end(); it++){ for (std::vector::iterator jt = it->Instances.begin(); jt != it->Instances.end(); jt++){ for (int i=0; i<(int)PrevGeoIDs.size(); i++){ if (jt->aObjectID == PrevGeoIDs[i]){jt->aObjectID = NewGeoIDs[i]; break;} } //An instance that has a reference to a nonexistant geometry ID should have been caught on load, so not handled here } } //ignore all metadata from file that's merged in. NeedRender = true; return true; } //behaviors of check valid: //for load: //errors would cause errors, not solved by assuming a defualt value, or things explicitely denied in the spec //warnings would be a source of ambiguity or senslessness, but won't crash anything. //checkvalid has two parameters. //FixNode: one for whether to modify anything ///IgnoreWarning: output warnings or not. //1) halt on error, show all warnings but don't change anything //2) try to fix the error, halt if can't do anything to fix, warning if changes made //3) option to suppress warning (shouldn't hve to propegate) //move down! //bool AmfFile::CheckValid(bool Strict, std::string* pMessage) //{ // return true; //} void AmfFile::ClearAll() { Clear(); //Clears underlying AMF data CurTick = 0; MaxTick = 0; CurrentMessage = ""; CancelIO = false; NeedRender = true; MinX = MaxX = MinY = MaxY = MinZ = MaxZ = 0; CurImportUnits = UNIT_MM; CurColorView = CV_ALL; CurViewMode = VM_SOLID; SubDivLevel = 4; ClearError(); } //************************************************************************ //importing meshes //************************************************************************ bool AmfFile::ImportMesh(std::string MeshFilePath, int AmfObjectIndex, int AmfMeshIndex) //imports a mesh into a mesh node specified (stl or x3d only) { ClearError(); std::string FileExtension = MeshFilePath.substr(MeshFilePath.size()-4, 3); if (FileExtension == "STL" || FileExtension == "stl" || FileExtension == "Stl"){ if (!LoadStl(MeshFilePath)) return false; return ImportStl(AmfObjectIndex, AmfMeshIndex); } else if (FileExtension == "X3D" || FileExtension == "x3d" || FileExtension == "X3d"){ if (!LoadX3d(MeshFilePath, "", NULL)) return false; return ImportX3d(AmfObjectIndex, AmfMeshIndex); } else { LastError += "Error: Unrecognized mesh file type. Currently only stl and x3d are supported. Aborting.\n"; return false; } NeedRender = true; } bool AmfFile::LoadStl(std::string StlFilePath) { ClearError(); //load the stl file into memory if (!StlFile.Load(StlFilePath)){ LastError += "Error: Could not load stl file.\nPlease check the file path and integrity of the stl file. Aborting.\n"; return false; } return true; } bool AmfFile::GetStlMeshSize(double* XSize, double* YSize, double* ZSize) { ClearError(); if (!StlFile.IsLoaded){ LastError += "Error: No Stl file has been loaded yet to read dimensions from. Aborting.\n"; return false; } Vec3D Size = StlFile.GetSize(); *XSize = Size.x; *YSize = Size.y; *ZSize = Size.z; return true; } bool AmfFile::ImportStl(int AmfObjectIndex, int AmfMeshIndex) { ClearError(); if (!StlFile.IsLoaded){ LastError += "Error: No Stl file has been loaded yet to import into the amf. Aborting.\n"; return false; } //make a location to add the stl mesh to in the amf int PrevNumObj = GetNumObjects(); nMesh* pnMesh = GetMesh(AmfObjectIndex, AmfMeshIndex, true); if (!pnMesh){ LastError += "Error: Could not determine AMF mesh to load STL into.\nPlease check Object and Mesh indices. Aborting.\n"; return false; } //catch if we added an object and rename it to the mesh we're importing! if (PrevNumObj != GetNumObjects()) Objects.back().SetName(StlFile.ObjectName); int NumPrevVert = pnMesh->GetNumVertices(); double UnitsScaleFactor = GetImportScaleFactor(); //Clear(); //figure out a reasonable weld distance Vec3D p1, p2; StlFile.ComputeBoundingBox(p2, p1); p1 -= p2; aWeldVertex::WeldThresh = UnitsScaleFactor*(std::min(std::min(p1.x, p1.y), p1.z))/100000.0; //weld threshold will always ne very small compared to the stl if (aWeldVertex::WeldThresh == 0) aWeldVertex::WeldThresh = DBL_MIN; //deal with numerical issues with very small objects (very unlikely...) CurrentMessage = "Sorting vertices..."; //put vertices in a temporary container... std::vector tmp; std::vector OrigToWeldIndex; //maps original vertex index to new welded vertex index std::vector Vertices; tmp.reserve(3*StlFile.Facets.size()); OrigToWeldIndex.reserve(3*StlFile.Facets.size()); for (int i=0; i<(int)StlFile.Facets.size(); i++){ //iterate through all the facets in the STL file for (int j=0; j<3; j++){ //each point in this facet tmp.push_back(aWeldVertex(UnitsScaleFactor*StlFile.Facets[i].v[j], 3*i+j)); OrigToWeldIndex.push_back(3*i+j); } } std::sort(tmp.begin(), tmp.end(), aWeldVertex::IsSoftLessThan); CurrentMessage = "Welding coincident vertices..."; //put non-duplicates in the actual vertices vector (and keep track of them) Vertices.reserve(3*StlFile.Facets.size()); int RevIt = 0; //reverse iterator int NumUniqueVerts = 0; for (int i=0; i<(int)tmp.size(); i++){ //iterate through all the facets in the STL file RevIt = 1; bool FoundOne = false; //have we found an identical vertex? while(NumUniqueVerts-RevIt >= 0 && Vertices[NumUniqueVerts-RevIt].z > tmp[i].v.z - aWeldVertex::WeldThresh){ if (tmp[i].v.IsNear(Vertices[NumUniqueVerts - RevIt], aWeldVertex::WeldThresh)){ //if its NOT near by one already in the vertices array, go add it and move on FoundOne = true; OrigToWeldIndex[i] = NumUniqueVerts - RevIt; RevIt++; break; } RevIt++; } if (!FoundOne){ Vertices.push_back(tmp[i].v); OrigToWeldIndex[i] = NumUniqueVerts; NumUniqueVerts++; } } CurrentMessage = "Creating AMF mesh: Adding vertices..."; pnMesh->Vertices.VertexList.reserve(pnMesh->Vertices.VertexList.size() + Vertices.size()); //save re-allocation as we add vertices... nVertex TmpVertex; for (std::vector::iterator it = Vertices.begin(); it != Vertices.end(); it++){ TmpVertex = nVertex(it->x, it->y, it->z); //linux compat pnMesh->AddVertex(TmpVertex); } CurrentMessage = "Creating AMF mesh: Resizing mesh facets..."; //fill in triangles nVolume* pNewVolume = pnMesh->NewVolume(StlFile.ObjectName); pNewVolume->Triangles.resize(StlFile.Facets.size()); //reserve space for all the triangles (saves re-allocating vector) CurrentMessage = "Creating AMF mesh: Adding facets..."; int NumTriangles = (int)StlFile.Facets.size(); int ThisVNum; for (int i=0; i<3*NumTriangles; i++){ ThisVNum = tmp[i].OrigIndex%3; switch (ThisVNum){ case 0: pNewVolume->Triangles[tmp[i].OrigIndex/3].v1 = NumPrevVert+OrigToWeldIndex[i]; break; case 1: pNewVolume->Triangles[tmp[i].OrigIndex/3].v2 = NumPrevVert+OrigToWeldIndex[i]; break; case 2: pNewVolume->Triangles[tmp[i].OrigIndex/3].v3 = NumPrevVert+OrigToWeldIndex[i]; break; } } //assign a material where one exists: if ((int)Materials.size() > 1) pNewVolume->SetMaterialID(Materials[1].aID); //if there's a material besides the void material... NeedRender = true; return true; } bool AmfFile::LoadX3d(std::string X3dFilePath, std::string ImagePath, std::string* ImgPathErrorReturn) //imports an x3d into a mesh node specified { ClearError(); //load the x3d file into memory X3dLoadResult X3dLoad = X3dFile.Load(X3dFilePath, ImagePath); switch (X3dLoad){ case XLR_BADFILEPATH: if (ImgPathErrorReturn) *ImgPathErrorReturn = ""; LastError += "Error: Could not load x3d at the file path. Aborting.\n"; return false; case XLR_NOSHAPE: if (ImgPathErrorReturn) *ImgPathErrorReturn = ""; LastError += "Error: No valid shape data found in the x3d file. Only indexed face sets are supported. Aborting.\n"; return false; case XLR_BADIMAGEPATH: if (ImgPathErrorReturn) *ImgPathErrorReturn = X3dFile.ImagePath; LastError += "Error: Image texture not loaded succesfully. Check the validity of the path. Aborting.\n"; return false; default: if (ImgPathErrorReturn) *ImgPathErrorReturn = ""; return true; } } bool AmfFile::GetX3dMeshSize(double* XSize, double* YSize, double* ZSize) { ClearError(); if (!X3dFile.IsLoaded){ LastError += "Error: No Stl file has been loaded yet to read dimensions from. Aborting.\n"; return false; } X3dFile.GetSize(*XSize, *YSize, *ZSize);; return true; } bool AmfFile::ImportX3d(int AmfObjectIndex, int AmfMeshIndex) //imports an x3d into a mesh node specified { ClearError(); if (!X3dFile.IsLoaded){ LastError += "Error: No X3d file has been loaded yet to import into the amf. Aborting.\n"; return false; } //make a location to add the x3d to in the amf int PrevNumObj = GetNumObjects(); nMesh* pnMesh = GetMesh(AmfObjectIndex, AmfMeshIndex, true); if (!pnMesh){ LastError += "Error: Could not determine AMF mesh to load X3d into.\nPlease check Object and Mesh indices. Aborting.\n"; return false; } //catch if we added an object and rename it to the mesh we're importing! if (PrevNumObj != GetNumObjects()){ std::string NewObjName = X3dFile.filePath; int Start = NewObjName.find_last_of("\\/"); if (Start != std::string::npos) NewObjName = NewObjName.substr(Start + 1, NewObjName.size() - Start - 1); int End = NewObjName.find_last_of("."); if (End != std::string::npos) NewObjName = NewObjName.substr(0, End); Objects.back().SetName(NewObjName); } double UnitsScaleFactor = GetImportScaleFactor(); int RIndex, GIndex, BIndex, AIndex; //AMF texture ID's, to be set as we add textures std::vector pVolumes; //a vector of length of number of x3d shapes containing the pointer to the AMF volume they should be loaded in to. std::vectorCoordsBeginIndex; //a vector of length of number of x3d shapes containing which vertex index the local vertex indices should start at X3dFillImportInfo(pnMesh, &pVolumes, &CoordsBeginIndex); //add each "shape" object of the x3d file as a separate volume within this mesh... int ShapeCount = 0; for (std::vector::iterator iS = X3dFile.xShapes.begin(); iS != X3dFile.xShapes.end(); iS++){ CurrentMessage = "Creating AMF mesh: Adding vertices..."; //we've only implemented IndexedFaceSets so far... if (!iS->IsIndexedFaceSet()) break; xIndexedFaceSetNode* pFaceSet = &iS->xIndexedFaceSet; nVolume* pCurVolume = pVolumes[ShapeCount]; //flags for if there is face or vertex color info bool TexturePresent = (pFaceSet->HasTexture && iS->xAppearance.ImageTexture.Width() != 0); //do we have texture mapping data? //load in texture data (should only ever be one per x3d shape) if (TexturePresent){ bool Tiled = iS->xAppearance.repeatS && iS->xAppearance.repeatT; //if either direction is tiled, then we tile the texture RIndex = AddTexture(&iS->xAppearance.ImageTexture, CR, Tiled); GIndex = AddTexture(&iS->xAppearance.ImageTexture, CG, Tiled); BIndex = AddTexture(&iS->xAppearance.ImageTexture, CB, Tiled); if (iS->xAppearance.ImageTexture.HasAlphaChannel()) AIndex = AddTexture(&iS->xAppearance.ImageTexture, CA, Tiled); } //Add vertices to mesh int NumVerts = pFaceSet->GetNumCoords(); pnMesh->Vertices.VertexList.reserve(pnMesh->Vertices.VertexList.size() + NumVerts); //save re-allocation as we add vertices... nVertex TmpVertex; for (int i=0; iColors && pFaceSet->colorPerVertex){ if (pFaceSet->HasAlpha){ TmpVertex = nVertex(pFaceSet->GetCoord(i, AX_X)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Y)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Z)*UnitsScaleFactor, nColor(pFaceSet->GetColorVert(i, CC_R), pFaceSet->GetColorVert(i, CC_G), pFaceSet->GetColorVert(i, CC_B),pFaceSet->GetColorVert(i, CC_A))); pnMesh->AddVertex(TmpVertex); } else { TmpVertex = nVertex(pFaceSet->GetCoord(i, AX_X)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Y)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Z)*UnitsScaleFactor, nColor(pFaceSet->GetColorVert(i, CC_R), pFaceSet->GetColorVert(i, CC_G), pFaceSet->GetColorVert(i, CC_B))); pnMesh->AddVertex(TmpVertex); } } else { TmpVertex = nVertex(pFaceSet->GetCoord(i, AX_X)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Y)*UnitsScaleFactor, pFaceSet->GetCoord(i, AX_Z)*UnitsScaleFactor); pnMesh->AddVertex(TmpVertex); } } CurrentMessage = "Creating AMF mesh: Adding facets..."; //add material color double tr = iS->xAppearance.MatColorRed; double tg = iS->xAppearance.MatColorGreen; double tb = iS->xAppearance.MatColorBlue; nColor tmp = nColor(tr, tg, tb); if (tr != -1 && tg != -1 && tb != -1) pCurVolume->SetColor(tmp); //Add the triangles nTriangle *CurTri; int NumTri = pFaceSet->GetNumTriangles(); int NumPrevVert = CoordsBeginIndex[ShapeCount]; //where to start with the triangles we'll be adding nTriangle TmpTri; nTexmap TmpTexMap; for (int i=0; iColors && !pFaceSet->colorPerVertex){ if (pFaceSet->HasAlpha) ThisColor = nColor(pFaceSet->GetColorFace(i, CC_R), pFaceSet->GetColorFace(i, CC_G), pFaceSet->GetColorFace(i, CC_B), pFaceSet->GetColorFace(i, CC_A)); else ThisColor = nColor(pFaceSet->GetColorFace(i, CC_R), pFaceSet->GetColorFace(i, CC_G), pFaceSet->GetColorFace(i, CC_B)); TmpTri = nTriangle(pFaceSet->GetCoordInd(i, 0)+NumPrevVert, pFaceSet->GetCoordInd(i, 1)+NumPrevVert, pFaceSet->GetCoordInd(i, 2)+NumPrevVert, ThisColor); CurTri = pCurVolume->AddTriangle(TmpTri); } else { TmpTri = nTriangle(pFaceSet->GetCoordInd(i, 0)+NumPrevVert, pFaceSet->GetCoordInd(i, 1)+NumPrevVert, pFaceSet->GetCoordInd(i, 2)+NumPrevVert); CurTri = pCurVolume->AddTriangle(TmpTri); } if (TexturePresent){ TmpTexMap = nTexmap(RIndex, GIndex, BIndex, pFaceSet->GetTexCoord(i,0,TCA_S), pFaceSet->GetTexCoord(i,1,TCA_S), pFaceSet->GetTexCoord(i,2,TCA_S), pFaceSet->GetTexCoord(i,0,TCA_T), pFaceSet->GetTexCoord(i,1,TCA_T), pFaceSet->GetTexCoord(i,2,TCA_T)); CurTri->SetTexMap(TmpTexMap); } } //assign a material where one exists: if ((int)Materials.size() > 1) pCurVolume->SetMaterialID(Materials[1].aID); //if there's a material besides the void material... ShapeCount++; } ToOneTexturePerVolume(); //needed to conform to AMF standards (and to make OpenGL rendering a million times easier NeedRender = true; return true; } //move down... void AmfFile::ToOneTexturePerVolume(void) { } void AmfFile::X3dFillImportInfo(nMesh* pMesh, std::vector* pVolumes, std::vector* pCoordsBeginIndex) //resizes pVolume to the number of x3d shapes and fills with a pointer to the volume (creating new volumes) each should be loaded in to. alse fills pCoordsBeginIndex with what vertex index in the AMF mesh vertex list these coordinates start... { //figure out which shape objects go into which AMF Volumes (one each, unless they reference the same coordinate set) int NumX3dShapes = X3dFile.xShapes.size(); std::vector ToShapes; //a vector of length of number of x3d shapes containing the x3d Shape index this shape will be added to ToShapes.resize(NumX3dShapes, -1); int NumVols = 0; pCoordsBeginIndex->clear(); pCoordsBeginIndex->resize(NumX3dShapes, -1); int CurNumCoord = pMesh->GetNumVertices(); for (int i=0; iVolumes.reserve(pMesh->Volumes.size() + NumVols); //reserve AMF volumes so resize doesn't invalidate the pointers... pVolumes->clear(); pVolumes->resize(NumX3dShapes, NULL); for (int i=0; iNewVolume(X3dFile.xShapes[i].xIndexedFaceSet.CoordDef); } } for (int i=0; iGetBBMin(); *pXMinOut = Min.x; *pYMinOut = Min.y; *pZMinOut = Min.z; return true; } else return false; } return false; } bool AmfFile::GetEnvlMax(double* pXMaxOut, double* pYMaxOut, double* pZMaxOut, int RenderIndex) { if (NeedRender) Render(); if (RenderIndex == -1){ *pXMaxOut = MaxX; *pYMaxOut = MaxY; *pZMaxOut = MaxZ; return true; } else { CMeshSlice* pMesh = GetRenderMesh(RenderIndex); if (pMesh){ Vec3D Max = pMesh->GetBBMax(); *pXMaxOut = Max.x; *pYMaxOut = Max.y; *pZMaxOut = Max.z; return true; } else return false; } return false; } bool AmfFile::GetEnvlSize(double* pXSizeOut, double* pYSizeOut, double* pZSizeOut, int RenderIndex) { double MaxX, MaxY, MaxZ, MinX, MinY, MinZ = 0; if (GetEnvlMax(&MaxX, &MaxY, &MaxZ, RenderIndex) && GetEnvlMin(&MinX, &MinY, &MinZ, RenderIndex)){ *pXSizeOut = MaxX-MinX; *pXSizeOut = MaxX-MinX; *pXSizeOut = MaxX-MinX; return true; } else return false; } bool AmfFile::GetEnvlRotQuat(double* pWRotOut, double* pXRotOut, double* pYRotOut, double* pZRotOut, int RenderIndex) { if (NeedRender) Render(); //? if (RenderIndex == -1){ *pWRotOut = 1.0; *pXRotOut = 0.0; *pYRotOut = 0.0; *pZRotOut = 0.0; return true; } else { CMeshSlice* pMesh = GetRenderMesh(RenderIndex); if (pMesh){ CQuat Rot = pMesh->GetRot(); *pWRotOut = Rot.w; *pXRotOut = Rot.x; *pYRotOut = Rot.y; *pZRotOut = Rot.z; return true; } else return false; } } bool AmfFile::GetEnvlRotAngleAxis(double* pAngleRadOut, double* pNXOut, double* pNYOut, double* pNZOut, int RenderIndex) { double w, x, y, z, Angle; Vec3D Axis; if (GetEnvlRotQuat(&w, &x, &y, &z, RenderIndex)){ CQuat Rot = CQuat(w, x, y, z); Rot.AngleAxis(Angle, Axis); *pAngleRadOut = Angle; *pNXOut = Axis.x; *pNYOut = Axis.y; *pNZOut = Axis.z; return true; } else return false; } bool AmfFile::GetEnvlOrigin(double* pXOriginOut, double* pYOriginOut, double* pZOriginOut, int RenderIndex) { if (NeedRender) Render(); //? if (RenderIndex == -1){ *pXOriginOut = 0.0; *pYOriginOut = 0.0; *pZOriginOut = 0.0; return true; } else { CMeshSlice* pMesh = GetRenderMesh(RenderIndex); if (pMesh){ Vec3D Orig = pMesh->GetOffset(); *pXOriginOut = Orig.x; *pYOriginOut = Orig.y; *pZOriginOut = Orig.z; return true; } else return false; } } bool AmfFile::GetEnvlDims(double* pIDimOut, double* pJDimOut, double* pKDimOut, int RenderIndex) { if (NeedRender) Render(); //? if (RenderIndex == -1){ GetEnvlSize(pIDimOut, pJDimOut, pKDimOut, RenderIndex); return true; } else { CMeshSlice* pMesh = GetRenderMesh(RenderIndex); if (pMesh){ Vec3D Dim = pMesh->GetOrigDim(); *pIDimOut = Dim.x; *pJDimOut = Dim.y; *pKDimOut = Dim.z; return true; } else return false; } } bool AmfFile::Scale(double ScaleFactorX, double ScaleFactorY, double ScaleFactorZ, bool ScaleConstellations, bool ScaleEquations) //note: does not scale material equations { ClearError(); if (ScaleEquations){LastError += "Scaling Equations is not yet supported. Aborting."; return false;} for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++) { for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++) { for (std::vector::iterator kt = jt->Vertices.VertexList.begin(); kt != jt->Vertices.VertexList.end(); kt++) { kt->SetCoordinates(kt->GetX()*ScaleFactorX, kt->GetY()*ScaleFactorY, kt->GetZ()*ScaleFactorZ); } } } if (ScaleConstellations){ for (std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++) { for (std::vector::iterator jt = it->Instances.begin(); jt != it->Instances.end(); jt++) { jt->DeltaX *= ScaleFactorX; jt->DeltaY *= ScaleFactorY; jt->DeltaZ *= ScaleFactorZ; } } } NeedRender = true; return true; } //************************************************************************ //Amf Objects: //************************************************************************ std::string AmfFile::GetObjectName(int ObjectIndex) { nObject* pObj = GetObject(ObjectIndex); if (pObj) return pObj->GetName(); else return ""; } void AmfFile::RenameObject(int ObjectIndex, std::string NewName) { nObject* pObj = GetObject(ObjectIndex); if (pObj) pObj->SetName(NewName); } void AmfFile::RemoveObject(int ObjectIndex) { nObject* pObj = GetObject(ObjectIndex); if (pObj){ DeleteGeometry(pObj->aID); NeedRender = true; } } void AmfFile::TranslateObject(int ObjectIndex, double dx, double dy, double dz) { nObject* pObj = GetObject(ObjectIndex); if (pObj){ pObj->Translate(dx, dy, dz); NeedRender = true; } } void AmfFile::RotateObject(int ObjectIndex, double rx, double ry, double rz) { nObject* pObj = GetObject(ObjectIndex); if (pObj){ pObj->Rotate(rx, ry, rz); NeedRender = true; } } //************************************************************************ //Amf Meshes //************************************************************************ int AmfFile::GetMeshCount(int ObjectIndex) { nObject* pObject = GetObject(ObjectIndex); if (pObject) return pObject->GetNumMeshes(); else return -1; } //************************************************************************ //Amf Volumes //************************************************************************ int AmfFile::GetVolumeCount(int ObjectIndex, int MeshIndex) { nMesh* pMesh = GetMesh(ObjectIndex, MeshIndex); if (pMesh) return pMesh->Volumes.size(); else return -1; } std::string AmfFile::GetVolumeName(int ObjectIndex, int MeshIndex, int VolumeIndex) { nVolume* pVol = GetVolume(ObjectIndex, MeshIndex, VolumeIndex); if (pVol) return pVol->GetName(); else return ""; } void AmfFile::RenameVolume(int ObjectIndex, int MeshIndex, int VolumeIndex, std::string NewName) { nVolume* pVol = GetVolume(ObjectIndex, MeshIndex, VolumeIndex); if (pVol) pVol->SetName(NewName); } int AmfFile::GetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex) { nVolume* pVol = GetVolume(ObjectIndex, MeshIndex, VolumeIndex); if (pVol){ int Index = 0; for (std::vector::iterator it = Materials.begin(); it != Materials.end(); it++){ int ThisMatID; if (pVol->GetMaterialID(&ThisMatID) && it->aID == ThisMatID) return Index; //if (it->aID == pVol->aMaterialID) return Index; Index++; } } return -1; } bool AmfFile::SetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex, int MaterialIndex) { ClearError(); nVolume* pVol = GetVolume(ObjectIndex, MeshIndex, VolumeIndex); if (pVol){ nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ pVol->SetMaterialID(pMat->aID); NeedRender = true; return true; } } LastError += "Could not locate the specified volume."; return false; } //************************************************************************ //Amf Constellations: //************************************************************************ std::string AmfFile::GetConstellationName(int ConstellationIndex) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst) return pConst->GetName(); else return ""; } void AmfFile::RenameConstellation(int ConstellationIndex, std::string NewName) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst) pConst->SetName(NewName); } void AmfFile::RemoveConstellation(int ConstellationIndex) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst){ DeleteGeometry(pConst->aID); NeedRender = true; } } bool AmfFile::IsConstellationReferencedBy(int ConstellationIndex, int ConstellationIndexToCheck) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst){ nConstellation* pConstRef = GetConstellation(ConstellationIndexToCheck); if (pConstRef) return pConst->IsReferencedBy(pConstRef); else return true; //if not a valid material, it clearly does not reference this material... } else return false; } //************************************************************************ //Amf Constellations: //************************************************************************ int AmfFile::GetInstanceCount(int ConstellationIndex) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst) return pConst->GetNumInstances(); else return -1; } int AmfFile::AddInstance(int ConstellationIndex) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst){ int aID = GetUsedGeoID(); pConst->AddInstance(aID); NeedRender = true; return (int)pConst->Instances.size()-1; } else return -1; } void AmfFile::RemoveInstance(int ConstellationIndex, int InstanceIndex) { nConstellation* pConst = GetConstellation(ConstellationIndex); if (pConst){ if (InstanceIndex < 0 || InstanceIndex >= (int)pConst->Instances.size()) return; pConst->Instances.erase(pConst->Instances.begin() + InstanceIndex); NeedRender = true; } } bool AmfFile::SetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex, int InstanceObjectIndex) { ClearError(); nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ nObject* pObject = GetObject(InstanceObjectIndex); if (pObject){ pInst->aObjectID = pObject->aID; NeedRender = true; return true; } } LastError += "Could not locate the specified object."; return false; } bool AmfFile::SetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex, int InstanceConstellationIndex) { ClearError(); nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ nConstellation* pConst = GetConstellation(InstanceConstellationIndex); if (pConst){ pInst->aObjectID = pConst->aID; NeedRender = true; return true; } } LastError += "Could not locate the specified constellation."; return false; } int AmfFile::GetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex) { nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ int Index = 0; for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (it->aID == pInst->aObjectID) return Index; Index++; } } return -1; } int AmfFile::GetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex) { nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ int Index = 0; for (std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ if (it->aID == pInst->aObjectID) return Index; Index++; } } return -1; } bool AmfFile::SetInstanceParam(int ConstellationIndex, int InstanceIndex, InstanceParamD ParamD, double Value) { ClearError(); nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ switch (ParamD){ case INST_DX: pInst->DeltaX = Value; break; case INST_DY: pInst->DeltaY = Value; break; case INST_DZ: pInst->DeltaZ = Value; break; case INST_RX: pInst->rX = Value; break; case INST_RY: pInst->rY = Value; break; case INST_RZ: pInst->rZ = Value; break; } NeedRender = true; return true; } LastError += "Could not locate the specified instance."; return false; } double AmfFile::GetInstanceParam(int ConstellationIndex, int InstanceIndex, InstanceParamD ParamD) { nInstance* pInst = GetInstance(ConstellationIndex, InstanceIndex); if (pInst){ switch (ParamD){ case INST_DX: return pInst->DeltaX; case INST_DY: return pInst->DeltaY; case INST_DZ: return pInst->DeltaZ; case INST_RX: return pInst->rX; case INST_RY: return pInst->rY; case INST_RZ: return pInst->rZ; } } return -1.0; } //************************************************************************ //Amf Materials: //************************************************************************ std::string AmfFile::GetMaterialName(int MaterialIndex) { nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat) return pMat->GetName(); else return ""; } void AmfFile::RenameMaterial(int MaterialIndex, std::string NewName) { if (MaterialIndex == 0) return; //protect the void material nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat) pMat->SetName(NewName); } void AmfFile::RemoveMaterial(int MaterialIndex) { if (MaterialIndex == 0) return; //protect the void material nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ DeleteMaterial(pMat->aID); NeedRender = true; } } bool AmfFile::IsMaterialReferencedBy(int MaterialIndex, int MaterialIndexToCheck) { nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ nMaterial* pMatRef = GetMaterial(MaterialIndexToCheck); if (pMatRef) return pMat->IsReferencedBy(pMatRef); else return true; //if not a valid material, it clearly does not reference this material... } else return false; } bool AmfFile::SetMaterialColorD(int MaterialIndex, double Red, double Green, double Blue) { ClearError(); if (Red<0) Red = 0; if (Green<0) Green = 0; if (Blue<0) Blue = 0; if (Red>1.0) Red = 1.0; if (Green>1.0) Green = 1.0; if (Blue>1.0) Blue = 1.0; nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat && pMat->aID != 0){ //protect the void material pMat->SetConstColor(Red, Green, Blue); NeedRender = true; return true; } LastError += "Could not locate the specified material."; return false; } bool AmfFile::GetMaterialColorD(int MaterialIndex, double *Red, double *Green, double *Blue) { ClearError(); nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){pMat->GetConstColor(Red, Green, Blue); return true;} LastError += "Could not locate the specified material."; return false; } bool AmfFile::GetMaterialColorI(int MaterialIndex, int *Red, int *Green, int *Blue){ ClearError(); nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ double R, G, B; pMat->GetConstColor(&R, &G, &B); *Red = (int)(R*255.0); *Green = (int)(G*255.0); *Blue = (int)(B*255.0); return true; } LastError += "Could not locate the specified material."; return false; } //************************************************************************ //Amf Composites //************************************************************************ int AmfFile::GetCompositeCount(int MaterialIndex) { nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat) return pMat->GetNumComposites(); else return -1; } void AmfFile::ClearComposites(int MaterialIndex) { nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ NeedRender = true; pMat->Composites.clear(); } } int AmfFile::AddComposite(int MaterialIndex, int MaterialIndexToComposite) { ClearError(); if (MaterialIndex == 0) return -1; //protect the void material nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ if (pMat->AddCompositeInstance(MaterialIndexToComposite, "1", &LastError) == -1) return -1; NeedRender = true; return (int)pMat->Composites.size()-1; } else return -1; } void AmfFile::RemoveComposite(int MaterialIndex, int CompositeIndex) { if (MaterialIndex == 0) return; //protect the void material nMaterial* pMat = GetMaterial(MaterialIndex); if (pMat){ if (CompositeIndex < 0 || CompositeIndex >= (int)pMat->Composites.size()) return; pMat->Composites.erase(pMat->Composites.begin() + CompositeIndex); NeedRender = true; } } bool AmfFile::SetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex, int CompositeMaterialIndex) { if (MaterialIndex == 0) return false; //protect the void material nMaterial* pMat = GetMaterial(MaterialIndex); nMaterial* pMatRef = GetMaterial(CompositeMaterialIndex); if (pMat && pMatRef){ if (pMat->IsReferencedBy(pMatRef)) return false; //don't allow circular references nComposite* pComp = GetComposite(MaterialIndex, CompositeIndex); if (pComp){ pComp->aMaterialID = pMatRef->aID; NeedRender = true; return true; } else return false; } else return false; } int AmfFile::GetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex) { nComposite* pComp = GetComposite(MaterialIndex, CompositeIndex); if (pComp){ int Index = 0; for (std::vector::iterator it = Materials.begin(); it != Materials.end(); it++){ if (it->aID == pComp->aMaterialID) return Index; Index++; } } return -1; } std::string AmfFile::GetCompositeEquation(int MaterialIndex, int CompositeIndex) { nComposite* pComp = GetComposite(MaterialIndex, CompositeIndex); if (pComp){return pComp->GetEquation();} else return ""; } bool AmfFile::SetCompositeEquation(int MaterialIndex, int CompositeIndex, std::string Equation) { ClearError(); nComposite* pComp = GetComposite(MaterialIndex, CompositeIndex); if (pComp){ NeedRender = true; return pComp->SetEquation(Equation, this, &LastError); } LastError += "Could not locate the specified composite."; return false; } //************************************************************************ //Output utilities //************************************************************************ bool AmfFile::SetSubdivisionLevel(int Level) { NeedRender = true; ClearError(); LastError += "Curved triangles coming soon."; return false; //To be implemented } void AmfFile::DrawGL() { if (NeedRender) Render(); for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ std::cerr << "drawing AmfFile not possible" << std::endl; //jt->Draw(); //name stack... } } } unsigned char* AmfFile::GetSliceBitmapRGBA(double PixelSizeX, double PixelSizeY, double SliceHeightZ, int* XSizeOut, int* YSizeOut, double SurfaceDepth) { ClearError(); *XSizeOut = 0; *YSizeOut = 0; if (!GenerateLayer(PixelSizeX, PixelSizeY, SliceHeightZ, SurfaceDepth, &LastError)) return NULL; *XSizeOut = CurSlice.Width(); *YSizeOut = CurSlice.Height(); return CurSlice.GetRGBABits(); } int* AmfFile::GetSliceSegmentsXY(double ZHeight, int* NumSegmentsOut) { ClearError(); LastError += "Slice segment export coming soon..."; return NULL; } //************************************************************************ //Errors and information //************************************************************************ std::string AmfFile::GetInfoString(bool MeshInfo) { std::ostringstream os; os << "Amf Statistics:\n"; if (MeshInfo){ int NumVerts = 0; int NumTri = 0; for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++) { for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++) { NumVerts += jt->Vertices.VertexList.size(); for (std::vector::iterator kt = jt->Volumes.begin(); kt != jt->Volumes.end(); kt++) { NumTri += kt->Triangles.size(); } } } os << "Number of Vertices: " << NumVerts << "\nNumber of Triangles: " << NumTri; } return os.str().c_str(); } //************************************************************************ //[Preotected functions] //************************************************************************ int AmfFile::AddTexture(CSimpleImage* pImageIn, Channel ChannelToGet, bool TiledIn) //this is really slow right now... optimize later. { Textures.push_back(nTexture(this)); //add the texture! nTexture* pTex = &(Textures.back()); int iw = pImageIn->Width(); int ih = pImageIn->Height(); pTex->aWidth = iw; pTex->aHeight= ih; pTex->aDepth = 1; pTex->aTiled = TiledIn; pTex->Type = TT_GRAYSCALE; pTex->aID = GetUnusedTexID(); unsigned char* pBits = pImageIn->GetRGBABits(); // for (int j=0; jpixel(i, j); switch (ChannelToGet){ case CR: pTex->BinaryData.push_back(*pBits); break; case CG: pTex->BinaryData.push_back(*(pBits+1)); break; case CB: pTex->BinaryData.push_back(*(pBits+2)); break; case CA: if (pImageIn->HasAlphaChannel()){ pTex->BinaryData.push_back(*(pBits+3)); } break; } pBits += 4; //always 4 bytes per pixel } // } NeedRender = true; return pTex->aID; } double AmfFile::GetImportScaleFactor(void) //gets scaling factor based on CurImportUnits and current Amf Units. Sets amf units to CurImportUnits if first mesh to be imported. { if (CurImportUnits == aUnit) return 1.0; //see if there's any vertices yet... bool AnyVerts = false; for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ if (jt->Vertices.VertexList.size() != 0){AnyVerts = true; break; break;} } } if (!AnyVerts) {aUnit = CurImportUnits; return 1.0;} double CurFactor = 1.0; //convert import units to mm: switch (CurImportUnits){ case UNIT_M: CurFactor = 1000.0; break; case UNIT_IN: CurFactor = 25.4; break; case UNIT_FT: CurFactor = 12*25.4; break; case UNIT_UM: CurFactor = 0.001; break; } //convert to Amf units switch (aUnit){ case UNIT_M: CurFactor *= 0.001; break; case UNIT_IN: CurFactor *= 1.0/25.4; break; case UNIT_FT: CurFactor *= 1.0/(12*25.4); break; case UNIT_UM: CurFactor *= 1000; break; } return CurFactor; } bool AmfFile::ComputeBoundingBox() { MinX = MaxX = MinY = MaxY = MinZ = MaxZ = 0; Vec3D tmpMax, tmpMin; bool FoundAny = false; for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ FoundAny = true; tmpMax = jt->GetBBMax(); tmpMin = jt->GetBBMin(); MinX = (std::min)(tmpMin.x, MinX); MaxX = (std::max)(tmpMax.x, MaxX); MinY = (std::min)(tmpMin.y, MinY); MaxY = (std::max)(tmpMax.y, MaxY); MinZ = (std::min)(tmpMin.z, MinZ); MaxZ = (std::max)(tmpMax.z, MaxZ); } } return FoundAny; } void AmfFile::GetMinMax(double& xMinOut, double& yMinOut, double& zMinOut, double& xMaxOut, double& yMaxOut, double& zMaxOut) { if (NeedRender) Render(); //TODO: Account for constellations... xMinOut = yMinOut = zMinOut = xMaxOut = yMaxOut = zMaxOut = 0; if (Objects.size() == 0) return; if (Objects[0].Meshes.size()==0) return; //todo: might be later objects that have a mesh? if (Objects[0].Meshes[0].Vertices.VertexList.size()==0) return; xMinOut = xMaxOut = Objects[0].Meshes[0].Vertices.VertexList[0].Coordinates.X; yMinOut = yMaxOut = Objects[0].Meshes[0].Vertices.VertexList[0].Coordinates.Y; zMinOut = zMaxOut = Objects[0].Meshes[0].Vertices.VertexList[0].Coordinates.Z; for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++) { for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++) { for (std::vector::iterator kt = jt->Vertices.VertexList.begin(); kt != jt->Vertices.VertexList.end(); kt++) { xMinOut = std::min(xMinOut, kt->GetX()); yMinOut = std::min(yMinOut, kt->GetY()); zMinOut = std::min(zMinOut, kt->GetZ()); xMaxOut = std::max(xMaxOut, kt->GetX()); yMaxOut = std::max(yMaxOut, kt->GetY()); zMaxOut = std::max(zMaxOut, kt->GetZ()); } } } } void AmfFile::GetSize(double& xOut, double& yOut, double& zOut) { double xMin, yMin, zMin, xMax, yMax, zMax; GetMinMax(xMin, yMin, zMin, xMax, yMax, zMax); xOut = xMax-xMin; yOut = yMax-yMin; zOut = zMax-zMin; } nObject* AmfFile::GetObject(int ObjectIndex, bool CanCreate) { if (ObjectIndex < 0) return NULL; if (ObjectIndex >= (int)Objects.size()){ if (CanCreate){Objects.resize(ObjectIndex+1, nObject(this)); Objects.back().SetName("Default");} else return NULL; } return &Objects[ObjectIndex]; } nMesh* AmfFile::GetMesh(int ObjectIndex, int MeshIndex, bool CanCreate) { nObject* pObject = GetObject(ObjectIndex, CanCreate); if (pObject){ if (MeshIndex < 0) return NULL; if (MeshIndex >= (int)pObject->Meshes.size()){ if (CanCreate){pObject->Meshes.resize(MeshIndex+1);} else return NULL; } return &pObject->Meshes[MeshIndex]; } else return NULL; } nVolume* AmfFile::GetVolume(int ObjectIndex, int MeshIndex, int VolumeIndex, bool CanCreate) { nMesh* pMesh = GetMesh(ObjectIndex, MeshIndex, CanCreate); if (pMesh){ if (VolumeIndex < 0) return NULL; if (VolumeIndex >= (int)pMesh->Volumes.size()){ if (CanCreate){pMesh->Volumes.resize(VolumeIndex+1);} else return NULL; } return &pMesh->Volumes[VolumeIndex]; } else return NULL; } nConstellation* AmfFile::GetConstellation(int ConstellationIndex, bool CanCreate) { if (ConstellationIndex < 0) return NULL; if (ConstellationIndex >= (int)Constellations.size()){ if (CanCreate){ Constellations.resize(ConstellationIndex+1, nConstellation(this)); Constellations.back().SetName("Default");} else return NULL; } return &Constellations[ConstellationIndex]; } nMaterial* AmfFile::GetMaterial(int MaterialIndex, bool CanCreate) { if (MaterialIndex < 0) return NULL; if (MaterialIndex >= (int)Materials.size()){ if (CanCreate){Materials.resize(MaterialIndex+1, nMaterial(this)); Materials.back().SetName("Default");} else return NULL; } return &Materials[MaterialIndex]; } nInstance* AmfFile::GetInstance(int ConstellationIndex, int InstanceIndex, bool CanCreate) { nConstellation* pConst = GetConstellation(ConstellationIndex, CanCreate); if (pConst){ if (InstanceIndex < 0) return NULL; if (InstanceIndex >= (int)pConst->Instances.size()){ if (CanCreate){pConst->Instances.resize(InstanceIndex+1);} else return NULL; } return &pConst->Instances[InstanceIndex]; } else return NULL; } nComposite* AmfFile::GetComposite(int MaterialIndex, int CompositeIndex, bool CanCreate) { nMaterial* pMaterial = GetMaterial(MaterialIndex, CanCreate); if (pMaterial){ if (CompositeIndex < 0) return NULL; if (CompositeIndex >= (int)pMaterial->Composites.size()){ if (CanCreate){pMaterial->Composites.resize(CompositeIndex+1);} else return NULL; } return &pMaterial->Composites[CompositeIndex]; } else return NULL; } bool AmfFile::Render() //generates RenderedObjs; { RenderedObjs.clear(); //don't keep adding to the list - regenerate it! Vec3D TotalOff; CQuat TotalRot; std::vector IndexStack; //render all constellations (recusively) //int counter = 0; for (std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ TotalOff = Vec3D(0,0,0); TotalRot = CQuat(1,0,0,0); //no rotation... if (IsTopLevelGeo(it->aID)){ // IndexStack.push_back(it->aID); RenderConstellation(&(*it), &IndexStack, TotalOff, TotalRot, CurColorView, CurViewMode, SubDivLevel); // IndexStack.pop_back(); } //counter++; } //render all top level objects (directly) //counter=0; for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (IsTopLevelGeo(it->aID)){ // IndexStack.push_back(it->aID); RenderObject(&(*it), &IndexStack, Vec3D(0,0,0), CQuat(1,0,0,0), CurColorView, CurViewMode, SubDivLevel); // IndexStack.pop_back(); } //counter++; } //Make specific IDs for each object... //int ObjNum = 0; //for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ // for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ // jt->GlNameIndexStack.push_back(ObjNum); // } // ObjNum++; //} // BoundsChanged = true; ComputeBoundingBox(); NeedRender = false; return true; } //quaternion properties (for my reference) //1) To rotate a vector V, form a quaternion with w = 0; To rotate by Quaternion Q, do Q*V*Q.Conjugate() and trim off the w component. //2) To do multiple rotations: To Rotate by Q1 THEN Q2, Q2*Q1*V*Q1.Conjugate*Q2.Conjugate(), or make a Qtot = Q2*Q1 and do Qtot*V*Qtot.Conjucate() //3) Q1*Q1.Conjugate - Identity //4) To do a reverse rotation Q1, just do Q1.conjugate*V*Q1 //http://www.cprogramming.com/tutorial/3d/quaternions.html bool AmfFile::RenderConstellation(nConstellation* pConst, std::vector* pIndexStack, Vec3D CurOff, CQuat CurRot, ColorView CurColorView, ViewMode CurViewMode, int SubDivLev) //for recursion { Vec3D CurOffRef = CurOff; CQuat CurRotRef = CurRot; //get const INDEX int ConstIndex = -1; for (int i=0; i<(int)Constellations.size(); i++) if (&Constellations[i] == pConst) ConstIndex = i; if (ConstIndex == -1) return false; pIndexStack->push_back(ConstIndex); int InstanceIndex = 0; for (std::vector::iterator jt = pConst->Instances.begin(); jt != pConst->Instances.end(); jt++){ pIndexStack->push_back(InstanceIndex); CurOff = CurOffRef; CurRot = CurRotRef; //Compute Local rotation: CQuat XRot = CQuat(jt->rX*d2r, Vec3D(1,0,0)); CQuat YRot = CQuat(jt->rY*d2r, Vec3D(0,1,0)); CQuat ZRot = CQuat(jt->rZ*d2r, Vec3D(0,0,1)); CQuat ThisRot = ZRot*YRot*XRot; //rotation (by X then Y then Z) //Compute local translation Vec3D ThisOff = /*CurUnitsScale*/Vec3D(jt->DeltaX, jt->DeltaY, jt->DeltaZ); //order: //1) rotate local rotation //2) translate local translation //3) rotate current rotation (and rotate local translation... //4) translate current translation CQuat Offset = CQuat(ThisOff); Offset = CurRot*Offset*CurRot.Conjugate(); //rotate previous offsets in proper order CurRot = CurRot*ThisRot; //keep track of total rotation (rotate this amount, then everything previous CurOff = Offset.ToVec() + CurOff; //add in this offset //if this id is a constellation: nConstellation* pnConstTmp = GetConstellationByID(jt->aObjectID); if (pnConstTmp){ //this is a constellation if (!RenderConstellation(pnConstTmp, pIndexStack, CurOff, CurRot, CurColorView, CurViewMode, SubDivLev)) return false; //recurse! } else { //this is an object if (!RenderObject(GetObjectByID(jt->aObjectID), pIndexStack, CurOff, CurRot, CurColorView, CurViewMode, SubDivLev)) return false; } pIndexStack->pop_back(); InstanceIndex++; } pIndexStack->pop_back(); return true; } bool AmfFile::RenderObject(nObject* pObj, std::vector* pIndexStack, Vec3D CurOff, CQuat CurRot, ColorView CurColorView, ViewMode CurViewMode, int SubDivLev) //actually adds an object to RenderedObjs (rotate first, then offset) { if (!pObj) return false; //get object INDEX int ObjIndex = -1; for (int i=0; i<(int)Objects.size(); i++) if (&Objects[i] == pObj) ObjIndex = i; if (ObjIndex == -1) return false; pIndexStack->push_back(ObjIndex); // pIndexStack->push_back(pObj->aID); pIndexStack->push_back(RenderedObjs.size()); //last integer is the GuiIndex RenderedObjs.push_back(nObjectExt(this, pObj, pIndexStack, CurOff, CurRot, CurColorView, CurViewMode, SubDivLev)); pIndexStack->pop_back(); pIndexStack->pop_back(); return true; } nObjectExt* AmfFile::GetRenderObject(int RenderIndex) { if (RenderIndex <0 || RenderIndex >= (int)RenderedObjs.size()) return NULL; if (NeedRender) Render(); // return &RenderedObjs[RenderIndex]; int Counter = 0; for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ int NumMesh = it->Meshes.size(); if (RenderIndex < Counter+NumMesh) return &(*it); Counter += NumMesh; } return NULL; } CMeshSlice* AmfFile::GetRenderMesh(int RenderIndex) { if (RenderIndex <0 || RenderIndex >= (int)RenderedObjs.size()) return NULL; if (NeedRender) Render(); int Counter = 0; for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ int NumMesh = it->Meshes.size(); for (int i=0; iMeshes[i]; Counter++; } } return NULL; } bool AmfFile::GenerateLayer(double PixelSizeX, double PixelSizeY, double SliceHeightZ, double SurfaceDepthIn, std::string* pMessage) { ClearError(); Vec3D BMin = Vec3D(MinX, MinY, MinZ); Vec3D BMax = Vec3D(MaxX, MaxY, MaxZ); // SurfDepth = SurfaceDepthIn; Vec3D PrintOrigin = BMin; Vec3D PrintSize = BMax-BMin; int XOrigin = (int)(PrintOrigin.x/PixelSizeX); int YOrigin = (int)(PrintOrigin.y/PixelSizeY); int XPix = (int)(PrintSize.x/PixelSizeX) + 1; int YPix = (int)(PrintSize.y/PixelSizeY) + 1; // ZPix = (int)(PrintSize.z/VoxSize.z) + 1; if (!CurSlice.AllocateRGBA(XPix, YPix)){ // = QImage(XPix, YPix, QImage::Format_ARGB32); //32 bit Color if (pMessage) *pMessage += "Insufficient memory to create bitmap. Please lower resolution.\n"; return false; } CurSlice.Fill(255, 255, 255, 0); //erase bitmap if (SliceHeightZ < BMin.z || SliceHeightZ > BMax.z){*pMessage += "Requested layer out of bounds.\n"; return false;} //out of bounds! // CurLayer = Layer; double ZHeight = SliceHeightZ; //(Layer + 0.5)*VoxSize.z + PrintOrigin.z; //get center of voxels... int XMinPix, YMinPix, XMaxPix, YMaxPix; //pixel coords for envelope of sub-meshes // nObjectExt::aThis.clear(); int ThisObjID = 0; // int RenderIndex = 0; //make individual bitmaps for (std::vector::iterator it = RenderedObjs.begin(); it != RenderedObjs.end(); it++){ int ThisMeshID = 0; for (std::vector::iterator jt = it->Meshes.begin(); jt != it->Meshes.end(); jt++){ if (ZHeight < jt->GetBBMin().z || ZHeight > jt->GetBBMax().z) continue; //if slice is above or below this mesh don't bother slicing! CSimpleImage tmp; //TODO: this has to get memory every time... //round down mins to pixel below... XMinPix = (int)((jt->GetBBMin().x)/PixelSizeX); XMaxPix = (int)((jt->GetBBMax().x)/PixelSizeX)+1; //if its exact, we do an extra column of pixels... YMinPix = (int)((jt->GetBBMin().y)/PixelSizeY); YMaxPix = (int)((jt->GetBBMax().y)/PixelSizeY)+1; //if its exact, we do an extra row of pixels... //temp... // jt->pObjExt = &(*it); // nObjectExt::aThis.push_back(&(*it)); //remember staticly which member of this class we are based on ID... // jt->pGetColor = &it->GetColorCallback; if(jt->GetSlice(&tmp, ZHeight, SurfaceDepthIn, XMinPix*PixelSizeX, XMaxPix*PixelSizeX, YMinPix*PixelSizeY, YMaxPix*PixelSizeY, XMaxPix-XMinPix, YMaxPix-YMinPix, ThisObjID, pMessage)){ ImposeBitmap(&CurSlice, &tmp, XOrigin, YOrigin, XMinPix, YMinPix); } else return false; // RenderIndex++; ThisMeshID++; } ThisObjID++; } return true; } void AmfFile::ImposeBitmap(CSimpleImage* pBase, CSimpleImage* pImposed, int BaseXOrigin, int BaseYOrigin, int ImpXOrigin, int ImpYOrigin) //X, Y origin is the location within pBase that pImposed should be added. { int ImposedXSize = pImposed->Width(); int ImposedYSize = pImposed->Height(); int BaseXSize = pBase->Width(); int BaseYSize = pBase->Height(); int CurAbsX, CurAbsY; unsigned char* pDataRGBABase = pBase->GetRGBABits(); unsigned char* pDataRGBAImposed = pImposed->GetRGBABits(); unsigned char *pCurRowImposed, *pCurRowBase; for(int iy=0; iy= BaseYSize) continue; pCurRowImposed = pDataRGBAImposed+iy*4*ImposedXSize; pCurRowBase = pDataRGBABase+CurAbsY*4*BaseXSize; for(int ix=0; ix= BaseXSize) continue; //could do some smarter compositing here... if (*(pCurRowImposed+4*ix+3)== 255){ //if this pixel in the image to add is not transparent (at all, for now...) *(pCurRowBase + 4*CurAbsX) = *(pCurRowImposed+4*ix); *(pCurRowBase + 4*CurAbsX+1) = *(pCurRowImposed+4*ix+1); *(pCurRowBase + 4*CurAbsX+2) = *(pCurRowImposed+4*ix+2); *(pCurRowBase + 4*CurAbsX+3) = *(pCurRowImposed+4*ix+3); } else { //if it is transparent, don't mess with the base image! // *(pCurRowBase + 4*CurAbsX) = *(pCurRowBase + 4*CurAbsX+1) = *(pCurRowBase + 4*CurAbsX+2) = 255; // *(pCurRowBase + 4*CurAbsX+3) = 0; } } } } //************************************************************************ //nObjectExt class //************************************************************************ //std::vector nObjectExt::aThis; CColor nObjectExt::nColor2CColor(nColor& ColorIn, Vec3D* pLoc) { if (pLoc) return CColor(ColorIn.GetR(pLoc->X(), pLoc->Y(), pLoc->Z()), ColorIn.GetG(pLoc->X(), pLoc->Y(), pLoc->Z()), ColorIn.GetB(pLoc->X(), pLoc->Y(), pLoc->Z())); else return CColor(ColorIn.GetR(), ColorIn.GetG(), ColorIn.GetB()); } //void nObjectExt::GetColorCallback(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut, int aObjectID) //function to get color based on location //{ //// if (aObjectID >= aThis.size()){ //if no valid pointer back to an actuall class instanct... //// *rOut = 0; //// *gOut = 0; //// *bOut = 0; //// *aOut = 1.0; //// } //// else { // int nObjectID = aObjectID/MaxMeshPerObj; // int nMeshID = aObjectID-nObjectID*MaxMeshPerObj; // // nObjectExt* pCurThis = nObjectExt::aThis[nObjectID]; // Vec3D TmpPt = Vec3D(xIn, yIn, zIn); // TmpPt = /*pCurThis->pAmf->GetUnitsScaleFromMm()*/pCurThis->OriginalLoc(TmpPt); // pCurThis->pAmf->GetMaterialByID(pCurThis->MaterialIDs[nMeshID])->GetColorAt(TmpPt.x, TmpPt.y, TmpPt.z, rOut, gOut, bOut, aOut); //// } //} typedef struct{int ix[4];} inds; //container for the four Amf indicies that will make up a texture... bool nObjectExt::RenderMesh(nAmf* pAmfIn, nObject* pObj, std::vector* pIndexStack, Vec3D& OffsetIn, CQuat& RotIn, ColorView& CurColorView, ViewMode& CurViewMode, int& SubDivLevel) { pAmf = pAmfIn; //Offset = OffsetIn; //Rot = RotIn; //will do mesh subdivide in here eventually...! //options here for how we color... CVertex v[3]; nVertex* pCurVert; bool NormExists[3]; Vec3D TriNormal; CColor DefaultColor = CColor(0.5, 0.5, 0.5); for (std::vector::iterator jt = pObj->Meshes.begin(); jt != pObj->Meshes.end(); jt++){ //meshes for (std::vector::iterator kt = jt->Volumes.begin(); kt != jt->Volumes.end(); kt++){ //Volumes Meshes.push_back(CMeshSlice()); //add a mesh object for each volume, since we're only currently supporting a single texture per mesh... CMesh* CurMesh = &Meshes.back(); //for everythign else which is just CMesh member CurMesh->GlNameIndexStack = *pIndexStack; // CurMesh->GlNameIndex = pObj->aID; //But, our opengl picking will always be by Object level std::vector AddedTextures; //keep a list of which AMF tex ID's we've added as textures to mesh class the index of these should match the index in the Textures[] array in the mesh nMaterial* pMat = NULL; MaterialIDs.push_back(-1); //no material if (kt->MaterialIDExists){ pMat = pAmf->GetMaterialByID(kt->aMaterialID); MaterialIDs.back() = kt->aMaterialID; //set to this material ID } //TEMP!!! (allows slicer to get colors for bitmap...) Meshes.back().pMaterial = pMat; // Meshes.back().pObjExt = this; Meshes.back().pAmf = pAmfIn; for (std::vector::iterator lt = kt->Triangles.begin(); lt != kt->Triangles.end(); lt++){ //Triangles for(int i=0; i<3; i++){ v[i].Clear(); //make sure no lingering data in our re-usable vertex object... switch (i){ case 0: pCurVert = &(jt->Vertices.VertexList[lt->v1]); break; case 1: pCurVert = &(jt->Vertices.VertexList[lt->v2]); break; case 2: pCurVert = &(jt->Vertices.VertexList[lt->v3]); break; } v[i].v = /*UnitsScale*/Vec3D(pCurVert->GetX(), pCurVert->GetY(), pCurVert->GetZ()); //todo:get normal from AMF! NormExists[i] = false; if (pCurVert->NormalExists){ //got lots to do as far as subdividing to do here........... v[i].n = Vec3D(pCurVert->Normal.nX, pCurVert->Normal.nY, pCurVert->Normal.nZ); v[i].HasNormal = true; NormExists[i] = true; //flag to not apply triangle normal later... } //set color based on view option... v[i].HasColor = true; switch (CurColorView){ case CV_TRI: case CV_TRICOLOR: case CV_TRITEX: if (lt->ColorExists) v[i].VColor = nColor2CColor(lt->Color, &v[i].v); else v[i].VColor = DefaultColor; break; case CV_VERT: if (pCurVert->ColorExists) v[i].VColor = nColor2CColor(pCurVert->Color, &v[i].v); else v[i].VColor = DefaultColor; break; case CV_VOL: if (kt->ColorExists) v[i].VColor = nColor2CColor(kt->Color, &v[i].v); else v[i].VColor = DefaultColor; break; case CV_OBJ: if (pObj->ColorExists) v[i].VColor = nColor2CColor(pObj->Color, &v[i].v); else v[i].VColor = DefaultColor; break; case CV_MAT: if (kt->MaterialIDExists && pMat != NULL && pMat->ColorExists) v[i].VColor = nColor2CColor(pMat->Color, &v[i].v); else v[i].VColor = DefaultColor; break; case CV_ALL: //order of precedence: material < object < volume < vertex < triangle if (lt->ColorExists) v[i].VColor = nColor2CColor(lt->Color, &v[i].v); else if (pCurVert->ColorExists) v[i].VColor = nColor2CColor(pCurVert->Color, &v[i].v); else if (kt->ColorExists) v[i].VColor = nColor2CColor(kt->Color, &v[i].v); else if (pObj->ColorExists) v[i].VColor = nColor2CColor(pObj->Color, &v[i].v); else if (kt->MaterialIDExists && pMat != NULL && pMat->ColorExists) v[i].VColor = nColor2CColor(pMat->Color, &v[i].v); else v[i].VColor = DefaultColor; //set the color to some break; default: v[i].VColor = DefaultColor; break; } } //NORMALS! if (!NormExists[0] || NormExists[1] || NormExists[2]){ //if any of the normals weren't set from the AMF apply triangle normal Vec3D tmp = v[2].v-v[0].v; //gcc compat TriNormal = ((v[1].v-v[0].v).Cross(tmp)).Normalized(); if (!NormExists[0]) v[0].n = TriNormal; if (!NormExists[1]) v[1].n = TriNormal; if (!NormExists[2]) v[2].n = TriNormal; } //TEXTURES! if (lt->TexMapExists && (CurColorView == CV_TRITEX || CurColorView == CV_TRI || CurColorView == CV_ALL)){ //if there's a texture map and we want to see textures... nTexmap* pMap = lt->GetpTexMap(); int aRID = pMap->RTexID; int aGID = pMap->GTexID; int aBID = pMap->BTexID; int aAID = pMap->ATexID; if (aRID == -1 || aGID == -1 || aBID == -1) return false; //Technically this is allowed, but not handled correctly yet. int MeshTexIndex = -1; //what mesh texture index does this triangle reference? //check and return index if we've already added a texture to this mesh with the same indices... int NumAdded = AddedTextures.size(); for (int i=0; iGetTextureByID(aRID); if (pTex) pTex->GetSize(&w[0], &h[0]); else return false; pTex = pAmf->GetTextureByID(aGID); if (pTex) pTex->GetSize(&w[1], &h[1]); else return false; pTex= pAmf->GetTextureByID(aBID); if (pTex) pTex->GetSize(&w[2], &h[2]); else return false; if (pMap->ATexIDExists) pAmf->GetTextureByID(aAID)->GetSize(&w[3], &h[3]); if (w[0] != w[1] || w[0] != w[2] || (w[3] != -1 && w[0] != w[3])) return false; //a width did not match up! if (h[0] != h[1] || h[0] != h[2] || (h[3] != -1 && h[0] != h[3])) return false; //a height did not match up! //tile this texture if R, G, or B texture in AMF is tiled... bool TileThisOne = (pAmf->GetTextureByID(pMap->RTexID)->aTiled || pAmf->GetTextureByID(pMap->GTexID)->aTiled || pAmf->GetTextureByID(pMap->BTexID)->aTiled); CTexture* NewTexture = CurMesh->AddTexture(CTexture()); // CurMesh->Textures.push_back(CTexture()); //Add the texture! inds TheseInds = {{aRID, aGID, aBID, aAID}}; AddedTextures.push_back(TheseInds); MeshTexIndex = CurMesh->GetTextureCount()-1; if (pMap->ATexIDExists) NewTexture->LoadData(w[0], h[0], pAmf->GetTextureByID(aRID)->BinaryData.data(), pAmf->GetTextureByID(aGID)->BinaryData.data(), pAmf->GetTextureByID(aBID)->BinaryData.data(), pAmf->GetTextureByID(aAID)->BinaryData.data(), TileThisOne); else NewTexture->LoadData(w[0], h[0], pAmf->GetTextureByID(aRID)->BinaryData.data(), pAmf->GetTextureByID(aGID)->BinaryData.data(), pAmf->GetTextureByID(aBID)->BinaryData.data(), TileThisOne); } try{CurMesh->AddFacet(v[0], v[1], v[2], TexMap(MeshTexIndex, pMap->uTex1, pMap->uTex2, pMap->uTex3, pMap->vTex1, pMap->vTex2, pMap->vTex3));} catch(std::bad_alloc){return false;} } else { //otherwise try{CurMesh->AddFacet(v[0], v[1], v[2]);} catch(std::bad_alloc){return false;} } //TODO: get edges into mesh object... //TEMP: exhaustive check of edges! CLine tmpLine; for (std::vector::iterator mt = jt->Vertices.EdgeList.begin(); mt != jt->Vertices.EdgeList.end(); mt++){ CFacet* pCurFacet = CurMesh->GetpFacet(CurMesh->GetFacetCount()-1); // Facets.back(); //from v0 to v1 if (mt->v1 == lt->v1 && mt->v2 == lt->v2){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[0], pCurFacet->vi[1], Vec3D(mt->dx1, mt->dy1, mt->dz1), Vec3D(mt->dx2, mt->dy2, mt->dz2)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[0] = true; pCurFacet->ei[0] = CurMesh->GetLineCount()-1; } else if (mt->v2 == lt->v1 && mt->v1 == lt->v2){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[0], pCurFacet->vi[1], -Vec3D(mt->dx2, mt->dy2, mt->dz2), -Vec3D(mt->dx1, mt->dy1, mt->dz1)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[0] = true; pCurFacet->ei[0] = CurMesh->GetLineCount()-1; } //from v1 to v2 else if (mt->v1 == lt->v2 && mt->v2 == lt->v3){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[1], pCurFacet->vi[2], Vec3D(mt->dx1, mt->dy1, mt->dz1), Vec3D(mt->dx2, mt->dy2, mt->dz2)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[1] = true; pCurFacet->ei[1] = CurMesh->GetLineCount()-1; } else if (mt->v2 == lt->v2 && mt->v1 == lt->v3){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[1], pCurFacet->vi[2], -Vec3D(mt->dx2, mt->dy2, mt->dz2), -Vec3D(mt->dx1, mt->dy1, mt->dz1)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[1] = true; pCurFacet->ei[1] = CurMesh->GetLineCount()-1; } //from v2 to v0 else if (mt->v1 == lt->v3 && mt->v2 == lt->v1){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[2], pCurFacet->vi[0], Vec3D(mt->dx1, mt->dy1, mt->dz1), Vec3D(mt->dx2, mt->dy2, mt->dz2)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[2] = true; pCurFacet->ei[2] = CurMesh->GetLineCount()-1; } else if (mt->v2 == lt->v3 && mt->v1 == lt->v1){ //v1, v2 may not be in correct order!! tmpLine = CLine(pCurFacet->vi[2], pCurFacet->vi[0], -Vec3D(mt->dx2, mt->dy2, mt->dz2), -Vec3D(mt->dx1, mt->dy1, mt->dz1)); CurMesh->AddLine(tmpLine); pCurFacet->HasEdge[2] = true; pCurFacet->ei[2] = CurMesh->GetLineCount()-1; } } } //do specified translations and rotations... //experiement with curved triangles... // CurMesh->SubdivideMe(); // CurMesh->SubdivideMe(); // CurMesh->SubdivideMe(); // CurMesh->SubdivideMe(); // CurMesh->SubdivideMe(); // CurMesh->SubdivideMe(); // CurMesh->DrawSmooth = false; Meshes.back().Rot = RotIn; Meshes.back().Offset = OffsetIn + CurMesh->GetBBMin().Rot(RotIn); Meshes.back().OrigDim = CurMesh->GetBBSize(); // Meshes.back().OrigBBMin = CurMesh->GetBBMin(); CurMesh->Rotate(RotIn); CurMesh->Translate(OffsetIn); } } return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/Amf.cpp000066400000000000000000000352141231531733200234010ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ // Amf_WinDll.cpp : Defines the exported functions for the DLL application. // #include "Amf.h" #include "AMF_File.h" //Need to translate. Can't use the same enums because must be defined in interface header as well as within library. static UnitSystem TranslateEnum(Amf::aUnitSystem UnitsIn){switch (UnitsIn){case Amf::aUNIT_MM: return UNIT_MM; case Amf::aUNIT_M: return UNIT_M; case Amf::aUNIT_IN: return UNIT_IN; case Amf::aUNIT_FT: return UNIT_FT; case Amf::aUNIT_UM: return UNIT_UM; default: return UNIT_MM;}} static Amf::aUnitSystem TranslateEnum(UnitSystem UnitsIn){switch (UnitsIn){case UNIT_MM: return Amf::aUNIT_MM; case UNIT_M: return Amf::aUNIT_M; case UNIT_IN: return Amf::aUNIT_IN; case UNIT_FT: return Amf::aUNIT_FT; case UNIT_UM: return Amf::aUNIT_UM; default: return Amf::aUNIT_MM;}} static InstanceParamD TranslateEnum(Amf::aInstanceParamD ParamIn){switch (ParamIn){case Amf::aINST_DX: return INST_DX; case Amf::aINST_DY: return INST_DY; case Amf::aINST_DZ: return INST_DZ; case Amf::aINST_RX: return INST_RX; case Amf::aINST_RY: return INST_RY; case Amf::aINST_RZ: return INST_RZ; default: return INST_DX;}} static Amf::aInstanceParamD TranslateEnum(InstanceParamD ParamIn){switch (ParamIn){case INST_DX: return Amf::aINST_DX; case INST_DY: return Amf::aINST_DY; case INST_DZ: return Amf::aINST_DZ; case INST_RX: return Amf::aINST_RX; case INST_RY: return Amf::aINST_RY; case INST_RZ: return Amf::aINST_RZ; default: return Amf::aINST_DX;}} static EnvelopeData TranslateEnum(Amf::aEnvelopeData DataIn){switch (DataIn){case Amf::aENVL_XMIN: return ENVL_XMIN; case Amf::aENVL_YMIN: return ENVL_YMIN; case Amf::aENVL_ZMIN: return ENVL_ZMIN; case Amf::aENVL_XMAX: return ENVL_XMAX; case Amf::aENVL_YMAX: return ENVL_YMAX; case Amf::aENVL_ZMAX: return ENVL_ZMAX; case Amf::aENVL_XSIZE: return ENVL_XSIZE; case Amf::aENVL_YSIZE: return ENVL_YSIZE; case Amf::aENVL_ZSIZE: return ENVL_ZSIZE; default: return ENVL_XMIN;}} Amf::Amf() {pData = new AmfFile();} Amf::~Amf() {delete pData;} Amf::Amf(const Amf& In) {*this = In;} Amf& Amf::operator=(const Amf& In){*pData = *In.pData; return *this;} //Amf I/O bool Amf::Save(std::string AmfFilePath, bool Compressed){return pData->Save(AmfFilePath, Compressed);} bool Amf::Load(std::string AmfFilePath, bool StrictLoad){return pData->Load(AmfFilePath, StrictLoad);} bool Amf::ImportAmf(std::string AmfFilePath, bool StrictLoad) {return pData->ImportAmf(AmfFilePath, StrictLoad);} void Amf::ClearAll() {pData->ClearAll();} //importing meshes bool Amf::ImportMesh(std::string MeshFilePath, int AmfObjectIndex, int AmfMeshIndex) {return pData->ImportMesh(MeshFilePath, AmfObjectIndex, AmfMeshIndex);} //imports a mesh into a mesh node specified (stl or x3d only) bool Amf::LoadStl(std::string StlFilePath){return pData->LoadStl(StlFilePath);} //imports an stl into a mesh node specified bool Amf::GetStlMeshSize(double* XSize, double* YSize, double* ZSize){return pData->GetStlMeshSize(XSize, YSize, ZSize);} bool Amf::ImportStl(int AmfObjectIndex, int AmfMeshIndex) {return pData->ImportStl(AmfObjectIndex, AmfMeshIndex);} //imports an stl into a mesh node specified bool Amf::LoadX3d(std::string X3dFilePath, std::string ImagePath, std::string* ImgPathErrorReturn){return pData->LoadX3d(X3dFilePath, ImagePath, ImgPathErrorReturn);} //imports an x3d into a mesh node specified bool Amf::GetX3dMeshSize(double* XSize, double* YSize, double* ZSize){return pData->GetX3dMeshSize(XSize, YSize, ZSize);} bool Amf::ImportX3d(int AmfObjectIndex, int AmfMeshIndex){return pData->ImportX3d(AmfObjectIndex, AmfMeshIndex);} //imports an x3d into a mesh node specified //exporting meshes bool Amf::ExportSTL(std::string StlFilePath){return pData->ExportSTL(StlFilePath);} //Units void Amf::SetImportUnits(aUnitSystem Units) {pData->SetImportUnits(TranslateEnum(Units));} Amf::aUnitSystem Amf::GetUnits(void){return TranslateEnum(pData->GetUnits());} std::string Amf::GetUnitsString(void){return pData->GetUnitsString();} std::string Amf::GetUnitsString(aUnitSystem Units){return pData->GetUnitsString(TranslateEnum(Units));} void Amf::SetUnits(aUnitSystem Units){pData->SetUnits(TranslateEnum(Units));} double Amf::ConvertUnits(double Value, aUnitSystem OriginalUnits, aUnitSystem DesiredUnits){return pData->ConvertUnits(Value, TranslateEnum(OriginalUnits), TranslateEnum(DesiredUnits));} double Amf::ToCurrentUnits(double Value, aUnitSystem OriginalUnits){return pData->ToCurrentUnits(Value, TranslateEnum(OriginalUnits));} double Amf::FromCurrentUnits(double Value, aUnitSystem DesiredUnits){return pData->FromCurrentUnits(Value, TranslateEnum(DesiredUnits));} //Size of Amf double Amf::GetEnvelopeData(aEnvelopeData Data) {return pData->GetEnvelopeData(TranslateEnum(Data));} bool Amf::GetEnvlMin(double* pXMinOut, double* pYMinOut, double* pZMinOut, int RenderIndex) {return pData->GetEnvlMin(pXMinOut, pYMinOut, pZMinOut, RenderIndex);} bool Amf::GetEnvlMax(double* pXMaxOut, double* pYMaxOut, double* pZMaxOut, int RenderIndex) {return pData->GetEnvlMax(pXMaxOut, pYMaxOut, pZMaxOut, RenderIndex);} bool Amf::GetEnvlSize(double* pXSizeOut, double* pYSizeOut, double* pZSizeOut, int RenderIndex) {return pData->GetEnvlSize(pXSizeOut, pYSizeOut, pZSizeOut, RenderIndex);} bool Amf::GetEnvlRotQuat(double* pWRotOut, double* pXRotOut, double* pYRotOut, double* pZRotOut, int RenderIndex) {return pData->GetEnvlRotQuat(pWRotOut, pXRotOut, pYRotOut, pZRotOut, RenderIndex);} bool Amf::GetEnvlRotAngleAxis(double* pAngleRadOut, double* pNXOut, double* pNYOut, double* pNZOut, int RenderIndex) {return pData->GetEnvlRotAngleAxis(pAngleRadOut, pNXOut, pNYOut, pNZOut, RenderIndex);} bool Amf::GetEnvlOrigin(double* pXOriginOut, double* pYOriginOut, double* pZOriginOut, int RenderIndex) {return pData->GetEnvlOrigin(pXOriginOut, pYOriginOut, pZOriginOut, RenderIndex);} bool Amf::GetEnvlDims(double* pIDimOut, double* pJDimOut, double* pKDimOut, int RenderIndex) {return pData->GetEnvlDims(pIDimOut, pJDimOut, pKDimOut, RenderIndex);} bool Amf::Scale(double ScaleFactor, bool ScaleConstellations, bool ScaleEquations){return pData->Scale(ScaleFactor, ScaleConstellations, ScaleEquations);} bool Amf::Scale(double XScaleFactor, double YScaleFactor, double ZScaleFactor, bool ScaleConstellations, bool ScaleEquations){return pData->Scale(XScaleFactor, YScaleFactor, ZScaleFactor, ScaleConstellations, ScaleEquations);} //Amf Objects: int Amf::GetObjectCount(void) {return pData->GetObjectCount();} std::string Amf::GetObjectName(int ObjectIndex) {return pData->GetObjectName(ObjectIndex);} void Amf::RenameObject(int ObjectIndex, std::string NewName){pData->RenameObject(ObjectIndex, NewName);} int Amf::AddObject(std::string ObjectName){return pData->AddObject(ObjectName);} void Amf::RemoveObject(int ObjectIndex) {pData->RemoveObject(ObjectIndex);} void Amf::TranslateObject(int ObjectIndex, double dx, double dy, double dz) {pData->TranslateObject(ObjectIndex, dx, dy, dz);} void Amf::RotateObject(int ObjectIndex, double rx, double ry, double rz) {pData->RotateObject(ObjectIndex, rx, ry, rz);} //Amf Meshes int Amf::GetMeshCount(int ObjectIndex){return pData->GetMeshCount(ObjectIndex);} //Amf Volumes int Amf::GetVolumeCount(int ObjectIndex, int MeshIndex) {return pData->GetVolumeCount(ObjectIndex, MeshIndex);} std::string Amf::GetVolumeName(int ObjectIndex, int MeshIndex, int VolumeIndex){return pData->GetVolumeName(ObjectIndex, MeshIndex, VolumeIndex);} void Amf::RenameVolume(int ObjectIndex, int MeshIndex, int VolumeIndex, std::string NewName){return pData->RenameVolume(ObjectIndex, MeshIndex, VolumeIndex, NewName);} int Amf::GetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex){return pData->GetVolumeMaterialIndex(ObjectIndex, MeshIndex, VolumeIndex);} bool Amf::SetVolumeMaterialIndex(int ObjectIndex, int MeshIndex, int VolumeIndex, int MaterialIndex){return pData->SetVolumeMaterialIndex(ObjectIndex, MeshIndex, VolumeIndex, MaterialIndex);} //Amf Constellations: int Amf::GetConstellationCount(void) {return pData->GetConstellationCount();} std::string Amf::GetConstellationName(int ConstellationIndex) {return pData->GetConstellationName(ConstellationIndex);} void Amf::RenameConstellation(int ConstellationIndex, std::string NewName){pData->RenameConstellation(ConstellationIndex, NewName);} int Amf::AddConstellation(std::string ConstellationName){return pData->AddConstellation(ConstellationName);} void Amf::RemoveConstellation(int ConstellationIndex) {pData->RemoveConstellation(ConstellationIndex);} bool Amf::IsConstellationReferencedBy(int ConstellationIndex, int ConstellationIndexToCheck){return pData->IsConstellationReferencedBy(ConstellationIndex, ConstellationIndexToCheck);} //Amf Instances int Amf::GetInstanceCount(int ConstellationIndex){return pData->GetInstanceCount(ConstellationIndex);} int Amf::AddInstance(int ConstellationIndex) {return pData->AddInstance(ConstellationIndex);} void Amf::RemoveInstance(int ConstellationIndex, int InstanceIndex) {pData->RemoveInstance(ConstellationIndex, InstanceIndex);} bool Amf::SetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex, int InstanceObjectIndex) {return pData->SetInstanceObjectIndex(ConstellationIndex, InstanceIndex, InstanceObjectIndex);} bool Amf::SetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex, int InstanceConstellationIndex) {return pData->SetInstanceConstellationIndex(ConstellationIndex, InstanceIndex, InstanceConstellationIndex);} int Amf::GetInstanceObjectIndex(int ConstellationIndex, int InstanceIndex) {return pData->GetInstanceObjectIndex(ConstellationIndex, InstanceIndex);} int Amf::GetInstanceConstellationIndex(int ConstellationIndex, int InstanceIndex) {return pData->GetInstanceConstellationIndex(ConstellationIndex, InstanceIndex);} bool Amf::SetInstanceParam(int ConstellationIndex, int InstanceIndex, aInstanceParamD ParamD, double Value) {return pData->SetInstanceParam(ConstellationIndex, InstanceIndex, TranslateEnum(ParamD), Value);} double Amf::GetInstanceParam(int ConstellationIndex, int InstanceIndex, aInstanceParamD ParamD) {return pData->GetInstanceParam(ConstellationIndex, InstanceIndex, TranslateEnum(ParamD));} //Amf Materials: int Amf::GetMaterialCount(void) {return pData->GetMaterialCount();} std::string Amf::GetMaterialName(int MaterialIndex) {return pData->GetMaterialName(MaterialIndex);} void Amf::RenameMaterial(int MaterialIndex, std::string NewName){pData->RenameMaterial(MaterialIndex, NewName);} int Amf::AddMaterial(std::string MaterialName){return pData->AddMaterial(MaterialName);} int Amf::AddMaterial(std::string MaterialName, int Red, int Green, int Blue) {return pData->AddMaterial(MaterialName, Red, Green, Blue);} int Amf::AddMaterial(std::string MaterialName, double Red, double Green, double Blue) {return pData->AddMaterial(MaterialName, Red, Green, Blue);} void Amf::RemoveMaterial(int MaterialIndex) {pData->RemoveMaterial(MaterialIndex);} bool Amf::IsMaterialReferencedBy(int MaterialIndex, int MaterialIndexToCheck) {return pData->IsMaterialReferencedBy(MaterialIndex, MaterialIndexToCheck);} bool Amf::SetMaterialColorD(int MaterialIndex, double Red, double Green, double Blue){return pData->SetMaterialColorD(MaterialIndex, Red, Green, Blue);} bool Amf::SetMaterialColorI(int MaterialIndex, int Red, int Green, int Blue){return pData->SetMaterialColorI(MaterialIndex, Red, Green, Blue);} bool Amf::GetMaterialColorD(int MaterialIndex, double *Red, double *Green, double *Blue){return pData->GetMaterialColorD(MaterialIndex, Red, Green, Blue);} bool Amf::GetMaterialColorI(int MaterialIndex, int *Red, int *Green, int *Blue){return pData->GetMaterialColorI(MaterialIndex, Red, Green, Blue);} //Amf Composites int Amf::GetCompositeCount(int MaterialIndex){return pData->GetCompositeCount(MaterialIndex);} void Amf::ClearComposites(int MaterialIndex){pData->ClearComposites(MaterialIndex);} int Amf::AddComposite(int MaterialIndex, int MaterialIndexToComposite){return pData->AddComposite(MaterialIndex, MaterialIndexToComposite);} void Amf::RemoveComposite(int MaterialIndex, int CompositeIndex){pData->RemoveComposite(MaterialIndex, CompositeIndex);} bool Amf::SetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex, int CompositeMaterialIndex){return pData->SetCompositeMaterialIndex(MaterialIndex, CompositeIndex, CompositeMaterialIndex);} //1-based (because 0 always VOID material int Amf::GetCompositeMaterialIndex(int MaterialIndex, int CompositeIndex){return pData->GetCompositeMaterialIndex(MaterialIndex, CompositeIndex);} //1-based (because 0 always VOID material std::string Amf::GetCompositeEquation(int MaterialIndex, int CompositeIndex){return pData->GetCompositeEquation(MaterialIndex, CompositeIndex);} //use! ToAmfString() bool Amf::SetCompositeEquation(int MaterialIndex, int CompositeIndex, std::string Equation) {return pData->SetCompositeEquation(MaterialIndex, CompositeIndex, Equation);} //Amf Textures: int Amf::GetTextureCount(void) {return pData->GetTextureCount();} //Output utilities bool Amf::SetSubdivisionLevel(int Level){return pData->SetSubdivisionLevel(Level);} void Amf::DrawGL(){pData->DrawGL();} unsigned char* Amf::GetSliceBitmapRGBA(double PixelSizeX, double PixelSizeY, double SliceHeightZ, int* XSizeOut, int* YSizeOut, double SurfaceDepth){return pData->GetSliceBitmapRGBA(PixelSizeX, PixelSizeY, SliceHeightZ, XSizeOut, YSizeOut, SurfaceDepth);} int* Amf::GetSliceSegmentsXY(double ZHeight, int* NumSegmentsOut){return pData->GetSliceSegmentsXY(ZHeight, NumSegmentsOut);} //Errors and information std::string Amf::GetInfoString(bool MeshInfo) {return pData->GetInfoString(MeshInfo);} std::string* Amf::pLastErrorMsg(){return pData->pLastErrorMsg();} std::string Amf::GetLastErrorMsg(){return pData->GetLastErrorMsg();} //Real time status info on long i/o operations bool* Amf::pCancelIO(){return pData->pCancelIO();} int* Amf::pCurTick(){return pData->pCurTick();} int* Amf::pMaxTick(){return pData->pMaxTick();} std::string* Amf::pStatusMsg(){return pData->pStatusMsg();} repsnapper-2.3.2a5/libraries/amf/amftools-code/src/Equation.cpp000066400000000000000000000165441231531733200244700ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "Equation.h" #include "nTexture.h" #include "nAmf.h" #include #ifdef WIN32 //for UINT_MAX (windows finds automagically) #else #include //for UINT_MAX #endif nAmf* CEquation::pAmfStatic = NULL; CEquation::CEquation(void) { pP = NULL; pEqCache = NULL; Clear(); } CEquation::~CEquation(void) { if (pP) delete pP; // pP = NULL; if (pEqCache) delete pEqCache; // pEqCache = NULL; } void CEquation::Clear(void) { XVar = 0; YVar = 0; ZVar = 0; IsConstant = true; ConstantValue = 0.0; pAmf = NULL; if (pP) delete pP; pP = NULL; if (pEqCache) delete pEqCache; pEqCache = NULL; } CEquation& CEquation::operator=(const CEquation& In) { if (pP) delete pP; pP = NULL; if (pEqCache) delete pEqCache; pEqCache = NULL; IsConstant = In.IsConstant; ConstantValue = In.ConstantValue; pAmf = In.pAmf; std::string tmp = In.ToAmfString(); if (In.pP) FromAmfString(tmp, In.pAmf); return *this; } void CEquation::FromConstant(double Value) //set the equation to a constant, non-varying value { IsConstant = true; ConstantValue = Value; } void CEquation::FromAmfString(std::string& EqIn, nAmf* pAmfIn) { if (EqIn == "") return; //catch invalid equations! pAmf = pAmfIn; //figure out if its constant if (EqIn.find_first_of("(^*/%+-=<>&|\\!xXyYzZ") == EqIn.npos){ //if we don't find any of these... (this may be inefficient...) IsConstant = true; ConstantValue = atof(EqIn.c_str()); } else { //is an actual equation... pEqCache = new std::string(EqIn); IniParser(); pP->SetExpr(Amf2MuParser(EqIn)); IsConstant = false; } } std::string CEquation::ToAmfString(void) const { if (IsConstant){ std::ostringstream strs; strs << ConstantValue; return strs.str(); } else if (pEqCache) return *pEqCache; else return ""; } bool CEquation::CheckParse(std::string* pMessage) //tries an evaluation to see if equation is valid... { pAmfStatic = pAmf; //make sure MuParser uses the right set of textures... if (IsConstant) return true; else { //if evaluating equation if (!pP){ if (pMessage) *pMessage += "Error: Equation parser not initialized\n"; return false; //parser has not been initialized yet... } XVar = 0; YVar = 0; ZVar = 0; double result; try{result = pP->Eval();} catch (mu::Parser::exception_type &e){ if (pMessage) *pMessage += "Error: " + e.GetMsg() + "\n"; return false; } return true; } } double CEquation::Eval(double x, double y, double z, bool UnitRange) //Evaluates at specified location. UnitRange truncates to between 0 and 1. { pAmfStatic = pAmf; //make sure MuParser uses the right set of textures... if (IsConstant) return ConstantValue; else { //if evaluating equation if (!pP) return 0; //parser has not been initialized yet... XVar = x; YVar = y; ZVar = z; double result; try{result = pP->Eval();} catch (mu::Parser::exception_type &e){ return 0; } if (UnitRange){ if (result<0) result = 0; if (result > 1.0) result = 1.0; } return result; } } void CEquation::Scale(double ScaleFactor) { //TODO: do manual equation simplification to avoid bloat scaling back and forth? std::ostringstream strs; strs << 1.0/ScaleFactor; std::string Factor = strs.str(); std::string TmpEq = ToAmfString(); findAndReplace(TmpEq, "x", "("+Factor+"*x)"); findAndReplace(TmpEq, "X", "("+Factor+"*X)"); findAndReplace(TmpEq, "y", "("+Factor+"*y)"); findAndReplace(TmpEq, "Y", "("+Factor+"*Y)"); findAndReplace(TmpEq, "z", "("+Factor+"*z)"); findAndReplace(TmpEq, "Z", "("+Factor+"*Z)"); FromAmfString(TmpEq, pAmf); } void CEquation::IniParser() { if (!pP){ //if not already initialized... pP = new mu::Parser; pP->DefineOprt("%", CEquation::Mod, 6); pP->DefineOprt("&", AND, 1); pP->DefineOprt("|", OR, 1); // pP->DefineOprt("\\", XOR, 1); // = "\" with escape sequence pP->DefineInfixOprt("!", NOT); pP->DefineFun("floor", &CEquation::Floor, false); pP->DefineFun("ceil", &CEquation::Ceil, false); pP->DefineFun("abs", &CEquation::Abs, false); pP->DefineFun("rand", &CEquation::Rand, false); pP->DefineFun("tex", &CEquation::Tex, false); pP->DefineVar("x", &XVar); pP->DefineVar("y", &YVar); pP->DefineVar("z", &ZVar); } } std::string CEquation::Amf2MuParser(std::string& Equation) //translates from AMF syntax to MuParser syntax { std::string tmp = Equation; findAndReplace(tmp, "=", "=="); //replace isEqual operator // other filtering here of bad AMF equations.... return tmp; } std::string CEquation::MuParser2Amf(std::string& Equation) //translates from MuParser syntax to AMF syntax { return ""; } double CEquation::texture(int textureID, double uIn, double vIn, double wIn) { return pAmfStatic->GetTextureByID(textureID)->GetValue(uIn, vIn, wIn); } //Pseudo-random spatial map stuff: unsigned long int CEquation::rand_seed(unsigned long int x) { return (1664525*x+1013904223) & 0x7fffffffUL; } unsigned long int CEquation::taus_get(taus_state* state){ unsigned long b; b = (((state->s1 << 13UL) & 0xffffffffUL) ^ state->s1) >> 19UL; state->s1 = (((state->s1 & 0xfffffffeUL) << 12UL) & 0xffffffffUL) ^ b; b = (((state->s2 << 2UL) & 0xffffffffUL) ^ state->s2) >> 25UL; state->s2 = (((state->s2 & 0xfffffff8UL) << 4UL) & 0xffffffffUL) ^ b; b = (((state->s3 << 3UL) & 0xffffffffUL) ^ state->s3) >> 11UL; state->s3 = (((state->s3 & 0xfffffff0UL) << 17UL) & 0xffffffffUL) ^ b; return (state->s1 ^ state->s2 ^ state->s3); } double CEquation::prsm(double x, double y, double z, int k) { taus_state state; float tx, ty, tz; tx = (float) x; ty = (float) y; tz = (float) z; /* Convert floating point numbers to ints*/ unsigned long int ts1 = *(unsigned int*)&tx; unsigned long int ts2 = *(unsigned int*)&ty; unsigned long int ts3 = *(unsigned int*)&tz; /* Convert coordinates to random seeds */ state.s1 = rand_seed(ts1); state.s2 = rand_seed(ts2); state.s3 = rand_seed(ts3); state.s1 = rand_seed(state.s1 ^ state.s3); state.s2 = rand_seed(state.s2 ^ state.s1); state.s3 = rand_seed(state.s3 ^ state.s2); state.s1 = rand_seed(state.s1 ^ state.s3); state.s2 = rand_seed(state.s2 ^ state.s1); state.s3 = rand_seed(state.s3 ^ state.s2); /* "warm up" generator and generate k-th number */ for (int i=0; i for license details. *******************************************************************************/ #include "Mesh.h" #include #include #ifdef USE_OPEN_GL #ifdef XX_WIN32 #include #endif #include #endif #define STL_LABEL_SIZE 80 CMesh::CMesh(void) { Clear(); } CMesh::~CMesh(void) { } //copy constructure CMesh::CMesh(CMesh& s) { *this = s; } //overload = CMesh& CMesh::operator=(const CMesh& s) { Facets.resize(s.Facets.size()); for (int i = 0; i<(int)Facets.size(); i++) Facets[i] = s.Facets[i]; Vertices.resize(s.Vertices.size()); for (int i = 0; i<(int)Vertices.size(); i++) Vertices[i] = s.Vertices[i]; Lines.resize(s.Lines.size()); for (int i = 0; i<(int)Lines.size(); i++) Lines[i] = s.Lines[i]; Textures = s.Textures; //Textures.resize(s.Textures.size()); //for (int i = 0; i<(int)Textures.size(); i++) // Textures[i] = s.Textures[i]; DrawNormals = s.DrawNormals; DrawTextures = s.DrawTextures; DrawSmooth = s.DrawSmooth; DrawEdges = s.DrawEdges; DrawShaded = s.DrawShaded; IgnoreNames = s.IgnoreNames; BodyColor = s.BodyColor; //default base color BoundBoxColor = s.BoundBoxColor; //default bounding box color _CurBBMin = s._CurBBMin; _CurBBMax = s._CurBBMax; GlNameIndexStack = s.GlNameIndexStack; NeedBBCalc = s.NeedBBCalc; MeshChanged(); return *this; } void CMesh::Clear() { Facets.clear(); Vertices.clear(); Lines.clear(); Textures.clear(); DrawNormals = false; DrawTextures = true; DrawSmooth = true; DrawEdges = false; DrawShaded = true; IgnoreNames = false; BodyColor = CColor(1, 1, 1, 1); //default base color BoundBoxColor = CColor(0, 0, 0, 1); //default bounding box color _CurBBMin = Vec3D(0,0,0); _CurBBMax = Vec3D(0,0,0); NeedBBCalc = false; GlNameIndexStack.clear(); } void CMesh::WriteXML(CXmlStreamWrite* pXML, bool MeshOnly) { pXML->OpenElement("CMesh"); pXML->SetElementB("DrawSmooth", DrawSmooth); pXML->OpenElement("BodyColor"); pXML->SetElementD("R", BodyColor.r); pXML->SetElementD("G", BodyColor.g); pXML->SetElementD("B", BodyColor.b); pXML->SetElementD("A", BodyColor.a); pXML->CloseElement(); pXML->OpenElement("Vertices"); std::vector::iterator VIt; for(VIt=Vertices.begin(); VIt != Vertices.end(); VIt++){ pXML->OpenElement("Vertex"); pXML->SetElementD("Vx", VIt->v.x); pXML->SetElementD("Vy", VIt->v.y); pXML->SetElementD("Vz", VIt->v.z); if (!MeshOnly){ if (VIt->n != Vec3D(0,0,0)){ pXML->SetElementD("Nx", VIt->n.x); pXML->SetElementD("Ny", VIt->n.y); pXML->SetElementD("Nz", VIt->n.z); } pXML->SetElementD("R", VIt->VColor.r); pXML->SetElementD("G", VIt->VColor.g); pXML->SetElementD("B", VIt->VColor.b); pXML->SetElementD("A", VIt->VColor.a); // if (VIt->DrawOffset != Vec3D(0,0,0)){ // pXML->SetElementD("DOx", VIt->DrawOffset.x); // pXML->SetElementD("DOy", VIt->DrawOffset.y); // pXML->SetElementD("DOz", VIt->DrawOffset.z); // } } pXML->CloseElement(); } pXML->CloseElement(); pXML->OpenElement("Facets"); std::vector::iterator FIt; for(FIt=Facets.begin(); FIt != Facets.end(); FIt++){ pXML->OpenElement("Facet"); pXML->SetElementI("V0", FIt->vi[0]); pXML->SetElementI("V1", FIt->vi[1]); pXML->SetElementI("V2", FIt->vi[2]); if (!MeshOnly){ if (FIt->n != Vec3D(0,0,0)){ pXML->SetElementD("Nx", FIt->n.x); pXML->SetElementD("Ny", FIt->n.y); pXML->SetElementD("Nz", FIt->n.z); } pXML->SetElementD("R", FIt->FColor.r); pXML->SetElementD("G", FIt->FColor.g); pXML->SetElementD("B", FIt->FColor.b); pXML->SetElementD("A", FIt->FColor.a); pXML->SetElementI("Name", FIt->Name); } pXML->CloseElement(); } pXML->CloseElement(); pXML->OpenElement("Lines"); std::vector::iterator LIt; for(LIt=Lines.begin(); LIt != Lines.end(); LIt++){ pXML->OpenElement("Line"); pXML->SetElementI("V0", LIt->vi[0]); pXML->SetElementI("V1", LIt->vi[1]); pXML->CloseElement(); } pXML->CloseElement(); pXML->CloseElement(); } bool CMesh::ReadXML(CXmlStreamRead* pXML) { Clear(); if (!pXML->GetElementB("DrawSmooth", &DrawSmooth)) DrawSmooth = false; if (pXML->OpenElement("BodyColor")){ if (!pXML->GetElementD("R", &BodyColor.r)) BodyColor.r = 1.0; if (!pXML->GetElementD("G", &BodyColor.g)) BodyColor.g = 1.0; if (!pXML->GetElementD("B", &BodyColor.b)) BodyColor.b = 1.0; if (!pXML->GetElementD("A", &BodyColor.a)) BodyColor.a = 1.0; pXML->CloseElement(); } CVertex tmp; if (pXML->OpenElement("Vertices")){ while (pXML->OpenElement("Vertex", true)){ if (!pXML->GetElementD("Vx", &tmp.v.x)) tmp.v.x = 0.0; if (!pXML->GetElementD("Vy", &tmp.v.y)) tmp.v.y = 0.0; if (!pXML->GetElementD("Vz", &tmp.v.z)) tmp.v.z = 0.0; if (!pXML->GetElementD("Nx", &tmp.n.x)) tmp.n.x = 0.0; if (!pXML->GetElementD("Ny", &tmp.n.y)) tmp.n.y = 0.0; if (!pXML->GetElementD("Nz", &tmp.n.z)) tmp.n.z = 0.0; if (!pXML->GetElementD("R", &tmp.VColor.r)) tmp.VColor.r = 1.0; if (!pXML->GetElementD("G", &tmp.VColor.g)) tmp.VColor.g = 1.0; if (!pXML->GetElementD("B", &tmp.VColor.b)) tmp.VColor.b = 1.0; if (!pXML->GetElementD("A", &tmp.VColor.a)) tmp.VColor.a = 1.0; // if (!pXML->GetElementD("DOx", &tmp.DrawOffset.x)) tmp.DrawOffset.x = 0.0; // if (!pXML->GetElementD("DOy", &tmp.DrawOffset.y)) tmp.DrawOffset.y = 0.0; // if (!pXML->GetElementD("DOz", &tmp.DrawOffset.z)) tmp.DrawOffset.z = 0.0; Vertices.push_back(tmp); } pXML->CloseElement(); } CFacet Ftmp; if (pXML->OpenElement("Facets")){ while (pXML->OpenElement("Facet", true)){ if (!pXML->GetElementI("V0", &Ftmp.vi[0])) Ftmp.vi[0] = 0; if (!pXML->GetElementI("V1", &Ftmp.vi[1])) Ftmp.vi[1] = 0; if (!pXML->GetElementI("V2", &Ftmp.vi[2])) Ftmp.vi[2] = 0; if (!pXML->GetElementD("Nx", &Ftmp.n.x)) Ftmp.n.x = 0.0; if (!pXML->GetElementD("Ny", &Ftmp.n.y)) Ftmp.n.y = 0.0; if (!pXML->GetElementD("Nz", &Ftmp.n.z)) Ftmp.n.z = 0.0; if (!pXML->GetElementD("R", &Ftmp.FColor.r)) Ftmp.FColor.r = 1.0; if (!pXML->GetElementD("G", &Ftmp.FColor.g)) Ftmp.FColor.g = 1.0; if (!pXML->GetElementD("B", &Ftmp.FColor.b)) Ftmp.FColor.b = 1.0; if (!pXML->GetElementD("A", &Ftmp.FColor.a)) Ftmp.FColor.a = 1.0; if (!pXML->GetElementI("Name", &Ftmp.Name)) Ftmp.Name = -1; Facets.push_back(Ftmp); } pXML->CloseElement(); } CLine Ltmp; if (pXML->OpenElement("Lines")){ while (pXML->OpenElement("Line", true)){ if (!pXML->GetElementI("V0", &Ltmp.vi[0])) Ltmp.vi[0] = 0; if (!pXML->GetElementI("V1", &Ltmp.vi[1])) Ltmp.vi[1] = 0; Lines.push_back(Ltmp); } pXML->CloseElement(); } NeedBBCalc = true; CalcFaceNormals(); CalcVertNormals(); return true; } bool CMesh::LoadSTL(std::string filename) { FILE *fp; bool binary=false; #ifdef XX_WIN32 fopen_s(&fp, filename.c_str(), "r"); //secure version. preferred on windows platforms... #else fp = fopen(filename.c_str(), "r"); #endif if(fp == NULL) return false; /* Find size of file */ fseek(fp, 0, SEEK_END); int file_size = ftell(fp); int facenum; /* Check for binary or ASCII file */ fseek(fp, STL_LABEL_SIZE, SEEK_SET); fread(&facenum, sizeof(int), 1, fp); int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+12*sizeof(float) )*facenum ; if(file_size == expected_file_size) binary = true; unsigned char tmpbuf[128]; fread(tmpbuf,sizeof(tmpbuf),1,fp); for(unsigned int i = 0; i < sizeof(tmpbuf); i++){ if(tmpbuf[i] > 127){ binary=true; break; } } // Now we know if the stl file is ascii or binary. fclose(fp); bool RetVal; if(binary) RetVal = LoadBinarySTL(filename); else RetVal = LoadAsciiSTL(filename); // UpdateBoundingBox(); //get the bounding box here and now... NeedBBCalc = true; //AddFacet should have set this, but just to make sure! MeshChanged(); return RetVal; } bool CMesh::LoadBinarySTL(std::string filename) { FILE *fp; #ifdef XX_WIN32 fopen_s(&fp, filename.c_str(), "rb"); //secure version. preferred on windows platforms... #else fp = fopen(filename.c_str(), "rb"); #endif if(fp == NULL) return false; int facenum; fseek(fp, STL_LABEL_SIZE, SEEK_SET); fread(&facenum, sizeof(int), 1, fp); Clear(); // For each triangle read the normal, the three coords and a short set to zero float N[3]; float P[9]; short attr; for(int i=0;i "facet normal 0 0 0" (We throw this out and recalculate based on vertices) if(ret!=3){ // we could be in the case of a multiple solid object, where after a endfaced instead of another facet we have to skip two lines: // endloop // endfacet //endsolid <- continue on ret==0 will skip this line //solid ascii <- and this one. // facet normal 0.000000e+000 7.700727e-001 -6.379562e-001 lineCnt++; continue; } ret=fscanf(fp, "%*s %*s"); // --> "outer loop" ret=fscanf(fp, "%*s %f %f %f\n", &P[0], &P[1], &P[2]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s %f %f %f\n", &P[3], &P[4], &P[5]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s %f %f %f\n", &P[6], &P[7], &P[8]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s"); // --> "endloop" ret=fscanf(fp, "%*s"); // --> "endfacet" lineCnt+=7; if(feof(fp)) break; AddFacet(Vec3D(P[0], P[1], P[2]), Vec3D(P[3], P[4], P[5]), Vec3D(P[6], P[7], P[8])); } fclose(fp); CalcFaceNormals(); return true; } bool CMesh::SaveSTL(std::string filename, bool Binary) const { //writes ascii stl file... FILE *fp; #ifdef XX_WIN32 if (Binary) fopen_s (&fp, filename.c_str(),"wb"); //secure version. preferred on windows platforms... else fopen_s(&fp, filename.c_str(),"w"); #else if (Binary) fp = fopen(filename.c_str(),"wb"); else fp = fopen(filename.c_str(),"w"); #endif if(fp==0) return false; int NumFaces = (int)Facets.size(); if(Binary){ // Write Header std::string tmp = "DefaultSTL "; //char header[128]=; fwrite(tmp.c_str(),80,1,fp); // write number of facets fwrite(&NumFaces,1,sizeof(int),fp); unsigned short attributes=0; for(int i=0; i::iterator it = Facets.begin(); it != Facets.end(); it++){ if (DrawTextures && it->HasTexture){ glEnable(GL_TEXTURE_2D); int ThisTexInd = it->Map.TexIndex; if (ThisTexInd != CurTex && ThisTexInd < NumTex){ glBindTexture(GL_TEXTURE_2D, Textures[ThisTexInd].TexName()); // TexNames[ThisTexInd]); Textures[ThisTexInd].SetGlBorderColor(BodyColor.r, BodyColor.g, BodyColor.b, BodyColor.a); CurTex = ThisTexInd; } } glBegin(GL_TRIANGLES); if (!DrawSmooth){ //if setting things per triangle, can do normal and color here... glNormal3d(it->n.x, it->n.y, it->n.z); // if (!bIngoreColors) glColor3d(Facets[i].FColor.r, Facets[i].FColor.g, Facets[i].FColor.b); } for (int j=0; j<3; j++) { CVertex& CurVert = Vertices[it->vi[j]]; //just a local reference for readability if (DrawSmooth){ //if we want to draw smoothed normals/colors per vertex glNormal3d(CurVert.n.x, CurVert.n.y, CurVert.n.z); } if (CurVert.HasColor) glColor3d(CurVert.VColor.r, CurVert.VColor.g, CurVert.VColor.b); if (DrawTextures && it->HasTexture){ glTexCoord2d(it->Map.uc[j], it->Map.vc[j]); glColor3f(1.0, 1.0, 1.0); //white background for all textured polys so they don't get tinted } glVertex3d(CurVert.v.x/* + CurVert.DrawOffset.x*/, CurVert.v.y/* + CurVert.DrawOffset.y*/, CurVert.v.z/* + CurVert.DrawOffset.z*/); } glEnd(); glDisable(GL_TEXTURE_2D); //end textures... // if (!bIgnoreNames && it->HasName) glPopName(); } //draw any lines that are defined.... if (DrawEdges){ glLineWidth(1.0); glBegin(GL_LINES); glColor3d(0, 0, 0); //black only for now... for (int i=0; i<(int)Lines.size(); i++) { for (int j=0; j<2; j++) { CVertex& CurVert = Vertices[Lines[i].vi[j]]; //just a local reference for readability glVertex3d(CurVert.v.x/* + CurVert.DrawOffset.x*/, CurVert.v.y/* + CurVert.DrawOffset.y*/, CurVert.v.z/* + CurVert.DrawOffset.z*/); } } glEnd(); } } else { // wireframe for (int i=0; i<(int)Facets.size(); i++) { glBegin(GL_LINE_LOOP); glNormal3d(Facets[i].n.x, Facets[i].n.y, Facets[i].n.z); for (int j=0; j<3; j++) { CVertex& CurVert = Vertices[Facets[i].vi[j]]; //just a local reference for readability glColor3d(CurVert.VColor.r, CurVert.VColor.g, CurVert.VColor.b); glVertex3d(CurVert.v.x/* + CurVert.DrawOffset.x*/, CurVert.v.y/* + CurVert.DrawOffset.y*/, CurVert.v.z/* + CurVert.DrawOffset.z*/); } glEnd(); } } if (DrawNormals) { glColor3d(1,1,0); glBegin(GL_LINES); for (int i=0; i<(int)Facets.size(); i++) { Vec3D c = (Vertices[Facets[i].vi[0]].v + Vertices[Facets[i].vi[1]].v + Vertices[Facets[i].vi[2]].v)/3; Vec3D c2 = c - Facets[i].n*3; glVertex3d(c.x, c.y, c.z); glVertex3d(c2.x, c2.y, c2.z); } glEnd(); } /* //draw bounding box? if (DrawBoundingBox){ //todo: manage bounding box recalculation automatically glColor3d(BoundBoxColor.r,BoundBoxColor.g,BoundBoxColor.b); glBegin(GL_LINE_LOOP); //bottom square glVertex3d(_CurBBMin.x, _CurBBMin.y, _CurBBMin.z); glVertex3d(_CurBBMin.x, _CurBBMax.y, _CurBBMin.z); glVertex3d(_CurBBMax.x, _CurBBMax.y, _CurBBMin.z); glVertex3d(_CurBBMax.x, _CurBBMin.y, _CurBBMin.z); glVertex3d(_CurBBMin.x, _CurBBMin.y, _CurBBMin.z); glVertex3d(_CurBBMin.x, _CurBBMin.y, _CurBBMax.z); //up to top square glVertex3d(_CurBBMin.x, _CurBBMax.y, _CurBBMax.z); glVertex3d(_CurBBMax.x, _CurBBMax.y, _CurBBMax.z); glVertex3d(_CurBBMax.x, _CurBBMin.y, _CurBBMax.z); glVertex3d(_CurBBMin.x, _CurBBMin.y, _CurBBMax.z); glEnd(); glBegin(GL_LINES); glVertex3d(_CurBBMin.x, _CurBBMax.y, _CurBBMin.z); glVertex3d(_CurBBMin.x, _CurBBMax.y, _CurBBMax.z); glVertex3d(_CurBBMax.x, _CurBBMax.y, _CurBBMin.z); glVertex3d(_CurBBMax.x, _CurBBMax.y, _CurBBMax.z); glVertex3d(_CurBBMax.x, _CurBBMin.y, _CurBBMin.z); glVertex3d(_CurBBMax.x, _CurBBMin.y, _CurBBMax.z); glEnd(); } */ // delete [] TexNames; if (!IgnoreNames) for (int i=0; i=0; k--){ //DO THIS BACKWARDS!!!! (more likely to have just added one next to us...) if (abs(Points[j].x - Vertices[k].v.x) < WeldThresh && abs(Points[j].y - Vertices[k].v.y) < WeldThresh && abs(Points[j].z - Vertices[k].v.z) < WeldThresh){ //if points are identical... FoundIndex[j] = k; break; //kicks out of for loop, because we've found! } } } if (FoundIndex[j] == -1){ //if we didn't find one... CVertex ThisPoint; ThisPoint.v.x = Points[j].x; ThisPoint.v.y = Points[j].y; ThisPoint.v.z = Points[j].z; ThisPoint.VColor = Colors[j]; Vertices.push_back(ThisPoint); FoundIndex[j] = (int)Vertices.size() - 1; //-1 because zero-index based. //TODO fail gracefully if we run out of memory so that vector can't allocate. } } // CFacet ThisFacet; // for (int m=0; m<3; m++) ThisFacet.vi[m] = FoundIndex[m]; Facets.push_back(CFacet(FoundIndex[0], FoundIndex[1], FoundIndex[2])); //TODO... select whether to create new object or add to existing... NeedBBCalc = true; MeshChanged(); return &Facets.back(); } CFacet* CMesh::AddFacet(const Vec3D& v1, const Vec3D& v2, const Vec3D& v3, const TexMap& MapIn) //adds a facet... with color info { CFacet* pFacet = AddFacet(v1, v2, v3, true); pFacet->HasTexture = true; pFacet->Map = MapIn; return pFacet; } CFacet* CMesh::AddFacet(const CVertex& v1, const CVertex& v2, const CVertex& v3) { Vertices.push_back(v1); Vertices.push_back(v2); Vertices.push_back(v3); Facets.push_back(CFacet((int)Vertices.size() - 3, (int)Vertices.size() - 2, (int)Vertices.size() - 1)); //TODO... select whether to create new object or add to existing... NeedBBCalc = true; MeshChanged(); return &Facets.back(); } CFacet* CMesh::AddFacet(const CVertex& v1, const CVertex& v2, const CVertex& v3, const TexMap& MapIn) //adds a facet... with texture map { CFacet* pFacet = AddFacet(v1, v2, v3); pFacet->HasTexture = true; pFacet->Map = MapIn; return pFacet; } ////--------------------------------------------------------------------------- //void CMesh::ComputeBoundingBox(Vec3D &pmin, Vec3D &pmax) ////--------------------------------------------------------------------------- //{ // UpdateBoundingBox(); // pmin = _CurBBMin; // pmax = _CurBBMax; // //} //--------------------------------------------------------------------------- void CMesh::UpdateBoundingBox(void) //--------------------------------------------------------------------------- { if (Vertices.size() == 0){ _CurBBMin = _CurBBMax = Vec3D(0,0,0); return; } _CurBBMin = _CurBBMax = Vertices[0].v; for (int i=0; i<(int)Vertices.size(); i++) { _CurBBMin.x = _CurBBMin.x < Vertices[i].v.x ? _CurBBMin.x : Vertices[i].v.x; _CurBBMin.y = _CurBBMin.y < Vertices[i].v.y ? _CurBBMin.y : Vertices[i].v.y; _CurBBMin.z = _CurBBMin.z < Vertices[i].v.z ? _CurBBMin.z : Vertices[i].v.z; _CurBBMax.x = _CurBBMax.x > Vertices[i].v.x ? _CurBBMax.x : Vertices[i].v.x; _CurBBMax.y = _CurBBMax.y > Vertices[i].v.y ? _CurBBMax.y : Vertices[i].v.y; _CurBBMax.z = _CurBBMax.z > Vertices[i].v.z ? _CurBBMax.z : Vertices[i].v.z; } } //--------------------------------------------------------------------------- void CMesh::Translate(Vec3D d) //--------------------------------------------------------------------------- {// translate geometry for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v += d; } NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::Scale(Vec3D s) //--------------------------------------------------------------------------- {// scale geometry //check for zero scale factor if(s.x==0 || s.y==0 || s.z==0) return; for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v.x *= s.x; Vertices[i].v.y *= s.y; Vertices[i].v.z *= s.z; // Vertices[i].n.x *= s.x; //do we really want to scale these? // Vertices[i].n.y *= s.y; // Vertices[i].n.z *= s.z; /// Facets[i].n.Normalize(); } NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::Rotate(Vec3D ax, double a) //--------------------------------------------------------------------------- { Rotate(CQuat(a, ax)); //for (int i=0; i<(int)Vertices.size(); i++) { // Vertices[i].v = Vertices[i].v.Rot(ax, a); // Vertices[i].n = Vertices[i].n.Rot(ax, a); // Vertices[i].DrawOffset = Vertices[i].DrawOffset.Rot(ax, a); // //} //for (int i=0; i<(int)Facets.size(); i++) { // Facets[i].n = Facets[i].n.Rot(ax, a); //} //UpdateBoundingBox(); //MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::Rotate(CQuat QRot) //--------------------------------------------------------------------------- { for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v = Vertices[i].v.Rot(QRot); Vertices[i].n = Vertices[i].n.Rot(QRot); // Vertices[i].DrawOffset = Vertices[i].DrawOffset.Rot(QRot); } for (int i=0; i<(int)Facets.size(); i++) { Facets[i].n = Facets[i].n.Rot(QRot); } NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::RotX(double a) //--------------------------------------------------------------------------- { for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v.RotX(a); Vertices[i].n.RotX(a); } for (int i=0; i<(int)Facets.size(); i++) { Facets[i].n.RotX(a); } NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::RotY(double a) //--------------------------------------------------------------------------- { for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v.RotY(a); Vertices[i].n.RotY(a); } for (int i=0; i<(int)Facets.size(); i++) { Facets[i].n.RotY(a); } NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::RotZ(double a) //--------------------------------------------------------------------------- { for (int i=0; i<(int)Vertices.size(); i++) { Vertices[i].v.RotZ(a); Vertices[i].n.RotZ(a); } for (int i=0; i<(int)Facets.size(); i++) { Facets[i].n.RotZ(a); } NeedBBCalc = true; MeshChanged(); } void CMesh::WeldClose(float Distance) { int* NumVertHere = new int[Vertices.size()]; //keeps track of how many vertices have been averaged to get here... int* ConsolidateMap = new int[Vertices.size()]; //maps the whole vertex list to the welded vertex list (IE has holes) int* OldNewMap = new int [Vertices.size()]; //maps the old, larger vertex list to the new, smaller one. for (int i=0; i<(int)Vertices.size(); i++){ NumVertHere[i] = 1; ConsolidateMap[i] = i; OldNewMap[i] = -1; } for (int i=0; i<(int)Facets.size(); i++){ //look through facets so we don't have to do exhaustive On2 search of all vertex combos for (int j=0; j<3; j++){ //look at all three combinations of vertices... int Vi1 = Facets[i].vi[j]; int np = -1; while (np != Vi1){ np = Vi1; Vi1 = ConsolidateMap[Vi1]; } //iterates NewMap to get the final value... int Vi2 = Facets[i].vi[(j+1)%3]; np = -1; while (np != Vi2){ np = Vi2; Vi2 = ConsolidateMap[Vi2]; } //iterates NewMap to get the final value... if (Vi1 != Vi2 && (Vertices[Vi1].v-Vertices[Vi2].v).Length() < Distance){ //if they are close enough but not already the same... Vertices[Vi1].v = (Vertices[Vi1].v*NumVertHere[Vi1] + Vertices[Vi2].v*NumVertHere[Vi2]) / (NumVertHere[Vi1]+NumVertHere[Vi2]); //Vertex 1 is the weighted average NumVertHere[Vi1] = NumVertHere[Vi1] + NumVertHere[Vi2]; //count how many vertices make up this point now... ConsolidateMap[Vi2] = Vi1; //effectively deletes Vi2... (points to Vi1) } } } std::vector NewFacets; std::vector NewVertices; for (int i=0; i<(int)Vertices.size(); i++){ if (ConsolidateMap[i] == i) { //if this vertex ended up being part of the welded part NewVertices.push_back(Vertices[i]); //add to the new vertex list OldNewMap[i] = NewVertices.size()-1; } } //update the vertex indices for (int i=0; i<(int)Facets.size(); i++){ //look through facets so we don't have to do exhaustive On2 search of all vertex combos for (int j=0; j<3; j++){ //look at all three combinations of vertices... int n = Facets[i].vi[j]; int np = -1; while (np != n){ np = n; n = ConsolidateMap[n]; } //iterates NewMap to get the final value... Facets[i].vi[j] = OldNewMap[n]; } if (!(Facets[i].vi[0] == Facets[i].vi[1] || Facets[i].vi[0] == Facets[i].vi[2] || Facets[i].vi[2] == Facets[i].vi[1])) //if there aren't any the same... NewFacets.push_back(Facets[i]); } Facets = NewFacets; Vertices = NewVertices; delete [] NumVertHere; NumVertHere = NULL; delete [] ConsolidateMap; ConsolidateMap = NULL; delete [] OldNewMap; OldNewMap = NULL; CalcVertNormals(); //re-calculate normals! MeshChanged(); } void CMesh::RemoveDupLines(void) { //first order lines so lower index is first: int tmpHold; for (int i=0; i<(int)Lines.size(); i++){ if(Lines[i].vi[0] > Lines[i].vi[1]){ tmpHold = Lines[i].vi[0]; Lines[i].vi[0] = Lines[i].vi[1]; Lines[i].vi[1] = tmpHold; } } //now sort them... std::sort(Lines.begin(), Lines.end()); //iterate up, checking for duplicates and removing... for (int i=1; i<(int)Lines.size(); i++){ //size changes, but that's ok! if (Lines[i] == Lines[i-1]){ Lines.erase(Lines.begin()+i); i--; } } } void CMesh::SubdivideMe(void) { std::vector NewFacets; std::vector NewVertices; std::vector NewLines; for (std::vector::iterator it = Facets.begin(); it != Facets.end(); it++){ CVertex tmpOldVerts[3]; CLine tmpOldLines[3]; //check lines for(int i=0; i<3; i++){ tmpOldVerts[i] = Vertices[it->vi[i]]; if (it->HasEdge[i]) tmpOldLines[i] = Lines[it->ei[i]]; //else default empty line and no tangents } // normalize edge tangets if specified for (int i=0; i<3; i++) { //each edge Vec3D ThisEdge = (tmpOldVerts[(i+1)%3].v-tmpOldVerts[i].v); for (int j=0; j<2; j++){ //each tangent if (tmpOldLines[i].vt[j] == Vec3D(0,0,0)) tmpOldLines[i].HasTangent[j] = false; if (tmpOldLines[i].HasTangent[j]){ tmpOldLines[i].vt[j].Normalize(); // *(p[(i+1)%3]-p[i]).Length(); <<<<<< Normalize by length????? if (tmpOldLines[i].vt[j].Dot(ThisEdge) < 0) tmpOldLines[i].vt[j] = -tmpOldLines[i].vt[j]; //make them all ccw as view from outside of triangle } } } // for each vertex... // if both edge tangents specified: overwrite normal // if one edge tangent and normal: bring normal into perpendicular with the one edge, then calculate other edge // if one edge tangent and no normal: Other edge tangent is the edge. Set it as such and calculate normall accordingly // if no edge tangent and normal: Calculate edge tangents from normal and edge directions // if no edge tangents, no normal: set tangents to edges and normal accordingly //for each vertex //if normal //if 1et: bring normal perp, calc other et //else if 0et: calc both from normal //set any nonexistant et's to its edge //calc normal from et's for (int i=0; i<3; i++){ //for each vertex CLine* pL0 = &tmpOldLines[i]; //line 0 (dealing w tangent 0) CLine* pL1 = &tmpOldLines[(i-1+3)%3]; //line 1 (dealing w tangent 1) CVertex* pV = &tmpOldVerts[i]; Vec3D EdgeAhead = (tmpOldVerts[(i+1)%3].v-pV->v); Vec3D EdgeBehind = (pV->v-tmpOldVerts[(i-1+3)%3].v); //POINTING OUT FROM TRIANGLE as vertex tangent would if (pV->HasNormal){ if (pL0->HasTangent[0] && !pL1->HasTangent[1]){ //first has tangent, second doesn't Vec3D Perp = pV->n.Cross(pL0->vt[0]); Vec3D NewNorm = pL0->vt[0].Cross(Perp); Perp = NewNorm.Cross(EdgeBehind); pL1->vt[1] = Perp.Cross(NewNorm).Normalized(); pL1->HasTangent[1] = true; } else if (!pL0->HasTangent[0] && pL1->HasTangent[1]){ //second has tangent, first doesn't Vec3D Perp = pV->n.Cross(pL1->vt[1]); Vec3D NewNorm = pL1->vt[1].Cross(Perp); Perp = EdgeAhead.Cross(NewNorm); pL0->vt[0] = NewNorm.Cross(Perp).Normalized(); pL0->HasTangent[0] = true; } else if (!pL0->HasTangent[0] && !pL1->HasTangent[1]){ //neither has tangent Vec3D Perp = EdgeAhead.Cross(pV->n); //Edge ahead... pL0->vt[0] = pV->n.Cross(Perp).Normalized(); Perp = pV->n.Cross(EdgeBehind); //Edge ahead... pL1->vt[1] = Perp.Cross(pV->n).Normalized(); pL0->HasTangent[0] = true; pL1->HasTangent[1] = true; } //else (both have tangents) we will recalculate the normal according to the tangents later } else { //no Normal info, set nonexistant edge tangents to the straight edges. (todo: optimize by doing quick interpolation later) if (!pL0->HasTangent[0]){ pL0->vt[0] = EdgeAhead.Normalized(); //unnecessary normalization) pL0->HasTangent[0] = true; } if (!pL1->HasTangent[1]){ pL1->vt[1] = EdgeBehind.Normalized(); pL1->HasTangent[1] = true; } } //All edge tangetns are normalized to 1 at this point. multply each by edge length to make hermite work pL0->vt[0] *= EdgeAhead.Length(); pL1->vt[1] *= EdgeBehind.Length(); //calc normal! pV->n = pL1->vt[1].Cross(pL0->vt[0]).Normalized(); pV->HasNormal = true; } //CLine tmpLines[9]; //CFacet tmpFacets[4]; Vec3D NewV[3], NewN[3], NewT[3]; //edge 1! HermiteInterpolation(tmpOldVerts[0].v, tmpOldVerts[0].n, tmpOldLines[0].vt[0], tmpOldVerts[1].v, tmpOldVerts[1].n, tmpOldLines[0].vt[1], 0.5, NewV[0], NewN[0], NewT[0]); HermiteInterpolation(tmpOldVerts[1].v, tmpOldVerts[1].n, tmpOldLines[1].vt[0], tmpOldVerts[2].v, tmpOldVerts[2].n, tmpOldLines[1].vt[1], 0.5, NewV[1], NewN[1], NewT[1]); HermiteInterpolation(tmpOldVerts[2].v, tmpOldVerts[2].n, tmpOldLines[2].vt[0], tmpOldVerts[0].v, tmpOldVerts[0].n, tmpOldLines[2].vt[1], 0.5, NewV[2], NewN[2], NewT[2]); int NumPrevVerts = NewVertices.size(); int NumPrevLines = NewLines.size(); CVertex tmpVerts[6]; //stored ccw as viewed from outside tmpVerts[0] = tmpOldVerts[0]; tmpVerts[1] = CVertex(NewN[0], NewV[0]); tmpVerts[1].HasColor = tmpOldVerts[0].HasColor; //todo: average eventually! tmpVerts[1].VColor = tmpOldVerts[0].VColor; tmpVerts[2] = tmpOldVerts[1]; tmpVerts[3] = CVertex(NewN[1], NewV[1]); tmpVerts[3].HasColor = tmpOldVerts[1].HasColor; //todo: average eventually! tmpVerts[3].VColor = tmpOldVerts[1].VColor; tmpVerts[4] = tmpOldVerts[2]; tmpVerts[5] = CVertex(NewN[2], NewV[2]); tmpVerts[5].HasColor = tmpOldVerts[2].HasColor; //todo: average eventually! tmpVerts[5].VColor = tmpOldVerts[2].VColor; for (int i=0; i<6; i++) NewVertices.push_back(tmpVerts[i]); //stored as ccw as viewed from outside... NewLines.push_back(CLine(NumPrevVerts, NumPrevVerts+1, tmpOldLines[0].vt[0], NewT[0])); NewLines.push_back(CLine(NumPrevVerts+1, NumPrevVerts+2, NewT[0], tmpOldLines[0].vt[1])); NewLines.push_back(CLine(NumPrevVerts+2, NumPrevVerts+3, tmpOldLines[1].vt[0], NewT[1])); NewLines.push_back(CLine(NumPrevVerts+3, NumPrevVerts+4, NewT[1], tmpOldLines[1].vt[1])); NewLines.push_back(CLine(NumPrevVerts+4, NumPrevVerts+5, tmpOldLines[2].vt[0], NewT[2])); NewLines.push_back(CLine(NumPrevVerts+5, NumPrevVerts, NewT[2], tmpOldLines[2].vt[1])); NewLines.push_back(CLine(NumPrevVerts+1, NumPrevVerts+3)); NewLines.push_back(CLine(NumPrevVerts+3, NumPrevVerts+5)); NewLines.push_back(CLine(NumPrevVerts+5, NumPrevVerts+1)); CFacet tmpFacets[4]; //0, 1, 2, middle Vec3D FacetNorms[4]; Vec3D tmp; tmp = tmpVerts[5].v-tmpVerts[0].v; FacetNorms[0] = (tmpVerts[1].v-tmpVerts[0].v).Cross(tmp).Normalized(); tmp = tmpVerts[3].v-tmpVerts[1].v; FacetNorms[1] = (tmpVerts[2].v-tmpVerts[1].v).Cross(tmp).Normalized(); tmp = tmpVerts[4].v-tmpVerts[5].v; FacetNorms[2] = (tmpVerts[3].v-tmpVerts[5].v).Cross(tmp).Normalized(); tmp = tmpVerts[3].v-tmpVerts[5].v; FacetNorms[3] = (tmpVerts[1].v-tmpVerts[5].v).Cross(tmp).Normalized(); tmpFacets[0] = CFacet(FacetNorms[0], NumPrevVerts+0, NumPrevVerts+1, NumPrevVerts+5); tmpFacets[0].ei[0] = NumPrevLines; tmpFacets[0].HasEdge[0] = true; tmpFacets[0].ei[2] = NumPrevLines+5; tmpFacets[0].HasEdge[2] = true; tmpFacets[1] = CFacet(FacetNorms[1], NumPrevVerts+1, NumPrevVerts+2, NumPrevVerts+3); tmpFacets[1].ei[0] = NumPrevLines+1; tmpFacets[1].HasEdge[0] = true; tmpFacets[1].ei[1] = NumPrevLines+2; tmpFacets[1].HasEdge[1] = true; tmpFacets[2] = CFacet(FacetNorms[2], NumPrevVerts+5, NumPrevVerts+3, NumPrevVerts+4); tmpFacets[2].ei[1] = NumPrevLines+3; tmpFacets[2].HasEdge[1] = true; tmpFacets[2].ei[2] = NumPrevLines+4; tmpFacets[2].HasEdge[2] = true; tmpFacets[3] = CFacet(FacetNorms[3], NumPrevVerts+5, NumPrevVerts+1, NumPrevVerts+3); NewFacets.push_back(tmpFacets[0]); NewFacets.push_back(tmpFacets[1]); NewFacets.push_back(tmpFacets[2]); NewFacets.push_back(tmpFacets[3]); } //commit changes!! Facets = NewFacets; Vertices = NewVertices; Lines = NewLines; NeedBBCalc = true; MeshChanged(); } //--------------------------------------------------------------------------- void CMesh::HermiteInterpolation(Vec3D v0, Vec3D n0, Vec3D t0, Vec3D v1, Vec3D n1, Vec3D t1, double s, Vec3D& vs, Vec3D& ns, Vec3D& ts) //--------------------------------------------------------------------------- {// interpolate between two vertices at pointion s (0-1), given position, tangent, and normal double s2 = s*s; double s3 = s2*s; // compute new point double h1 = 2*s3 - 3*s2 + 1; double h2 = -2*s3 + 3*s2; double h3 = s3 - 2*s2 + s; double h4 = s3 - s2; vs = h1*v0 + h2*v1 + h3*t0 + h4*t1; // compute tangent double dh1 = 3*2*s2 - 2*3*s; double dh2 = -3*2*s2 + 2*3*s; double dh3 = 3*s2 - 2*2*s + 1; double dh4 = 3*s2 - 2*s; ts = (dh1*v0 + dh2*v1 + dh3*t0 + dh4*t1).Normalized(); Vec3D nstemp = (n0*(1-s)+n1*s).Normalized(); Vec3D sd = nstemp.Cross(ts); ns = (ts.Cross(sd)).Normalized(); // ns = nstemp; } ////////////////////CTEXTURE///////////////// void CTexture::LoadData(int WidthIn, int HeightIn, unsigned char* RGBAdata, bool TiledIn) { Width = WidthIn; Height = HeightIn; Tiled = TiledIn; RGBAImage.clear(); for (int j=HeightIn-1; j>=0; j--){ //AMF starts pixel data from the upper left. Open GL expects lower left. for (int i=0; i=0; j--){ //AMF starts pixel data from the upper left. Open GL expects lower left. for (int i=0; i AData(WidthIn*HeightIn, 255); //make alpha data... all opaque. LoadData(WidthIn, HeightIn, Rdata, Gdata, Bdata, AData.data(), TiledIn); } // //void CTexture::ResizeToMult2(void) //resizes the internal image to a multiple of 2, stores the factors. //{ // //TODO:: the right thing to do here would be to actually resize the image!! not just pad it... need resizing library/algorithm though. // // //find closest multiple of 2 equal or greater to image size // ActWidth = 4; // while (ActWidth NewImg = std::vector(4*ActWidth*ActHeight, 0); //create and initialize with zeros // for (int j=0; j for license details. *******************************************************************************/ #include "MeshSlice.h" #include #include "SimpleImage.h" //#include "nMaterial.h" //TODO: Get rid of this AMF dependence!!! //#include "AMF_Render.h" //GET rid of this, too... #include "AMF_File.h" //...and this... CMeshSlice::CMeshSlice(void) { pMaterial = NULL; // pObjExt = NULL; Initialized = false; pGetColor = NULL; } CMeshSlice::~CMeshSlice(void) { } void CMeshSlice::MeshChanged(void) //invalidates all cached voxelizing info! { if (Initialized){ Initialized = false; _TriLayerZ = -1; _TriLayerPZ = -1; CurTriLayer.clear(); YEnvMaxIterator = CurTriLayer.begin(); _TriLineY = -1; _TriLinePY = -1; CurTriLine.clear(); XEnvMaxIterator = CurTriLine.begin(); Envelopes.clear(); ZEnvMaxIterator = Envelopes.begin(); //but no elements... basically just voids it! _ZActual = -1; _YActual = -1; _XActual = -1; CurTriPoints.clear(); XPtIter = CurTriPoints.begin(); _TriPointPX = -1; _IsCurInside = false; CurTriPoint.clear(); } } double CMeshSlice::GetClosestFreeZ(double ZIn) //returns the next Z value that does not intersect any vertices { double CurZ = ZIn; // double MultFact = 1.0; for (std::vector::iterator it = Vertices.begin(); it != Vertices.end(); it++){ if (it->v.z == CurZ){ CurZ += 2*CurZ*DBL_EPSILON; //MultFact *= 2.0; it = Vertices.begin(); //-1 is because it will increment before next time around, and we want to start over from 0 } } return CurZ; } //double CMeshSlice::GetClosestFreeY(double YIn) //returns the next Y value that does not intersect any vertices IN CurTriLayer! //{ // double CurY = YIn; // for (std::vector::iterator it = Facets.begin(); it != Facets.end(); it++){ // if (Vertices[it->vi[0]].v.y == CurY || Vertices[it->vi[1]].v.y == CurY || Vertices[it->vi[2]].v.y == CurY){ // CurY += DBL_EPSILON; // it = Facets.begin()-1; //-1 is because it will increment before next time around, and we want to start over from 0 // } // } // return CurY; //} void CMeshSlice::FillTriLayer(double z, double ZPad) //fills in TriHeight with all triangles that bridge this plane { if (ZPad < 0) ZPad = -ZPad; // only positive! if(z == _TriLayerZ && ZPad == _TriLayerPZ) return; //if we've already done this... double LastMaxZ = _ZActual + _TriLayerPZ; double LastMinZ = _ZActual - _TriLayerPZ; _ZActual = GetClosestFreeZ(z); double CurMaxZ = _ZActual+ZPad; double CurMinZ = _ZActual-ZPad; _TriLayerZ = z; //cache these calls _TriLayerPZ = ZPad; //optimized for sequential ascending Z steps, but works otherwise... if (CurMaxZ < LastMaxZ || CurMinZ < LastMinZ){ //if we've gone backwards (downwards) we have to start over from the beginning! CurTriLayer.clear(); //start over... ZEnvMaxIterator = Envelopes.begin(); } //Add in triangles with minimum Z envelopes less than the CurMaxZ while (ZEnvMaxIterator != Envelopes.end() && ZEnvMaxIterator->MinZ <= CurMaxZ){ //add in all newly within range, just from where we left the iterator... if(ZEnvMaxIterator->MaxZ >= CurMinZ) CurTriLayer.push_back(*ZEnvMaxIterator); // only add if Max Z Envelope is less than CurMinZ before adding ZEnvMaxIterator++; } //remove elements elready in list with max Z envelope less than CurMinZ std::list::iterator it = CurTriLayer.begin(); while (it != CurTriLayer.end()){ //get rid of all elements in the list with maximum values less than MinZ if (it->MaxZ::iterator FIter; //bool NoneEqual = false; // //while (!NoneEqual){ // NoneEqual = true; // CurTriLayer.clear(); //clear previous list // m=0; // for (FIter = Facets.begin(); FIter != Facets.end(); FIter++){ // IsAbove = true; IsBelow = true; // for (int n=0; n<3; n++){ // CurZ = Vertices[FIter->vi[n]].v.z; // // if(CurZ > z) IsBelow = false; // else if(CurZ < z) IsAbove = false; // else /* if(CurZ == z) */{ //START OVER with infintesimebly incremented Z value // z += FLT_EPSILON; // NoneEqual = false; // break; break; //start the whole process over // }; // } // if (!IsAbove && !IsBelow) CurTriLayer.push_back(m); //if this facet is not fully above or fully below our ZPlane // // m++; // } //} } bool CMeshSlice::FillTriLine(double y, double z, double YPad, double ZPad) //fills in TriHeight with all triangles that bridge this plane { if (YPad < 0) YPad = -YPad; // only positive! if(y == _TriLineY && z == _TriLayerZ && YPad == _TriLinePY && ZPad == _TriLayerPZ) return true; //if we've already done this... FillTriLayer(z, ZPad); //exits immediately if z is the same as cached... if (CurTriLayer.size() == 0){CurTriLine.clear(); return true;} //if no triangles in this layer, no lines! easy! double LastMaxY = _YActual + _TriLinePY; double LastMinY = _YActual - _TriLinePY; _YActual = y; //start here. We will increment if we hit an edge dead on... _TriLineY = y; //cache these calls _TriLinePY = YPad; bool HitEdge = true; while(HitEdge){ HitEdge = false; double CurMaxY = _YActual+YPad; double CurMinY = _YActual-YPad; //optimized for sequential ascending Y steps, but works otherwise... if (CurMaxY < LastMaxY || CurMinY < LastMinY){ //if we've gone backwards (downwards) we have to start over from the beginning! CurTriLine.clear(); //start over... YEnvMaxIterator = CurTriLayer.begin(); } //Add in triangles with minimum Y envelopes less than the CurMaxY while (YEnvMaxIterator != CurTriLayer.end() && YEnvMaxIterator->MinY <= CurMaxY){ //add in all newly within range, just from where we left the iterator... if(YEnvMaxIterator->MaxY >= CurMinY) CurTriLine.push_back(*YEnvMaxIterator); // only add if Max Y Envelope is less than CurMinY before adding YEnvMaxIterator++; } //remove elements elready in list with max Y envelope less than CurMinY std::list::iterator it = CurTriLine.begin(); while (it != CurTriLine.end()){ //get rid of all elements in the list with maximum values less than MinY if (it->MaxY::iterator ZFIter; for (ZFIter = CurTriLayer.begin(); ZFIter != CurTriLayer.end(); ZFIter++){ V1y = Vertices[Facets[ZFIter->TriIndex].vi[0]].v.y; V2y = Vertices[Facets[ZFIter->TriIndex].vi[1]].v.y; V3y = Vertices[Facets[ZFIter->TriIndex].vi[2]].v.y; //trivial checks (should get most of them...) if (V1y < y && V2y < y && V3y < y) continue; if (V1y > y && V2y > y && V3y > y) continue; //IntersectLine( double tmp; // IntType = IntersectXRay(&Facets[*ZFIter], y, z, p, pu, pv); IntersectionType IntType2 = IntersectXRay(&Facets[ZFIter->TriIndex], y, z, tmp); // if (IntType != IntType2 || (IntType==IT_INSIDE && p.x != tmp)) // int UhOh=1; IntType = IntType2; p.x = tmp; if (IntType == IT_EDGE){ //if any equal, add a tiny amount to Y y += FLT_EPSILON; NoneEqual = false; break; break; } else if (IntType == IT_INSIDE){ // if(IntersectXRay(&Facets[*ZFIter], y, z, p, pu, pv)) { //if it intersects // if (InsideTri(p, Vertices[Facets[*ZFIter].vi[0]].v, Vertices[Facets[*ZFIter].vi[1]].v, Vertices[Facets[*ZFIter].vi[2]].v)){ CurTriLine.push_back(p.x); } // } } } if (CurTriLine.size()%2 ==1) return false; std::sort(CurTriLine.begin(), CurTriLine.end()); return true; */ } bool CMeshSlice::FillTriPoints(void) //fills points based on _YActual _ZActual, and the tris in TriLine. returns false increments _YActual (to re-do FillTriLine with) and try again. { IntersectionType IntType; double TmpXIntersect; CurTriPoints.clear(); for (std::list::iterator it = CurTriLine.begin(); it != CurTriLine.end(); it++){ if (_YActual <= it->MaxY && _YActual >= it->MinY && _ZActual <= it->MaxZ && _ZActual >= it->MinZ){ IntType = IntersectXRay(&Facets[it->TriIndex], _YActual, _ZActual, TmpXIntersect); if (IntType == IT_EDGE) return false; else if (IntType == IT_INSIDE) CurTriPoints.push_back(TmpXIntersect); } } std::sort(CurTriPoints.begin(), CurTriPoints.end()); XPtIter = CurTriPoints.begin(); //ready to iterate _IsCurInside = false; //not inside the part if we just reset this array!! return true; } //--------------------------------------------------------------------------- bool CMeshSlice::IsInside(Vec3D* Point, double TexDepth, CColor* pColor) //--------------------------------------------------------------------------- { if (TexDepth<0) TexDepth = -TexDepth; FillTriLine(Point->y, Point->z, TexDepth, TexDepth); //returns very fast if previously used z or y layers... ////// double LastMaxX = _XActual + _TriPointPX; double LastMinX = _XActual - _TriPointPX; _XActual = Point->x; _TriPointPX = TexDepth; double CurMaxX = _XActual + _TriPointPX; double CurMinX = _XActual - _TriPointPX; //optimized for sequential ascending X steps, but works otherwise... if (CurMaxX < LastMaxX || CurMinX < LastMinX){ //if we've gone backwards (downwards) we have to start over from the beginning! _IsCurInside = false; CurTriPoint.clear(); XPtIter = CurTriPoints.begin(); //reset the iterators XEnvMaxIterator = CurTriLine.begin(); } //Add in triangles with minimum X envelopes less than the CurMaxX while (XEnvMaxIterator != CurTriLine.end() && XEnvMaxIterator->MinX <= CurMaxX){ //add in all newly within range, just from where we left the iterator... if(XEnvMaxIterator->MaxX >= CurMinX) CurTriPoint.push_back(*XEnvMaxIterator); // only add if Max Z Envelope is less than CurMinZ before adding XEnvMaxIterator++; } //remove elements elready in list with max X envelope less than CurMinZ std::list::iterator it = CurTriPoint.begin(); while (it != CurTriPoint.end()){ //get rid of all elements in the list with maximum values less than MinZ if (it->MaxX::iterator it = CurTriPoint.begin(); it != CurTriPoint.end(); it++){ //iterate through all the triangle within scope CFacet* pCurFacet = &Facets[it->TriIndex]; GetTriDist(pCurFacet, Point, u, v, dist2); if (dist2HasTexture){ if (pCurFacet->Map.TexIndex < (int)Textures.size()) pCurTexture = &Textures[pCurFacet->Map.TexIndex]; //u coord is from vertex 1 to vertex 2, v coord is v1 to v3 PicU = pCurFacet->Map.uc[0] + u*(pCurFacet->Map.uc[1]-pCurFacet->Map.uc[0]) + v*(pCurFacet->Map.uc[2]-pCurFacet->Map.uc[0]); PicV = pCurFacet->Map.vc[0] + u*(pCurFacet->Map.vc[1]-pCurFacet->Map.vc[0]) + v*(pCurFacet->Map.vc[2]-pCurFacet->Map.vc[0]); if (PicU == 1.0) PicU = 1.0-DBL_MIN; //stay off the upper edge without grabbing a pix from 0.0... if (PicV == 1.0) PicV = 1.0-DBL_MIN; //stay off the upper edge... if (pCurTexture && pCurTexture->Tiled){ //if we're tiling the textures do the mod... UseTexColors = true; PicU = fmod(PicU, 1.0); if (PicU < 0) PicU += 1.0; //becuase fmod of a negative number is negative remainder PicV = fmod(PicV, 1.0); if (PicV < 0) PicV += 1.0; //becuase fmod of a negative number is negative remainder } else { //not tiling texture, only do texture if we're within [0, 1] if (PicU >= 0 && PicU < 1 && PicV >= 0 && PicV < 1) UseTexColors = true; } } if (UseTexColors && pCurTexture){ int XPix = (int)(PicU*pCurTexture->Width); //int YPix = Texture.Height - (int)(PicV*Texture.Height)-1; int YPix = (int)(PicV*pCurTexture->Height); unsigned char* pPix = &(pCurTexture->RGBAImage[4*(YPix*pCurTexture->Width + XPix)]); *pColor = CColor(*pPix/255.0, *(pPix+1)/255.0, *(pPix+2)/255.0, *(pPix+3)/255.0); } else { //no texture, so linearly interpolate the vertices! CColor V0 = Vertices[pCurFacet->vi[0]].VColor; CColor V1 = Vertices[pCurFacet->vi[1]].VColor; CColor V2 = Vertices[pCurFacet->vi[2]].VColor; double R = V0.r + u*(V1.r-V0.r) + v*(V2.r-V0.r); double G = V0.g + u*(V1.g-V0.g) + v*(V2.g-V0.g); double B = V0.b + u*(V1.b-V0.b) + v*(V2.b-V0.b); *pColor = CColor(R, G, B, 1.0); } } } } } return true; } else return false; ////// //std::vector::iterator LIter; //int count = 0; //for (LIter = CurTriLine.begin(); LIter != CurTriLine.end(); LIter++){ // if (Point->x < *LIter) break; // count ++; //} //if (count%2 == 1) return true; //if we've passed an odd number of facets... //else return false; } /* //--------------------------------------------------------------------------- int CMeshSlice::GetXIntersections(double z, double y, double* pIntersections, int NumtoCheck, int* pToCheck) //--------------------------------------------------------------------------- { //returns the number of intersections, stored in pIntersections. pToCheck is a vector of facet indices that are in this Z plane... Vec3D p; double pu, pv, V1y, V2y, V3y; int NumFound = 0; for (int i=0; i y && V2y > y && V3y > y) continue; if(IntersectXRay(&Facets[pToCheck[i]], y, z, p, pu, pv)) { //if it intersects if (InsideTri(p, Vertices[Facets[pToCheck[i]].vi[0]].v, Vertices[Facets[pToCheck[i]].vi[1]].v, Vertices[Facets[pToCheck[i]].vi[2]].v)){ pIntersections[NumFound++] = p.x; //(1.0 - pu - pv)*Vertices[Facets[pToCheck[i]].vi[0]].v.x + pu*Vertices[Facets[pToCheck[i]].vi[1]].v.x + pv*Vertices[Facets[pToCheck[i]].vi[2]].v.x; } } } // if (NumFound%2 != 0) std::cout << "Uh-oh! Found an odd number of intersections!"; //sort intersections... (bubble sort = slow, but these should be super small... double tmp; for (int i=0; i pIntersections[j+1]){ tmp = pIntersections[j+1]; pIntersections[j+1] = pIntersections[j]; pIntersections[j] = tmp; } } } return NumFound; } //--------------------------------------------------------------------------- bool CMeshSlice::InsideTri(Vec3D& p, Vec3D& v0, Vec3D& v1, Vec3D& v2) //--------------------------------------------------------------------------- {// True if point p projects to within triangle (v0;v1;v2) Vec3D xax = (v1-v0).Normalized(); Vec3D zax = ((v2-v0).Cross(xax)).Normalized(); Vec3D yax = zax.Cross(xax).Normalized(); Vec3D p0(0,0,1); Vec3D p1((v1-v0).Dot(xax),(v1-v0).Dot(yax),1); Vec3D p2((v2-v0).Dot(xax),(v2-v0).Dot(yax),1); Vec3D pt((p-v0).Dot(xax),(p-v0).Dot(yax),1); double d0 = Det(p0,p1,pt); double d1 = Det(p1,p2,pt); double d2 = Det(p2,p0,pt); if (d0<=0 && d1<=0 && d2<=0) return true; if (d0>=0 && d1>=0 && d2>=0) return true; return false; } //--------------------------------------------------------------------------- double CMeshSlice::Det(Vec3D& v0, Vec3D& v1, Vec3D& v2) //--------------------------------------------------------------------------- { // Compute determinant of 3x3 matrix v0,v1,v2 return v0.x*(v1.y*v2.z-v1.z*v2.y) + v0.y*(v1.z*v2.x-v1.x*v2.z) + v0.z*(v1.x*v2.y-v1.y*v2.x); } */ IntersectionType CMeshSlice::IntersectXRay(CFacet* pFacet, double y, double z, double& XIntersect) { //http://www.blackpawn.com/texts/pointinpoly/default.html Vec3D vA = Vertices[pFacet->vi[0]].v; Vec3D vB = Vertices[pFacet->vi[1]].v; Vec3D vC = Vertices[pFacet->vi[2]].v; double v0y = vC.y-vA.y; //u double v0z = vC.z-vA.z; double v1y = vB.y-vA.y; //v double v1z = vB.z-vA.z; double v2y = y-vA.y; double v2z = z-vA.z; double dot00=v0y*v0y+v0z*v0z; double dot01=v0y*v1y+v0z*v1z; double dot02=v0y*v2y+v0z*v2z; double dot11=v1y*v1y+v1z*v1z; double dot12=v1y*v2y+v1z*v2z; double invDenom = 1.0/(dot00*dot11-dot01*dot01); double u=(dot11*dot02-dot01*dot12)*invDenom; double v=(dot00*dot12-dot01*dot02)*invDenom; if ((u >= 0) && (v >= 0) && (u + v <= 1)){ if (u == 0 || v == 0 || u+v==1) return IT_EDGE; else { XIntersect = vA.x+u*(vC.x-vA.x)+v*(vB.x-vA.x); return IT_INSIDE; } } else return IT_OUTSIDE; } bool CMeshSlice::GetTriDist(CFacet* pFacetCheck, Vec3D* pPointIn, double& UOut, double& VOut, double& Dist2Out) //gets distance of provided point to closest UV coordinate of within the triangle. returns true if sensible distance, otherwise false { //http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf //Regions: // E1 (t) // \ 2| // \| // |\ // | \ 1 // 3 | \ // | 0 \ // ___|________\____ E0 (s) // | \ 6 // 4 | 5 \ Vec3D B = Vertices[pFacetCheck->vi[0]].v; Vec3D E0 = Vertices[pFacetCheck->vi[1]].v - B; //(s) Vec3D E1 = Vertices[pFacetCheck->vi[2]].v - B; //(t) Vec3D D = B - *pPointIn; double a = E0.Dot(E0); double b = E0.Dot(E1); double c = E1.Dot(E1); double d = E0.Dot(D); double e = E1.Dot(D); double f = D.Dot(D); double det=a*c-b*b; double s = b*e-c*d; double t = b*d-a*e; //determine which region... //Q(s,t) = as^2+2bst+ct^2+2ds+2et+f if (s+t <= det){ if (s<0){ if (t<0){ //Region 4 //TODO: CHECK ACCURATE! // Grad(Q) = 2(as+bt+d,bs+ct+e) :: (derivative w respect to s, t) // (0,1)*Grad(Q(0,0)) = (0,1)*(d,e) = e :: is grad from tip of region 2 in directon of leg toward origin (0,1)... // (1,0)*Grad(Q(0,0)) = (1,0)*(d,e) = d // min on edge t=0 if (0,1)*Grad(Q(0,0)) < 0 ) // min on edge s=0 otherwise if (e<0){ // minimum on edge t=0 t=0; t=(d >=0 ? 0 :(-d >=a ? 1:-d/a)); } else { // minimum on edge s=0 s=0; t=(e >=0 ? 0 :(-e >=c ? 1:-e/c)); } } else { //Region 3 // F(t) = Q(0,t) = ct^2 + 2et + f // F(t)/2 = ct+e // F(T) = 0 when T = -e/c s=0; t=(e >=0 ? 0 :(-e >=c ? 1:-e/c)); } } else if (t<0){ //Region 5 (like region 3) // F(s) = Q(s,0) = as^2 + 2ds + f // F(s)/2 = as+d // F(S) = 0 when S = -d/a t=0; t=(d >=0 ? 0 :(-d >=a ? 1:-d/a)); } else { //Region 0 double invdet = 1/det; s *= invdet; t *= invdet; } } else { if (s<0){ //Region 2 // Grad(Q) = 2(as+bt+d,bs+ct+e) :: (derivative w respect to s, t) // (0,-1)*Grad(Q(0,1)) = (0,-1)*(b+d,c+e) = -(c+e) :: is grad from tip of region 2 in directon of leg toward origin (0,1)... // (1,-1)*Grad(Q(0,1)) = (1,-1)*(b+d,c+e) = (b+d)-(c+e) // min on edge s+t=1 if (1,-1)*Grad(Q(0,1)) < 0 ) // min on edge s=0 otherwise double tmp0 = b+d; double tmp1 = c+e; if ( tmp1 > tmp0 ){ // minimum on edge s+t=1 double numer = tmp1 - tmp0; double denom = a-2*b+c; s = ( numer >= denom ? 1 : numer/denom ); t = 1-s; } else { // minimum on edge s=0 s = 0; t = ( tmp1 <= 0 ? 1 : ( e >= 0 ? 0 : -e/c ) ); } } else if (t<0){ //Region 6 //TODO: CHECK ACCURATE! // Grad(Q) = 2(as+bt+d,bs+ct+e) :: (derivative w respect to s, t) // (-1,0)*Grad(Q(1,0)) = (-1,0)*(a+d,b+e) = -(a+d) :: is grad from tip of region 2 in directon of leg toward origin (0,1)... // (-1,1)*Grad(Q(1,0)) = (-1,1)*(a+d,b+e) = (b+e)-(a+d) // min on edge s+t=1 if (-1,1)*Grad(Q(0,1)) < 0 ) // min on edge t=0 otherwise double tmp0 = b+e; double tmp1 = a+d; if ( tmp1 > tmp0 ){ // minimum on edge s+t=1 double numer = tmp1 - tmp0; double denom = a-2*b+c; t = ( numer >= denom ? 1 : numer/denom ); s = 1-t; } else { // minimum on edge t=0 t = 0; s = ( tmp1 <= 0 ? 1 : ( d >= 0 ? 0 : -d/a ) ); } } else { //Region 1 // F(s) = Q(s,1-s) = (a-2b+c)s^2 + 2(b-c+d-e)s + (c+2e+f) // F(s)/2 = (a-2b+c)s + (b-c+d-e) // F(S) = 0 when S = (c+e-b-d)/(a-2b+c) // a-2b+c = |E0-E1|^2 > 0, so only sign of c+e-b-d need be considered double numer = c+e-b-d; if (numer <= 0) s=0; else { double denom = a-2*b+c; s = (numer >= denom ? 1 : numer/denom); } t=1-s; } } //check one or the other? should be same! Vec3D ClosestPoint = B+s*E0+t*E1; double D2 = (ClosestPoint-*pPointIn).Length2(); double D22 = a*s*s+2*b*s*t+c*t*t+2*d*s+2*e*t+f; UOut = s; VOut = t; Dist2Out = D22; return true; } /* //--------------------------------------------------------------------------- IntersectionType CMeshSlice::IntersectXRay(CFacet* pFacet, double y, double z, Vec3D& p, double& pu, double& pv) //--------------------------------------------------------------------------- { // compute intersection point P of triangle plane with ray from origin O in direction D // D assumed to be normalized // if no interstion, return false // u and v are barycentric coordinates of the intersection point P = (1 - u - v)A + uB + vC // see http://www.devmaster.net/wiki/Ray-triangle_intersection Vec3D d = Vec3D(1,0,0); Vec3D o = Vec3D(-1e9, y, z); Vec3D a = Vertices[pFacet->vi[0]].v; Vec3D b = Vertices[pFacet->vi[1]].v; Vec3D c = Vertices[pFacet->vi[2]].v; //Vec3D n = pFacet->n; //((b-a).Cross(c-a)).Normalized(); Vec3D n = ((b-a).Cross(c-a)).Normalized(); //if (n.x > 0){ //flip vertices... // Vec3D tmp = a; // a = b; // b = tmp; // n = ((b-a).Cross(c-a)).Normalized(); //} double dn = d.Dot(n); if (fabs(dn)<1E-5) return IT_OUTSIDE; //parallel double dist = -(o-a).Dot(n)/dn; Vec3D sD = d*dist; p = o+sD; double V1, V2, V3; V1 = (b-a).Cross(p-a).Dot(n); V2 = (c-b).Cross(p-b).Dot(n); V3 = (a-c).Cross(p-c).Dot(n); if (abs(V1)<1e-12 || abs(V2)<1e-12 || abs(V3)<1e-12) return IT_EDGE; //TODO:FISHY THRESHHOLD! if (V1 >=0 && V2 >=0 && V3 >=0) return IT_INSIDE; // if (V1 >=0 && V2 >=0 && V2 >=0) return true; <-Was this, but pretty obviously typo I think!!! //if (V1 <=0 && V2 <=0 && V2 <=0) return true; else return IT_OUTSIDE; } */ bool CMeshSlice::GetSlice(CSimpleImage* pImgOut, double ZHeight, double SurfDepth, double XMin, double XMax, double YMin, double YMax, int XPix, int YPix, int aObjectID, std::string* pMessage) { //initial checks... if (XMax == XMin || YMax == YMin || XPix <= 0 || YPix <= 0) return false; if (XMin > XMax){ double tmp = XMin; XMin = XMax; XMax = tmp;} //make sure Max is bigger then Min... if (YMin > YMax){ double tmp = YMin; YMin = YMax; YMax = tmp;} //make sure Max is bigger then Min... if (!Initialized) Initialize(); //prepare the image (should already exist...) //*pImgOut = QImage(XPix, YPix, QImage::Format_ARGB32); if (!pImgOut->AllocateRGBA(XPix, YPix)){ if (pMessage) *pMessage += "Insufficient memory to create bitmap. Please lower resolution.\n"; return false; } //*pImgOut = QImage(XPix, YPix, QImage::Format_Mono); //pImgOut->setColor(0, qRgb(255, 255, 255)); //for now, 1-bit image, index 0 is white //pImgOut->setColor(1, qRgb(0, 0, 0)); //index 1 is black //pImgOut->fill(0); CColor CurColor; //Min and Max sections are the very edge of the picture... but we must sample at the center of pixels! Vec3D CurPoint = Vec3D(0,0,ZHeight); double XStep = (XMax-XMin)/XPix; double YStep = (YMax-YMin)/YPix; double XBegin = XMin + XStep/2; //offset half pixel to sample at center of grid points double YBegin = YMin + YStep/2; //offset half pixel to sample at center of grid points double tR, tG, tB, tA; //do each pixel... //QRgb* pCurPixel; unsigned char* pCurPixel = pImgOut->GetRGBABits(); for (int j=0; jscanLine(j); for (int i=0; iFromCurrentUnits(1.0, UNIT_MM) // double UnitScale = pMaterial->pnAmf->GetUnitsScaleFromMm(); // if (pObjExt) TmpPt = /*UnitScale*pObjExt-> */OriginalLoc(TmpPt); TmpPt = OriginalLoc(TmpPt); pMaterial->GetColorAt(TmpPt.x, TmpPt.y, TmpPt.z, &tR, &tG, &tB, &tA); *pCurPixel = (unsigned char)(tR*255); *(pCurPixel+1) = (unsigned char)(tG*255); *(pCurPixel+2) = (unsigned char)(tB*255); *(pCurPixel+3) = (unsigned char)(tA*255); } else { //if no material defined, put opaque black *pCurPixel = *(pCurPixel+1) = *(pCurPixel+2) = 0; *(pCurPixel+3) = 255; } //using agnostic info... //if (pGetColor){ // pGetColor(CurPoint.x, CurPoint.y, CurPoint.z, &tR, &tG, &tB, &tA, aObjectID); // *pCurPixel = qRgba(tR*255, tG*255, tB*255, tA*255); //} //else *pCurPixel = qRgba(0, 0, 0, 255); } else { //if there was a surface texture here, use the color returned by IsInside() *pCurPixel = (unsigned char)(CurColor.r*255); *(pCurPixel+1) = (unsigned char)(CurColor.g*255); *(pCurPixel+2) = (unsigned char)(CurColor.b*255); *(pCurPixel+3) = (unsigned char)(CurColor.a*255); } } else { //if not inside, make it transparent! *pCurPixel = *(pCurPixel+1) = *(pCurPixel+2) = *(pCurPixel+3) = 0; } pCurPixel += 4; //go to next pixel } } return true; } void CMeshSlice::Initialize() { Initialized = true; int NumFacets = Facets.size(); Envelopes.reserve(NumFacets); for (int i=0; i for license details. *******************************************************************************/ #include "STL_File.h" #ifdef WIN32 #include #endif #include #include //#include //#include "QOpenGL.h" //Elements adapted from vcg code... double aWeldVertex::WeldThresh = 0; #define STL_LABEL_SIZE 80 CSTL_File::CSTL_File(void) { Clear(); } CSTL_File::~CSTL_File(void) { } //copy constructure CSTL_File::CSTL_File(CSTL_File& s) { *this = s; } //overload = CSTL_File& CSTL_File::operator=(const CSTL_File& s) { Facets.resize(s.Size()); int Size = Facets.size(); for (int i = 0; i 127){ binary=true; break; } } // Now we know if the stl file is ascii or binary. fclose(fp); bool RetVal; if(binary) RetVal = LoadBinary(filename); else RetVal = LoadAscii(filename); if (RetVal) IsLoaded=true; //extract object name from path std::string NewObjName = filename; int Start = NewObjName.find_last_of("\\/"); if (Start != std::string::npos) NewObjName = NewObjName.substr(Start + 1, NewObjName.size() - Start - 1); int End = NewObjName.find_last_of("."); if (End != std::string::npos) NewObjName = NewObjName.substr(0, End); ObjectName = NewObjName; return RetVal; } bool CSTL_File::LoadBinary(std::string filename) { FILE *fp; fp = fopen(filename.c_str(), "rb"); if(fp == NULL) return false; int facenum; fseek(fp, STL_LABEL_SIZE, SEEK_SET); fread(&facenum, sizeof(int), 1, fp); Clear(); // For each triangle read the normal, the three coords and a short set to zero float N[3]; float P[9]; short attr; for(int i=0;i "facet normal 0 0 0" if(ret!=3){ // we could be in the case of a multiple solid object, where after a endfaced instead of another facet we have to skip two lines: // endloop // endfacet //endsolid <- continue on ret==0 will skip this line //solid ascii <- and this one. // facet normal 0.000000e+000 7.700727e-001 -6.379562e-001 lineCnt++; continue; } ret=fscanf(fp, "%*s %*s"); // --> "outer loop" ret=fscanf(fp, "%*s %f %f %f\n", &P[0], &P[1], &P[2]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s %f %f %f\n", &P[3], &P[4], &P[5]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s %f %f %f\n", &P[6], &P[7], &P[8]); // --> "vertex x y z" if(ret!=3) return false; ret=fscanf(fp, "%*s"); // --> "endloop" ret=fscanf(fp, "%*s"); // --> "endfacet" lineCnt+=7; if(feof(fp)) break; AddFacet(N[0], N[1], N[2], P[0], P[1], P[2], P[3], P[4], P[5], P[6], P[7], P[8]); } fclose(fp); return true; } bool CSTL_File::Save(std::string filename, bool Binary) const { //writes ascii stl file... FILE *fp; if (Binary) fp = fopen(filename.c_str(),"wb"); else fp = fopen(filename.c_str(),"w"); if(fp==0) return false; int NumFaces = (int)Facets.size(); if(Binary){ // Write Header std::string tmp = ObjectName; tmp += " "; //char header[128]=; fwrite(tmp.c_str(),80,1,fp); // write number of facets fwrite(&NumFaces,1,sizeof(int),fp); unsigned short attributes=0; for(int i=0; i for license details. *******************************************************************************/ #include "SimpleImage.h" #include #include #define STBI_NO_HDR #include "stb_image/stb_image.h" CSimpleImage::CSimpleImage(void) { pDataRGBA = NULL; // pDataIndex = NULL; DataWidth = 0; DataHeight = 0; AlphaPresent = false; // CurIndexMode = IM_VBW; } CSimpleImage::~CSimpleImage(void) { if (pDataRGBA) delete [] pDataRGBA; // if (pDataIndex) delete [] pDataIndex; // DataWidth = 0; // DataHeight = 0; } CSimpleImage& CSimpleImage::operator=(const CSimpleImage& In) { AllocateRGBA(In.DataWidth, In.DataHeight); memcpy(pDataRGBA, In.pDataRGBA, DataWidth*DataHeight*4); AlphaPresent = In.AlphaPresent; // CurIndexMode = In.CurIndexMode; // if (In.pDataIndex){ // if there's index data // IndexFromRGBA(CurIndexMode); // } return *this; } bool CSimpleImage::LoadImage(std::string FilePath) { int x,y,n; unsigned char *data = stbi_load(FilePath.c_str(), &x, &y, &n, 4); if (data == NULL) return false; if (n==2 || n==4) AlphaPresent = true; else AlphaPresent = false; if (!AllocateRGBA(x, y)) return false; memcpy(pDataRGBA, data, x*y*4); stbi_image_free(data); return true; } bool CSimpleImage::AllocateRGBA(int WidthIn, int HeightIn) { if (WidthIn<0 || HeightIn<0) return false; if (WidthIn*HeightIn == DataWidth*DataHeight){ DataWidth = WidthIn; DataHeight = HeightIn; return true; //already correct size allocated } if (pDataRGBA) delete [] pDataRGBA; pDataRGBA = NULL; //not necessary, but good habit // if (pDataIndex) delete [] pDataIndex; // pDataIndex = NULL; if (WidthIn != 0 && HeightIn != 0){ try {pDataRGBA = new unsigned char [WidthIn*HeightIn*4];} catch (std::bad_alloc&){return false;} } DataWidth = WidthIn; DataHeight = HeightIn; return true; } void CSimpleImage::Fill(unsigned char R, unsigned char G, unsigned char B, unsigned char A) { if (A == 255) AlphaPresent = false; unsigned char* pDataRGBAIterator = pDataRGBA; for (int i=0; i for license details. *******************************************************************************/ #include "X3D_File.h" #include //#include "QOpenGL.h" #include "XmlStream.h" //#include //#include //#include //repeated... #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif CX3D_File::CX3D_File(void) { Clear(); } CX3D_File::~CX3D_File(void) { } X3dLoadResult CX3D_File::Load(std::string filename, std::string ImgPathIn) { Clear(); CXmlStreamRead XML; if (!XML.LoadFile(filename)) return XLR_BADFILEPATH; filePath = filename; ImagePath = ImgPathIn; errors = ""; X3dLoadResult tmpRes; if (XML.OpenElement("Scene")){ int NumDown = 0; while (XML.OpenElement("Transform")) NumDown++; //ignore groups and transforms for now... while (XML.OpenElement("Group")) NumDown++; //ignore groups and transforms for now... while (XML.OpenElement("Transform")) NumDown++; //ignore groups and transforms for now... while (XML.OpenElement("Group")) NumDown++; //ignore groups and transforms for now... while (XML.OpenElement("Transform")) NumDown++; //ignore groups and transforms for now... while (XML.OpenElement("Group")) NumDown++; //ignore groups and transforms for now... //read as many shape tags as there are... xShapeNode tmpShape; while(XML.OpenElement("Shape", true)){ // tmpRes = tmpShape.ReadXML(&XML, this, &errors); if (tmpRes != XLR_SUCCESS) return tmpRes; xShapes.push_back(tmpShape); } // if (xShapes.size() != 0) XML.UpLevel(); // for (int i=0; i::iterator it = xShapes.begin(); it != xShapes.end(); it++) { if (it->xIndexedFaceSet.Coordinate.size()%3 != 0) continue; for (std::vector::iterator jt = it->xIndexedFaceSet.Coordinate.begin(); jt < it->xIndexedFaceSet.Coordinate.end(); jt += 3) { minX = (std::min)(minX, *jt); minY = (std::min)(minY, *(jt+1)); minZ = (std::min)(minZ, *(jt+2)); maxX = (std::max)(maxX, *jt); maxY = (std::max)(maxY, *(jt+1)); maxZ = (std::max)(maxZ, *(jt+2)); } } } void CX3D_File::GetSize(double& sizeX, double& sizeY, double& sizeZ) { double xmin, ymin, zmin, xmax, ymax, zmax; GetMinMax(xmin, ymin, zmin, xmax, ymax, zmax); sizeX = xmax-xmin; sizeY = ymax-ymin; sizeZ = zmax-zmin; } void CX3D_File::Str2Data(std::string* pS, std::vector* pD) { int Size = pS->size(); char *a=new char[Size+1]; a[Size]=0; memcpy(a,pS->c_str(),Size); char* pEnd = a; while (*pEnd != '\0'){ pD->push_back(strtol(pEnd, &pEnd, 10)); while (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n') pEnd++; } // // std::stringstream ss(*pS); // int i; // while (ss >> i) pD->push_back(i); } void CX3D_File::Str2Data(std::string* pS, std::vector* pD) { int Size = pS->size(); char *a=new char[Size+1]; a[Size]=0; memcpy(a,pS->c_str(),Size); char* pEnd = a; while (*pEnd != '\0'){ pD->push_back(strtod(pEnd, &pEnd)); while (*pEnd != 0 && *pEnd <= 33 ) pEnd++; //includes all whitespace, including space. } // std::stringstream ss(*pS); // double i; // while (ss >> i) pD->push_back(i); } X3dLoadResult xAppearanceNode::ReadXML(CXmlStreamRead* pXML, CX3D_File* pX3dFile, std::string* pRetMessage) { Clear(); if (pXML->OpenElement("ImageTexture")){ std::string ImgPath; pXML->GetElAttS("url", &ImgPath); if (!pXML->GetElAttB("repeatS", &repeatS)) repeatS = true; //defaults to true! if (!pXML->GetElAttB("repeatT", &repeatT)) repeatT = true; //defaults to true! // QList test = QImageReader::supportedImageFormats(); //if we've provided an image path, load that! if (pX3dFile->ImagePath != ""){ if (!ImageTexture.LoadImage(pX3dFile->ImagePath)) return XLR_BADIMAGEPATH; } //otherwise try loading as is in the x3d file: else if (!ImageTexture.LoadImage(ImgPath)){ //if not at the absolute path... //get image filename (without original path) and try in the folder the x3d file was in size_t start = ImgPath.find_last_of("/\\") +1; if (start == 0) start = ImgPath.find_first_of("\"")+1;//nothing found... size_t end = start; while (ImgPath[end] != '\"') end++; std::string imgName = ImgPath.substr(start, end-start); //get x3d file path std::string FilePath = pX3dFile->filePath.substr(0, pX3dFile->filePath.find_last_of("/\\")+1); //load the image here, or give an error if cannot find it... if (!ImageTexture.LoadImage(FilePath + imgName)){ //check the folder that the x3d file was located in pX3dFile->ImagePath = FilePath + imgName; *pRetMessage += "Could not find texture file " + imgName + ".\n"; return XLR_BADIMAGEPATH; } } // pX3dFile->imagePath = ""; //flag for succesful image load... pXML->CloseElement(); } if (pXML->OpenElement("Material")){ std::string Data; if (pXML->GetElAttS("diffuseColor", &Data)){ std::vector Color; CX3D_File::Str2Data(&Data, &Color); MatColorRed = Color[0]; MatColorGreen = Color[1]; MatColorBlue = Color[2]; } pXML->CloseElement(); } return XLR_SUCCESS; } xIndexedFaceSetNode& xIndexedFaceSetNode::operator=(const xIndexedFaceSetNode& x) { coordIndex=x.coordIndex; texCoordIndex=x.texCoordIndex; Coordinate=x.Coordinate; TextureCoordinate=x.TextureCoordinate; colorPerVertex=x.colorPerVertex; colorIndex=x.colorIndex; Color=x.Color; ColorRGBA=x.ColorRGBA; CoordDef=x.CoordDef; CoordUse=x.CoordUse; NumVertPerFacet=x.NumVertPerFacet; Colors=x.Colors; ColByIndex=x.ColByIndex; HasAlpha=x.HasAlpha; HasTexture=x.HasTexture; return *this; } void xIndexedFaceSetNode::Clear() { coordIndex.clear(); texCoordIndex.clear(); Coordinate.clear(); TextureCoordinate.clear(); colorPerVertex = true; colorIndex.clear(); Color.clear(); ColorRGBA.clear(); CoordDef=""; CoordUse=""; NumVertPerFacet = 0; Colors = false; ColByIndex = false; HasAlpha = false; HasTexture = false; } X3dLoadResult xIndexedFaceSetNode::ReadXML(CXmlStreamRead* pXML, std::string* pRetMessage) { Clear(); std::string tmp; if (pXML->GetElAttS("coordIndex", &tmp)) CX3D_File::Str2Data(&tmp, &coordIndex); if (pXML->GetElAttS("colorIndex", &tmp)) CX3D_File::Str2Data(&tmp, &colorIndex); if (pXML->GetElAttS("texCoordIndex", &tmp)) CX3D_File::Str2Data(&tmp, &texCoordIndex); colorPerVertex = true; if (pXML->GetElAttS("colorPerVertex", &tmp)){ if (tmp == "false" || tmp == "False") colorPerVertex = false; //default is true... } if (pXML->OpenElement("Coordinate")){ if (!pXML->GetElAttS("DEF", &CoordDef)) CoordDef=""; if (!pXML->GetElAttS("USE", &CoordUse)) CoordUse=""; if (pXML->GetElAttS("point", &tmp)) CX3D_File::Str2Data(&tmp, &Coordinate); pXML->CloseElement(); } if (pXML->OpenElement("TextureCoordinate")){ if (pXML->GetElAttS("point", &tmp)) CX3D_File::Str2Data(&tmp, &TextureCoordinate); pXML->CloseElement(); } if (pXML->OpenElement("Color")){ if (pXML->GetElAttS("color", &tmp)) CX3D_File::Str2Data(&tmp, &Color); pXML->CloseElement(); } if (pXML->OpenElement("ColorRGBA")){ if (pXML->GetElAttS("color", &tmp)) CX3D_File::Str2Data(&tmp, &ColorRGBA); pXML->CloseElement(); } if (!FillDerivedInfo()) return XLR_NOSHAPE; return XLR_SUCCESS; } bool xIndexedFaceSetNode::FillDerivedInfo() //fills in these calculated other parameters for easy access later. { NumVertPerFacet = 0; //triangles or quads? if (coordIndex.size() > 3 && coordIndex[3] == -1) NumVertPerFacet = 3; //triangles! else if (coordIndex.size() > 4 && coordIndex[4] == -1) NumVertPerFacet = 4; //quads! else return false; Colors = false; if (Color.size() != 0 || ColorRGBA.size() != 0) Colors = true; ColByIndex = false; if (colorIndex.size() != 0) ColByIndex = true; HasAlpha = false; if (ColorRGBA.size() != 0) HasAlpha = true; HasTexture = false; if (texCoordIndex.size() != 0 && TextureCoordinate.size() != 0) HasTexture = true; return true; } int xIndexedFaceSetNode::GetNumTriangles() //returns 2x number of quads if x3d has quads... { if (NumVertPerFacet == 3) return coordIndex.size()/4; else if (NumVertPerFacet == 4) return coordIndex.size()*2/5; else return 0; } int xIndexedFaceSetNode::GetCoordInd(int TriNum, int VertNum) //VertNum is 0, 1, or 2 (copy to GetTexCoordInd()) { if (NumVertPerFacet == 3) return coordIndex[TriNum*4+VertNum]; else if (NumVertPerFacet == 4){ if(TriNum%2 == 0) return coordIndex[(TriNum/2)*5+VertNum]; //first triangle of quad (012) else if (VertNum != 0) return coordIndex[(TriNum/2)*5+1+VertNum]; //second triangle of quad, last two verts ([0]23) else return coordIndex[(TriNum/2)*5]; //second triangle of quad, first vert (0[23]) } else return -1; } double xIndexedFaceSetNode::GetColorFace(int TriNum, ColChan Chan) //triangle color (make sure Color && !colorPerVertex and HasAplpha if requesting alpha) { if (NumVertPerFacet == 4) TriNum /=2; if (ColByIndex){ if (HasAlpha) return ColorRGBA[colorIndex[TriNum]*4+(int)Chan]; else return Color[colorIndex[TriNum]*3+(int)Chan]; } else { if (HasAlpha) return ColorRGBA[TriNum*4+(int)Chan]; else return Color[TriNum*3+(int)Chan]; } } double xIndexedFaceSetNode::GetColorVert(int CoordNum, ColChan Chan) //vertex color (make sure Color && colorPerVertex and HasAlpha if requesting alpha) { if (ColByIndex){ //AMF does not support vertixes being mapped to different colors for different tirangles. if (HasAlpha) return ColorRGBA[0*4+(int)Chan]; else return Color[0*3+(int)Chan]; } else { if (HasAlpha) return ColorRGBA[CoordNum*4+(int)Chan]; else return Color[CoordNum*3+(int)Chan]; } } double xIndexedFaceSetNode::GetColorVert(int TriNum, int VertNum, ColChan Chan) //triangle color (make sure Color && colorPerVertex and HasAplpha if requesting alpha) { if (ColByIndex){ if (HasAlpha) return ColorRGBA[colorIndex[GetCoordInd(TriNum, VertNum)]*4+(int)Chan]; else return Color[colorIndex[GetCoordInd(TriNum, VertNum)]*3+(int)Chan]; } else { if (HasAlpha) return ColorRGBA[GetCoordInd(TriNum, VertNum)*4+(int)Chan]; else return Color[GetCoordInd(TriNum, VertNum)*3+(int)Chan]; } } int xIndexedFaceSetNode::GetTexCoordInd(int TriNum, int VertNum) //copied fromG etCoordInd () { if (NumVertPerFacet == 3) return texCoordIndex[TriNum*4+VertNum]; else if (NumVertPerFacet == 4){ if(TriNum%2 == 0) return texCoordIndex[(TriNum/2)*5+VertNum]; //first triangle of quad (012) else if (VertNum != 0) return texCoordIndex[(TriNum/2)*5+1+VertNum]; //second triangle of quad, last two verts ([0]23) else return texCoordIndex[(TriNum/2)*5]; //second triangle of quad, first vert (0[23]) } else return -1; } X3dLoadResult xShapeNode::ReadXML(CXmlStreamRead* pXML, CX3D_File* pX3dFile, std::string* pRetMessage) { Clear(); X3dLoadResult tmpRes; if (pXML->OpenElement("IndexedFaceSet")){ tmpRes = xIndexedFaceSet.ReadXML(pXML, pRetMessage); if (tmpRes != XLR_SUCCESS) return tmpRes; pXML->CloseElement(); } if (pXML->OpenElement("Appearance")){ tmpRes = xAppearance.ReadXML(pXML, pX3dFile, pRetMessage); if (tmpRes != XLR_SUCCESS) return tmpRes; pXML->CloseElement(); } return XLR_SUCCESS; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/XmlCompress.cpp000066400000000000000000000210421231531733200251440ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "XmlCompress.h" #ifdef WIN32 #include "zip/zip.h" #include "zip/unzip.h" #else //Mac/Linux zip header includes here // using libzip http://nih.at/libzip/ #include "zip.h" #endif bool CompressFile(std::string ZipName, std::string FilePath, std::string* pError) //filepath string to zip into location of ZipName (also a filepath) { std::vector Files; Files.push_back(FilePath); return CompressFiles(ZipName, &Files, pError); } bool CompressFiles(std::string ZipName, std::vector* pFilePaths, std::string* pError) //pointer to a vector of filepath strings to zip into location of ZipName (also a filepath) { #ifdef WIN32 HZIP hz = CreateZip(ZipName.c_str(),0); if (!hz){if (pError) *pError += "Could not create ZIP archive. Aborting\n"; return false;} int NumFiles = pFilePaths->size(); for (int i=0; isize(); for (int i=0; i *data, std::string* pError) { std::vector FileNames; FileNames.push_back(FileName); std::vector > Datas; bool RetRes = GetCompressedFiles(ZipName, &FileNames, &Datas, pError); if (RetRes){ *data = Datas[0]; return true; } else return false; } bool GetCompressedFiles(std::string ZipName, std::vector* pFileNames, std::vector >* data, std::string* pError) { #ifdef WIN32 HZIP hz = OpenZip(ZipName.c_str(),0); if (!hz){if(pError) *pError += ("Unable to open ZIP archive. Aborting.\n"); return false;} ZIPENTRY ze; if (GetZipItem(hz, -1, &ze) != ZR_OK) {if(pError) *pError += ("Unable to return information about ZIP archive. Aborting.\n"); return false;} int NumFiles = ze.index; //set up returns for data... data->resize(NumFiles); for (int i=0; isize(); for (int j=0; jresize(NumFiles); for (uint i=0; isize(); const char * entryname = zip_get_name(hz, i, 0); struct zip_stat stat; err = zip_stat_index(hz, i, 0, &stat); for (int j=0; j* pFileNames, std::vector >* data, std::string* pError) { #ifdef WIN32 HZIP hz = OpenZip(ZipName.c_str(),0); if (!hz){if(pError) *pError += ("Unable to open ZIP archive. Aborting.\n"); return false;} ZIPENTRY ze; if (GetZipItem(hz, -1, &ze) != ZR_OK) {if(pError) *pError += ("Unable to return information about ZIP archive. Aborting.\n"); return false;} int NumFiles = ze.index; //set up returns for the number of files... pFileNames->resize(NumFiles); data->resize(NumFiles); for (int i=0; iresize(NumFiles); data->resize(NumFiles); for (int i=0; i for license details. *******************************************************************************/ #include "XmlStream.h" #include #include #include "rapidxml/rapidxml_print.h" #include "XmlCompress.h" ////////////////////////////////CXmlStreamRead///////////////////////////// CXmlStreamRead::CXmlStreamRead() //std::string FilePathToRead) { LastTagSearched = ""; tmp = ""; LastError = ""; } CXmlStreamRead::~CXmlStreamRead(void) { } bool CXmlStreamRead::LoadFile(std::string FilePathToRead) { //determine if its compressed or not... FILE *fp; bool binary=false; fp = fopen(FilePathToRead.c_str(), "r"); if(fp == NULL){ LastError = "Error: Could not open file. Aborting.\n"; return false; } std::string BeginFile; std::string tmp; tmp.resize(5); fread((void*)tmp.data(), 5, 1, fp); fclose(fp); if (tmp == "(size)); data[size] = '\0'; stream.close(); } else { //see if it's compressed as zip //filename within zip is the name of zip stripped of any folders... int StartName = FilePathToRead.find_last_of('/')+1; int EndName = FilePathToRead.size(); std::string Name = FilePathToRead.substr(StartName, EndName-StartName); if (!GetCompressedFile(FilePathToRead, Name, &data, &LastError)){ LastError += "Error: File identified as compressed AMF (does not begin with \" data_output = data; //buffer for reading/writing that won't get changed by parser (possible big allocation = slow here!) try{ doc.parse(&data.front()); //doc.parse<0>(&data.front()); } catch (rapidxml::parse_error& Error){ int ErrLoc = Error.where() - &data.front(); //find line number: int LineNumber = 0; for(int i=0; i= 0){ if(data_output[ErrLoc + RelIndex1] == '\n') Counter++; if (RelIndex1 < 200) break; } RelIndex1++; //step back up the last decrement and the newline if(Counter < NumLinesUp) NumLinesUp = Counter; //only needed if we hit the beginning of the file Counter = 0; while(Counter <= NumLinesDown && ErrLoc+ ++RelIndex2 < (int)data_output.size()){ if(data_output[ErrLoc + RelIndex2] == '\n') Counter++; if (RelIndex2 > 200) break; } RelIndex2--; //undo last increment if(Counter < NumLinesDown) NumLinesDown = Counter; //only needed if we hit the beginning of the file int CurLineNum = LineNumber - NumLinesUp+1; os << CurLineNum++ << ":"; //stat off right if we're at beginning of file for(int i=RelIndex1; i* tmpElement; bool IsSameTag = (tag == StrStack.back()); //flag to see if we just searched for this one if (IsSameTag && RepeatingTag){ //if this IS the last tag we searched for and we're looking for siblings... tmpElement = ElStack.back()->next_sibling(tag.c_str(), 0, false); //try to find a next sibling if (tmpElement){ //if we find it, move the top of the stack to the new sibling ElStack.back() = tmpElement; return true; } } else { //If not the same tag we searched for (or we searched for the same tag name as a child element) tmpElement = ElStack.back()->first_node(tag.c_str(), 0, false); //if this is the first time we've searched for the tag if (tmpElement){ ElStack.push_back(tmpElement); //if first element of this type StrStack.push_back(tag); return true; } } if (IsSameTag && RepeatingTag) CloseElement(); //automatically close the tag we were searching repeatedly for... return false; } bool CXmlStreamRead::GetElementS(std::string tag, std::string* pString, bool RepeatingTag) { if (!OpenElement(tag, RepeatingTag)) return false; *pString = std::string(ElStack.back()->first_node()->value()); if (*pString == "") return false; if (!RepeatingTag) CloseElement(); //if we're not expecting to load more tags of the same name... return true; } bool CXmlStreamRead::GetElAttS(std::string Att, std::string* pStringReturn) { pTmpAtt = ElStack.back()->first_attribute(Att.c_str(), 0, false); if (!pTmpAtt){ //right now, ignore emtpy tags, just return nothing *pStringReturn = ""; return false; } *pStringReturn = std::string(pTmpAtt->value()); return ("" == (*pStringReturn))?false:true; } bool CXmlStreamRead::GetElDataS(std::string* pStringReturn) { pTmpNode = ElStack.back()->first_node(); if (!pTmpNode){ *pStringReturn = ""; return false; } *pStringReturn = std::string(pTmpNode->value()); return (*pStringReturn == "")?false:true; } ////////////////////////////////CXmlStreamWrite///////////////////////////// CXmlStreamWrite::CXmlStreamWrite() { filename = ""; LastError = ""; ToWrite = ""; AnyToWrite = false; IndentNextClose = true; WantCompressed = false; CurIndent = 0; } bool CXmlStreamWrite::BeginXmlFile(std::string FilePathToWrite, bool Compressed) { filename = FilePathToWrite; WantCompressed = Compressed; std::string ThisFile = filename; if (WantCompressed) ThisFile += ".tmp"; //if compressed, create a temporary file... CurIndent = 0; fp = fopen(ThisFile.c_str(),"w"); if(fp){ fprintf(fp,"\n"); fprintf(fp,"\n"); } else {LastError += "Could not begin file at this path. Aborting.\n"; return false;} return true; } bool CXmlStreamWrite::EndXmlFile() { if (fp){ if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); //write any remaining part of the last tag... fclose(fp); } else {LastError += "Invalid file pointer encountered on saving XML. Aborting.\n"; return false;} if (WantCompressed){ if (CompressFile(filename, filename+".tmp", &LastError)){ remove((filename+".tmp").c_str()); //delete the temp file return true; } else { //if no commpression (IE on a platform with zip compress not yet implemented) just use the ascii version LastError += "Could not compress AMF. Saved uncompressed version instead.\n"; rename((filename+".tmp").c_str(), filename.c_str()); return false; } } return true; } void CXmlStreamWrite::OpenElement(std::string tag) { if(fp){ //if write... if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); //write any remaining part of the last tag... fwrite(Ind, 1, CurIndent, fp); IndentNextClose = true; fprintf(fp,"<%s", tag.c_str()); AnyToWrite = true; ToWrite = ">\n"; CurIndent += 2; StrStack.push_back(tag); } } void CXmlStreamWrite::CloseElement(void) { if(fp){ if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); //write any remaining part of the last tag... CurIndent -= 2; if (IndentNextClose) fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"\n", StrStack.back().c_str()); AnyToWrite = false; StrStack.pop_back(); } } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/muparser/000077500000000000000000000000001231531733200240235ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/src/muparser/muParser.cpp000066400000000000000000000305451231531733200263340ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParser.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include /** \brief Pi (what else?). */ #define PARSER_CONST_PI 3.141592653589793238462643 /** \brief The eulerian number. */ #define PARSER_CONST_E 2.718281828459045235360287 using namespace std; /** \file \brief Implementation of the standard floating point parser. */ /** \brief Namespace for mathematical applications. */ namespace mu { //--------------------------------------------------------------------------- // Trigonometric function value_type Parser::Sin(value_type v) { return sin(v); } value_type Parser::Cos(value_type v) { return cos(v); } value_type Parser::Tan(value_type v) { return tan(v); } value_type Parser::ASin(value_type v) { return asin(v); } value_type Parser::ACos(value_type v) { return acos(v); } value_type Parser::ATan(value_type v) { return atan(v); } value_type Parser::Sinh(value_type v) { return sinh(v); } value_type Parser::Cosh(value_type v) { return cosh(v); } value_type Parser::Tanh(value_type v) { return tanh(v); } value_type Parser::ASinh(value_type v) { return log(v + sqrt(v * v + 1)); } value_type Parser::ACosh(value_type v) { return log(v + sqrt(v * v - 1)); } value_type Parser::ATanh(value_type v) { return ((value_type)0.5 * log((1 + v) / (1 - v))); } //--------------------------------------------------------------------------- // Logarithm functions value_type Parser::Log2(value_type v) { return log(v)/log((value_type)2); } // Logarithm base 2 value_type Parser::Log10(value_type v) { return log10(v); } // Logarithm base 10 value_type Parser::Ln(value_type v) { return log(v); } // Logarithm base e (natural logarithm) //--------------------------------------------------------------------------- // misc value_type Parser::Exp(value_type v) { return exp(v); } value_type Parser::Abs(value_type v) { return fabs(v); } value_type Parser::Sqrt(value_type v) { return sqrt(v); } value_type Parser::Rint(value_type v) { return floor(v + (value_type)0.5); } value_type Parser::Sign(value_type v) { return (value_type)((v<0) ? -1 : (v>0) ? 1 : 0); } //--------------------------------------------------------------------------- /** \brief Callback for the unary minus operator. \param v The value to negate \return -v */ value_type Parser::UnaryMinus(value_type v) { return -v; } //--------------------------------------------------------------------------- /** \brief Callback for adding multiple values. \param [in] a_afArg Vector with the function arguments \param [in] a_iArgc The size of a_afArg */ value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) { if (!a_iArgc) throw exception_type(_T("too few arguments for function sum.")); value_type fRes=0; for (int i=0; i> fVal; stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading if (iEnd==(stringstream_type::pos_type)-1) return 0; *a_iPos += (int)iEnd; *a_fVal = fVal; return 1; } //--------------------------------------------------------------------------- /** \brief Constructor. Call ParserBase class constructor and trigger Function, Operator and Constant initialization. */ Parser::Parser() :ParserBase() { AddValIdent(IsVal); InitCharSets(); InitFun(); InitConst(); InitOprt(); } //--------------------------------------------------------------------------- /** \brief Define the character sets. \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars This function is used for initializing the default character sets that define the characters to be useable in function and variable names and operators. */ void Parser::InitCharSets() { DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") ); DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") ); } //--------------------------------------------------------------------------- /** \brief Initialize the default functions. */ void Parser::InitFun() { // trigonometric functions DefineFun(_T("sin"), Sin); DefineFun(_T("cos"), Cos); DefineFun(_T("tan"), Tan); // arcus functions DefineFun(_T("asin"), ASin); DefineFun(_T("acos"), ACos); DefineFun(_T("atan"), ATan); // hyperbolic functions DefineFun(_T("sinh"), Sinh); DefineFun(_T("cosh"), Cosh); DefineFun(_T("tanh"), Tanh); // arcus hyperbolic functions DefineFun(_T("asinh"), ASinh); DefineFun(_T("acosh"), ACosh); DefineFun(_T("atanh"), ATanh); // Logarithm functions DefineFun(_T("log2"), Log2); DefineFun(_T("log10"), Log10); DefineFun(_T("log"), Log10); DefineFun(_T("ln"), Ln); // misc DefineFun(_T("exp"), Exp); DefineFun(_T("sqrt"), Sqrt); DefineFun(_T("sign"), Sign); DefineFun(_T("rint"), Rint); DefineFun(_T("abs"), Abs); // Functions with variable number of arguments DefineFun(_T("sum"), Sum); DefineFun(_T("avg"), Avg); DefineFun(_T("min"), Min); DefineFun(_T("max"), Max); } //--------------------------------------------------------------------------- /** \brief Initialize constants. By default the parser recognizes two constants. Pi ("pi") and the eulerian number ("_e"). */ void Parser::InitConst() { DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); DefineConst(_T("_e"), (value_type)PARSER_CONST_E); } //--------------------------------------------------------------------------- /** \brief Initialize operators. By default only the unary minus operator is added. */ void Parser::InitOprt() { DefineInfixOprt(_T("-"), UnaryMinus); } //--------------------------------------------------------------------------- void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) { // this is just sample code to illustrate modifying variable names on the fly. // I'm not sure anyone really needs such a feature... /* string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); string sRepl = std::string("_") + sVar + "_"; int nOrigVarEnd = nEnd; cout << "variable detected!\n"; cout << " Expr: " << *pExpr << "\n"; cout << " Start: " << nStart << "\n"; cout << " End: " << nEnd << "\n"; cout << " Var: \"" << sVar << "\"\n"; cout << " Repl: \"" << sRepl << "\"\n"; nEnd = nStart + sRepl.length(); cout << " End: " << nEnd << "\n"; pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); cout << " New expr: " << *pExpr << "\n"; */ } //--------------------------------------------------------------------------- /** \brief Numerically differentiate with regard to a variable. \param [in] a_Var Pointer to the differentiation variable. \param [in] a_fPos Position at which the differentiation should take place. \param [in] a_fEpsilon Epsilon used for the numerical differentiation. Numerical differentiation uses a 5 point operator yielding a 4th order formula. The default value for epsilon is 0.00074 which is numeric_limits::epsilon() ^ (1/5) as suggested in the muparser forum: http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 */ value_type Parser::Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon) const { value_type fRes(0), fBuf(*a_Var), f[4] = {0,0,0,0}, fEpsilon(a_fEpsilon); // Backwards compatible calculation of epsilon inc case the user doesnt provide // his own epsilon if (fEpsilon==0) fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); *a_Var = fBuf; // restore variable fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); return fRes; } } // namespace mu repsnapper-2.3.2a5/libraries/amf/amftools-code/src/muparser/muParserBase.cpp000066400000000000000000002236221231531733200271270ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBase.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include #include #ifdef MUP_USE_OPENMP #include #endif using namespace std; /** \file \brief This file contains the basic implementation of the muparser engine. */ namespace mu { std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); bool ParserBase::g_DbgDumpCmdCode = false; bool ParserBase::g_DbgDumpStack = false; //------------------------------------------------------------------------------ /** \brief Identifiers for built in binary operators. When defining custom binary operators with #AddOprt(...) make sure not to choose names conflicting with these definitions. */ const char_type* ParserBase::c_DefaultOprt[] = { _T("<="), _T(">="), _T("!="), _T("=="), _T("<"), _T(">"), _T("+"), _T("-"), _T("*"), _T("/"), _T("^"), /*_T("and"), _T("or"), _T("xor"),*/ _T("&&"), _T("||"), _T("="), _T("("), _T(")"), _T("?"), _T(":"), 0 }; //------------------------------------------------------------------------------ /** \brief Constructor. \param a_szFormula the formula to interpret. \throw ParserException if a_szFormula is null. */ ParserBase::ParserBase() :m_pParseFormula(&ParserBase::ParseString) ,m_pRPN(NULL) ,m_vRPN() ,m_vStringBuf() ,m_pTokenReader() ,m_FunDef() ,m_PostOprtDef() ,m_InfixOprtDef() ,m_OprtDef() ,m_ConstDef() ,m_StrVarDef() ,m_VarDef() ,m_bOptimize(true) ,m_bBuiltInOp(true) ,m_sNameChars() ,m_sOprtChars() ,m_sInfixOprtChars() ,m_nIfElseCounter(0) ,m_vStackBuffer() ,m_nFinalResultIdx(0) { InitTokenReader(); } //--------------------------------------------------------------------------- /** \brief Copy constructor. Tha parser can be safely copy constructed but the bytecode is reset during copy construction. */ ParserBase::ParserBase(const ParserBase &a_Parser) :m_pParseFormula(&ParserBase::ParseString) ,m_pRPN(NULL) ,m_vRPN() ,m_vStringBuf() ,m_pTokenReader() ,m_FunDef() ,m_PostOprtDef() ,m_InfixOprtDef() ,m_nIfElseCounter(0) ,m_OprtDef() ,m_ConstDef() ,m_StrVarDef() ,m_VarDef() ,m_bOptimize(true) ,m_bBuiltInOp(true) { m_pTokenReader.reset(new token_reader_type(this)); Assign(a_Parser); } //--------------------------------------------------------------------------- ParserBase::~ParserBase() {} //--------------------------------------------------------------------------- /** \brief Assignement operator. Implemented by calling Assign(a_Parser). Self assignement is suppressed. \param a_Parser Object to copy to this. \return *this \throw nothrow */ ParserBase& ParserBase::operator=(const ParserBase &a_Parser) { Assign(a_Parser); return *this; } //--------------------------------------------------------------------------- /** \brief Copy state of a parser object to this. Clears Variables and Functions of this parser. Copies the states of all internal variables. Resets parse function to string parse mode. \param a_Parser the source object. */ void ParserBase::Assign(const ParserBase &a_Parser) { if (&a_Parser==this) return; // Don't copy bytecode instead cause the parser to create new bytecode // by resetting the parse function. ReInit(); m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants m_VarDef = a_Parser.m_VarDef; // Copy user defined variables m_bOptimize = a_Parser.m_bOptimize; m_bBuiltInOp = a_Parser.m_bBuiltInOp; m_vStringBuf = a_Parser.m_vStringBuf; m_vStackBuffer = a_Parser.m_vStackBuffer; m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; m_StrVarDef = a_Parser.m_StrVarDef; m_vStringVarBuf = a_Parser.m_vStringVarBuf; m_nIfElseCounter = a_Parser.m_nIfElseCounter; m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); // Copy function and operator callbacks m_FunDef = a_Parser.m_FunDef; // Copy function definitions m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation m_OprtDef = a_Parser.m_OprtDef; // binary operators m_sNameChars = a_Parser.m_sNameChars; m_sOprtChars = a_Parser.m_sOprtChars; m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; } //--------------------------------------------------------------------------- /** \brief Set the decimal separator. \param cDecSep Decimal separator as a character value. \sa SetThousandsSep By default muparser uses the "C" locale. The decimal separator of this locale is overwritten by the one provided here. */ void ParserBase::SetDecSep(char_type cDecSep) { char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Sets the thousands operator. \param cThousandsSep The thousands separator as a character \sa SetDecSep By default muparser uses the "C" locale. The thousands separator of this locale is overwritten by the one provided here. */ void ParserBase::SetThousandsSep(char_type cThousandsSep) { char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Resets the locale. The default locale used "." as decimal separator, no thousands separator and "," as function argument separator. */ void ParserBase::ResetLocale() { s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); SetArgSep(','); } //--------------------------------------------------------------------------- /** \brief Initialize the token reader. Create new token reader object and submit pointers to function, operator, constant and variable definitions. \post m_pTokenReader.get()!=0 \throw nothrow */ void ParserBase::InitTokenReader() { m_pTokenReader.reset(new token_reader_type(this)); } //--------------------------------------------------------------------------- /** \brief Reset parser to string parsing mode and clear internal buffers. Clear bytecode, reset the token reader. \throw nothrow */ void ParserBase::ReInit() const { m_pParseFormula = &ParserBase::ParseString; m_vStringBuf.clear(); m_vRPN.clear(); m_pTokenReader->ReInit(); m_nIfElseCounter = 0; } //--------------------------------------------------------------------------- void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) {} //--------------------------------------------------------------------------- /** \brief Returns the version of muparser. \param eInfo A flag indicating whether the full version info should be returned or not. Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL. */ string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const { string_type sCompileTimeSettings; stringstream_type ss; ss << MUP_VERSION; if (eInfo==pviFULL) { ss << _T(" (") << MUP_VERSION_DATE; ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT"); #ifdef _DEBUG ss << _T("; DEBUG"); #else ss << _T("; RELEASE"); #endif #ifdef _UNICODE ss << _T("; UNICODE"); #else #ifdef _MBCS ss << _T("; MBCS"); #else ss << _T("; ASCII"); #endif #endif #ifdef MUP_USE_OPENMP ss << _T("; OPENMP"); //#else // ss << _T("; NO_OPENMP"); #endif #if defined(MUP_MATH_EXCEPTIONS) ss << _T("; MATHEXC"); //#else // ss << _T("; NO_MATHEXC"); #endif ss << _T(")"); } return ss.str(); } //--------------------------------------------------------------------------- /** \brief Add a value parsing function. When parsing an expression muParser tries to detect values in the expression string using different valident callbacks. Thuis it's possible to parse for hex values, binary values and floating point values. */ void ParserBase::AddValIdent(identfun_type a_pCallback) { m_pTokenReader->AddValIdent(a_pCallback); } //--------------------------------------------------------------------------- /** \brief Set a function that can create variable pointer for unknown expression variables. \param a_pFactory A pointer to the variable factory. \param pUserData A user defined context pointer. */ void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) { m_pTokenReader->SetVarCreator(a_pFactory, pUserData); } //--------------------------------------------------------------------------- /** \brief Add a function or operator callback to the parser. */ void ParserBase::AddCallback( const string_type &a_strName, const ParserCallback &a_Callback, funmap_type &a_Storage, const char_type *a_szCharSet ) { if (a_Callback.GetAddr()==0) Error(ecINVALID_FUN_PTR); const funmap_type *pFunMap = &a_Storage; // Check for conflicting operator or function names if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) Error(ecNAME_CONFLICT, -1, a_strName); CheckOprt(a_strName, a_Callback, a_szCharSet); a_Storage[a_strName] = a_Callback; ReInit(); } //--------------------------------------------------------------------------- /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid charakters. */ void ParserBase::CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback, const string_type &a_szCharSet) const { if ( !a_sName.length() || (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || (a_sName[0]>='0' && a_sName[0]<='9')) { switch(a_Callback.GetCode()) { case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); default: Error(ecINVALID_NAME, -1, a_sName); } } } //--------------------------------------------------------------------------- /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid charakters. */ void ParserBase::CheckName(const string_type &a_sName, const string_type &a_szCharSet) const { if ( !a_sName.length() || (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || (a_sName[0]>='0' && a_sName[0]<='9')) { Error(ecINVALID_NAME); } } //--------------------------------------------------------------------------- /** \brief Set the formula. \param a_strFormula Formula as string_type \throw ParserException in case of syntax errors. Triggers first time calculation thus the creation of the bytecode and scanning of used variables. */ void ParserBase::SetExpr(const string_type &a_sExpr) { // Check locale compatibility std::locale loc; if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) Error(ecLOCALE); // 20060222: Bugfix for Borland-Kylix: // adding a space to the expression will keep Borlands KYLIX from going wild // when calling tellg on a stringstream created from the expression after // reading a value at the end of an expression. (mu::Parser::IsVal function) // (tellg returns -1 otherwise causing the parser to ignore the value) string_type sBuf(a_sExpr + _T(" ") ); m_pTokenReader->SetFormula(sBuf); ReInit(); } //--------------------------------------------------------------------------- /** \brief Get the default symbols used for the built in operators. \sa c_DefaultOprt */ const char_type** ParserBase::GetOprtDef() const { return (const char_type **)(&c_DefaultOprt[0]); } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of functions, variables, constants. */ void ParserBase::DefineNameChars(const char_type *a_szCharset) { m_sNameChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of binary operators and postfix operators. */ void ParserBase::DefineOprtChars(const char_type *a_szCharset) { m_sOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of infix operators. */ void ParserBase::DefineInfixOprtChars(const char_type *a_szCharset) { m_sInfixOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in name identifiers. \sa #ValidOprtChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidNameChars() const { assert(m_sNameChars.size()); return m_sNameChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in operator definitions. \sa #ValidNameChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidOprtChars() const { assert(m_sOprtChars.size()); return m_sOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in infix operator definitions. \sa #ValidNameChars, #ValidOprtChars */ const char_type* ParserBase::ValidInfixOprtChars() const { assert(m_sInfixOprtChars.size()); return m_sInfixOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. */ void ParserBase::DefinePostfixOprt(const string_type &a_sName, fun_type1 a_pFun, bool a_bAllowOpt) { AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, ValidOprtChars() ); } //--------------------------------------------------------------------------- /** \brief Initialize user defined functions. Calls the virtual functions InitFun(), InitConst() and InitOprt(). */ void ParserBase::Init() { InitCharSets(); InitFun(); InitConst(); InitOprt(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. \param [in] a_sName operator Identifier \param [in] a_pFun Operator callback function \param [in] a_iPrec Operator Precedence (default=prSIGN) \param [in] a_bAllowOpt True if operator is volatile (default=false) \sa EPrec */ void ParserBase::DefineInfixOprt(const string_type &a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) { AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, ValidInfixOprtChars() ); } //--------------------------------------------------------------------------- /** \brief Define a binary operator. \param [in] a_pFun Pointer to the callback function. \param [in] a_iPrec Precedence of the operator. \param [in] a_bAllowOpt If this is true the operator may be optimized away. */ void ParserBase::DefineOprt( const string_type &a_sName, fun_type2 a_pFun, unsigned a_iPrec, EOprtAssociativity a_eAssociativity, bool a_bAllowOpt ) { // Check for conflicts with built in operator names for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); ParseString(); // implicitely create or update the map with the // used variables stored in the token reader if not already done m_pTokenReader->IgnoreUndefVar(false); } catch(exception_type &e) { m_pTokenReader->IgnoreUndefVar(false); throw e; } // Make sure to stay in string parse mode, dont call ReInit() // because it deletes the array with the used variables m_pParseFormula = &ParserBase::ParseString; return m_pTokenReader->GetUsedVar(); } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ const varmap_type& ParserBase::GetVar() const { return m_VarDef; } //--------------------------------------------------------------------------- /** \brief Return a map containing all parser constants. */ const valmap_type& ParserBase::GetConst() const { return m_ConstDef; } //--------------------------------------------------------------------------- /** \brief Return prototypes of all parser functions. \return #m_FunDef \sa FunProt \throw nothrow The return type is a map of the public type #funmap_type containing the prototype definitions for all numerical parser functions. String functions are not part of this map. The Prototype definition is encapsulated in objects of the class FunProt one per parser function each associated with function names via a map construct. */ const funmap_type& ParserBase::GetFunDef() const { return m_FunDef; } //--------------------------------------------------------------------------- /** \brief Retrieve the formula. */ const string_type& ParserBase::GetExpr() const { return m_pTokenReader->GetExpr(); } //--------------------------------------------------------------------------- ParserBase::token_type ParserBase::ApplyNumFunc(const token_type &a_FunTok, const std::vector &a_vArg) const { token_type valTok; int iArgCount = (unsigned)a_vArg.size(); void *pFunc = a_FunTok.GetFuncAddr(); assert(pFunc); // Collect the function arguments from the value stack switch(a_FunTok.GetArgCount()) { case -1: // Function with variable argument count // copy arguments into a vector { if (iArgCount==0) Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); std::vector vArg(iArgCount); for (int i=0; i &a_vArg) const { // I dont't really do any calculation here. A dummy value serving as a placeholder // for the bulk functions return value is returned. This works as long as the optimizer // is deactivated with the flVOLATILE flag. This is ok since the result of the first // parsing run from string is now discarded anyway. (since V1.35) token_type valTok; valTok.SetVal(1); valTok.AddFlags(token_type::flVOLATILE); m_vRPN.AddBulkFun(a_FunTok.GetFuncAddr(), (int)a_vArg.size()); return valTok; } //--------------------------------------------------------------------------- /** \brief Execute a function that takes a single string argument. \param a_FunTok Function token. \throw exception_type If the function token is not a string function */ ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok, const std::vector &a_vArg) const { if (a_vArg.back().GetCode()!=cmSTRING) Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); token_type valTok; int iArgCount = (unsigned)a_vArg.size(); void *pFunc = a_FunTok.GetFuncAddr(); assert(pFunc); try { // Collect the function arguments from the value stack switch(a_FunTok.GetArgCount()) { case 0: valTok.SetVal( ((strfun_type1)pFunc)(a_vArg[0].GetAsString().c_str()) ); break; case 1: valTok.SetVal( ((strfun_type2)pFunc)(a_vArg[1].GetAsString().c_str(), a_vArg[0].GetVal()) ); break; case 2: valTok.SetVal( ((strfun_type3)pFunc)(a_vArg[2].GetAsString().c_str(), a_vArg[1].GetVal(), a_vArg[0].GetVal()) ); break; default: Error(ecINTERNAL_ERROR); } } catch(ParserError& /*e*/) { Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); } // Find out if the result will depend on a variable /** \todo remove this loop, put content in the loop that takes the argument values. (Attention: SetVal will reset Flags.) */ bool bVolatile = a_FunTok.IsFlagSet(token_type::flVOLATILE); for (int i=0; (bVolatile==false) && (i &a_stOpt, ParserStack &a_stVal, int a_iArgCount) const { assert(m_pTokenReader.get()); // Operator stack empty or does not contain tokens with callback functions if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) return; token_type funTok = a_stOpt.pop(); assert(funTok.GetFuncAddr()); // Binary operators must rely on their internal operator number // since counting of operators relies on commas for function arguments // binary operators do not have commas in their expression int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; // determine how many parameters the function needs. To remember iArgCount includes the // string parameter whilst GetArgCount() counts only numeric parameters. int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); // Thats the number of numerical parameters int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) Error(ecINTERNAL_ERROR); if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); // Collect the numeric function arguments from the value stack and store them // in a vector std::vector stArg; for (int i=0; iGetPos(), funTok.GetAsString()); } // for string functions add the string argument if (funTok.GetCode()==cmFUNC_STR) { stArg.push_back( a_stVal.pop() ); if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); } // String functions accept only one parameter if (funTok.GetType()==tpSTR) { token_type token( ApplyStrFunc(funTok, stArg) ); a_stVal.push( token ); } else { token_type token( (funTok.GetCode()==cmFUNC_BULK) ? ApplyBulkFunc(funTok, stArg) : ApplyNumFunc(funTok, stArg) ); a_stVal.push( token ); } } //--------------------------------------------------------------------------- void ParserBase::ApplyIfElse(ParserStack &a_stOpt, ParserStack &a_stVal) const { // Check if there is an if Else clause to be calculated while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) { token_type opElse = a_stOpt.pop(); MUP_ASSERT(a_stOpt.size()>0); // Take the value associated with the else branch from the value stack token_type vVal2 = a_stVal.pop(); MUP_ASSERT(a_stOpt.size()>0); MUP_ASSERT(a_stVal.size()>=2); // it then else is a ternary operator Pop all three values from the value s // tack and just return the right value token_type vVal1 = a_stVal.pop(); token_type vExpr = a_stVal.pop(); a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2); // Result of if then else is always volatile, the // function optimizer won't handle it properly a_stVal.top().AddFlags(token_type::flVOLATILE); token_type opIf = a_stOpt.pop(); MUP_ASSERT(opElse.GetCode()==cmELSE); MUP_ASSERT(opIf.GetCode()==cmIF); m_vRPN.AddIfElse(cmENDIF); } // while pending if-else-clause found } //--------------------------------------------------------------------------- void ParserBase::ApplyBinOprt(ParserStack &a_stOpt, ParserStack &a_stVal) const { if (a_stOpt.top().GetCode()==cmOPRT_INFIX) { // First check for presence of an infix operator ApplyFunc(a_stOpt, a_stVal, 1); } else { // user defined binary operator if (a_stOpt.top().GetCode()==cmOPRT_BIN) { ApplyFunc(a_stOpt, a_stVal, 2); } else { // internal binary operator MUP_ASSERT(a_stVal.size()>=2); token_type valTok1 = a_stVal.pop(), valTok2 = a_stVal.pop(), optTok = a_stOpt.pop(), resTok; if ( valTok1.GetType()!=valTok2.GetType() || (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); value_type x = valTok2.GetVal(), y = valTok1.GetVal(); switch (optTok.GetCode()) { // built in binary operators //case cmAND: resTok.SetVal( (int)x & (int)y ); break; //case cmOR: resTok.SetVal( (int)x | (int)y ); break; //case cmXOR: resTok.SetVal( (int)x ^ (int)y ); break; case cmLAND: resTok.SetVal( (int)x && (int)y ); break; case cmLOR: resTok.SetVal( (int)x || (int)y ); break; case cmLT: resTok.SetVal( x < y ); break; case cmGT: resTok.SetVal( x > y ); break; case cmLE: resTok.SetVal( x <= y ); break; case cmGE: resTok.SetVal( x >= y ); break; case cmNEQ: resTok.SetVal( x != y ); break; case cmEQ: resTok.SetVal( x == y ); break; case cmADD: resTok.SetVal( x + y ); break; case cmSUB: resTok.SetVal( x - y ); break; case cmMUL: resTok.SetVal( x * y ); break; case cmDIV: #if defined(MUP_MATH_EXCEPTIONS) if (y==0) { Error(ecDIV_BY_ZERO); } #endif resTok.SetVal( x / y ); break; case cmPOW: resTok.SetVal(pow(x, y)); break; case cmASSIGN: // The assignement operator needs special treatment // it uses a different format when stored in the bytecode! { if (valTok2.GetCode()!=cmVAR) Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); // // The Assignment does no longer take place in the string parsing step. This would // change the variable value when performing lazy evaluation of if-then-else clauses. // Consequently the numerical result from the string parsing step maybe incorrect in such // cases. This is not a problem it is discarded anyway! // Problem case: "0? a=10:0,a" -> Would return 10 instead of 0 which is incorrect! // value_type *pVar = valTok2.GetVar(); resTok.SetVal( /*pVar =*/ y ); resTok.AddFlags(token_type::flVOLATILE); a_stVal.push( resTok ); m_vRPN.AddAssignOp(pVar); return; // we must return since the following // stuff does not apply } default: Error(ecINTERNAL_ERROR, 8); } // Create the bytecode entries if (!m_bOptimize) { // Optimization flag is not set m_vRPN.AddOp(optTok.GetCode()); } else if ( valTok1.IsFlagSet(token_type::flVOLATILE) || valTok2.IsFlagSet(token_type::flVOLATILE) ) { // Optimization flag is not set, but one of the value // depends on a variable m_vRPN.AddOp(optTok.GetCode()); resTok.AddFlags(token_type::flVOLATILE); } else { // operator call can be optimized; If optimization is possible // the two previous tokens must be value tokens / they will be removed // and replaced with the result of the pending operation. m_vRPN.RemoveValEntries(2); m_vRPN.AddVal(resTok.GetVal()); } a_stVal.push( resTok ); } } } //--------------------------------------------------------------------------- /** \brief Apply a binary operator. \param a_stOpt The operator stack \param a_stVal The value stack */ void ParserBase::ApplyRemainingOprt(ParserStack &stOpt, ParserStack &stVal) const { while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) { token_type tok = stOpt.top(); switch (tok.GetCode()) { case cmOPRT_INFIX: case cmOPRT_BIN: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmLT: case cmGT: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: //case cmAND: //case cmOR: //case cmXOR: case cmLAND: case cmLOR: case cmASSIGN: ApplyBinOprt(stOpt, stVal); break; case cmELSE: ApplyIfElse(stOpt, stVal); break; default: Error(ecINTERNAL_ERROR); } } } //--------------------------------------------------------------------------- /** \brief Parse the command code. \sa ParseString(...) Command code contains precalculated stack positions of the values and the associated operators. The Stack is filled beginning from index one the value at index zero is not used at all. */ value_type ParserBase::ParseCmdCode() const { return ParseCmdCodeBulk(0, 0); } //--------------------------------------------------------------------------- /** \brief Custum Pow function with optimization if the power is an integer value. */ value_type ParserBase::Pow(value_type v1, value_type v2) { int v2i = (int)v2; if (v2==v2i) { switch(v2i) { case 0: return 1; case 1: return v1; case 2: return v1*v1; case 3: return v1*v1*v1; case 4: return v1*v1*v1*v1; case 5: return v1*v1*v1*v1*v1; default: return std::pow(v1, v2i); } } else return std::pow(v1, v2); } //--------------------------------------------------------------------------- /** \brief Evaluate the RPN. \param nOffset The offset added to variable addresses (for bulk mode) \param nThreadID OpenMP Thread id of the calling thread */ value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const { assert(nThreadID<=s_MaxNumOpenMPThreads); value_type *Stack = &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; int sidx(0); for (const SToken *pTok = m_pRPN; ; ++pTok) { switch (pTok->Cmd) { // built in binary operators case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue; case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue; case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue; case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue; case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue; case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue; case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue; case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue; case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue; case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue; case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue; case cmDIV: --sidx; #if defined(MUP_MATH_EXCEPTIONS) if (Stack[1+sidx]==0) Error(ecDIV_BY_ZERO); #endif Stack[sidx] /= Stack[1+sidx]; continue; case cmPOW: { --sidx; Stack[sidx] = ParserBase::Pow(Stack[sidx], Stack[1+sidx]); continue; } case cmASSIGN: --sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; case cmIF: if (Stack[sidx--]==0) pTok += pTok->Oprt.offset; continue; case cmELSE: pTok += pTok->Oprt.offset; continue; case cmENDIF: continue; // value and variable tokens case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue; case cmVAL: Stack[++sidx] = pTok->Val.data; continue; // Next is treatment of string functions case cmFUNC_STR: { sidx -= pTok->Fun.argc -1; // The index of the string argument in the string table int iIdxStack = pTok->Fun.idx; MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); switch(pTok->Fun.argc) // switch according to argument count { case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue; case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue; case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue; } continue; } // Next is treatment of numeric functions case cmFUNC: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch(iArgCount) { case 0: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue; case 1: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue; case 2: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue; case 3: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; case 4: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; case 5: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; case 6: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; case 7: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; case 8: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; case 9: sidx -= iArgCount -1; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; case 10:sidx -= iArgCount -1; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; default: if (iArgCount>0) // function with variable arguments store the number as a negative value Error(ecINTERNAL_ERROR, 1); sidx -= -iArgCount - 1; Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount); continue; } } case cmFUNC_BULK: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch(iArgCount) { case 0: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue; case 1: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue; case 2: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue; case 3: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; case 4: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; case 5: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; case 6: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; case 7: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type7 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; case 8: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type8 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; case 9: sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type9 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; case 10:sidx -= iArgCount -1; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; default: Error(ecINTERNAL_ERROR, 2); continue; } } case cmEND: return Stack[m_nFinalResultIdx]; default: Error(ecINTERNAL_ERROR, 3); return 0; } // switch CmdCode } } //--------------------------------------------------------------------------- void ParserBase::CreateRPN() const { if (!m_pTokenReader->GetExpr().length()) Error(ecUNEXPECTED_EOF, 0); ParserStack stOpt, stVal; ParserStack stArgCount; token_type opta, opt; // for storing operators token_type val, tval; // for storing value string_type strBuf; // buffer for string function arguments ReInit(); // The outermost counter counts the number of seperated items // such as in "a=10,b=20,c=c+a" stArgCount.push(1); for(;;) { opt = m_pTokenReader->ReadNextToken(); switch (opt.GetCode()) { // // Next three are different kind of value entries // case cmSTRING: opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token stVal.push(opt); m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer break; case cmVAR: stVal.push(opt); m_vRPN.AddVar( static_cast(opt.GetVar()) ); break; case cmVAL: stVal.push(opt); m_vRPN.AddVal( opt.GetVal() ); break; case cmELSE: m_nIfElseCounter--; if (m_nIfElseCounter<0) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); ApplyRemainingOprt(stOpt, stVal); m_vRPN.AddIfElse(cmELSE); stOpt.push(opt); break; case cmARG_SEP: if (stArgCount.empty()) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); ++stArgCount.top(); // fallthrough intentional (no break!) case cmEND: ApplyRemainingOprt(stOpt, stVal); break; case cmBC: { // The argument count for parameterless functions is zero // by default an opening bracket sets parameter count to 1 // in preparation of arguments to come. If the last token // was an opening bracket we know better... if (opta.GetCode()==cmBO) --stArgCount.top(); ApplyRemainingOprt(stOpt, stVal); // Check if the bracket content has been evaluated completely if (stOpt.size() && stOpt.top().GetCode()==cmBO) { // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check // if there is either a function or a sign pending // neither the opening nor the closing bracket will be pushed back to // the operator stack // Check if a function is standing in front of the opening bracket, // if yes evaluate it afterwards check for infix operators assert(stArgCount.size()); int iArgCount = stArgCount.pop(); stOpt.pop(); // Take opening bracket from stack if (iArgCount>1 && ( stOpt.size()==0 || (stOpt.top().GetCode()!=cmFUNC && stOpt.top().GetCode()!=cmFUNC_BULK && stOpt.top().GetCode()!=cmFUNC_STR) ) ) Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); // The opening bracket was popped from the stack now check if there // was a function before this bracket if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX && stOpt.top().GetCode()!=cmOPRT_BIN && stOpt.top().GetFuncAddr()!=0) { ApplyFunc(stOpt, stVal, iArgCount); } } } // if bracket content is evaluated break; // // Next are the binary operator entries // //case cmAND: // built in binary operators //case cmOR: //case cmXOR: case cmIF: m_nIfElseCounter++; // fallthrough intentional (no break!) case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: case cmOPRT_BIN: // A binary operator (user defined or built in) has been found. while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && stOpt.top().GetCode() != cmIF) { int nPrec1 = GetOprtPrecedence(stOpt.top()), nPrec2 = GetOprtPrecedence(opt); if (stOpt.top().GetCode()==opt.GetCode()) { // Deal with operator associativity EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) { break; } } else if (nPrec1 < nPrec2) { // In case the operators are not equal the precedence decides alone... break; } ApplyBinOprt(stOpt, stVal); } // while ( ... ) if (opt.GetCode()==cmIF) m_vRPN.AddIfElse(opt.GetCode()); // The operator can't be evaluated right now, push back to the operator stack stOpt.push(opt); break; // // Last section contains functions and operators implicitely mapped to functions // case cmBO: stArgCount.push(1); stOpt.push(opt); break; case cmOPRT_INFIX: case cmFUNC: case cmFUNC_BULK: case cmFUNC_STR: stOpt.push(opt); break; case cmOPRT_POSTFIX: stOpt.push(opt); ApplyFunc(stOpt, stVal, 1); // this is the postfix operator break; default: Error(ecINTERNAL_ERROR, 3); } // end of switch operator-token opta = opt; if ( opt.GetCode() == cmEND ) { m_vRPN.Finalize(); break; } if (ParserBase::g_DbgDumpStack) { StackDump(stVal, stOpt); m_vRPN.AsciiDump(); } } // while (true) // Store pointer to start of bytecode m_pRPN = m_vRPN.GetBase(); if (ParserBase::g_DbgDumpCmdCode) { m_vRPN.AsciiDump(); } if (m_nIfElseCounter>0) Error(ecMISSING_ELSE_CLAUSE); // get the last value (= final result) from the stack MUP_ASSERT(stArgCount.size()==1); m_nFinalResultIdx = stArgCount.top(); if (m_nFinalResultIdx==0) Error(ecINTERNAL_ERROR, 9); if (stVal.size()==0) Error(ecEMPTY_EXPRESSION); if (stVal.top().GetType()!=tpDBL) Error(ecSTR_RESULT); m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); } //--------------------------------------------------------------------------- /** \brief One of the two main parse functions. \sa ParseCmdCode(...) Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing. */ value_type ParserBase::ParseString() const { CreateRPN(); m_pParseFormula = &ParserBase::ParseCmdCode; return (this->*m_pParseFormula)(); } //--------------------------------------------------------------------------- /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws thats the only purpose of this function. */ void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const { throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); } //------------------------------------------------------------------------------ /** \brief Clear all user defined variables. \throw nothrow Resets the parser to string parsing mode by calling #ReInit. */ void ParserBase::ClearVar() { m_VarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Remove a variable from internal storage. \throw nothrow Removes a variable if it exists. If the Variable does not exist nothing will be done. */ void ParserBase::RemoveVar(const string_type &a_strVarName) { varmap_type::iterator item = m_VarDef.find(a_strVarName); if (item!=m_VarDef.end()) { m_VarDef.erase(item); ReInit(); } } //------------------------------------------------------------------------------ /** \brief Clear all functions. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearFun() { m_FunDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined constants. Both numeric and string constants will be removed from the internal storage. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearConst() { m_ConstDef.clear(); m_StrVarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined postfix operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearPostfixOprt() { m_PostOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined binary operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearOprt() { m_OprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear the user defined Prefix operators. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::ClearInfixOprt() { m_InfixOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Enable or disable the formula optimization feature. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::EnableOptimizer(bool a_bIsOn) { m_bOptimize = a_bIsOn; ReInit(); } //--------------------------------------------------------------------------- /** \brief Enable the dumping of bytecode amd stack content on the console. \param bDumpCmd Flag to enable dumping of the current bytecode to the console. \param bDumpStack Flag to enable dumping of the stack content is written to the console. This function is for debug purposes only! */ void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) { ParserBase::g_DbgDumpCmdCode = bDumpCmd; ParserBase::g_DbgDumpStack = bDumpStack; } //------------------------------------------------------------------------------ /** \brief Enable or disable the built in binary operators. \throw nothrow \sa m_bBuiltInOp, ReInit() If you disable the built in binary operators there will be no binary operators defined. Thus you must add them manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize the parser by calling ReInit(). */ void ParserBase::EnableBuiltInOprt(bool a_bIsOn) { m_bBuiltInOp = a_bIsOn; ReInit(); } //------------------------------------------------------------------------------ /** \brief Query status of built in variables. \return #m_bBuiltInOp; true if built in operators are enabled. \throw nothrow */ bool ParserBase::HasBuiltInOprt() const { return m_bBuiltInOp; } //------------------------------------------------------------------------------ /** \brief Get the argument separator character. */ char_type ParserBase::GetArgSep() const { return m_pTokenReader->GetArgSep(); } //------------------------------------------------------------------------------ /** \brief Set argument separator. \param cArgSep the argument separator character. */ void ParserBase::SetArgSep(char_type cArgSep) { m_pTokenReader->SetArgSep(cArgSep); } //------------------------------------------------------------------------------ /** \brief Dump stack content. This function is used for debugging only. */ void ParserBase::StackDump(const ParserStack &a_stVal, const ParserStack &a_stOprt) const { ParserStack stOprt(a_stOprt), stVal(a_stVal); mu::console() << _T("\nValue stack:\n"); while ( !stVal.empty() ) { token_type val = stVal.pop(); if (val.GetType()==tpSTR) mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); else mu::console() << _T(" ") << val.GetVal() << _T(" "); } mu::console() << "\nOperator stack:\n"; while ( !stOprt.empty() ) { if (stOprt.top().GetCode()<=cmASSIGN) { mu::console() << _T("OPRT_INTRNL \"") << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] << _T("\" \n"); } else { switch(stOprt.top().GetCode()) { case cmVAR: mu::console() << _T("VAR\n"); break; case cmVAL: mu::console() << _T("VAL\n"); break; case cmFUNC: mu::console() << _T("FUNC \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; case cmEND: mu::console() << _T("END\n"); break; case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; case cmIF: mu::console() << _T("IF\n"); break; case cmELSE: mu::console() << _T("ELSE\n"); break; case cmENDIF: mu::console() << _T("ENDIF\n"); break; default: mu::console() << stOprt.top().GetCode() << _T(" "); break; } } stOprt.pop(); } mu::console() << dec << endl; } //------------------------------------------------------------------------------ /** \brief Evaluate an expression containing comma seperated subexpressions \param [out] nStackSize The total number of results available \return Pointer to the array containing all expression results This member function can be used to retriev all results of an expression made up of multiple comma seperated subexpressions (i.e. "x+y,sin(x),cos(y)") */ value_type* ParserBase::Eval(int &nStackSize) const { (this->*m_pParseFormula)(); nStackSize = m_nFinalResultIdx; // (for historic reasons the stack starts at position 1) return &m_vStackBuffer[1]; } //--------------------------------------------------------------------------- /** \brief Return the number of results on the calculation stack. If the expression contains comma seperated subexpressions (i.e. "sin(y), x+y"). There mey be more than one return value. This function returns the number of available results. */ int ParserBase::GetNumResults() const { return m_nFinalResultIdx; } //--------------------------------------------------------------------------- /** \brief Calculate the result. A note on const correctness: I consider it important that Calc is a const function. Due to caching operations Calc changes only the state of internal variables with one exception m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update. \pre A formula must be set. \pre Variables must have been set (if needed) \sa #m_pParseFormula \return The evaluation result \throw ParseException if no Formula is set or in case of any other error related to the formula. */ value_type ParserBase::Eval() const { return (this->*m_pParseFormula)(); } //--------------------------------------------------------------------------- void ParserBase::Eval(value_type *results, int nBulkSize) { CreateRPN(); int i = 0; #ifdef MUP_USE_OPENMP //#define DEBUG_OMP_STUFF #ifdef DEBUG_OMP_STUFF int *pThread = new int[nBulkSize]; int *pIdx = new int[nBulkSize]; #endif int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); int nThreadID, ct=0; omp_set_num_threads(nMaxThreads); #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) for (i=0; i \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserBytecode.h" #include #include #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" #include "muParserStack.h" /** \file \brief Implementation of the parser bytecode class. */ namespace mu { //--------------------------------------------------------------------------- /** \brief Bytecode default constructor. */ ParserByteCode::ParserByteCode() :m_iStackPos(0) ,m_iMaxStackSize(0) ,m_vRPN() { m_vRPN.reserve(50); } //--------------------------------------------------------------------------- /** \brief Copy constructor. Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) */ ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode) { Assign(a_ByteCode); } //--------------------------------------------------------------------------- /** \brief Assignment operator. Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) */ ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode) { Assign(a_ByteCode); return *this; } //--------------------------------------------------------------------------- /** \brief Copy state of another object to this. \throw nowthrow */ void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) { if (this==&a_ByteCode) return; m_iStackPos = a_ByteCode.m_iStackPos; m_vRPN = a_ByteCode.m_vRPN; m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; } //--------------------------------------------------------------------------- /** \brief Add a Variable pointer to bytecode. \param a_pVar Pointer to be added. \throw nothrow */ void ParserByteCode::AddVar(value_type *a_pVar) { ++m_iStackPos; SToken tok; tok.Cmd = cmVAR; tok.Val.ptr = a_pVar; m_vRPN.push_back(tok); m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); } //--------------------------------------------------------------------------- /** \brief Add a Variable pointer to bytecode. Value entries in byte code consist of:
  • value array position of the value
  • the operator code according to ParserToken::cmVAL
  • the value stored in #mc_iSizeVal number of bytecode entries.
\param a_pVal Value to be added. \throw nothrow */ void ParserByteCode::AddVal(value_type a_fVal) { ++m_iStackPos; SToken tok; tok.Cmd = cmVAL; tok.Val.data = a_fVal; m_vRPN.push_back(tok); m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); } //--------------------------------------------------------------------------- /** \brief Add an operator identifier to bytecode. Operator entries in byte code consist of:
  • value array position of the result
  • the operator code according to ParserToken::ECmdCode
\sa ParserToken::ECmdCode */ void ParserByteCode::AddOp(ECmdCode a_Oprt) { --m_iStackPos; SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); /* Testcode fr RPN optimierung. Ist zwar funktionsfhig, wird aber derzeit nicht verwendet. (pat hier nicht richtig rein...) std::size_t sz = m_vRPN.size(); // reorder RPN to make optimization easier // Problemflle: // 1+sin(a)+2 // 1+(2+a) // (a+2)+2 // 1+sin(a)+cos(a)+2 switch(a_Oprt) { case cmADD: if (sz>=3 && m_vRPN[sz-2].Cmd==cmVAL && m_vRPN[sz-3].Cmd==cmVAL) { m_vRPN[sz-3].Val.data += m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } else if ( sz>=4 && m_vRPN[sz-2].Cmd==cmVAL && (m_vRPN[sz-3].Cmd==cmADD || m_vRPN[sz-3].Cmd==cmSUB) && m_vRPN[sz-4].Cmd==cmVAR && m_vRPN[sz-5].Cmd==cmVAL) { m_vRPN[sz-5].Val.data += m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } break; case cmSUB: if (sz>=3 && m_vRPN[sz-2].Cmd==cmVAL && m_vRPN[sz-3].Cmd==cmVAL) { m_vRPN[sz-3].Val.data -= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } else if ( sz>=4 && m_vRPN[sz-2].Cmd==cmVAL && (m_vRPN[sz-3].Cmd==cmADD || m_vRPN[sz-3].Cmd==cmSUB) && m_vRPN[sz-4].Cmd==cmVAR && m_vRPN[sz-5].Cmd==cmVAL) { m_vRPN[sz-5].Val.data -= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } break; case cmMUL: if (sz>=3 && m_vRPN[sz-2].Cmd==cmVAL && m_vRPN[sz-3].Cmd==cmVAL) { m_vRPN[sz-3].Val.data *= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } else if ( sz>=4 && m_vRPN[sz-2].Cmd==cmVAL && (m_vRPN[sz-3].Cmd==cmMUL || m_vRPN[sz-3].Cmd==cmDIV) && m_vRPN[sz-4].Cmd==cmVAR && m_vRPN[sz-5].Cmd==cmVAL) { m_vRPN[sz-5].Val.data *= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } break; case cmDIV: if (sz>=3 && m_vRPN[sz-2].Cmd==cmVAL && m_vRPN[sz-3].Cmd==cmVAL) { m_vRPN[sz-3].Val.data /= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } else if ( sz>=4 && m_vRPN[sz-2].Cmd==cmVAL && (m_vRPN[sz-3].Cmd==cmMUL || m_vRPN[sz-3].Cmd==cmDIV) && m_vRPN[sz-4].Cmd==cmVAR && m_vRPN[sz-5].Cmd==cmVAL) { m_vRPN[sz-5].Val.data /= m_vRPN[sz-2].Val.data; m_vRPN.pop_back(); m_vRPN.pop_back(); m_iStackPos++; } break; } */ } //--------------------------------------------------------------------------- void ParserByteCode::AddIfElse(ECmdCode a_Oprt) { SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add an assignement operator Operator entries in byte code consist of:
  • cmASSIGN code
  • the pointer of the destination variable
\sa ParserToken::ECmdCode */ void ParserByteCode::AddAssignOp(value_type *a_pVar) { --m_iStackPos; SToken tok; tok.Cmd = cmASSIGN; tok.Val.ptr = a_pVar; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddFun(void *a_pFun, int a_iArgc) { if (a_iArgc>=0) { m_iStackPos = m_iStackPos - a_iArgc + 1; } else { m_iStackPos = m_iStackPos + a_iArgc + 1; } m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); SToken tok; tok.Cmd = cmFUNC; tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add a bulk function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddBulkFun(void *a_pFun, int a_iArgc) { m_iStackPos = m_iStackPos - a_iArgc + 1; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); SToken tok; tok.Cmd = cmFUNC_BULK; tok.Fun.argc = a_iArgc; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); } //--------------------------------------------------------------------------- /** \brief Add Strung function entry to the parser bytecode. \throw nothrow A string function entry consists of the stack position of the return value, followed by a cmSTRFUNC code, the function pointer and an index into the string buffer maintained by the parser. */ void ParserByteCode::AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx) { m_iStackPos = m_iStackPos - a_iArgc + 1; SToken tok; tok.Cmd = cmFUNC_STR; tok.Fun.argc = a_iArgc; tok.Fun.idx = a_iIdx; tok.Fun.ptr = a_pFun; m_vRPN.push_back(tok); m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); } //--------------------------------------------------------------------------- /** \brief Add end marker to bytecode. \throw nothrow */ void ParserByteCode::Finalize() { SToken tok; tok.Cmd = cmEND; m_vRPN.push_back(tok); rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit // Determine the if-then-else jump offsets ParserStack stIf, stElse; int idx; for (int i=0; i<(int)m_vRPN.size(); ++i) { switch(m_vRPN[i].Cmd) { case cmIF: stIf.push(i); break; case cmELSE: stElse.push(i); idx = stIf.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; case cmENDIF: idx = stElse.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; } } } //--------------------------------------------------------------------------- const SToken* ParserByteCode::GetBase() const { if (m_vRPN.size()==0) throw ParserError(ecINTERNAL_ERROR); else return &m_vRPN[0]; } //--------------------------------------------------------------------------- std::size_t ParserByteCode::GetMaxStackSize() const { return m_iMaxStackSize+1; } //--------------------------------------------------------------------------- /** \brief Delete the bytecode. \throw nothrow The name of this function is a violation of my own coding guidelines but this way it's more in line with the STL functions thus more intuitive. */ void ParserByteCode::clear() { m_vRPN.clear(); m_iStackPos = 0; m_iMaxStackSize = 0; } //--------------------------------------------------------------------------- /** \brief Remove a value number of entries from the bytecode. \attention Currently I don't test if the entries are really value entries. */ void ParserByteCode::RemoveValEntries(unsigned a_iNumber) { assert(m_iStackPos >= a_iNumber); m_vRPN.resize(m_vRPN.size()-a_iNumber); m_iStackPos -= (a_iNumber); } //--------------------------------------------------------------------------- /** \brief Dump bytecode (for debugging only!). */ void ParserByteCode::AsciiDump() { if (!m_vRPN.size()) { mu::console() << _T("No bytecode available\n"); return; } mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n"); for (std::size_t i=0; i \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserCallback.h" /** \file \brief Implementation of the parser callback class. */ namespace mu { //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(a_iPrec) ,m_eOprtAsct(oaNONE) ,m_iCode(a_iCode) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing funcstion callbacks taking two arguments. \throw nothrow */ ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing binary operator callbacks. \param a_pFun Pointer to a static function taking two arguments \param a_bAllowOpti A flag indicating this funcation can be optimized \param a_iPrec The operator precedence \param a_eOprtAsct The operators associativity \throw nothrow */ ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eOprtAsct) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(a_iPrec) ,m_eOprtAsct(a_eOprtAsct) ,m_iCode(cmOPRT_BIN) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(3) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(4) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(5) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(6) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(7) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(8) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(9) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(10) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Constructor for constructing funcstion callbacks taking two arguments. \throw nothrow */ ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(3) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(4) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(5) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(6) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(7) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(8) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(9) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(10) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_BULK) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(-1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC) ,m_iType(tpDBL) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(1) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) ,m_iArgc(2) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmFUNC_STR) ,m_iType(tpSTR) ,m_bAllowOpti(a_bAllowOpti) {} //--------------------------------------------------------------------------- /** \brief Default constructor. \throw nothrow */ ParserCallback::ParserCallback() :m_pFun(0) ,m_iArgc(0) ,m_iPri(-1) ,m_eOprtAsct(oaNONE) ,m_iCode(cmUNKNOWN) ,m_iType(tpVOID) ,m_bAllowOpti(0) {} //--------------------------------------------------------------------------- /** \brief Copy constructor. \throw nothrow */ ParserCallback::ParserCallback(const ParserCallback &ref) { m_pFun = ref.m_pFun; m_iArgc = ref.m_iArgc; m_bAllowOpti = ref.m_bAllowOpti; m_iCode = ref.m_iCode; m_iType = ref.m_iType; m_iPri = ref.m_iPri; m_eOprtAsct = ref.m_eOprtAsct; } //--------------------------------------------------------------------------- /** \brief Clone this instance and return a pointer to the new instance. */ ParserCallback* ParserCallback::Clone() const { return new ParserCallback(*this); } //--------------------------------------------------------------------------- /** \brief Return tru if the function is conservative. Conservative functions return always the same result for the same argument. \throw nothrow */ bool ParserCallback::IsOptimizable() const { return m_bAllowOpti; } //--------------------------------------------------------------------------- /** \brief Get the callback address for the parser function. The type of the address is void. It needs to be recasted according to the argument number to the right type. \throw nothrow \return #pFun */ void* ParserCallback::GetAddr() const { return m_pFun; } //--------------------------------------------------------------------------- /** \brief Return the callback code. */ ECmdCode ParserCallback::GetCode() const { return m_iCode; } //--------------------------------------------------------------------------- ETypeCode ParserCallback::GetType() const { return m_iType; } //--------------------------------------------------------------------------- /** \brief Return the operator precedence. \throw nothrown Only valid if the callback token is an operator token (binary or infix). */ int ParserCallback::GetPri() const { return m_iPri; } //--------------------------------------------------------------------------- /** \brief Return the operators associativity. \throw nothrown Only valid if the callback token is a binary operator token. */ EOprtAssociativity ParserCallback::GetAssociativity() const { return m_eOprtAsct; } //--------------------------------------------------------------------------- /** \brief Returns the number of function Arguments. */ int ParserCallback::GetArgc() const { return m_iArgc; } } // namespace mu repsnapper-2.3.2a5/libraries/amf/amftools-code/src/muparser/muParserError.cpp000066400000000000000000000322361231531733200273450ustar00rootroot00000000000000/* __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "muParserError.h" namespace mu { const ParserErrorMsg ParserErrorMsg::m_Instance; //------------------------------------------------------------------------------ const ParserErrorMsg& ParserErrorMsg::Instance() { return m_Instance; } //------------------------------------------------------------------------------ string_type ParserErrorMsg::operator[](unsigned a_iIdx) const { return (a_iIdx \___ >|__| \/ \/ \/ \/ Copyright (C) 2011 Ingo Berg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include "muParserTokenReader.h" #include "muParserBase.h" /** \file \brief This file contains the parser token reader implementation. */ namespace mu { // Forward declaration class ParserBase; //--------------------------------------------------------------------------- /** \brief Copy constructor. \sa Assign \throw nothrow */ ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) { Assign(a_Reader); } //--------------------------------------------------------------------------- /** \brief Assignement operator. Self assignement will be suppressed otherwise #Assign is called. \param a_Reader Object to copy to this token reader. \throw nothrow */ ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) { if (&a_Reader!=this) Assign(a_Reader); return *this; } //--------------------------------------------------------------------------- /** \brief Assign state of a token reader to this token reader. \param a_Reader Object from which the state should be copied. \throw nothrow */ void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) { m_pParser = a_Reader.m_pParser; m_strFormula = a_Reader.m_strFormula; m_iPos = a_Reader.m_iPos; m_iSynFlags = a_Reader.m_iSynFlags; m_UsedVar = a_Reader.m_UsedVar; m_pFunDef = a_Reader.m_pFunDef; m_pConstDef = a_Reader.m_pConstDef; m_pVarDef = a_Reader.m_pVarDef; m_pStrVarDef = a_Reader.m_pStrVarDef; m_pPostOprtDef = a_Reader.m_pPostOprtDef; m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; m_pOprtDef = a_Reader.m_pOprtDef; m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; m_vIdentFun = a_Reader.m_vIdentFun; m_pFactory = a_Reader.m_pFactory; m_pFactoryData = a_Reader.m_pFactoryData; m_iBrackets = a_Reader.m_iBrackets; m_cArgSep = a_Reader.m_cArgSep; } //--------------------------------------------------------------------------- /** \brief Constructor. Create a Token reader and bind it to a parser object. \pre [assert] a_pParser may not be NULL \post #m_pParser==a_pParser \param a_pParent Parent parser object of the token reader. */ ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) :m_pParser(a_pParent) ,m_strFormula() ,m_iPos(0) ,m_iSynFlags(0) ,m_bIgnoreUndefVar(false) ,m_pFunDef(NULL) ,m_pPostOprtDef(NULL) ,m_pInfixOprtDef(NULL) ,m_pOprtDef(NULL) ,m_pConstDef(NULL) ,m_pStrVarDef(NULL) ,m_pVarDef(NULL) ,m_pFactory(NULL) ,m_pFactoryData(NULL) ,m_vIdentFun() ,m_UsedVar() ,m_fZero(0) ,m_iBrackets(0) ,m_lastTok() ,m_cArgSep(',') { assert(m_pParser); SetParent(m_pParser); } //--------------------------------------------------------------------------- /** \brief Create instance of a ParserTokenReader identical with this and return its pointer. This is a factory method the calling function must take care of the object destruction. \return A new ParserTokenReader object. \throw nothrow */ ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const { std::auto_ptr ptr(new ParserTokenReader(*this)); ptr->SetParent(a_pParent); return ptr.release(); } //--------------------------------------------------------------------------- ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok) { m_lastTok = tok; return m_lastTok; } //--------------------------------------------------------------------------- void ParserTokenReader::AddValIdent(identfun_type a_pCallback) { m_vIdentFun.push_back(a_pCallback); } //--------------------------------------------------------------------------- void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) { m_pFactory = a_pFactory; m_pFactoryData = pUserData; } //--------------------------------------------------------------------------- /** \brief Return the current position of the token reader in the formula string. \return #m_iPos \throw nothrow */ int ParserTokenReader::GetPos() const { return m_iPos; } //--------------------------------------------------------------------------- /** \brief Return a reference to the formula. \return #m_strFormula \throw nothrow */ const string_type& ParserTokenReader::GetExpr() const { return m_strFormula; } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ varmap_type& ParserTokenReader::GetUsedVar() { return m_UsedVar; } //--------------------------------------------------------------------------- /** \brief Initialize the token Reader. Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. \pre [assert] triggered if a_szFormula==0 */ void ParserTokenReader::SetFormula(const string_type &a_strFormula) { m_strFormula = a_strFormula; ReInit(); } //--------------------------------------------------------------------------- /** \brief Set Flag that contronls behaviour in case of undefined variables beeing found. If true, the parser does not throw an exception if an undefined variable is found. otherwise it does. This variable is used internally only! It supresses a "undefined variable" exception in GetUsedVar(). Those function should return a complete list of variables including those the are not defined by the time of it's call. */ void ParserTokenReader::IgnoreUndefVar(bool bIgnore) { m_bIgnoreUndefVar = bIgnore; } //--------------------------------------------------------------------------- /** \brief Reset the token reader to the start of the formula. The syntax flags will be reset to a value appropriate for the start of a formula. \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR \throw nothrow \sa ESynCodes */ void ParserTokenReader::ReInit() { m_iPos = 0; m_iSynFlags = sfSTART_OF_LINE; m_iBrackets = 0; m_UsedVar.clear(); m_lastTok = token_type(); } //--------------------------------------------------------------------------- /** \brief Read the next token from the string. */ ParserTokenReader::token_type ParserTokenReader::ReadNextToken() { assert(m_pParser); std::stack FunArgs; const char_type *szFormula = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) ++m_iPos; if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if // undefined variables occur. // (The GetUsedVar function must suppress the error for // undefined variables in order to collect all variable // names including the undefined ones.) if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return SaveBeforeReturn(tok); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached } //--------------------------------------------------------------------------- void ParserTokenReader::SetParent(ParserBase *a_pParent) { m_pParser = a_pParent; m_pFunDef = &a_pParent->m_FunDef; m_pOprtDef = &a_pParent->m_OprtDef; m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; m_pPostOprtDef = &a_pParent->m_PostOprtDef; m_pVarDef = &a_pParent->m_VarDef; m_pStrVarDef = &a_pParent->m_StrVarDef; m_pConstDef = &a_pParent->m_ConstDef; } //--------------------------------------------------------------------------- /** \brief Extract all characters that belong to a certain charset. \param a_szCharSet [in] Const char array of the characters allowed in the token. \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. \param a_iPos [in] Position in the string from where to start reading. \return The Position of the first character not listed in a_szCharSet. \throw nothrow */ int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, string_type &a_sTok, int a_iPos) const { int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); if (iEnd==(int)string_type::npos) iEnd = (int)m_strFormula.length(); // Assign token string if there was something found if (a_iPos!=iEnd) a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); return iEnd; } //--------------------------------------------------------------------------- /** \brief Check Expression for the presence of a binary operator token. Userdefined binary operator "++" gives inconsistent parsing result for the equations "a++b" and "a ++ b" if alphabetic characters are allowed in operator tokens. To avoid this this function checks specifically for operator tokens. */ int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, int a_iPos) const { int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidInfixOprtChars(), a_iPos); if (iEnd==(int)string_type::npos) iEnd = (int)m_strFormula.length(); // Assign token string if there was something found if (a_iPos!=iEnd) { a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return iEnd; } else { // There is still the chance of having to deal with an operator consisting exclusively // of alphabetic characters. return ExtractToken(MUP_CHARS, a_sTok, a_iPos); } } //--------------------------------------------------------------------------- /** \brief Check if a built in operator or other token can be found \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) { const char_type **const pOprtDef = m_pParser->GetOprtDef(), *const szFormula = m_strFormula.c_str(); // Compare token with function and operator strings // check string for operator/function for (int i=0; pOprtDef[i]; i++) { std::size_t len( std::char_traits::length(pOprtDef[i]) ); if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) { switch(i) { //case cmAND: //case cmOR: //case cmXOR: case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: //if (len!=sTok.length()) // continue; // The assignement operator need special treatment if (i==cmASSIGN && m_iSynFlags & noASSIGN) Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); if (!m_pParser->HasBuiltInOprt()) continue; if (m_iSynFlags & noOPT) { // Maybe its an infix operator not an operator // Both operator types can share characters in // their identifiers if ( IsInfixOpTok(a_Tok) ) return true; Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); } m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0; break; case cmBO: if (m_iSynFlags & noBO) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); if (m_lastTok.GetCode()==cmFUNC) m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; else m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; ++m_iBrackets; break; case cmBC: if (m_iSynFlags & noBC) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; if (--m_iBrackets<0) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); break; case cmELSE: if (m_iSynFlags & noELSE) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; case cmIF: if (m_iSynFlags & noIF) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; break; default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... Error(ecINTERNAL_ERROR); } // switch operator id m_iPos += (int)len; a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); return true; } // if operator string found } // end of for all operator strings return false; } //--------------------------------------------------------------------------- bool ParserTokenReader::IsArgSep(token_type &a_Tok) { const char_type* szFormula = m_strFormula.c_str(); if (szFormula[m_iPos]==m_cArgSep) { // copy the separator into null terminated string char_type szSep[2]; szSep[0] = m_cArgSep; szSep[1] = 0; if (m_iSynFlags & noARG_SEP) Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; m_iPos++; a_Tok.Set(cmARG_SEP, szSep); return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check for End of Formula. \return true if an end of formula is found false otherwise. \param a_Tok [out] If an eof is found the corresponding token will be stored there. \throw nothrow \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok */ bool ParserTokenReader::IsEOF(token_type &a_Tok) { const char_type* szFormula = m_strFormula.c_str(); // check for EOF if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) { if ( m_iSynFlags & noEND ) Error(ecUNEXPECTED_EOF, m_iPos); if (m_iBrackets>0) Error(ecMISSING_PARENS, m_iPos, _T(")")); m_iSynFlags = 0; a_Tok.Set(cmEND); return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) { string_type sTok; int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; funmap_type::const_iterator item = m_pInfixOprtDef->find(sTok); if (item==m_pInfixOprtDef->end()) return false; a_Tok.Set(item->second, sTok); m_iPos = (int)iEnd; if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; } //--------------------------------------------------------------------------- /** \brief Check whether the token at a given position is a function token. \param a_Tok [out] If a value token is found it will be placed here. \throw ParserException if Syntaxflags do not allow a function at a_iPos \return true if a function token has been found false otherwise. \pre [assert] m_pParser!=0 */ bool ParserTokenReader::IsFunTok(token_type &a_Tok) { string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; funmap_type::const_iterator item = m_pFunDef->find(strTok); if (item==m_pFunDef->end()) return false; // Check if the next sign is an opening bracket const char_type *szFormula = m_strFormula.c_str(); if (szFormula[iEnd]!='(') return false; a_Tok.Set(item->second, strTok); m_iPos = (int)iEnd; if (m_iSynFlags & noFUN) Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); m_iSynFlags = noANY ^ noBO; return true; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a binary operator. \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsOprt(token_type &a_Tok) { const char_type *const szExpr = m_strFormula.c_str(); string_type strTok; int iEnd = ExtractOperatorToken(strTok, m_iPos); if (iEnd==m_iPos) return false; // Check if the operator is a built in operator, if so ignore it here const char_type **const pOprtDef = m_pParser->GetOprtDef(); for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) { if (string_type(pOprtDef[i])==strTok) return false; } // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); for ( ; it!=m_pOprtDef->rend(); ++it) { const string_type &sID = it->first; if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) { a_Tok.Set(it->second, strTok); // operator was found if (m_iSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can share characters in their identifiers. if ( IsInfixOpTok(a_Tok) ) return true; else { // nope, no infix operator return false; //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); } } m_iPos += (int)sID.length(); m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN; return true; } } return false; } //--------------------------------------------------------------------------- /** \brief Check if a string position contains a unary post value operator. */ bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) { // Do not check for postfix operators if they are not allowed at // the current expression index. // // This will fix the bug reported here: // // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 // if (m_iSynFlags & noPOSTOP) return false; // // Tricky problem with equations like "3m+5": // m is a postfix operator, + is a valid sign for postfix operators and // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. // // This is a special case so this routine slightly differs from the other // token readers. // Test if there could be a postfix operator string_type sTok; int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); if (iEnd==m_iPos) return false; // iteraterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); for ( ; it!=m_pPostOprtDef->rend(); ++it) { if (sTok.find(it->first)!=0) continue; a_Tok.Set(it->second, sTok); m_iPos += (int)it->first.length(); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; return true; } return false; } //--------------------------------------------------------------------------- /** \brief Check whether the token at a given position is a value token. Value tokens are either values or constants. \param a_Tok [out] If a value token is found it will be placed here. \return true if a value token has been found. */ bool ParserTokenReader::IsValTok(token_type &a_Tok) { assert(m_pConstDef); assert(m_pParser); #if defined(_MSC_VER) #pragma warning( disable : 4244 ) #endif string_type strTok; value_type fVal(0); int iEnd(0); // 2.) Check for user defined constant // Read everything that could be a constant name iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd!=m_iPos) { valmap_type::const_iterator item = m_pConstDef->find(strTok); if (item!=m_pConstDef->end()) { m_iPos = iEnd; a_Tok.SetVal(item->second, strTok); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } // 3.call the value recognition functions provided by the user // Call user defined value recognition functions std::vector::const_iterator item = m_vIdentFun.begin(); for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) { int iStart = m_iPos; if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) { strTok.assign(m_strFormula.c_str(), iStart, m_iPos); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); a_Tok.SetVal(fVal, strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } return false; #if defined(_MSC_VER) #pragma warning( default : 4244 ) #endif } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is a variable token. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a variable token has been found. */ bool ParserTokenReader::IsVarTok(token_type &a_Tok) { if (!m_pVarDef->size()) return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; varmap_type::const_iterator item = m_pVarDef->find(strTok); if (item==m_pVarDef->end()) return false; if (m_iSynFlags & noVAR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); m_iPos = iEnd; a_Tok.SetVar(item->second, strTok); m_UsedVar[item->first] = item->second; // Add variable to used-var-list m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; // Zur Info hier die SynFlags von IsVal(): // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } //--------------------------------------------------------------------------- bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) { if (!m_pStrVarDef || !m_pStrVarDef->size()) return false; string_type strTok; int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); if (iEnd==m_iPos) return false; strmap_type::const_iterator item = m_pStrVarDef->find(strTok); if (item==m_pStrVarDef->end()) return false; if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_iPos = iEnd; if (!m_pParser->m_vStringVarBuf.size()) Error(ecINTERNAL_ERROR); a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP); return true; } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is an undefined variable. \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. \return true if a variable token has been found. \throw nothrow */ bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) { string_type strTok; int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); if ( iEnd==m_iPos ) return false; if (m_iSynFlags & noVAR) { // 20061021 added token string strTok instead of a_Tok.GetAsString() as the // token identifier. // related bug report: // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); } // If a factory is available implicitely create new variables if (m_pFactory) { value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); a_Tok.SetVar(fVar, strTok ); // Do not use m_pParser->DefineVar( strTok, fVar ); // in order to define the new variable, it will clear the // m_UsedVar array which will kill previousely defined variables // from the list // This is safe because the new variable can never override an existing one // because they are checked first! (*m_pVarDef)[strTok] = fVar; m_UsedVar[strTok] = fVar; // Add variable to used-var-list } else { a_Tok.SetVar((value_type*)&m_fZero, strTok); m_UsedVar[strTok] = 0; // Add variable to used-var-list } m_iPos = iEnd; // Call the variable factory in order to let it define a new parser variable m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; return true; } //--------------------------------------------------------------------------- /** \brief Check wheter a token at a given position is a string. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a string token has been found. \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok \throw nothrow */ bool ParserTokenReader::IsString(token_type &a_Tok) { if (m_strFormula[m_iPos]!='"') return false; string_type strBuf(&m_strFormula[m_iPos+1]); std::size_t iEnd(0), iSkip(0); // parser over escaped '\"' end replace them with '"' for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) { if (strBuf[iEnd-1]!='\\') break; strBuf.replace(iEnd-1, 2, _T("\"") ); iSkip++; } if (iEnd==string_type::npos) Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_STR, m_iPos, strTok); m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); return true; } //--------------------------------------------------------------------------- /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws thats the only purpose of this function. */ void ParserTokenReader::Error( EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const { m_pParser->Error(a_iErrc, a_iPos, a_sTok); } //--------------------------------------------------------------------------- void ParserTokenReader::SetArgSep(char_type cArgSep) { m_cArgSep = cArgSep; } //--------------------------------------------------------------------------- char_type ParserTokenReader::GetArgSep() const { return m_cArgSep; } } // namespace mu repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nAmf.cpp000066400000000000000000000364511231531733200235630ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nAmf.h" #include "XmlStream.h" #define THISAMFVERSION 1.1 //the version of the amf standard implemented in this code. #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif nAmf::nAmf(void) { Clear(); } nAmf::~nAmf(void) { } nAmf& nAmf::operator=(const nAmf& In) { UnitsExist = In.UnitsExist; aUnit = In.aUnit; VersionExists = In.VersionExists; aVersion = In.aVersion; Objects = In.Objects; Metadata = In.Metadata; Constellations = In.Constellations; Textures = In.Textures; Materials = In.Materials; //MUST update all the internal pointer to AMF root (this) within the different classes for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++) it->pnAmf = this; for (std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++) it->pnAmf = this; for (std::vector::iterator it = Materials.begin(); it != Materials.end(); it++) it->pnAmf = this; for (std::vector::iterator it = Textures.begin(); it != Textures.end(); it++) it->pnAmf = this; return *this; } void nAmf::Clear(void) { UnitsExist = false; aUnit = UNIT_MM; //default VersionExists = true; aVersion = THISAMFVERSION; Objects.clear(); Metadata.clear(); Constellations.clear(); Textures.clear(); Materials.clear(); Materials.push_back(nMaterial(this)); Materials.back().aID = 0; Materials.back().Metadata.push_back(nMetadata(MD_NAME, "[Void]")); //this is the only way to set the name of the protected null material Materials.back().SetConstColor(0.0, 0.0, 0.0, 0.0); //transparent! // AppendObject(); //always need at least one object to be valid AMF } bool nAmf::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; pXML->OpenElement("amf"); if (UnitsExist){ switch (aUnit){ case UNIT_MM: pXML->SetElAttS("unit", "millimeter"); break; case UNIT_M: pXML->SetElAttS("unit", "meter"); break; case UNIT_IN: pXML->SetElAttS("unit", "inch"); break; case UNIT_FT: pXML->SetElAttS("unit", "feet"); break; case UNIT_UM: pXML->SetElAttS("unit", "micron"); break; default: break; } } if (VersionExists) pXML->SetElAttD("version", aVersion); for(std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } for(std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (it->aID == -1) it->aID = GetUnusedGeoID(); //make extra sure we don't write a bad object ID! if (!it->WriteXML(pXML, pMessage, pCancelFlag)) return false; } for(std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } for(std::vector::iterator it = Textures.begin(); it != Textures.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; if (pCancelFlag && *pCancelFlag) return false; } if (Materials.size()>1){ //There will always be a reserved "void" material at index 0 of this array that should not be written to the amf file for(std::vector::iterator it = Materials.begin()+1; it != Materials.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; if (pCancelFlag && *pCancelFlag) return false; } } pXML->CloseElement(); return true; } bool nAmf::ReadXML(CXmlStreamRead* pXML, bool StrictLoad, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; Clear(); std::string tmpUnits; if (pXML->GetElAttS("unit", &tmpUnits)){ UnitsExist = true; if (tmpUnits == "millimeter") aUnit = UNIT_MM; else if (tmpUnits == "meter") aUnit = UNIT_M; else if (tmpUnits == "inch") aUnit = UNIT_IN; else if (tmpUnits == "feet") aUnit = UNIT_FT; else if (tmpUnits == "micron") aUnit = UNIT_UM; } if (pXML->GetElAttD("version", &aVersion)) VersionExists = true; //todo: check against version numbers like 1.2.1 //read as many metadata tags as there are... nMetadata tmpMeta; while(pXML->OpenElement("metadata", true)){ // if (!tmpMeta.ReadXML(pXML, this, StrictLoad, pMessage)) return false; Metadata.push_back(tmpMeta); } //read as many object tags as there are... nObject tmpObj(this); while(pXML->OpenElement("object", true)){ // if (!tmpObj.ReadXML(pXML, this, StrictLoad, pMessage, pCancelFlag)) return false; Objects.push_back(tmpObj); if (pCancelFlag && *pCancelFlag) return false; } //read as many constellation tags as there are... nConstellation tmpCon(this); while(pXML->OpenElement("constellation", true)){ // if (!tmpCon.ReadXML(pXML, this, StrictLoad, pMessage)) return false; Constellations.push_back(tmpCon); if (pCancelFlag && *pCancelFlag) return false; } //read as many texture tags as there are... nTexture tmpTex(this); while(pXML->OpenElement("texture", true)){ // if (!tmpTex.ReadXML(pXML, this, StrictLoad, pMessage)) return false; Textures.push_back(tmpTex); if (pCancelFlag && *pCancelFlag) return false; } //read as many material tags as there are... nMaterial tmpMat(this); while(pXML->OpenElement("material", true)){ // if (!tmpMat.ReadXML(pXML, this, StrictLoad, pMessage)) return false; Materials.push_back(tmpMat); if (pCancelFlag && *pCancelFlag) return false; } return CheckValid(!StrictLoad, pMessage); } bool nAmf::CheckValid(bool FixNode, std::string* pMessage) { //Check if units exist if (!UnitsExist){ if (FixNode) {UnitsExist = true; aUnit = UNIT_MM;} if (pMessage){ *pMessage += "Warning: No physical units specified. "; if (FixNode) *pMessage += "Defaulting to mm.\n"; else *pMessage += "\n"; } } //Check if version info exists if (!VersionExists){ if (FixNode) {VersionExists = true; aVersion = THISAMFVERSION;} if (pMessage){ *pMessage += "Warning: No Amf version specified. "; if (FixNode) *pMessage += "Parser will attempt to harmonize with current AMF version.\n"; else *pMessage += "\n"; } } //Check for valid version if (VersionExists && aVersion != THISAMFVERSION){ if (FixNode) {aVersion = THISAMFVERSION;} if (pMessage){ *pMessage += "Warning: Outdated or invalid Amf version designation. "; if (FixNode) *pMessage += "Parser will attempt to harmonize with current AMF version.\n"; else *pMessage += "\n"; } } //Check if file contains geometry (nothing to fix. Just report this warning if (Objects.size() == 0){ if (FixNode) {AppendObject("Default");} if (pMessage){ *pMessage += "Warning: No objects found in amf. "; if (FixNode) *pMessage += "Adding a default object.\n"; else *pMessage += "\n"; } } return true; } //UTILITIES int nAmf::GetUsedGeoID(void){ //return first object in Objects if (Objects.size() != 0) return Objects.front().aID; else if (Constellations.size() != 0) return Constellations.front().aID; else return -1; } int nAmf::GetUnusedGeoID(void) { int CandidateID = 0; bool CandidateInUse = true; while (CandidateInUse){ CandidateID++; CandidateInUse = false; //check object vector for (std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (it->aID == CandidateID){ CandidateInUse = true; break; } } //check constellation vector if (!CandidateInUse){ //if we didn't find one in the object vector for (std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ if (it->aID == CandidateID){ CandidateInUse = true; break; } } } } return CandidateID; } int nAmf::GetUnusedTexID(void){ int CandidateID = 0; bool CandidateInUse = true; while (CandidateInUse){ CandidateID++; CandidateInUse = false; //cycle through texture vector for (std::vector::iterator it = Textures.begin(); it != Textures.end(); it++){ if (it->aID == CandidateID){ CandidateInUse = true; break; } } } return CandidateID; } int nAmf::GetUnusedMatID(void){ int CandidateID = 0; bool CandidateInUse = true; while (CandidateInUse){ CandidateID++; CandidateInUse = false; //cycle through texture vector for (std::vector::iterator it = Materials.begin(); it != Materials.end(); it++){ if (it->aID == CandidateID){ CandidateInUse = true; break; } } } return CandidateID; } bool nAmf::IsDuplicateGeoID(int IdToCheck) { int NumFound = 0; for (std::vector::iterator it = Objects.begin(); it!=Objects.end(); it++){if(it->aID==IdToCheck) NumFound++;} for (std::vector::iterator it = Constellations.begin(); it!=Constellations.end(); it++){if(it->aID==IdToCheck) NumFound++;} if (NumFound > 1) return true; else return false; } bool nAmf::IsDuplicateTexID(int IdToCheck) { int NumFound = 0; for (std::vector::iterator it = Textures.begin(); it!=Textures.end(); it++){if(it->aID==IdToCheck) NumFound++;} if (NumFound > 1) return true; else return false; } bool nAmf::IsDuplicateMatID(int IdToCheck) { int NumFound = 0; for (std::vector::iterator it = Materials.begin(); it!=Materials.end(); it++){if(it->aID==IdToCheck) NumFound++;} if (NumFound > 1) return true; else return false; } std::string nAmf::GetGeoNameFromID(int GeometryID) //finds the name of the object or constellation with this internal ID { //Look in the objects nObject* pObj = GetObjectByID(GeometryID); if (pObj) return "Obj: " + pObj->GetName(); //Look in the constellations nConstellation* pConst = GetConstellationByID(GeometryID); if (pConst) return "Const: " + pConst->GetName(); //Didn't find this id... return "Invalid ID"; } std::string nAmf::GetMatNameFromID(int MaterialID) //returns name string for a material if it exists { nMaterial* tmpMat = GetMaterialByID(MaterialID); if (tmpMat) return tmpMat->GetName(); else if (MaterialID == 0) return "Void"; else return "Invalid Material ID"; } nObject* nAmf::GetObjectByID(int GeometryID) //returns pointer to a constellation that has this ID, or NULL if non exists. { for(std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (it->aID == GeometryID) return &(*it); } return NULL; } nConstellation* nAmf::GetConstellationByID(int GeometryID) //returns pointer to a constellation that has this ID, or NULL if non exists. { for(std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ if (it->aID == GeometryID) return &(*it); } return NULL; } nMaterial* nAmf::GetMaterialByID(int MaterialID) //returns a TEMPORARY pointer to the first material with the specified ID, or NULL if not found { for (std::vector::iterator it = Materials.begin(); it != Materials.end(); it++){ if(it->aID == MaterialID) return &(*it); } return NULL; //no valid material found with this ID } nTexture* nAmf::GetTextureByID(int TextureID) //returns a TEMPORARY pointer to the first texture with the specified ID, or NULL if not found { for (std::vector::iterator it = Textures.begin(); it != Textures.end(); it++){ if(it->aID == TextureID) return &(*it); } return NULL; //no valid material found with this ID } int nAmf::AppendObject(std::string NameIn){ Objects.push_back(nObject(this)); // int MyID = GetUnusedGeoID(); // Objects.back().aID = MyID; if (NameIn == "") NameIn = "Default"; Objects.back().SetName(NameIn); return Objects.back().aID; } int nAmf::AppendConstellation(std::string NameIn) { Constellations.push_back(nConstellation(this)); // int MyID = GetUnusedGeoID(); // Constellations.back().aID = MyID; if (NameIn == "") NameIn = "Default"; Constellations.back().SetName(NameIn); return Constellations.back().aID; } int nAmf::AppendMaterial(std::string NameIn) { Materials.push_back(nMaterial(this)); // int MyID = GetUnusedMatID(); // Materials.back().aID = MyID; if (NameIn == "") NameIn = "Default"; Materials.back().SetName(NameIn); return Materials.back().aID; } void nAmf::DeleteGeometry(int GeometryID) //Deletes by the internal object ID, not index in the vector!! { //remove all constellation instances to avoid having invalid ID's! for(std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ for (std::vector::iterator jt = it->Instances.begin(); jt != it->Instances.end()-1;){ //reverse iteration so erasing elements doesn't change index... if (jt->aObjectID == GeometryID){ it->Instances.erase(jt); //erase me!! //todo: Make sure // if (it->Instances.size() == 0){break; break;} // else if (jt != it->Instances.begin()) jt--; //because everything has shifted up by one... } else jt++; } } //find the object and remove it: in Object list for(std::vector::iterator it = Objects.begin(); it != Objects.end(); it++){ if (it->aID == GeometryID){ Objects.erase(it); break; //second break?? } } //or delete constellation in constellation list... for(std::vector::iterator it = Constellations.begin(); it != Constellations.end(); it++){ if (it->aID == GeometryID){ Constellations.erase(it); break; //second break?? } } } void nAmf::DeleteMaterial(int MaterialID) { if (MaterialID == 0) return; //can't delete the reserved void material //find the material and remove it: in Material list for(std::vector::iterator it = Materials.begin(); it != Materials.end(); it++){ if (it->aID == MaterialID){ Materials.erase(it, it+1); break; //second break?? } } } bool nAmf::IsTopLevelGeo(int GeometryID) { bool IsInstanced = false; for (std::vector::iterator it=Constellations.begin(); it != Constellations.end(); it++){ for (std::vector::iterator jt = it->Instances.begin(); jt != it->Instances.end(); jt++){ if (jt->aObjectID == GeometryID){ IsInstanced = true; break; } } } return !IsInstanced; } //std::string nAmf::GetMatName(nVolume* pVolume) //returns name string for material of this volume if it has one. //{ // nMaterial* tmpMat = GetMaterialByID(pVolume->aMaterialID); // if (tmpMat) return tmpMat->GetName(); // else return "No Material"; //} repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nColor.cpp000066400000000000000000000047351231531733200241360ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nColor.h" #include "XmlStream.h" #include "nAmf.h" nColor::nColor() { Clear(); } nColor::~nColor(void) { } nColor& nColor::operator=(const nColor& In) { R = In.R; G = In.G; B = In.B; AExists = In.AExists; A = In.A; return *this; } void nColor::Clear(void) { R.Clear(); G.Clear(); B.Clear(); AExists = false; A.Clear(); } bool nColor::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("color"); if (R.IsConst()) pXML->SetElementS("r", R.ToAmfString()); else pXML->SetElementS("r", R.ToAmfString(), true); if (G.IsConst()) pXML->SetElementS("g", G.ToAmfString()); else pXML->SetElementS("g", G.ToAmfString(), true); if (B.IsConst()) pXML->SetElementS("b", B.ToAmfString()); else pXML->SetElementS("b", B.ToAmfString(), true); if (AExists){ if (A.IsConst()) pXML->SetElementS("a", A.ToAmfString()); else pXML->SetElementS("a", A.ToAmfString(), true); } pXML->CloseElement(); return true; } bool nColor::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); std::string tmp; if (pXML->GetElementS("r", &tmp)) R.FromAmfString(tmp, pAmf); //CData should already be stripped off.... if (pXML->GetElementS("g", &tmp)) G.FromAmfString(tmp, pAmf); if (pXML->GetElementS("b", &tmp)) B.FromAmfString(tmp, pAmf); if (pXML->GetElementS("a", &tmp)){ AExists = true; A.FromAmfString(tmp, pAmf); } //do in material composite, too! return CheckValid(pAmf, !StrictLoad, pMessage); } bool nColor::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //TODO: return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nComposite.cpp000066400000000000000000000052341231531733200250150ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nComposite.h" #include "XmlStream.h" #include "nAmf.h" nComposite::nComposite(void) { Clear(); } nComposite::~nComposite(void) { } nComposite& nComposite::operator=(const nComposite& In) { aMaterialID = In.aMaterialID; MatEquation = In.MatEquation; return *this; } void nComposite::Clear(void) { aMaterialID = -1; MatEquation.Clear(); } bool nComposite::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("composite"); pXML->SetElAttI("materialid", aMaterialID); pXML->SetElDataS(MatEquation.ToAmfString(), true); pXML->CloseElement(); return true; } bool nComposite::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); pXML->GetElAttI("materialid", &aMaterialID); std::string tmp; if (pXML->GetElDataS(&tmp)) MatEquation.FromAmfString(tmp, pAmf); else {//loads equation if it exists (todo: move to check...) *pMessage += "Invalid equation in composite tag. Aborting. \n"; return false; } return CheckValid(pAmf, !StrictLoad, pMessage); } bool nComposite::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { if (!CheckEquation(pMessage)){ if (FixNode){ MatEquation.Clear(); if(pMessage) *pMessage += "Warning: Error found in equation. Removing Equation.\n";} else {if(pMessage) *pMessage += "Error: Error found in equation.\n"; return false;} } return true; } bool nComposite::SetEquation(std::string AmfEquationIn, nAmf* pAmf, std::string* pMessage) { MatEquation.FromAmfString(AmfEquationIn, pAmf); return CheckEquation(pMessage); } bool nComposite::ScaleEquation(double ScaleFactor, std::string* pMessage) //Scale factor is the factor we're changing the Amf (2.0 = doubling the object size) { MatEquation.Scale(ScaleFactor); return CheckEquation(pMessage); } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nConstellation.cpp000066400000000000000000000137361231531733200256770ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nConstellation.h" #include "XmlStream.h" #include "nAmf.h" nConstellation::nConstellation(nAmf* pnAmfIn) { pnAmf = pnAmfIn; Clear(); } nConstellation::~nConstellation(void) { } nConstellation& nConstellation::operator=(const nConstellation& In) { aID = In.aID; Instances = In.Instances; Metadata = In.Metadata; pnAmf = In.pnAmf; return *this; } void nConstellation::Clear(void) { aID = pnAmf->GetUnusedGeoID(); Instances.clear(); Metadata.clear(); } bool nConstellation::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("constellation"); pXML->SetElAttI("id", aID); for(std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } for(std::vector::iterator it = Instances.begin(); it != Instances.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } pXML->CloseElement(); return true; } bool nConstellation::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElAttI("id", &aID)) aID = -1; //read as many metadata tags as there are... nMetadata tmpMeta; while(pXML->OpenElement("metadata", true)){ // if (!tmpMeta.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Metadata.push_back(tmpMeta); } // if (Metadata.size() != 0) pXML->UpLevel(); // //read as many instance tags as there are... nInstance tmpInst; while(pXML->OpenElement("instance", true)){ // if (!tmpInst.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Instances.push_back(tmpInst); } // if (Instances.size() != 0) pXML->UpLevel(); // return CheckValid(pAmf, !StrictLoad, pMessage); } bool nConstellation::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //Check for invalid geometry ID if (aID < 0 || pAmf->IsDuplicateGeoID(aID)){ if (FixNode) { aID = pAmf->GetUnusedGeoID(); if (pMessage) *pMessage += "Warning: Invalid or duplicate geometry ID found. Setting to an unused ID. Constellations may need to be adjusted.\n"; } else { if (pMessage) *pMessage += "Error: Invalid or duplicate geometry ID found.\n"; return false; } } //check for no instances (just a warning...) if (Instances.size() == 0 && pMessage) {*pMessage += "Constellation found with no instances.\n"; } //Check for invalid geometry IDs in instances (here instead of nInstance so we can delete effonding ones to fix Amf) std::vector InsIndToDelete; int count=0; for (std::vector::iterator it = Instances.begin(); it!=Instances.end(); it++){ if (it->aObjectID < 0 || (pAmf->GetObjectByID(it->aObjectID) == NULL && pAmf->GetConstellationByID(it->aObjectID) == NULL)){ if (FixNode) { InsIndToDelete.push_back(count); if (pMessage) *pMessage += "Warning: Invalid geometry ID in instance. Deleting instance.\n"; } else { if (pMessage) *pMessage += "Error: Invalid geometry ID in instance.\n"; return false; } } count++; } for (int i=InsIndToDelete.size()-1; i >= 0; i--) Instances.erase(Instances.begin()+InsIndToDelete[i]); //go backwards so out indices stay correct... return true; } void nConstellation::SetName(std::string NewName) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME){ it->Data = NewName; //replace the name!! return; } } //if we get here there was no existing Name metadata so add one... Metadata.push_back(nMetadata(MD_NAME, NewName)); } std::string nConstellation::GetName(void) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME) return it->Data; } return ""; } bool nConstellation::IsReferencedBy(nConstellation* pConstellationCheck) //returns true if pUsesCheck references pCheck anywhere in its tree. { if (aID == pConstellationCheck->aID) return true; nConstellation* pTmpConst; std::vector OpenList; //list of constellations referenced by pUsesCheck OpenList.reserve(1000); //allcoate maximum reasonable number of materials because using iterators with a push-back inside loop can cause re-allocation and therefore bad iterator. OpenList.push_back(pConstellationCheck); for(std::vector::iterator jt = OpenList.begin(); jt != OpenList.end(); jt++){ for(std::vector::iterator it = (*jt)->Instances.begin(); it != (*jt)->Instances.end(); it++){ // for (int i=0; i<(*jt)->Instances.size(); i++){ pTmpConst = pnAmf->GetConstellationByID(it->aObjectID); if (pTmpConst){ //if this id is a constellation //check to see if it's already on the open list. If not, add it. bool inList = false; for (int i=0; i<(int)OpenList.size(); i++){ if (OpenList[i] == pTmpConst){ inList = true; break; } } if (!inList){ OpenList.push_back(pTmpConst); if (aID == pTmpConst->aID) return true; //we've found a recursion back to the one we're checking against! } } } } return false; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nCoordinates.cpp000066400000000000000000000043121231531733200253210ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nCoordinates.h" #include "XmlStream.h" nCoordinates::nCoordinates(void) { Clear(); } nCoordinates::~nCoordinates(void) { } nCoordinates::nCoordinates(const double Xin, const double Yin, const double Zin) { Clear(); X = Xin; Y = Yin; Z = Zin; } nCoordinates& nCoordinates::operator=(const nCoordinates& In) { X = In.X; Y = In.Y; Z = In.Z; return *this; } void nCoordinates::Clear(void) { X = 0; Y = 0; Z = 0; } bool nCoordinates::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("coordinates"); pXML->SetElementD("x", X); pXML->SetElementD("y", Y); pXML->SetElementD("z", Z); pXML->CloseElement(); return true; } bool nCoordinates::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElementD("x", &X)) {X = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("y", &Y)) {Y = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("z", &Z)) {Z = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} return CheckValid(pAmf, !StrictLoad, pMessage); } bool nCoordinates::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nEdge.cpp000066400000000000000000000060441231531733200237170ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nEdge.h" #include "XmlStream.h" nEdge::nEdge(void) { Clear(); } nEdge::~nEdge(void) { } nEdge& nEdge::operator=(const nEdge& In) { v1 = In.v1; v2 = In.v2; dx1 = In.dx1; dy1 = In.dy1; dz1 = In.dz1; dx2 = In.dx2; dy2 = In.dy2; dz2 = In.dz2; return *this; } void nEdge::Clear(void) { v1 = -1; v2 = -1; dx1 = 0.0; dy1 = 0.0; dz1 = 0.0; dx2 = 0.0; dy2 = 0.0; dz2 = 0.0; } bool nEdge::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("edge"); pXML->SetElementI("v1", v1); pXML->SetElementD("dx1", dx1); pXML->SetElementD("dy1", dy1); pXML->SetElementD("dz1", dz1); pXML->SetElementI("v2", v2); pXML->SetElementD("dx2", dx2); pXML->SetElementD("dy2", dy2); pXML->SetElementD("dz2", dz2); pXML->CloseElement(); return true; } bool nEdge::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); //required tags if (!pXML->GetElementI("v1", &v1)) {v1 = -1; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dx1", &dx1)) {dx1 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dy1", &dy1)) {dy1 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dz1", &dz1)) {dz1 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementI("v2", &v2)) {v2 = -1; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dx2", &dx2)) {dx2 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dy2", &dy2)) {dy2 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("dz2", &dz2)) {dz2 = 0.0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} return CheckValid(pAmf, !StrictLoad, pMessage); } bool nEdge::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { if (v1 == -1 || v2 == -1) return false; else return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nInstance.cpp000066400000000000000000000047071231531733200246230ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nInstance.h" #include "XmlStream.h" nInstance::nInstance(void) { Clear(); } nInstance::~nInstance(void) { } nInstance& nInstance::operator=(const nInstance& In) { aObjectID = In.aObjectID; DeltaX = In.DeltaX; DeltaY = In.DeltaY; DeltaZ = In.DeltaZ; rX = In.rX; rY = In.rY; rZ = In.rZ; return *this; } void nInstance::Clear(void) { aObjectID = -1; DeltaX = 0.0; DeltaY = 0.0; DeltaZ = 0.0; rX = 0.0; rY = 0.0; rZ = 0.0; } bool nInstance::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("instance"); pXML->SetElAttI("objectid", aObjectID); pXML->SetElementD("deltax", DeltaX); pXML->SetElementD("deltay", DeltaY); pXML->SetElementD("deltaz", DeltaZ); pXML->SetElementD("rx", rX); pXML->SetElementD("ry", rY); pXML->SetElementD("rz", rZ); pXML->CloseElement(); return true; } bool nInstance::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElAttI("objectid", &aObjectID)) aObjectID = -1; //required tags if (!pXML->GetElementD("deltax", &DeltaX)) DeltaX = 0; if (!pXML->GetElementD("deltay", &DeltaY)) DeltaY = 0; if (!pXML->GetElementD("deltaz", &DeltaZ)) DeltaZ = 0; if (!pXML->GetElementD("rx", &rX)) rX = 0; if (!pXML->GetElementD("ry", &rY)) rY = 0; if (!pXML->GetElementD("rz", &rZ)) rZ = 0; return CheckValid(pAmf, !StrictLoad, pMessage); } bool nInstance::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //valid aObjectID checked in nConstellation so we can delete bad instances to fix the Amf file. return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nMaterial.cpp000066400000000000000000000215141231531733200246100ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nMaterial.h" #include "XmlStream.h" #include "nAmf.h" nMaterial::nMaterial(nAmf* pnAmfIn) { pnAmf = pnAmfIn; Clear(); } nMaterial::~nMaterial(void) { } nMaterial& nMaterial::operator=(const nMaterial& In) { aID = In.aID; Composites = In.Composites; ColorExists = In.ColorExists; Color = In.Color; Metadata = In.Metadata; pnAmf = In.pnAmf; return *this; } void nMaterial::Clear(void) { aID = pnAmf->GetUnusedMatID(); Composites.clear(); ColorExists = true; Color.Clear(); Metadata.clear(); } bool nMaterial::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("material"); pXML->SetElAttI("id", aID); for(std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } if (ColorExists) if (!Color.WriteXML(pXML, pMessage)) return false; for(std::vector::iterator it = Composites.begin(); it != Composites.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } pXML->CloseElement(); return true; } bool nMaterial::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElAttI("id", &aID)) aID = -1; //read as many metadata tags as there are... nMetadata tmpMeta; while(pXML->OpenElement("metadata", true)){ // if (!tmpMeta.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Metadata.push_back(tmpMeta); } // if (Metadata.size() != 0) pXML->UpLevel(); // if (pXML->OpenElement("color")){Color.ReadXML(pXML, pAmf, StrictLoad, pMessage); ColorExists=true; pXML->CloseElement();} //read as many composite tags as there are... nComposite tmpComp; while(pXML->OpenElement("composite", true)){ // if (!tmpComp.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Composites.push_back(tmpComp); } // if (Composites.size() != 0) pXML->UpLevel(); // return CheckValid(pAmf, !StrictLoad, pMessage); } bool nMaterial::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //Check for invalid material ID if (aID < 0 || pAmf->IsDuplicateMatID(aID)){ if (FixNode) { aID = pAmf->GetUnusedMatID(); if (pMessage) *pMessage += "Warning: Invalid or duplicate material ID found. Setting to an unused ID. Composite equations may need to be adjusted.\n"; } else { if (pMessage) *pMessage += "Error: Invalid or duplicate material ID found.\n"; return false; } } //Check for invalid material IDs in composites (here instead of nComposite so we can delete effonding ones to fix Amf) std::vector CompIndToDelete; int count=0; for (std::vector::iterator it = Composites.begin(); it!=Composites.end(); it++){ if (it->aMaterialID < 0 || pAmf->GetMaterialByID(it->aMaterialID) == NULL){ if (FixNode) { CompIndToDelete.push_back(count); if (pMessage) *pMessage += "Warning: Invalid material ID in composite. Deleting composite.\n"; } else { if (pMessage) *pMessage += "Error: Invalid material ID in composite.\n"; return false; } } count++; } for (int i=CompIndToDelete.size()-1; i >= 0; i--) Composites.erase(Composites.begin()+CompIndToDelete[i]); //go backwards so out indices stay correct... return true; } void nMaterial::SetName(std::string NewName) { if (aID == 0) return; //protect the void material for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME){ it->Data = NewName; //replace the name!! return; } } //if we get here there was no existing Name metadata so add one... Metadata.push_back(nMetadata(MD_NAME, NewName)); } std::string nMaterial::GetName(void) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME) return it->Data; } return ""; } void nMaterial::GetColorAt(double xIn, double yIn, double zIn, double* rOut, double* gOut, double* bOut, double* aOut) { double tmpR, tmpG, tmpB, tmpA, tmpWeight; if (Composites.size() == 0){ if (ColorExists){Color.GetColor(xIn, yIn, zIn, rOut, gOut, bOut, aOut);} else{*rOut=0; *gOut=0; *bOut=0; if (aOut) *aOut=1.0;} } else { //do weighted average double SumR = 0; double SumG = 0; double SumB = 0; double SumA = 0; double SumWeight = 0; for (std::vector::iterator it = Composites.begin(); it != Composites.end(); it++){ tmpWeight = it->EvalEquation(xIn, yIn, zIn); if (tmpWeight < 0) tmpWeight = 0; //as per spec... up for discussion? pnAmf->GetMaterialByID(it->aMaterialID)->GetColorAt(xIn, yIn, zIn, &tmpR, &tmpG, &tmpB, &tmpA); SumR += tmpR*tmpWeight; SumG += tmpG*tmpWeight; SumB += tmpB*tmpWeight; SumA += tmpA*tmpWeight; SumWeight += tmpWeight; } *rOut = SumR/SumWeight; *gOut = SumG/SumWeight; *bOut = SumB/SumWeight; if (aOut) *aOut = SumA/SumWeight; //kep within range of 0 to 1 if (*rOut > 1.0) *rOut = 1.0; else if (*rOut < 0.0) *rOut = 0.0; if (*gOut > 1.0) *gOut = 1.0; else if (*gOut < 0.0) *gOut = 0.0; if (*bOut > 1.0) *bOut = 1.0; else if (*bOut < 0.0) *bOut = 0.0; if (aOut){ if (*aOut > 1.0) *aOut = 1.0; else if (*aOut < 0.0) *aOut = 0.0; } } } int nMaterial::AddCompositeInstance(int InstanceMaterialID, std::string AmfEquationIn, std::string* pMessage) //returns the index. Can't set a id here since we need top level access to make sure we can't create a recursive situation { if (aID == 0) -1; //protect the void material // nMaterial* pCurMat = GetMaterialByID(MaterialID); if (InstanceMaterialID != 0){ nMaterial* pInstanceMat = pnAmf->GetMaterialByID(InstanceMaterialID); if (!pInstanceMat){ if (pMessage) *pMessage += "Invalid material ID.\n"; return -1; //invalid material ID somewhere along the line } if(IsReferencedBy(pInstanceMat)){ if (pMessage) *pMessage += "Self reference (direct or recursive)\n"; return -1; //no self references/recursive self references } } nComposite tmpComp; tmpComp.aMaterialID = InstanceMaterialID; if (!tmpComp.SetEquation(AmfEquationIn, pnAmf, pMessage)) return -1; Composites.push_back(tmpComp); return Composites.size(); } void nMaterial::DeleteCompositeInstance(int CompositeIndex) { if (CompositeIndex < 0 || CompositeIndex >= (int)Composites.size()) return; Composites.erase(Composites.begin()+CompositeIndex); } //void nMaterial::DeleteCompositeInstance(int CompositeIndex) //{ //// nMaterial* pCurMat = GetMaterialByID(MaterialID); //// if (!pCurMat) return; //invalid material ID // std::vector::iterator CompDelIt = pCurMat->Composites.begin()+CompositeIndex; // pCurMat->Composites.erase(pCurMat->Composites.begin()+CompositeIndex); // //} bool nMaterial::IsReferencedBy(/*nMaterial* pCheck, */nMaterial* pMaterialCheck) { if (this == pMaterialCheck) return true; nMaterial* pTmpMat; std::vector OpenList; //list of constellations referenced by pUsesCheck OpenList.reserve(1000); //allcoate maximum reasonable number of materials because using iterators with a push-back inside loop can cause re-allocation and therefore bad iterator. OpenList.push_back(pMaterialCheck); for(std::vector::iterator jt = OpenList.begin(); jt < OpenList.end(); jt++){ for(std::vector::iterator it = (*jt)->Composites.begin(); it != (*jt)->Composites.end(); it++){ pTmpMat = pnAmf->GetMaterialByID(it->aMaterialID); if (pTmpMat){ //if this id is a constellation //check to see if it's already on the open list. If not, add it. bool inList = false; for (int i=0; i<(int)OpenList.size(); i++){ if (OpenList[i] == pTmpMat){ inList = true; break; } } if (!inList){ OpenList.push_back(pTmpMat); if (this == pTmpMat) return true; //we've found a recursion back to the one we're checking against! //OpenList may have re-allocated! } } } } return false; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nMesh.cpp000066400000000000000000000107261231531733200237510ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nMesh.h" #include "XmlStream.h" #include "nVolume.h" nMesh::nMesh(void) { Clear(); } nMesh::~nMesh(void) { } nMesh& nMesh::operator=(const nMesh& In) { Vertices = In.Vertices; Volumes = In.Volumes; return *this; } void nMesh::Clear(void) { Vertices.Clear(); Volumes.clear(); } bool nMesh::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; pXML->OpenElement("mesh"); //vertices... if (!Vertices.WriteXML(pXML, pMessage, pCancelFlag)) return false; //volumes for(std::vector::iterator it = Volumes.begin(); it != Volumes.end(); it++){ if (!it->WriteXML(pXML, pMessage, pCancelFlag)) return false; } pXML->CloseElement(); // return true; } bool nMesh::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; Clear(); //load vertices... if (pXML->OpenElement("vertices") && Vertices.ReadXML(pXML, pAmf, StrictLoad, pMessage, pCancelFlag)) pXML->CloseElement(); else return false; //read as many volume tags as there are... nVolume tmpVol; while(pXML->OpenElement("volume", true)){ // if (!tmpVol.ReadXML(pXML, pAmf, StrictLoad, pMessage, pCancelFlag)) return false; Volumes.push_back(tmpVol); } // if (Volumes.size() != 0) pXML->UpLevel(); // // pXML->UpLevel(); // return CheckValid(pAmf, !StrictLoad, pMessage); } bool nMesh::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //check if it contains any volumes if (Volumes.size() == 0){ if (pMessage) *pMessage += "Warning: No volumes in mesh tag.\n"; } //check if volume references any vertices that don't exist int NumVert = Vertices.VertexList.size(); for (std::vector::iterator it = Volumes.begin(); it!=Volumes.end(); it++){ std::vectorTriToDelete; int count=0; for (std::vector::iterator jt = it->Triangles.begin(); jt!=it->Triangles.end(); jt++){ bool DeleteTri = false; for (int i=0; i<3; i++){ int ThisInd; switch (i){ case 0: ThisInd = jt->v1; break; case 1: ThisInd = jt->v2; break; case 2: ThisInd = jt->v3; break; } if (ThisInd >= NumVert){ if (FixNode) { DeleteTri = true; if (pMessage) *pMessage += "Warning: Triangle references non-existent vertex. Deleting triangle.\n"; } else { if (pMessage) *pMessage += "Error: Triangle references non-existent vertex.\n"; return false; } } } if (DeleteTri) TriToDelete.push_back(count); count++; } for (int i=TriToDelete.size()-1; i >= 0; i--){ //go backwards so out indices stay correct... it->Triangles.erase(it->Triangles.begin()+TriToDelete[i]); } } return true; } //Utilities bool nMesh::Bounds(double* MinX, double* MaxX, double* MinY, double* MaxY, double* MinZ, double* MaxZ) //returns false if no vertices { if(Vertices.VertexList.size() == 0) return false; for (std::vector::iterator it = Vertices.VertexList.begin(); it!=Vertices.VertexList.end(); it++) { if (it == Vertices.VertexList.begin()){ //first time thru *MinX = it->GetX(); *MaxX = it->GetX(); *MinY = it->GetY(); *MaxY = it->GetY(); *MinZ = it->GetZ(); *MaxZ = it->GetZ(); } else { *MinX = std::min(*MinX, it->GetX()); *MaxX = std::max(*MaxX, it->GetX()); *MinY = std::min(*MinY, it->GetY()); *MaxY = std::max(*MaxY, it->GetY()); *MinZ = std::min(*MinZ, it->GetZ()); *MaxZ = std::max(*MaxZ, it->GetZ()); } } return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nMetadata.cpp000066400000000000000000000061561231531733200245770ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nMetadata.h" #include "XmlStream.h" nMetadata::nMetadata(void) { Clear(); } nMetadata::~nMetadata(void) { } void nMetadata::Clear(void) { Type = MD_INVALID; Data = ""; } nMetadata& nMetadata::operator=(const nMetadata& In) { Type = In.Type; Data = In.Data; return *this; } bool nMetadata::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { if (Data == ""){ *pMessage += "Warning: MetaData tag found with no data. Ignoring."; return true; //quick check to make sure we're not saving an empty element (crashes on load) } pXML->OpenElement("metadata"); switch (Type){ case MD_NAME: pXML->SetElAttS("type", "name"); break; case MD_DESCRIPTION: pXML->SetElAttS("type", "description"); break; case MD_URL: pXML->SetElAttS("type", "url"); break; case MD_AUTHOR: pXML->SetElAttS("type", "author"); break; case MD_COMPANY: pXML->SetElAttS("type", "company"); break; case MD_CAD: pXML->SetElAttS("type", "cad"); break; case MD_REVISION: pXML->SetElAttS("type", "revision"); break; case MD_TOLERANCE: pXML->SetElAttS("type", "tolerance"); break; case MD_VOLUME: pXML->SetElAttS("type", "volume"); break; case MD_ELASTICMOD: pXML->SetElAttS("type", "elasticmodulus"); break; case MD_POISSONRATIO: pXML->SetElAttS("type", "poissonratio"); break; default: break; } pXML->SetElDataS(Data); pXML->CloseElement(); return true; } bool nMetadata::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); std::string tmp; pXML->GetElAttS("type", &tmp); if (tmp == "name") Type = MD_NAME; else if (tmp == "description") Type = MD_DESCRIPTION; else if (tmp == "url") Type = MD_URL; else if (tmp == "author") Type = MD_AUTHOR; else if (tmp == "company") Type = MD_COMPANY; else if (tmp == "cad") Type = MD_CAD; else if (tmp == "revision") Type = MD_REVISION; else if (tmp == "tolerance") Type = MD_TOLERANCE; else if (tmp == "volume") Type = MD_VOLUME; else if (tmp == "elasticmodulus") Type = MD_ELASTICMOD; else if (tmp == "poissonratio") Type = MD_POISSONRATIO; pXML->GetElDataS(&Data); //loads name tag if it exists return CheckValid(pAmf, !StrictLoad, pMessage); } bool nMetadata::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nNormal.cpp000066400000000000000000000046121231531733200243020ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nNormal.h" #include "XmlStream.h" #include nNormal::nNormal(void) { Clear(); } nNormal::~nNormal(void) { } nNormal& nNormal::operator=(const nNormal& In) { nX = In.nX; nY = In.nY; nZ = In.nZ; return *this; } void nNormal::Clear(void) { nX = 0.0; nY = 0.0; nZ = 0.0; } bool nNormal::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("normal"); pXML->SetElementD("nx", nX); pXML->SetElementD("ny", nY); pXML->SetElementD("nz", nZ); pXML->CloseElement(); return true; } bool nNormal::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElementD("nx", &nX)) {nX = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("ny", &nY)) {nY = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementD("nz", &nZ)) {nZ = 0; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} return CheckValid(pAmf, !StrictLoad, pMessage); } bool nNormal::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { double Eps = 1e-10; //Threshold for how close to unit length is close enough double Length2 = nX*nX+nY*nY+nZ*nZ; if (Length2<1-Eps || Length2 > 1+Eps){ if (pMessage) *pMessage += "Non unit-length normal.\n"; if (FixNode){ double Length = sqrt(Length2); nX /= Length; nY /= Length; nZ /= Length; } else return false; } return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nObject.cpp000066400000000000000000000106151231531733200242600ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nObject.h" #include "XmlStream.h" #include "nMesh.h" #include "nMetadata.h" #include "nAmf.h" nObject::nObject(nAmf* pnAmfIn) { pnAmf = pnAmfIn; Clear(); } nObject::~nObject(void) { } nObject& nObject::operator=(const nObject& In) { Meshes = In.Meshes; ColorExists = In.ColorExists; Color = In.Color; Metadata = In.Metadata; aID = In.aID; pnAmf = In.pnAmf; return *this; } void nObject::Clear(void) { Meshes.clear(); ColorExists = false; Color.Clear(); Metadata.clear(); aID = pnAmf->GetUnusedGeoID(); } bool nObject::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; pXML->OpenElement("object"); pXML->SetElAttI("id", aID); for(std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } if (ColorExists) Color.WriteXML(pXML, pMessage); for(std::vector::iterator it = Meshes.begin(); it != Meshes.end(); it++){ if (!it->WriteXML(pXML, pMessage, pCancelFlag)) return false; } pXML->CloseElement(); return true; } bool nObject::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; Clear(); if (!pXML->GetElAttI("id", &aID)) aID = -1; //read as many metadata tags as there are... nMetadata tmpMeta; while(pXML->OpenElement("metadata", true)){ // if (!tmpMeta.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Metadata.push_back(tmpMeta); } if (pXML->OpenElement("color")){Color.ReadXML(pXML, pAmf, StrictLoad, pMessage); ColorExists=true; pXML->CloseElement();} //read as many triangle tags as there are... nMesh tmpMesh; while(pXML->OpenElement("mesh", true)){ // if (!tmpMesh.ReadXML(pXML, pAmf, StrictLoad, pMessage, pCancelFlag)) return false; Meshes.push_back(tmpMesh); } return CheckValid(pAmf, !StrictLoad, pMessage); } bool nObject::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //Check for invalid geometry ID if (aID < 0 || pAmf->IsDuplicateGeoID(aID)){ if (FixNode) { aID = pAmf->GetUnusedGeoID(); if (pMessage) *pMessage += "Warning: Invalid or duplicate geometry ID found. Setting to an unused ID. Constellations may need to be adjusted.\n"; } else { if (pMessage) *pMessage += "Error: Invalid or duplicate geometry ID found.\n"; return false; } } //check if it contains any meshes if (Meshes.size() == 0){ if (pMessage) *pMessage += "Warning: No meshes in object tag.\n"; } return true; } void nObject::SetName(std::string NewName) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME){ it->Data = NewName; //replace the name!! return; } } //if we get here there was no existing Name metadata so add one... Metadata.push_back(nMetadata(MD_NAME, NewName)); } std::string nObject::GetName(void) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME) return it->Data; } return ""; } void nObject::Translate(double dx, double dy, double dz) { for (std::vector::iterator it = Meshes.begin(); it != Meshes.end(); it++){ it->Translate(dx, dy, dz); } } void nObject::Rotate(double rx, double ry, double rz) { for (std::vector::iterator it = Meshes.begin(); it != Meshes.end(); it++){ it->Rotate(rx, ry, rz); } } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nTexmap.cpp000066400000000000000000000105151231531733200243070ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nTexmap.h" #include "XmlStream.h" nTexmap::nTexmap(void) { Clear(); } nTexmap::~nTexmap(void) { } nTexmap& nTexmap::operator=(const nTexmap& In) { RTexID = In.RTexID; GTexID = In.GTexID; BTexID = In.BTexID; ATexID = In.ATexID; ATexIDExists = In.ATexIDExists; uTex1 = In.uTex1; uTex2 = In.uTex2; uTex3 = In.uTex3; vTex1 = In.vTex1; vTex2 = In.vTex2; vTex3 = In.vTex3; wTex1 = In.wTex1; wTex2 = In.wTex2; wTex3 = In.wTex3; WExists = In.WExists; return *this; } void nTexmap::Clear(void) { RTexID = -1; GTexID = -1; BTexID = -1; ATexID = -1; ATexIDExists = false; uTex1 = 0.0; uTex2 = 0.0; uTex3 = 0.0; vTex1 = 0.0; vTex2 = 0.0; vTex3 = 0.0; wTex1 = 0.0; wTex2 = 0.0; wTex3 = 0.0; WExists = false; } bool nTexmap::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("texmap"); pXML->SetElAttI("rtexid", RTexID); pXML->SetElAttI("gtexid", GTexID); pXML->SetElAttI("btexid", BTexID); if (ATexIDExists) pXML->SetElAttI("atexid", ATexID); pXML->SetElementD("utex1", uTex1); pXML->SetElementD("utex2", uTex2); pXML->SetElementD("utex3", uTex3); pXML->SetElementD("vtex1", vTex1); pXML->SetElementD("vtex2", vTex2); pXML->SetElementD("vtex3", vTex3); if (WExists){ pXML->SetElementD("wtex1", wTex1); pXML->SetElementD("wtex2", wTex2); pXML->SetElementD("wtex3", wTex3); } pXML->CloseElement(); return true; } bool nTexmap::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); //required attributes if (!pXML->GetElAttI("rtexid", &RTexID)) RTexID = -1; if (!pXML->GetElAttI("gtexid", >exID)) GTexID = -1; if (!pXML->GetElAttI("btexid", &BTexID)) BTexID = -1; //optional attributes if (pXML->GetElAttI("atexid", &ATexID)) ATexIDExists = true; else ATexID = -1; //required tags if (!pXML->GetElementD("utex1", &uTex1)) uTex1 = 0.0; if (!pXML->GetElementD("utex2", &uTex2)) uTex2 = 0.0; if (!pXML->GetElementD("utex3", &uTex3)) uTex3 = 0.0; if (!pXML->GetElementD("vtex1", &vTex1)) vTex1 = 0.0; if (!pXML->GetElementD("vtex2", &vTex2)) vTex2 = 0.0; if (!pXML->GetElementD("vtex3", &vTex3)) vTex3 = 0.0; //optional tags if (pXML->GetElementD("wtex1", &wTex1)) WExists = true; else wTex1 = 0.0; if (pXML->GetElementD("wtex2", &wTex2)) WExists = true; else wTex2 = 0.0; if (pXML->GetElementD("wtex3", &wTex3)) WExists = true; else wTex3 = 0.0; //First draft AMF version of this tag: deprecated, but make sure we still read... //required tags if (vTex1 == 0 && vTex2 == 0 && vTex3 == 0){ if (!pXML->GetElementD("u1", &uTex1)) uTex1 = 0.0; if (!pXML->GetElementD("u2", &uTex2)) uTex2 = 0.0; if (!pXML->GetElementD("u3", &uTex3)) uTex3 = 0.0; if (!pXML->GetElementD("v1", &vTex1)) vTex1 = 0.0; if (!pXML->GetElementD("v2", &vTex2)) vTex2 = 0.0; if (!pXML->GetElementD("v3", &vTex3)) vTex3 = 0.0; //optional tags if (pXML->GetElementD("w1", &wTex1)) WExists = true; else wTex1 = 0.0; if (pXML->GetElementD("w2", &wTex2)) WExists = true; else wTex2 = 0.0; if (pXML->GetElementD("w3", &wTex3)) WExists = true; else wTex3 = 0.0; //end first AMF version tags } return CheckValid(pAmf, !StrictLoad, pMessage); } bool nTexmap::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { if (RTexID == -1) return false; if (GTexID == -1) return false; if (BTexID == -1) return false; if (ATexIDExists && ATexID == -1) return false; return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nTexture.cpp000066400000000000000000000205301231531733200245070ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nTexture.h" #include "XmlStream.h" #include "nAmf.h" nTexture::nTexture(nAmf* pnAmfIn) { pnAmf = pnAmfIn; Clear(); } nTexture::~nTexture(void) { } void nTexture::Clear(void) { aID = -1; aWidth = 1; aHeight = 1; aDepth = 1; Type = TT_GRAYSCALE; aTiled = true; aID = pnAmf->GetUnusedTexID(); BinaryData.clear(); } nTexture& nTexture::operator=(const nTexture& In) { aID = In.aID; aWidth = In.aWidth; aHeight = In.aHeight; aDepth = In.aDepth; Type = In.Type; aTiled = In.aTiled; BinaryData = In.BinaryData; pnAmf = In.pnAmf; return *this; } bool nTexture::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("texture"); pXML->SetElAttI("id", aID); pXML->SetElAttI("width", aWidth); pXML->SetElAttI("height", aHeight); pXML->SetElAttI("depth", aDepth); pXML->SetElAttB("tiled", aTiled); switch (Type){ case TT_GRAYSCALE: pXML->SetElAttS("type", "grayscale"); default: break; } pXML->SetElDataS(DataToBase64()); pXML->CloseElement(); return true; } bool nTexture::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); std::string tmp; if (!pXML->GetElAttI("id", &aID)) {*pMessage += "Did not find valid ID for texture."; return false;} if (!pXML->GetElAttI("width", &aWidth)) aWidth = 1; if (!pXML->GetElAttI("height", &aHeight)) aHeight = 1; if (!pXML->GetElAttI("depth", &aDepth)) aDepth = 1; if (!pXML->GetElAttB("tiled", &aTiled)) aTiled = true; std::string tmpType; if (pXML->GetElAttS("type", &tmpType)){ if(tmpType == "grayscale") Type = TT_GRAYSCALE; else {*pMessage += "Invalid texture type attribute encountered.\n";} } else Type = TT_GRAYSCALE; std::string tmpData; if (pXML->GetElDataS(&tmpData)) Base64ToData(tmpData); //todo: handle if CDATA! else {//loads equation if it exists *pMessage += "Load Error: Invalid data in texture tag. Aborting. \n"; return false; } return CheckValid(pAmf, !StrictLoad, pMessage); } bool nTexture::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //Check stated sizes: Width if (aWidth <= 0){ if (FixNode) {aWidth = 1; if (pMessage) *pMessage += "Warning: Invalid Texture width specified. Setting to 1.\n";} else {if (pMessage) *pMessage += "Error: Invalid Texture width specified.\n"; return false;} } //Check stated sizes: Height if (aHeight <= 0){ if (FixNode) {aHeight = 1; if (pMessage) *pMessage += "Warning: Invalid Texture height specified. Setting to 1.\n";} else {if (pMessage) *pMessage += "Error: Invalid Texture height specified.\n"; return false;} } //Check stated sizes: Depth if (aDepth <= 0){ if (FixNode) {aDepth = 1; if (pMessage) *pMessage += "Warning: Invalid Texture depth specified. Setting to 1.\n";} else {if (pMessage) *pMessage += "Error: Invalid Texture depth specified.\n"; return false; } } //Check data size int NumSpecPic = aWidth*aHeight*aDepth; if ((int)BinaryData.size() < NumSpecPic){ //too little data. BinaryData.resize(NumSpecPic, 0); if (pMessage) *pMessage += "Warning: Not enough texture data for the specified size. Padded with null pixels.\n"; // if (FixNode) {BinaryData.resize(NumSpecPic, 0); if (pMessage) *pMessage += "Warning: Not enough texture data for the specified size. Padded with black pixels.\n";} // else {if (pMessage) *pMessage += "Error: Not enough texture data for the specified size.\n"; return false; } } else if ((int)BinaryData.size() > NumSpecPic){ BinaryData.resize(NumSpecPic); if (pMessage) *pMessage += "Warning: Too much texture data for the specified size. Data truncated accordingly.\n"; // if (FixNode) {BinaryData.resize(NumSpecPic); if (pMessage) *pMessage += "Warning: Too much texture data for the specified size. Data truncated accordingly.\n";} // else {if (pMessage) *pMessage += "Error: Too much texture data for the specified size.\n"; return false; } } //Check for invalid geometry ID if (aID < 0 || pAmf->IsDuplicateTexID(aID)){ if (FixNode) { aID = pAmf->GetUnusedTexID(); if (pMessage) *pMessage += "Warning: Invalid or duplicate texture ID found. Setting to an unused ID. TexMap elements may need to be adjusted.\n"; } else { if (pMessage) *pMessage += "Error: Invalid or duplicate texture ID found.\n"; return false; } } return true; } bool nTexture::Base64ToData(std::string inputBase64) //converts base 64 to data. returns false if not valid B64 data { std::string decoded = FromBase64(inputBase64); if (decoded == "") return false; BinaryData = std::vector(decoded.begin(), decoded.end()); return true; } std::string nTexture::ToBase64(unsigned char const* bytes_to_encode, unsigned int in_len) // Ren Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; i<4; i++) ret += base64_chars[char_array_4[i]]; i = 0; } } if (i){ for(j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j <4; j++) char_array_4[j] = 0; for (j = 0; j <4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } double nTexture::GetValue(double uIn, double vIn, double wIn) { //get closest value (as opposed to interpolation) int uCoord, vCoord, wCoord; if (uIn == 1.0) uCoord = aWidth-1; else uCoord = (int)(uIn*aWidth); if (vIn == 1.0) vCoord = aHeight-1; else vCoord = (int)(vIn*aHeight); if (wIn == 1.0) wCoord = aDepth-1; else wCoord = (int)(wIn*aDepth); unsigned char val = BinaryData[aWidth*aHeight*wCoord+aWidth*vCoord+uCoord]; return (double)val/255.0; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nTriangle.cpp000066400000000000000000000065341231531733200246240ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nTriangle.h" #include "XmlStream.h" nTriangle::nTriangle(void) { Clear(); } nTriangle::~nTriangle(void) { } nTriangle& nTriangle::operator=(const nTriangle& In) { v1 = In.v1; v2 = In.v2; v3 = In.v3; ColorExists = In.ColorExists; Color = In.Color; TexMapExists = In.TexMapExists; TexMap = In.TexMap; // MapList = In.MapList; return *this; } void nTriangle::Clear(void) { v1 = 0; v2 = 0; v3 = 0; ColorExists = false; Color.Clear(); TexMapExists = false; TexMap.Clear(); // MapList.clear(); } bool nTriangle::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("triangle"); if (ColorExists) if (!Color.WriteXML(pXML, pMessage)) return false; pXML->SetElementI("v1", v1); pXML->SetElementI("v2", v2); pXML->SetElementI("v3", v3); if (TexMapExists) if (!TexMap.WriteXML(pXML, pMessage)) return false; pXML->CloseElement(); return true; } bool nTriangle::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); if (!pXML->GetElementI("v1", &v1)) {v1 = -1; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementI("v2", &v2)) {v2 = -1; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (!pXML->GetElementI("v3", &v3)) {v3 = -1; *pMessage = " tag found without a tag. Load canceled.\n"; return false;} if (pXML->OpenElement("color")){Color.ReadXML(pXML, pAmf, StrictLoad, pMessage); ColorExists=true; pXML->CloseElement();} if (pXML->OpenElement("texmap")){TexMap.ReadXML(pXML, pAmf, StrictLoad, pMessage); TexMapExists=true; pXML->CloseElement();} //read as many map tags as there are... //nTexmap tmpMap; // while(pXML->OpenElement("texmap", true)){ // // if (!tmpMap.ReadXML(pXML, pAmf, pMessage)) return false; // MapList.push_back(tmpMap); // MapListTest.push_back(0); //} //deprecated old tag now changed to Delete this eventually! if (pXML->OpenElement("map")){TexMap.ReadXML(pXML, pAmf, StrictLoad, pMessage); TexMapExists=true; pXML->CloseElement();} //while(pXML->OpenElement("map", true)){ // // if (!tmpMap.ReadXML(pXML, pAmf, pMessage)) return false; // MapList.push_back(tmpMap); // MapListTest.push_back(0); //} return true; } bool nTriangle::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { if (v1 == -1 || v2 == -1 || v3 == -1) return false; else return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nVertex.cpp000066400000000000000000000053221231531733200243260ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nVertex.h" #include "XmlStream.h" nVertex::nVertex(void) { Clear(); } nVertex::~nVertex(void) { } nVertex::nVertex(const double X, const double Y, const double Z) { Clear(); Coordinates = nCoordinates(X, Y, Z); } nVertex::nVertex(const double X, const double Y, const double Z, const nColor& ColorIn) { Clear(); Coordinates = nCoordinates(X, Y, Z); ColorExists = true; Color = ColorIn; } nVertex& nVertex::operator=(const nVertex& In) { Coordinates = In.Coordinates; NormalExists = In.NormalExists; Normal = In.Normal; ColorExists = In.ColorExists; Color = In.Color; return *this; } void nVertex::Clear(void) { Coordinates.Clear(); NormalExists = false; Normal.Clear(); ColorExists = false; Color.Clear(); } bool nVertex::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage) { pXML->OpenElement("vertex"); if (!Coordinates.WriteXML(pXML, pMessage)) return false; if (NormalExists) if (!Normal.WriteXML(pXML, pMessage)) return false; if (ColorExists) if(!Color.WriteXML(pXML, pMessage)) return false; pXML->CloseElement(); return true; } bool nVertex::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage) { Clear(); //required tags if (pXML->OpenElement("coordinates")){Coordinates.ReadXML(pXML, pAmf, StrictLoad, pMessage); pXML->CloseElement();} else {*pMessage += "No coordinates found in tag."; return false;} //optional tags if (pXML->OpenElement("normal")){Normal.ReadXML(pXML, pAmf, StrictLoad, pMessage); NormalExists=true; pXML->CloseElement();} if (pXML->OpenElement("color")){Color.ReadXML(pXML, pAmf, StrictLoad, pMessage); ColorExists=true; pXML->CloseElement();} return CheckValid(pAmf, !StrictLoad, pMessage); } bool nVertex::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //TODO: return true; } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nVertices.cpp000066400000000000000000000115471231531733200246430ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nVertices.h" #include "XmlStream.h" #include "nVertex.h" #include "nEdge.h" #include "Vec3D.h" nVertices::nVertices(void) { Clear(); } nVertices::~nVertices(void) { } nVertices& nVertices::operator=(const nVertices& In) { VertexList = In.VertexList; EdgeList = In.EdgeList; return *this; } void nVertices::Clear(void) { VertexList.clear(); EdgeList.clear(); } bool nVertices::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; pXML->OpenElement("vertices"); //vertices... for(std::vector::iterator it = VertexList.begin(); it != VertexList.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; if (pCancelFlag && *pCancelFlag) return false; } //edges for(std::vector::iterator it = EdgeList.begin(); it != EdgeList.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; if (pCancelFlag && *pCancelFlag) return false; } pXML->CloseElement(); return true; } bool nVertices::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; Clear(); //read as many vertex tags as there are... nVertex tmpVert; while(pXML->OpenElement("vertex", true)){ // if (!tmpVert.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; VertexList.push_back(tmpVert); if (pCancelFlag && *pCancelFlag) return false; } //read as many edge tags as there are... nEdge tmpEdge; while(pXML->OpenElement("edge", true)){ // if (!tmpEdge.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; EdgeList.push_back(tmpEdge); if (pCancelFlag && *pCancelFlag) return false; } return CheckValid(pAmf, !StrictLoad, pMessage); } bool nVertices::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { if (VertexList.size() == 0){ if (pMessage) *pMessage += "Warning: No vertices found in vertices tag.\n"; } //check if edges reference any vertices that don't exist int NumVert = VertexList.size(); std::vectorEdgeToDelete; int count=0; for (std::vector::iterator it = EdgeList.begin(); it!=EdgeList.end(); it++){ bool DeleteEdge = false; for (int i=0; i<2; i++){ int ThisInd; switch (i){ case 0: ThisInd = it->v1; break; case 1: ThisInd = it->v2; break; } if (ThisInd >= NumVert){ if (FixNode) { DeleteEdge = true; if (pMessage) *pMessage += "Warning: Edge references non-existent vertex. Deleting edge.\n"; } else { if (pMessage) *pMessage += "Error: Edge references non-existent vertex.\n"; return false; } } } if (DeleteEdge) EdgeToDelete.push_back(count); count++; } for (int i=EdgeToDelete.size()-1; i >= 0; i--){ //go backwards so out indices stay correct... EdgeList.erase(EdgeList.begin()+EdgeToDelete[i]); } //Todo: //check for duplicate edges (that reference the same two vertices) return true; } void nVertices::Translate(double dx, double dy, double dz) { for(std::vector::iterator it = VertexList.begin(); it != VertexList.end(); it++){ it->SetCoordinates(it->GetX()+dx, it->GetY()+dy, it->GetZ()+dz); } } void nVertices::Rotate(double rx, double ry, double rz) { for(std::vector::iterator it = VertexList.begin(); it != VertexList.end(); it++){ Vec3D Loc = Vec3D(it->GetX(), it->GetY(), it->GetZ()); Vec3D Normal = Vec3D(it->GetNX(), it->GetNY(), it->GetNZ()); Loc.RotX(rx); Loc.RotY(ry); Loc.RotZ(rz); Normal.RotX(rx); Normal.RotY(ry); Normal.RotZ(rz); it->SetCoordinates(Loc.x, Loc.y, Loc.z); it->SetNormal(Normal.x, Normal.y, Normal.z); } for (std::vector::iterator it = EdgeList.begin(); it!=EdgeList.end(); it++){ Vec3D t1=Vec3D(it->dx1, it->dy1, it->dz1); Vec3D t2=Vec3D(it->dx2, it->dy2, it->dz2); t1.RotX(rx); t1.RotY(ry); t1.RotZ(rz); t2.RotX(rx); t2.RotY(ry); t2.RotZ(rz); it->SetDirectionVectors(t1.x, t1.y, t1.z, t2.x, t2.y, t2.z); } } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/nVolume.cpp000066400000000000000000000117501231531733200243220ustar00rootroot00000000000000/******************************************************************************* Copyright (c) 2012, Jonathan Hiller This file is part of the AMF Tools suite. http://amf.wikispaces.com/ AMF Tools is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AMF Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. See for license details. *******************************************************************************/ #include "nVolume.h" #include "XmlStream.h" #include "nTriangle.h" nVolume::nVolume(void) { Clear(); } nVolume::~nVolume(void) { } nVolume::nVolume(std::string Name) { Clear(); if (Name != "") Metadata.push_back(nMetadata(MD_NAME, Name)); } nVolume& nVolume::operator=(const nVolume& In) { MaterialIDExists = In.MaterialIDExists; aMaterialID = In.aMaterialID; // TypeExists = In.TypeExists; // Type = In.Type; Triangles = In.Triangles; ColorExists = In.ColorExists; Color = In.Color; Metadata = In.Metadata; return *this; } void nVolume::Clear(void) { MaterialIDExists = false; aMaterialID = -1; // TypeExists = false; // Type = VT_OBJECT; Triangles.clear(); ColorExists = false; Color.Clear(); Metadata.clear(); } bool nVolume::WriteXML(CXmlStreamWrite* pXML, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; pXML->OpenElement("volume"); if (MaterialIDExists) pXML->SetElAttI("materialid", aMaterialID); // if (TypeExists){ // if (Type == VT_OBJECT) pXML->SetElAttS("type", "object"); // else if (Type == VT_SUPPORT) pXML->SetElAttS("type", "support"); // } for(std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; } if (ColorExists) if (!Color.WriteXML(pXML, pMessage)) return false; for(std::vector::iterator it = Triangles.begin(); it != Triangles.end(); it++){ if (!it->WriteXML(pXML, pMessage)) return false; if (pCancelFlag && *pCancelFlag) return false; } pXML->CloseElement(); return true; } bool nVolume::ReadXML(CXmlStreamRead* pXML, nAmf* pAmf, bool StrictLoad, std::string* pMessage, bool* pCancelFlag) { if (pCancelFlag && *pCancelFlag) return false; Clear(); if (pXML->GetElAttI("materialid", &aMaterialID)) MaterialIDExists = true; // std::string GetType; // if (pXML->GetElAttS("type", &GetType)){ // TypeExists = true; // if (GetType == "object") Type = VT_OBJECT; // else if(GetType == "support") Type = VT_SUPPORT; // else { // TypeExists = false; //invalid type // *pMessage += "invalid type attribute encountered. \"object\" and \"support\" are only supported values.\n"; // } //} //read as many metadata tags as there are... nMetadata tmpMeta; while(pXML->OpenElement("metadata", true)){ // if (!tmpMeta.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Metadata.push_back(tmpMeta); } // if (Metadata.size() != 0) pXML->UpLevel(); // if (pXML->OpenElement("color")){Color.ReadXML(pXML, pAmf, StrictLoad, pMessage); ColorExists=true; pXML->CloseElement();} //read as many triangle tags as there are... nTriangle tmpTri; while(pXML->OpenElement("triangle", true)){ // if (!tmpTri.ReadXML(pXML, pAmf, StrictLoad, pMessage)) return false; Triangles.push_back(tmpTri); if (pCancelFlag && *pCancelFlag) return false; } // if (Triangles.size() != 0) pXML->UpLevel(); // return CheckValid(pAmf, !StrictLoad, pMessage); } bool nVolume::CheckValid(nAmf* pAmf, bool FixNode, std::string* pMessage) { //copied from load... if (Triangles.size() == 0) {*pMessage += "No triangles in volume tag.\n"; return false;} //check for duplicate triangles? (i.e. referencing same vertices) else return true; } void nVolume::SetName(std::string NewName) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME){ it->Data = NewName; //replace the name!! return; } } //if we get here there was no existing Name metadata so add one... Metadata.push_back(nMetadata(MD_NAME, NewName)); } std::string nVolume::GetName(void) { for (std::vector::iterator it = Metadata.begin(); it != Metadata.end(); it++){ if(it->Type == MD_NAME) return it->Data; } return ""; } void nVolume::SetMaterialID(int NewMatId) { aMaterialID = NewMatId; MaterialIDExists = true; } bool nVolume::GetMaterialID(int* pMatIdRet) { if (MaterialIDExists){ *pMatIdRet = aMaterialID; return true; } else return false; //no materialID } repsnapper-2.3.2a5/libraries/amf/amftools-code/src/stb_image/000077500000000000000000000000001231531733200241175ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/src/stb_image/stb_image.cpp000066400000000000000000004145331231531733200265670ustar00rootroot00000000000000#include "stb_image/stb_image.h" #ifndef STBI_HEADER_FILE_ONLY #ifndef STBI_NO_HDR #include // ldexp #include // strcmp, strtok #endif #ifndef STBI_NO_STDIO #include #endif #include #include #include #include #ifndef _MSC_VER #ifdef __cplusplus #define stbi_inline inline #else #define stbi_inline #endif #else #define stbi_inline __forceinline #endif // implementation: typedef unsigned char uint8; typedef unsigned short uint16; typedef signed short int16; typedef unsigned int uint32; typedef signed int int32; typedef unsigned int uint; // should produce compiler error if size is wrong typedef unsigned char validate_uint32[sizeof(uint32)==4 ? 1 : -1]; #if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE) #define STBI_NO_WRITE #endif #define STBI_NOTUSED(v) (void)sizeof(v) #ifdef _MSC_VER #define STBI_HAS_LROTL #endif #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #endif /////////////////////////////////////////////// // // stbi struct and start_xxx functions // stbi structure is our basic context used by all images, so it // contains all the IO context, plus some basic image information typedef struct { uint32 img_x, img_y; int img_n, img_out_n; stbi_io_callbacks io; void *io_user_data; int read_from_callbacks; int buflen; uint8 buffer_start[128]; uint8 *img_buffer, *img_buffer_end; uint8 *img_buffer_original; } stbi; static void refill_buffer(stbi *s); // initialize a memory-decode context static void start_mem(stbi *s, uint8 const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; s->img_buffer = s->img_buffer_original = (uint8 *) buffer; s->img_buffer_end = (uint8 *) buffer+len; } // initialize a callback-based context static void start_callbacks(stbi *s, stbi_io_callbacks *c, void *user) { s->io = *c; s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; s->img_buffer_original = s->buffer_start; refill_buffer(s); } #ifndef STBI_NO_STDIO static int stdio_read(void *user, char *data, int size) { return (int) fread(data,1,size,(FILE*) user); } static void stdio_skip(void *user, unsigned n) { fseek((FILE*) user, n, SEEK_CUR); } static int stdio_eof(void *user) { return feof((FILE*) user); } static stbi_io_callbacks stbi_stdio_callbacks = { stdio_read, stdio_skip, stdio_eof, }; static void start_file(stbi *s, FILE *f) { start_callbacks(s, &stbi_stdio_callbacks, (void *) f); } //static void stop_file(stbi *s) { } #endif // !STBI_NO_STDIO static void stbi_rewind(stbi *s) { // conceptually rewind SHOULD rewind to the beginning of the stream, // but we just rewind to the beginning of the initial buffer, because // we only use it after doing 'test', which only ever looks at at most 92 bytes s->img_buffer = s->img_buffer_original; } static int stbi_jpeg_test(stbi *s); static stbi_uc *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp); static int stbi_png_test(stbi *s); static stbi_uc *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_png_info(stbi *s, int *x, int *y, int *comp); static int stbi_bmp_test(stbi *s); static stbi_uc *stbi_bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_tga_test(stbi *s); static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_tga_info(stbi *s, int *x, int *y, int *comp); static int stbi_psd_test(stbi *s); static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_hdr_test(stbi *s); static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_pic_test(stbi *s); static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_gif_test(stbi *s); static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp); static int stbi_gif_info(stbi *s, int *x, int *y, int *comp); // this is not threadsafe static const char *failure_reason; const char *stbi_failure_reason(void) { return failure_reason; } static int e(const char *str) { failure_reason = str; return 0; } // e - error // epf - error returning pointer to float // epuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS #define e(x,y) 0 #elif defined(STBI_FAILURE_USERMSG) #define e(x,y) e(y) #else #define e(x,y) e(x) #endif #define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) #define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) void stbi_image_free(void *retval_from_stbi_load) { free(retval_from_stbi_load); } #ifndef STBI_NO_HDR static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); #endif static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp) { if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp); if (stbi_png_test(s)) return stbi_png_load(s,x,y,comp,req_comp); if (stbi_bmp_test(s)) return stbi_bmp_load(s,x,y,comp,req_comp); if (stbi_gif_test(s)) return stbi_gif_load(s,x,y,comp,req_comp); if (stbi_psd_test(s)) return stbi_psd_load(s,x,y,comp,req_comp); if (stbi_pic_test(s)) return stbi_pic_load(s,x,y,comp,req_comp); #ifndef STBI_NO_HDR if (stbi_hdr_test(s)) { float *hdr = stbi_hdr_load(s, x,y,comp,req_comp); return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); } #endif // test tga last because it's a crappy test! if (stbi_tga_test(s)) return stbi_tga_load(s,x,y,comp,req_comp); return epuc("unknown image type", "Image not of any known type, or corrupt"); } #ifndef STBI_NO_STDIO unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) { FILE *f = fopen(filename, "rb"); unsigned char *result; if (!f) return epuc("can't fopen", "Unable to open file"); result = stbi_load_from_file(f,x,y,comp,req_comp); fclose(f); return result; } unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi s; start_file(&s,f); return stbi_load_main(&s,x,y,comp,req_comp); } #endif //!STBI_NO_STDIO unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi s; start_mem(&s,buffer,len); return stbi_load_main(&s,x,y,comp,req_comp); } unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi s; start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi_load_main(&s,x,y,comp,req_comp); } #ifndef STBI_NO_HDR float *stbi_loadf_main(stbi *s, int *x, int *y, int *comp, int req_comp) { unsigned char *data; #ifndef STBI_NO_HDR if (stbi_hdr_test(s)) return stbi_hdr_load(s,x,y,comp,req_comp); #endif data = stbi_load_main(s, x, y, comp, req_comp); if (data) return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); return epf("unknown image type", "Image not of any known type, or corrupt"); } float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi s; start_mem(&s,buffer,len); return stbi_loadf_main(&s,x,y,comp,req_comp); } float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi s; start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi_loadf_main(&s,x,y,comp,req_comp); } #ifndef STBI_NO_STDIO float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) { FILE *f = fopen(filename, "rb"); float *result; if (!f) return epf("can't fopen", "Unable to open file"); result = stbi_loadf_from_file(f,x,y,comp,req_comp); fclose(f); return result; } float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi s; start_file(&s,f); return stbi_loadf_main(&s,x,y,comp,req_comp); } #endif // !STBI_NO_STDIO #endif // !STBI_NO_HDR // these is-hdr-or-not is defined independent of whether STBI_NO_HDR is // defined, for API simplicity; if STBI_NO_HDR is defined, it always // reports false! int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { #ifndef STBI_NO_HDR stbi s; start_mem(&s,buffer,len); return stbi_hdr_test(&s); #else STBI_NOTUSED(buffer); STBI_NOTUSED(len); return 0; #endif } #ifndef STBI_NO_STDIO extern int stbi_is_hdr (char const *filename) { FILE *f = fopen(filename, "rb"); int result=0; if (f) { result = stbi_is_hdr_from_file(f); fclose(f); } return result; } extern int stbi_is_hdr_from_file(FILE *f) { #ifndef STBI_NO_HDR stbi s; start_file(&s,f); return stbi_hdr_test(&s); #else return 0; #endif } #endif // !STBI_NO_STDIO extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) { #ifndef STBI_NO_HDR stbi s; start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi_hdr_test(&s); #else return 0; #endif } #ifndef STBI_NO_HDR static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; static float l2h_gamma=2.2f, l2h_scale=1.0f; void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } #endif ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // enum { SCAN_load=0, SCAN_type, SCAN_header }; static void refill_buffer(stbi *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); if (n == 0) { // at end of file, treat same as if from memory s->read_from_callbacks = 0; s->img_buffer = s->img_buffer_end-1; *s->img_buffer = 0; } else { s->img_buffer = s->buffer_start; s->img_buffer_end = s->buffer_start + n; } } stbi_inline static int get8(stbi *s) { if (s->img_buffer < s->img_buffer_end) return *s->img_buffer++; if (s->read_from_callbacks) { refill_buffer(s); return *s->img_buffer++; } return 0; } stbi_inline static int at_eof(stbi *s) { if (s->io.read) { if (!(s->io.eof)(s->io_user_data)) return 0; // if feof() is true, check if buffer = end // special case: we've only got the special 0 character at the end if (s->read_from_callbacks == 0) return 1; } return s->img_buffer >= s->img_buffer_end; } stbi_inline static uint8 get8u(stbi *s) { return (uint8) get8(s); } static void skip(stbi *s, int n) { if (s->io.read) { int blen = s->img_buffer_end - s->img_buffer; if (blen < n) { s->img_buffer = s->img_buffer_end; (s->io.skip)(s->io_user_data, n - blen); return; } } s->img_buffer += n; } static int getn(stbi *s, stbi_uc *buffer, int n) { if (s->io.read) { int blen = s->img_buffer_end - s->img_buffer; if (blen < n) { int res, count; memcpy(buffer, s->img_buffer, blen); count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); res = (count == (n-blen)); s->img_buffer = s->img_buffer_end; return res; } } if (s->img_buffer+n <= s->img_buffer_end) { memcpy(buffer, s->img_buffer, n); s->img_buffer += n; return 1; } else return 0; } static int get16(stbi *s) { int z = get8(s); return (z << 8) + get8(s); } static uint32 get32(stbi *s) { uint32 z = get16(s); return (z << 16) + get16(s); } static int get16le(stbi *s) { int z = get8(s); return z + (get8(s) << 8); } static uint32 get32le(stbi *s) { uint32 z = get16le(s); return z + (get16le(s) << 16); } ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp // individual types do this automatically as much as possible (e.g. jpeg // does all cases internally since it needs to colorspace convert anyway, // and it never has alpha, so very few cases ). png can automatically // interleave an alpha=255 channel, but falls back to this for other cases // // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing static uint8 compute_y(int r, int g, int b) { return (uint8) (((r*77) + (g*150) + (29*b)) >> 8); } static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, uint x, uint y) { int i,j; unsigned char *good; if (req_comp == img_n) return data; assert(req_comp >= 1 && req_comp <= 4); good = (unsigned char *) malloc(req_comp * x * y); if (good == NULL) { free(data); return epuc("outofmem", "Out of memory"); } for (j=0; j < (int) y; ++j) { unsigned char *src = data + j * x * img_n ; unsigned char *dest = good + j * x * req_comp; #define COMBO(a,b) ((a)*8+(b)) #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (COMBO(img_n, req_comp)) { CASE(1,2) dest[0]=src[0], dest[1]=255; break; CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; CASE(2,1) dest[0]=src[0]; break; CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; default: assert(0); } #undef CASE } free(data); return good; } #ifndef STBI_NO_HDR static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { int i,k,n; float *output = (float *) malloc(x * y * comp * sizeof(float)); if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { for (k=0; k < n; ++k) { output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; } if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; } free(data); return output; } #define float2int(x) ((int) (x)) static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) { int i,k,n; stbi_uc *output = (stbi_uc *) malloc(x * y * comp); if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { for (k=0; k < n; ++k) { float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; if (z < 0) z = 0; if (z > 255) z = 255; output[i*comp + k] = (uint8) float2int(z); } if (k < comp) { float z = data[i*comp+k] * 255 + 0.5f; if (z < 0) z = 0; if (z > 255) z = 255; output[i*comp + k] = (uint8) float2int(z); } } free(data); return output; } #endif ////////////////////////////////////////////////////////////////////////////// // // "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) // // simple implementation // - channel subsampling of at most 2 in each dimension // - doesn't support delayed output of y-dimension // - simple interface (only one output format: 8-bit interleaved RGB) // - doesn't try to recover corrupt jpegs // - doesn't allow partial loading, loading multiple at once // - still fast on x86 (copying globals into locals doesn't help x86) // - allocates lots of intermediate memory (full size of all components) // - non-interleaved case requires this anyway // - allows good upsampling (see next) // high-quality // - upsampled channels are bilinearly interpolated, even across blocks // - quality integer IDCT derived from IJG's 'slow' // performance // - fast huffman; reasonable integer IDCT // - uses a lot of intermediate memory, could cache poorly // - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 // stb_jpeg: 1.34 seconds (MSVC6, default release build) // stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) // IJL11.dll: 1.08 seconds (compiled by intel) // IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) // IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) // huffman decoding acceleration #define FAST_BITS 9 // larger handles more cases; smaller stomps less cache typedef struct { uint8 fast[1 << FAST_BITS]; // weirdly, repacking this into AoS is a 10% speed loss, instead of a win uint16 code[256]; uint8 values[256]; uint8 size[257]; unsigned int maxcode[18]; int delta[17]; // old 'firstsymbol' - old 'firstcode' } huffman; typedef struct { #ifdef STBI_SIMD unsigned short dequant2[4][64]; #endif stbi *s; huffman huff_dc[4]; huffman huff_ac[4]; uint8 dequant[4][64]; // sizes for components, interleaved MCUs int img_h_max, img_v_max; int img_mcu_x, img_mcu_y; int img_mcu_w, img_mcu_h; // definition of jpeg image component struct { int id; int h,v; int tq; int hd,ha; int dc_pred; int x,y,w2,h2; uint8 *data; void *raw_data; uint8 *linebuf; } img_comp[4]; uint32 code_buffer; // jpeg entropy-coded buffer int code_bits; // number of valid bits unsigned char marker; // marker seen while filling entropy buffer int nomore; // flag if we saw a marker so must stop int scan_n, order[4]; int restart_interval, todo; } jpeg; static int build_huffman(huffman *h, int *count) { int i,j,k=0,code; // build size list for each symbol (from JPEG spec) for (i=0; i < 16; ++i) for (j=0; j < count[i]; ++j) h->size[k++] = (uint8) (i+1); h->size[k] = 0; // compute actual symbols (from jpeg spec) code = 0; k = 0; for(j=1; j <= 16; ++j) { // compute delta to add to code to compute symbol id h->delta[j] = k - code; if (h->size[k] == j) { while (h->size[k] == j) h->code[k++] = (uint16) (code++); if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); } // compute largest code + 1 for this size, preshifted as needed later h->maxcode[j] = code << (16-j); code <<= 1; } h->maxcode[j] = 0xffffffff; // build non-spec acceleration table; 255 is flag for not-accelerated memset(h->fast, 255, 1 << FAST_BITS); for (i=0; i < k; ++i) { int s = h->size[i]; if (s <= FAST_BITS) { int c = h->code[i] << (FAST_BITS-s); int m = 1 << (FAST_BITS-s); for (j=0; j < m; ++j) { h->fast[c+j] = (uint8) i; } } } return 1; } static void grow_buffer_unsafe(jpeg *j) { do { int b = j->nomore ? 0 : get8(j->s); if (b == 0xff) { int c = get8(j->s); if (c != 0) { j->marker = (unsigned char) c; j->nomore = 1; return; } } j->code_buffer |= b << (24 - j->code_bits); j->code_bits += 8; } while (j->code_bits <= 24); } // (1 << n) - 1 static uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; // decode a jpeg huffman value from the bitstream stbi_inline static int decode(jpeg *j, huffman *h) { unsigned int temp; int c,k; if (j->code_bits < 16) grow_buffer_unsafe(j); // look at the top FAST_BITS and determine what symbol ID it is, // if the code is <= FAST_BITS c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); k = h->fast[c]; if (k < 255) { int s = h->size[k]; if (s > j->code_bits) return -1; j->code_buffer <<= s; j->code_bits -= s; return h->values[k]; } // naive test is to shift the code_buffer down so k bits are // valid, then test against maxcode. To speed this up, we've // preshifted maxcode left so that it has (16-k) 0s at the // end; in other words, regardless of the number of bits, it // wants to be compared against something shifted to have 16; // that way we don't need to shift inside the loop. temp = j->code_buffer >> 16; for (k=FAST_BITS+1 ; ; ++k) if (temp < h->maxcode[k]) break; if (k == 17) { // error! code not found j->code_bits -= 16; return -1; } if (k > j->code_bits) return -1; // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k]; assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol j->code_bits -= k; j->code_buffer <<= k; return h->values[c]; } // combined JPEG 'receive' and JPEG 'extend', since baseline // always extends everything it receives. stbi_inline static int extend_receive(jpeg *j, int n) { unsigned int m = 1 << (n-1); unsigned int k; if (j->code_bits < n) grow_buffer_unsafe(j); #if 1 k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~bmask[n]; k &= bmask[n]; j->code_bits -= n; #else k = (j->code_buffer >> (32 - n)) & bmask[n]; j->code_bits -= n; j->code_buffer <<= n; #endif // the following test is probably a random branch that won't // predict well. I tried to table accelerate it but failed. // maybe it's compiling as a conditional move? if (k < m) return (-1 << n) + k + 1; else return k; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? static uint8 dezigzag[64+15] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, // let corrupt input sample past end 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }; // decode one 64-entry block-- static int decode_block(jpeg *j, short data[64], huffman *hdc, huffman *hac, int b) { int diff,dc,k; int t = decode(j, hdc); if (t < 0) return e("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; data[0] = (short) dc; // decode AC components, see JPEG spec k = 1; do { int r,s; int rs = decode(j, hac); if (rs < 0) return e("bad huffman code","Corrupt JPEG"); s = rs & 15; r = rs >> 4; if (s == 0) { if (rs != 0xf0) break; // end block k += 16; } else { k += r; // decode into unzigzag'd location data[dezigzag[k++]] = (short) extend_receive(j,s); } } while (k < 64); return 1; } // take a -128..127 value and clamp it and convert to 0..255 stbi_inline static uint8 clamp(int x) { // trick to use a single test to catch both cases if ((unsigned int) x > 255) { if (x < 0) return 0; if (x > 255) return 255; } return (uint8) x; } #define f2f(x) (int) (((x) * 4096 + 0.5)) #define fsh(x) ((x) << 12) // derived from jidctint -- DCT_ISLOW #define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ p2 = s2; \ p3 = s6; \ p1 = (p2+p3) * f2f(0.5411961f); \ t2 = p1 + p3*f2f(-1.847759065f); \ t3 = p1 + p2*f2f( 0.765366865f); \ p2 = s0; \ p3 = s4; \ t0 = fsh(p2+p3); \ t1 = fsh(p2-p3); \ x0 = t0+t3; \ x3 = t0-t3; \ x1 = t1+t2; \ x2 = t1-t2; \ t0 = s7; \ t1 = s5; \ t2 = s3; \ t3 = s1; \ p3 = t0+t2; \ p4 = t1+t3; \ p1 = t0+t3; \ p2 = t1+t2; \ p5 = (p3+p4)*f2f( 1.175875602f); \ t0 = t0*f2f( 0.298631336f); \ t1 = t1*f2f( 2.053119869f); \ t2 = t2*f2f( 3.072711026f); \ t3 = t3*f2f( 1.501321110f); \ p1 = p5 + p1*f2f(-0.899976223f); \ p2 = p5 + p2*f2f(-2.562915447f); \ p3 = p3*f2f(-1.961570560f); \ p4 = p4*f2f(-0.390180644f); \ t3 += p1+p4; \ t2 += p2+p3; \ t1 += p2+p4; \ t0 += p1+p3; #ifdef STBI_SIMD typedef unsigned short stbi_dequantize_t; #else typedef uint8 stbi_dequantize_t; #endif // .344 seconds on 3*anemones.jpg static void idct_block(uint8 *out, int out_stride, short data[64], stbi_dequantize_t *dequantize) { int i,val[64],*v=val; stbi_dequantize_t *dq = dequantize; uint8 *o; short *d = data; // columns for (i=0; i < 8; ++i,++d,++dq, ++v) { // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 && d[40]==0 && d[48]==0 && d[56]==0) { // no shortcut 0 seconds // (1|2|3|4|5|6|7)==0 0 seconds // all separate -0.047 seconds // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds int dcterm = d[0] * dq[0] << 2; v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; } else { IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) // constants scaled things up by 1<<12; let's bring them back // down, but keep 2 extra bits of precision x0 += 512; x1 += 512; x2 += 512; x3 += 512; v[ 0] = (x0+t3) >> 10; v[56] = (x0-t3) >> 10; v[ 8] = (x1+t2) >> 10; v[48] = (x1-t2) >> 10; v[16] = (x2+t1) >> 10; v[40] = (x2-t1) >> 10; v[24] = (x3+t0) >> 10; v[32] = (x3-t0) >> 10; } } for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { // no fast case since the first 1D IDCT spread components out IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) // constants scaled things up by 1<<12, plus we had 1<<2 from first // loop, plus horizontal and vertical each scale by sqrt(8) so together // we've got an extra 1<<3, so 1<<17 total we need to remove. // so we want to round that, which means adding 0.5 * 1<<17, // aka 65536. Also, we'll end up with -128 to 127 that we want // to encode as 0..255 by adding 128, so we'll add that before the shift x0 += 65536 + (128<<17); x1 += 65536 + (128<<17); x2 += 65536 + (128<<17); x3 += 65536 + (128<<17); // tried computing the shifts into temps, or'ing the temps to see // if any were out of range, but that was slower o[0] = clamp((x0+t3) >> 17); o[7] = clamp((x0-t3) >> 17); o[1] = clamp((x1+t2) >> 17); o[6] = clamp((x1-t2) >> 17); o[2] = clamp((x2+t1) >> 17); o[5] = clamp((x2-t1) >> 17); o[3] = clamp((x3+t0) >> 17); o[4] = clamp((x3-t0) >> 17); } } #ifdef STBI_SIMD static stbi_idct_8x8 stbi_idct_installed = idct_block; void stbi_install_idct(stbi_idct_8x8 func) { stbi_idct_installed = func; } #endif #define MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value static uint8 get_marker(jpeg *j) { uint8 x; if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; } x = get8u(j->s); if (x != 0xff) return MARKER_none; while (x == 0xff) x = get8u(j->s); return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] #define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, reset the entropy decoder and // the dc prediction static void reset(jpeg *j) { j->code_bits = 0; j->code_buffer = 0; j->nomore = 0; j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; j->marker = MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, // since we don't even allow 1<<30 pixels } static int parse_entropy_coded_data(jpeg *z) { reset(z); if (z->scan_n == 1) { int i,j; #ifdef STBI_SIMD __declspec(align(16)) #endif short data[64]; int n = z->order[0]; // non-interleaved data, we just need to process one block at a time, // in trivial scanline order // number of blocks to do just depends on how many actual "pixels" this // component has, independent of interleaved MCU blocking and such int w = (z->img_comp[n].x+7) >> 3; int h = (z->img_comp[n].y+7) >> 3; for (j=0; j < h; ++j) { for (i=0; i < w; ++i) { if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; #ifdef STBI_SIMD stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); #else idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); #endif // every data block is an MCU, so countdown the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) grow_buffer_unsafe(z); // if it's NOT a restart, then just bail, so we get corrupt data // rather than no data if (!RESTART(z->marker)) return 1; reset(z); } } } } else { // interleaved! int i,j,k,x,y; short data[64]; for (j=0; j < z->img_mcu_y; ++j) { for (i=0; i < z->img_mcu_x; ++i) { // scan an interleaved mcu... process scan_n components in order for (k=0; k < z->scan_n; ++k) { int n = z->order[k]; // scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (y=0; y < z->img_comp[n].v; ++y) { for (x=0; x < z->img_comp[n].h; ++x) { int x2 = (i*z->img_comp[n].h + x)*8; int y2 = (j*z->img_comp[n].v + y)*8; if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; #ifdef STBI_SIMD stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); #else idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); #endif } } } // after all interleaved components, that's an interleaved MCU, // so now count down the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) grow_buffer_unsafe(z); // if it's NOT a restart, then just bail, so we get corrupt data // rather than no data if (!RESTART(z->marker)) return 1; reset(z); } } } } return 1; } static int process_marker(jpeg *z, int m) { int L; switch (m) { case MARKER_none: // no marker found return e("expected marker","Corrupt JPEG"); case 0xC2: // SOF - progressive return e("progressive jpeg","JPEG format not supported (progressive)"); case 0xDD: // DRI - specify restart interval if (get16(z->s) != 4) return e("bad DRI len","Corrupt JPEG"); z->restart_interval = get16(z->s); return 1; case 0xDB: // DQT - define quantization table L = get16(z->s)-2; while (L > 0) { int q = get8(z->s); int p = q >> 4; int t = q & 15,i; if (p != 0) return e("bad DQT type","Corrupt JPEG"); if (t > 3) return e("bad DQT table","Corrupt JPEG"); for (i=0; i < 64; ++i) z->dequant[t][dezigzag[i]] = get8u(z->s); #ifdef STBI_SIMD for (i=0; i < 64; ++i) z->dequant2[t][i] = z->dequant[t][i]; #endif L -= 65; } return L==0; case 0xC4: // DHT - define huffman table L = get16(z->s)-2; while (L > 0) { uint8 *v; int sizes[16],i,m=0; int q = get8(z->s); int tc = q >> 4; int th = q & 15; if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); for (i=0; i < 16; ++i) { sizes[i] = get8(z->s); m += sizes[i]; } L -= 17; if (tc == 0) { if (!build_huffman(z->huff_dc+th, sizes)) return 0; v = z->huff_dc[th].values; } else { if (!build_huffman(z->huff_ac+th, sizes)) return 0; v = z->huff_ac[th].values; } for (i=0; i < m; ++i) v[i] = get8u(z->s); L -= m; } return L==0; } // check for comment block or APP blocks if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { skip(z->s, get16(z->s)-2); return 1; } return 0; } // after we see SOS static int process_scan_header(jpeg *z) { int i; int Ls = get16(z->s); z->scan_n = get8(z->s); if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return e("bad SOS component count","Corrupt JPEG"); if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG"); for (i=0; i < z->scan_n; ++i) { int id = get8(z->s), which; int q = get8(z->s); for (which = 0; which < z->s->img_n; ++which) if (z->img_comp[which].id == id) break; if (which == z->s->img_n) return 0; z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); z->order[i] = which; } if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); get8(z->s); // should be 63, but might be 0 if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); return 1; } static int process_frame_header(jpeg *z, int scan) { stbi *s = z->s; int Lf,p,i,q, h_max=1,v_max=1,c; Lf = get16(s); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG p = get8(s); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = get16(s); if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = get16(s); if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires c = get8(s); if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires s->img_n = c; for (i=0; i < c; ++i) { z->img_comp[i].data = NULL; z->img_comp[i].linebuf = NULL; } if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG"); for (i=0; i < s->img_n; ++i) { z->img_comp[i].id = get8(s); if (z->img_comp[i].id != i+1) // JFIF requires if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! return e("bad component ID","Corrupt JPEG"); q = get8(s); z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); z->img_comp[i].tq = get8(s); if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); } if (scan != SCAN_load) return 1; if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); for (i=0; i < s->img_n; ++i) { if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; z->img_mcu_w = h_max * 8; z->img_mcu_h = v_max * 8; z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; for (i=0; i < s->img_n; ++i) { // number of effective pixels (e.g. for non-interleaved MCU) z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; // to simplify generation, we'll allocate enough memory to decode // the bogus oversized data from using interleaved MCUs and their // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't // discard the extra data until colorspace conversion z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); if (z->img_comp[i].raw_data == NULL) { for(--i; i >= 0; --i) { free(z->img_comp[i].raw_data); z->img_comp[i].data = NULL; } return e("outofmem", "Out of memory"); } // align blocks for installable-idct using mmx/sse z->img_comp[i].data = (uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); z->img_comp[i].linebuf = NULL; } return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) #define DNL(x) ((x) == 0xdc) #define SOI(x) ((x) == 0xd8) #define EOI(x) ((x) == 0xd9) #define SOF(x) ((x) == 0xc0 || (x) == 0xc1) #define SOS(x) ((x) == 0xda) static int decode_jpeg_header(jpeg *z, int scan) { int m; z->marker = MARKER_none; // initialize cached marker to empty m = get_marker(z); if (!SOI(m)) return e("no SOI","Corrupt JPEG"); if (scan == SCAN_type) return 1; m = get_marker(z); while (!SOF(m)) { if (!process_marker(z,m)) return 0; m = get_marker(z); while (m == MARKER_none) { // some files have extra padding after their blocks, so ok, we'll scan if (at_eof(z->s)) return e("no SOF", "Corrupt JPEG"); m = get_marker(z); } } if (!process_frame_header(z, scan)) return 0; return 1; } static int decode_jpeg_image(jpeg *j) { int m; j->restart_interval = 0; if (!decode_jpeg_header(j, SCAN_load)) return 0; m = get_marker(j); while (!EOI(m)) { if (SOS(m)) { if (!process_scan_header(j)) return 0; if (!parse_entropy_coded_data(j)) return 0; if (j->marker == MARKER_none ) { // handle 0s at the end of image data from IP Kamera 9060 while (!at_eof(j->s)) { int x = get8(j->s); if (x == 255) { j->marker = get8u(j->s); break; } else if (x != 0) { return 0; } } // if we reach eof without hitting a marker, get_marker() below will fail and we'll eventually return 0 } } else { if (!process_marker(j, m)) return 0; } m = get_marker(j); } return 1; } // static jfif-centered resampling (across block boundaries) typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1, int w, int hs); #define div4(x) ((uint8) ((x) >> 2)) static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) { STBI_NOTUSED(out); STBI_NOTUSED(in_far); STBI_NOTUSED(w); STBI_NOTUSED(hs); return in_near; } static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) { // need to generate two samples vertically for every one in input int i; STBI_NOTUSED(hs); for (i=0; i < w; ++i) out[i] = div4(3*in_near[i] + in_far[i] + 2); return out; } static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) { // need to generate two samples horizontally for every one in input int i; uint8 *input = in_near; if (w == 1) { // if only one sample, can't do any interpolation out[0] = out[1] = input[0]; return out; } out[0] = input[0]; out[1] = div4(input[0]*3 + input[1] + 2); for (i=1; i < w-1; ++i) { int n = 3*input[i]+2; out[i*2+0] = div4(n+input[i-1]); out[i*2+1] = div4(n+input[i+1]); } out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); out[i*2+1] = input[w-1]; STBI_NOTUSED(in_far); STBI_NOTUSED(hs); return out; } #define div16(x) ((uint8) ((x) >> 4)) static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) { // need to generate 2x2 samples for every one in input int i,t0,t1; if (w == 1) { out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); return out; } t1 = 3*in_near[0] + in_far[0]; out[0] = div4(t1+2); for (i=1; i < w; ++i) { t0 = t1; t1 = 3*in_near[i]+in_far[i]; out[i*2-1] = div16(3*t0 + t1 + 8); out[i*2 ] = div16(3*t1 + t0 + 8); } out[w*2-1] = div4(t1+2); STBI_NOTUSED(hs); return out; } static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) { // resample with nearest-neighbor int i,j; in_far = in_far; for (i=0; i < w; ++i) for (j=0; j < hs; ++j) out[i*hs+j] = in_near[i]; return out; } #define float2fixed(x) ((int) ((x) * 65536 + 0.5)) // 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) // VC6 without processor=Pro is generating multiple LEAs per multiply! static void YCbCr_to_RGB_row(uint8 *out, const uint8 *y, const uint8 *pcb, const uint8 *pcr, int count, int step) { int i; for (i=0; i < count; ++i) { int y_fixed = (y[i] << 16) + 32768; // rounding int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; r = y_fixed + cr*float2fixed(1.40200f); g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); b = y_fixed + cb*float2fixed(1.77200f); r >>= 16; g >>= 16; b >>= 16; if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } out[0] = (uint8)r; out[1] = (uint8)g; out[2] = (uint8)b; out[3] = 255; out += step; } } #ifdef STBI_SIMD static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) { stbi_YCbCr_installed = func; } #endif // clean up the temporary component buffers static void cleanup_jpeg(jpeg *j) { int i; for (i=0; i < j->s->img_n; ++i) { if (j->img_comp[i].data) { free(j->img_comp[i].raw_data); j->img_comp[i].data = NULL; } if (j->img_comp[i].linebuf) { free(j->img_comp[i].linebuf); j->img_comp[i].linebuf = NULL; } } } typedef struct { resample_row_func resample; uint8 *line0,*line1; int hs,vs; // expansion factor in each axis int w_lores; // horizontal pixels pre-expansion int ystep; // how far through vertical expansion we are int ypos; // which pre-expansion row we're on } stbi_resample; static uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { int n, decode_n; // validate req_comp if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); z->s->img_n = 0; // load a jpeg image from whichever source if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; } // determine actual number of components to generate n = req_comp ? req_comp : z->s->img_n; if (z->s->img_n == 3 && n < 3) decode_n = 1; else decode_n = z->s->img_n; // resample and color-convert { int k; uint i,j; uint8 *output; uint8 *coutput[4]; stbi_resample res_comp[4]; for (k=0; k < decode_n; ++k) { stbi_resample *r = &res_comp[k]; // allocate line buffer big enough for upsampling off the edges // with upsample factor of 4 z->img_comp[k].linebuf = (uint8 *) malloc(z->s->img_x + 3); if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } r->hs = z->img_h_max / z->img_comp[k].h; r->vs = z->img_v_max / z->img_comp[k].v; r->ystep = r->vs >> 1; r->w_lores = (z->s->img_x + r->hs-1) / r->hs; r->ypos = 0; r->line0 = r->line1 = z->img_comp[k].data; if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; else r->resample = resample_row_generic; } // can't error after this so, this is safe output = (uint8 *) malloc(n * z->s->img_x * z->s->img_y + 1); if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } // now go ahead and resample for (j=0; j < z->s->img_y; ++j) { uint8 *out = output + n * z->s->img_x * j; for (k=0; k < decode_n; ++k) { stbi_resample *r = &res_comp[k]; int y_bot = r->ystep >= (r->vs >> 1); coutput[k] = r->resample(z->img_comp[k].linebuf, y_bot ? r->line1 : r->line0, y_bot ? r->line0 : r->line1, r->w_lores, r->hs); if (++r->ystep >= r->vs) { r->ystep = 0; r->line0 = r->line1; if (++r->ypos < z->img_comp[k].y) r->line1 += z->img_comp[k].w2; } } if (n >= 3) { uint8 *y = coutput[0]; if (z->s->img_n == 3) { #ifdef STBI_SIMD stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n); #else YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s->img_x, n); #endif } else for (i=0; i < z->s->img_x; ++i) { out[0] = out[1] = out[2] = y[i]; out[3] = 255; // not used if n==3 out += n; } } else { uint8 *y = coutput[0]; if (n == 1) for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; else for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; } } cleanup_jpeg(z); *out_x = z->s->img_x; *out_y = z->s->img_y; if (comp) *comp = z->s->img_n; // report original components, not output return output; } } static unsigned char *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp) { jpeg j; j.s = s; return load_jpeg_image(&j, x,y,comp,req_comp); } static int stbi_jpeg_test(stbi *s) { int r; jpeg j; j.s = s; r = decode_jpeg_header(&j, SCAN_type); stbi_rewind(s); return r; } static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp) { if (!decode_jpeg_header(j, SCAN_header)) { stbi_rewind( j->s ); return 0; } if (x) *x = j->s->img_x; if (y) *y = j->s->img_y; if (comp) *comp = j->s->img_n; return 1; } static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp) { jpeg j; j.s = s; return stbi_jpeg_info_raw(&j, x, y, comp); } // public domain zlib decode v0.2 Sean Barrett 2006-11-18 // simple implementation // - all input must be provided in an upfront buffer // - all output is written to a single output buffer (can malloc/realloc) // performance // - fast huffman // fast-way is faster to check than jpeg huffman, but slow way is slower #define ZFAST_BITS 9 // accelerate all cases in default tables #define ZFAST_MASK ((1 << ZFAST_BITS) - 1) // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) typedef struct { uint16 fast[1 << ZFAST_BITS]; uint16 firstcode[16]; int maxcode[17]; uint16 firstsymbol[16]; uint8 size[288]; uint16 value[288]; } zhuffman; stbi_inline static int bitreverse16(int n) { n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); return n; } stbi_inline static int bit_reverse(int v, int bits) { assert(bits <= 16); // to bit reverse n bits, reverse 16 and shift // e.g. 11 bits, bit reverse and shift away 5 return bitreverse16(v) >> (16-bits); } static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); memset(z->fast, 255, sizeof(z->fast)); for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; for (i=1; i < 16; ++i) assert(sizes[i] <= (1 << i)); code = 0; for (i=1; i < 16; ++i) { next_code[i] = code; z->firstcode[i] = (uint16) code; z->firstsymbol[i] = (uint16) k; code = (code + sizes[i]); if (sizes[i]) if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); z->maxcode[i] = code << (16-i); // preshift for inner loop code <<= 1; k += sizes[i]; } z->maxcode[16] = 0x10000; // sentinel for (i=0; i < num; ++i) { int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; z->size[c] = (uint8)s; z->value[c] = (uint16)i; if (s <= ZFAST_BITS) { int k = bit_reverse(next_code[s],s); while (k < (1 << ZFAST_BITS)) { z->fast[k] = (uint16) c; k += (1 << s); } } ++next_code[s]; } } return 1; } // zlib-from-memory implementation for PNG reading // because PNG allows splitting the zlib stream arbitrarily, // and it's annoying structurally to have PNG call ZLIB call PNG, // we require PNG read all the IDATs and combine them into a single // memory buffer typedef struct { uint8 *zbuffer, *zbuffer_end; int num_bits; uint32 code_buffer; char *zout; char *zout_start; char *zout_end; int z_expandable; zhuffman z_length, z_distance; } zbuf; stbi_inline static int zget8(zbuf *z) { if (z->zbuffer >= z->zbuffer_end) return 0; return *z->zbuffer++; } static void fill_bits(zbuf *z) { do { assert(z->code_buffer < (1U << z->num_bits)); z->code_buffer |= zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } stbi_inline static unsigned int zreceive(zbuf *z, int n) { unsigned int k; if (z->num_bits < n) fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; return k; } stbi_inline static int zhuffman_decode(zbuf *a, zhuffman *z) { int b,s,k; if (a->num_bits < 16) fill_bits(a); b = z->fast[a->code_buffer & ZFAST_MASK]; if (b < 0xffff) { s = z->size[b]; a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; } // not resolved by fast table, so compute it the slow way // use jpeg approach, which requires MSbits at top k = bit_reverse(a->code_buffer, 16); for (s=ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; if (s == 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; assert(z->size[b] == s); a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; } static int expand(zbuf *z, int n) // need to make room for n bytes { char *q; int cur, limit; if (!z->z_expandable) return e("output buffer limit","Corrupt PNG"); cur = (int) (z->zout - z->zout_start); limit = (int) (z->zout_end - z->zout_start); while (cur + n > limit) limit *= 2; q = (char *) realloc(z->zout_start, limit); if (q == NULL) return e("outofmem", "Out of memory"); z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; return 1; } static int length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; static int length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; static int dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int parse_huffman_block(zbuf *a) { for(;;) { int z = zhuffman_decode(a, &a->z_length); if (z < 256) { if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0; *a->zout++ = (char) z; } else { uint8 *p; int len,dist; if (z == 256) return 1; z -= 257; len = length_base[z]; if (length_extra[z]) len += zreceive(a, length_extra[z]); z = zhuffman_decode(a, &a->z_distance); if (z < 0) return e("bad huffman code","Corrupt PNG"); dist = dist_base[z]; if (dist_extra[z]) dist += zreceive(a, dist_extra[z]); if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG"); if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0; p = (uint8 *) (a->zout - dist); while (len--) *a->zout++ = *p++; } } } static int compute_huffman_codes(zbuf *a) { static uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; zhuffman z_codelength; uint8 lencodes[286+32+137];//padding for maximum single op uint8 codelength_sizes[19]; int i,n; int hlit = zreceive(a,5) + 257; int hdist = zreceive(a,5) + 1; int hclen = zreceive(a,4) + 4; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { int s = zreceive(a,3); codelength_sizes[length_dezigzag[i]] = (uint8) s; } if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; while (n < hlit + hdist) { int c = zhuffman_decode(a, &z_codelength); assert(c >= 0 && c < 19); if (c < 16) lencodes[n++] = (uint8) c; else if (c == 16) { c = zreceive(a,2)+3; memset(lencodes+n, lencodes[n-1], c); n += c; } else if (c == 17) { c = zreceive(a,3)+3; memset(lencodes+n, 0, c); n += c; } else { assert(c == 18); c = zreceive(a,7)+11; memset(lencodes+n, 0, c); n += c; } } if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } static int parse_uncompressed_block(zbuf *a) { uint8 header[4]; int len,nlen,k; if (a->num_bits & 7) zreceive(a, a->num_bits & 7); // discard // drain the bit-packed data into header k = 0; while (a->num_bits > 0) { header[k++] = (uint8) (a->code_buffer & 255); // wtf this warns? a->code_buffer >>= 8; a->num_bits -= 8; } assert(a->num_bits == 0); // now fill header the normal way while (k < 4) header[k++] = (uint8) zget8(a); len = header[1] * 256 + header[0]; nlen = header[3] * 256 + header[2]; if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG"); if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0; memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; a->zout += len; return 1; } static int parse_zlib_header(zbuf *a) { int cmf = zget8(a); int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = zget8(a); if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png // window = 1 << (8 + cinfo)... but who cares, we fully buffer output return 1; } // @TODO: should statically initialize these for optimal thread safety static uint8 default_length[288], default_distance[32]; static void init_defaults(void) { int i; // use <= to match clearly with spec for (i=0; i <= 143; ++i) default_length[i] = 8; for ( ; i <= 255; ++i) default_length[i] = 9; for ( ; i <= 279; ++i) default_length[i] = 7; for ( ; i <= 287; ++i) default_length[i] = 8; for (i=0; i <= 31; ++i) default_distance[i] = 5; } int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead static int parse_zlib(zbuf *a, int parse_header) { int final, type; if (parse_header) if (!parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; do { final = zreceive(a,1); type = zreceive(a,2); if (type == 0) { if (!parse_uncompressed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { // use fixed code lengths if (!default_distance[31]) init_defaults(); if (!zbuild_huffman(&a->z_length , default_length , 288)) return 0; if (!zbuild_huffman(&a->z_distance, default_distance, 32)) return 0; } else { if (!compute_huffman_codes(a)) return 0; } if (!parse_huffman_block(a)) return 0; } if (stbi_png_partial && a->zout - a->zout_start > 65536) break; } while (!final); return 1; } static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header) { a->zout_start = obuf; a->zout = obuf; a->zout_end = obuf + olen; a->z_expandable = exp; return parse_zlib(a, parse_header); } char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) { zbuf a; char *p = (char *) malloc(initial_size); if (p == NULL) return NULL; a.zbuffer = (uint8 *) buffer; a.zbuffer_end = (uint8 *) buffer + len; if (do_zlib(&a, p, initial_size, 1, 1)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { free(a.zout_start); return NULL; } } char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) { return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); } char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) { zbuf a; char *p = (char *) malloc(initial_size); if (p == NULL) return NULL; a.zbuffer = (uint8 *) buffer; a.zbuffer_end = (uint8 *) buffer + len; if (do_zlib(&a, p, initial_size, 1, parse_header)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { free(a.zout_start); return NULL; } } int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) { zbuf a; a.zbuffer = (uint8 *) ibuffer; a.zbuffer_end = (uint8 *) ibuffer + ilen; if (do_zlib(&a, obuffer, olen, 0, 1)) return (int) (a.zout - a.zout_start); else return -1; } char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) { zbuf a; char *p = (char *) malloc(16384); if (p == NULL) return NULL; a.zbuffer = (uint8 *) buffer; a.zbuffer_end = (uint8 *) buffer+len; if (do_zlib(&a, p, 16384, 1, 0)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { free(a.zout_start); return NULL; } } int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) { zbuf a; a.zbuffer = (uint8 *) ibuffer; a.zbuffer_end = (uint8 *) ibuffer + ilen; if (do_zlib(&a, obuffer, olen, 0, 0)) return (int) (a.zout - a.zout_start); else return -1; } // public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 // simple implementation // - only 8-bit samples // - no CRC checking // - allocates lots of intermediate memory // - avoids problem of streaming data between subsystems // - avoids explicit window management // performance // - uses stb_zlib, a PD zlib implementation with fast huffman decoding typedef struct { uint32 length; uint32 type; } chunk; #define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) static chunk get_chunk_header(stbi *s) { chunk c; c.length = get32(s); c.type = get32(s); return c; } static int check_png_header(stbi *s) { static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) if (get8u(s) != png_sig[i]) return e("bad png sig","Not a PNG"); return 1; } typedef struct { stbi *s; uint8 *idata, *expanded, *out; } png; enum { F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, F_avg_first, F_paeth_first }; static uint8 first_row_filter[5] = { F_none, F_sub, F_none, F_avg_first, F_paeth_first }; static int paeth(int a, int b, int c) { int p = a + b - c; int pa = abs(p-a); int pb = abs(p-b); int pc = abs(p-c); if (pa <= pb && pa <= pc) return a; if (pb <= pc) return b; return c; } // create the png data from post-deflated data static int create_png_image_raw(png *a, uint8 *raw, uint32 raw_len, int out_n, uint32 x, uint32 y) { stbi *s = a->s; uint32 i,j,stride = x*out_n; int k; int img_n = s->img_n; // copy it into a local for later assert(out_n == s->img_n || out_n == s->img_n+1); if (stbi_png_partial) y = 1; a->out = (uint8 *) malloc(x * y * out_n); if (!a->out) return e("outofmem", "Out of memory"); if (!stbi_png_partial) { if (s->img_x == x && s->img_y == y) { if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); } else { // interlaced: if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); } } for (j=0; j < y; ++j) { uint8 *cur = a->out + stride*j; uint8 *prior = cur - stride; int filter = *raw++; if (filter > 4) return e("invalid filter","Corrupt PNG"); // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; // handle first pixel explicitly for (k=0; k < img_n; ++k) { switch (filter) { case F_none : cur[k] = raw[k]; break; case F_sub : cur[k] = raw[k]; break; case F_up : cur[k] = raw[k] + prior[k]; break; case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; case F_paeth : cur[k] = (uint8) (raw[k] + paeth(0,prior[k],0)); break; case F_avg_first : cur[k] = raw[k]; break; case F_paeth_first: cur[k] = raw[k]; break; } } if (img_n != out_n) cur[img_n] = 255; raw += img_n; cur += out_n; prior += out_n; // this is a little gross, so that we don't switch per-pixel or per-component if (img_n == out_n) { #define CASE(f) \ case f: \ for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ for (k=0; k < img_n; ++k) switch (filter) { CASE(F_none) cur[k] = raw[k]; break; CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; CASE(F_up) cur[k] = raw[k] + prior[k]; break; CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; } #undef CASE } else { assert(img_n+1 == out_n); #define CASE(f) \ case f: \ for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ for (k=0; k < img_n; ++k) switch (filter) { CASE(F_none) cur[k] = raw[k]; break; CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; CASE(F_up) cur[k] = raw[k] + prior[k]; break; CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; } #undef CASE } } return 1; } static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n, int interlaced) { uint8 *final; int p; int save; if (!interlaced) return create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y); save = stbi_png_partial; stbi_png_partial = 0; // de-interlacing final = (uint8 *) malloc(a->s->img_x * a->s->img_y * out_n); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; int xspc[] = { 8,8,4,4,2,2,1 }; int yspc[] = { 8,8,8,4,4,2,2 }; int i,j,x,y; // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) { free(final); return 0; } for (j=0; j < y; ++j) for (i=0; i < x; ++i) memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n, a->out + (j*x+i)*out_n, out_n); free(a->out); raw += (x*out_n+1)*y; raw_len -= (x*out_n+1)*y; } } a->out = final; stbi_png_partial = save; return 1; } static int compute_transparency(png *z, uint8 tc[3], int out_n) { stbi *s = z->s; uint32 i, pixel_count = s->img_x * s->img_y; uint8 *p = z->out; // compute color-based transparency, assuming we've // already got 255 as the alpha value in the output assert(out_n == 2 || out_n == 4); if (out_n == 2) { for (i=0; i < pixel_count; ++i) { p[1] = (p[0] == tc[0] ? 0 : 255); p += 2; } } else { for (i=0; i < pixel_count; ++i) { if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) p[3] = 0; p += 4; } } return 1; } static int expand_palette(png *a, uint8 *palette, int len, int pal_img_n) { uint32 i, pixel_count = a->s->img_x * a->s->img_y; uint8 *p, *temp_out, *orig = a->out; p = (uint8 *) malloc(pixel_count * pal_img_n); if (p == NULL) return e("outofmem", "Out of memory"); // between here and free(out) below, exitting would leak temp_out = p; if (pal_img_n == 3) { for (i=0; i < pixel_count; ++i) { int n = orig[i]*4; p[0] = palette[n ]; p[1] = palette[n+1]; p[2] = palette[n+2]; p += 3; } } else { for (i=0; i < pixel_count; ++i) { int n = orig[i]*4; p[0] = palette[n ]; p[1] = palette[n+1]; p[2] = palette[n+2]; p[3] = palette[n+3]; p += 4; } } free(a->out); a->out = temp_out; STBI_NOTUSED(len); return 1; } static int stbi_unpremultiply_on_load = 0; static int stbi_de_iphone_flag = 0; void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply; } void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { stbi_de_iphone_flag = flag_true_if_should_convert; } static void stbi_de_iphone(png *z) { stbi *s = z->s; uint32 i, pixel_count = s->img_x * s->img_y; uint8 *p = z->out; if (s->img_out_n == 3) { // convert bgr to rgb for (i=0; i < pixel_count; ++i) { uint8 t = p[0]; p[0] = p[2]; p[2] = t; p += 3; } } else { assert(s->img_out_n == 4); if (stbi_unpremultiply_on_load) { // convert bgr to rgb and unpremultiply for (i=0; i < pixel_count; ++i) { uint8 a = p[3]; uint8 t = p[0]; if (a) { p[0] = p[2] * 255 / a; p[1] = p[1] * 255 / a; p[2] = t * 255 / a; } else { p[0] = p[2]; p[2] = t; } p += 4; } } else { // convert bgr to rgb for (i=0; i < pixel_count; ++i) { uint8 t = p[0]; p[0] = p[2]; p[2] = t; p += 4; } } } } static int parse_png_file(png *z, int scan, int req_comp) { uint8 palette[1024], pal_img_n=0; uint8 has_trans=0, tc[3]; uint32 ioff=0, idata_limit=0, i, pal_len=0; int first=1,k,interlace=0, iphone=0; stbi *s = z->s; z->expanded = NULL; z->idata = NULL; z->out = NULL; if (!check_png_header(s)) return 0; if (scan == SCAN_type) return 1; for (;;) { chunk c = get_chunk_header(s); switch (c.type) { case PNG_TYPE('C','g','B','I'): iphone = stbi_de_iphone_flag; skip(s, c.length); break; case PNG_TYPE('I','H','D','R'): { int depth,color,comp,filter; if (!first) return e("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); depth = get8(s); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); color = get8(s); if (color > 6) return e("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG"); filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG"); interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG"); if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG"); if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); if (scan == SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG"); // if SCAN_header, have to scan to see if we have a tRNS } break; } case PNG_TYPE('P','L','T','E'): { if (first) return e("first not IHDR", "Corrupt PNG"); if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); pal_len = c.length / 3; if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); for (i=0; i < pal_len; ++i) { palette[i*4+0] = get8u(s); palette[i*4+1] = get8u(s); palette[i*4+2] = get8u(s); palette[i*4+3] = 255; } break; } case PNG_TYPE('t','R','N','S'): { if (first) return e("first not IHDR", "Corrupt PNG"); if (z->idata) return e("tRNS after IDAT","Corrupt PNG"); if (pal_img_n) { if (scan == SCAN_header) { s->img_n = 4; return 1; } if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); pal_img_n = 4; for (i=0; i < c.length; ++i) palette[i*4+3] = get8u(s); } else { if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); if (c.length != (uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG"); has_trans = 1; for (k=0; k < s->img_n; ++k) tc[k] = (uint8) get16(s); // non 8-bit images will be larger } break; } case PNG_TYPE('I','D','A','T'): { if (first) return e("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; } if (ioff + c.length > idata_limit) { uint8 *p; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; while (ioff + c.length > idata_limit) idata_limit *= 2; p = (uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); z->idata = p; } if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG"); ioff += c.length; break; } case PNG_TYPE('I','E','N','D'): { uint32 raw_len; if (first) return e("first not IHDR", "Corrupt PNG"); if (scan != SCAN_load) return 1; if (z->idata == NULL) return e("no IDAT","Corrupt PNG"); z->expanded = (uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone); if (z->expanded == NULL) return 0; // zlib should set error free(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0; if (has_trans) if (!compute_transparency(z, tc, s->img_out_n)) return 0; if (iphone && s->img_out_n > 2) stbi_de_iphone(z); if (pal_img_n) { // pal_img_n == 3 or 4 s->img_n = pal_img_n; // record the actual colors we had s->img_out_n = pal_img_n; if (req_comp >= 3) s->img_out_n = req_comp; if (!expand_palette(z, palette, pal_len, s->img_out_n)) return 0; } free(z->expanded); z->expanded = NULL; return 1; } default: // if critical, fail if (first) return e("first not IHDR", "Corrupt PNG"); if ((c.type & (1 << 29)) == 0) { #ifndef STBI_NO_FAILURE_STRINGS // not threadsafe static char invalid_chunk[] = "XXXX chunk not known"; invalid_chunk[0] = (uint8) (c.type >> 24); invalid_chunk[1] = (uint8) (c.type >> 16); invalid_chunk[2] = (uint8) (c.type >> 8); invalid_chunk[3] = (uint8) (c.type >> 0); #endif return e(invalid_chunk, "PNG not supported: unknown chunk type"); } skip(s, c.length); break; } // end of chunk, read and skip CRC get32(s); } } static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp) { unsigned char *result=NULL; if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); if (parse_png_file(p, SCAN_load, req_comp)) { result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { result = convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } *x = p->s->img_x; *y = p->s->img_y; if (n) *n = p->s->img_n; } free(p->out); p->out = NULL; free(p->expanded); p->expanded = NULL; free(p->idata); p->idata = NULL; return result; } static unsigned char *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp) { png p; p.s = s; return do_png(&p, x,y,comp,req_comp); } static int stbi_png_test(stbi *s) { int r; r = check_png_header(s); stbi_rewind(s); return r; } static int stbi_png_info_raw(png *p, int *x, int *y, int *comp) { if (!parse_png_file(p, SCAN_header, 0)) { stbi_rewind( p->s ); return 0; } if (x) *x = p->s->img_x; if (y) *y = p->s->img_y; if (comp) *comp = p->s->img_n; return 1; } static int stbi_png_info(stbi *s, int *x, int *y, int *comp) { png p; p.s = s; return stbi_png_info_raw(&p, x, y, comp); } // Microsoft/Windows BMP image static int bmp_test(stbi *s) { int sz; if (get8(s) != 'B') return 0; if (get8(s) != 'M') return 0; get32le(s); // discard filesize get16le(s); // discard reserved get16le(s); // discard reserved get32le(s); // discard data offset sz = get32le(s); if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; return 0; } static int stbi_bmp_test(stbi *s) { int r = bmp_test(s); stbi_rewind(s); return r; } // returns 0..31 for the highest set bit static int high_bit(unsigned int z) { int n=0; if (z == 0) return -1; if (z >= 0x10000) n += 16, z >>= 16; if (z >= 0x00100) n += 8, z >>= 8; if (z >= 0x00010) n += 4, z >>= 4; if (z >= 0x00004) n += 2, z >>= 2; if (z >= 0x00002) n += 1, z >>= 1; return n; } static int bitcount(unsigned int a) { a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits a = (a + (a >> 8)); // max 16 per 8 bits a = (a + (a >> 16)); // max 32 per 8 bits return a & 0xff; } static int shiftsigned(int v, int shift, int bits) { int result; int z=0; if (shift < 0) v <<= -shift; else v >>= shift; result = v; z = bits; while (z < 8) { result += v >> z; z += bits; } return result; } static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) { uint8 *out; unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; stbi_uc pal[256][4]; int psize=0,i,j,compress=0,width; int bpp, flip_vertically, pad, target, offset, hsz; if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP"); get32le(s); // discard filesize get16le(s); // discard reserved get16le(s); // discard reserved offset = get32le(s); hsz = get32le(s); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { s->img_x = get16le(s); s->img_y = get16le(s); } else { s->img_x = get32le(s); s->img_y = get32le(s); } if (get16le(s) != 1) return epuc("bad BMP", "bad BMP"); bpp = get16le(s); if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); if (hsz == 12) { if (bpp < 24) psize = (offset - 14 - 24) / 3; } else { compress = get32le(s); if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); get32le(s); // discard sizeof get32le(s); // discard hres get32le(s); // discard vres get32le(s); // discard colorsused get32le(s); // discard max important if (hsz == 40 || hsz == 56) { if (hsz == 56) { get32le(s); get32le(s); get32le(s); get32le(s); } if (bpp == 16 || bpp == 32) { mr = mg = mb = 0; if (compress == 0) { if (bpp == 32) { mr = 0xffu << 16; mg = 0xffu << 8; mb = 0xffu << 0; ma = 0xffu << 24; fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 } else { mr = 31u << 10; mg = 31u << 5; mb = 31u << 0; } } else if (compress == 3) { mr = get32le(s); mg = get32le(s); mb = get32le(s); // not documented, but generated by photoshop and handled by mspaint if (mr == mg && mg == mb) { // ?!?!? return epuc("bad BMP", "bad BMP"); } } else return epuc("bad BMP", "bad BMP"); } } else { assert(hsz == 108); mr = get32le(s); mg = get32le(s); mb = get32le(s); ma = get32le(s); get32le(s); // discard color space for (i=0; i < 12; ++i) get32le(s); // discard color space parameters } if (bpp < 16) psize = (offset - 14 - hsz) >> 2; } s->img_n = ma ? 4 : 3; if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 target = req_comp; else target = s->img_n; // if they want monochrome, we'll post-convert out = (stbi_uc *) malloc(target * s->img_x * s->img_y); if (!out) return epuc("outofmem", "Out of memory"); if (bpp < 16) { int z=0; if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); } for (i=0; i < psize; ++i) { pal[i][2] = get8u(s); pal[i][1] = get8u(s); pal[i][0] = get8u(s); if (hsz != 12) get8(s); pal[i][3] = 255; } skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); if (bpp == 4) width = (s->img_x + 1) >> 1; else if (bpp == 8) width = s->img_x; else { free(out); return epuc("bad bpp", "Corrupt BMP"); } pad = (-width)&3; for (j=0; j < (int) s->img_y; ++j) { for (i=0; i < (int) s->img_x; i += 2) { int v=get8(s),v2=0; if (bpp == 4) { v2 = v & 15; v >>= 4; } out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; if (target == 4) out[z++] = 255; if (i+1 == (int) s->img_x) break; v = (bpp == 8) ? get8(s) : v2; out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; if (target == 4) out[z++] = 255; } skip(s, pad); } } else { int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; skip(s, offset - 14 - hsz); if (bpp == 24) width = 3 * s->img_x; else if (bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; pad = (-width) & 3; if (bpp == 24) { easy = 1; } else if (bpp == 32) { if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) easy = 2; } if (!easy) { if (!mr || !mg || !mb) { free(out); return epuc("bad masks", "Corrupt BMP"); } // right shift amt to put high bit in position #7 rshift = high_bit(mr)-7; rcount = bitcount(mr); gshift = high_bit(mg)-7; gcount = bitcount(mr); bshift = high_bit(mb)-7; bcount = bitcount(mr); ashift = high_bit(ma)-7; acount = bitcount(mr); } for (j=0; j < (int) s->img_y; ++j) { if (easy) { for (i=0; i < (int) s->img_x; ++i) { int a; out[z+2] = get8u(s); out[z+1] = get8u(s); out[z+0] = get8u(s); z += 3; a = (easy == 2 ? get8(s) : 255); if (target == 4) out[z++] = (uint8) a; } } else { for (i=0; i < (int) s->img_x; ++i) { uint32 v = (bpp == 16 ? get16le(s) : get32le(s)); int a; out[z++] = (uint8) shiftsigned(v & mr, rshift, rcount); out[z++] = (uint8) shiftsigned(v & mg, gshift, gcount); out[z++] = (uint8) shiftsigned(v & mb, bshift, bcount); a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); if (target == 4) out[z++] = (uint8) a; } } skip(s, pad); } } if (flip_vertically) { stbi_uc t; for (j=0; j < (int) s->img_y>>1; ++j) { stbi_uc *p1 = out + j *s->img_x*target; stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; for (i=0; i < (int) s->img_x*target; ++i) { t = p1[i], p1[i] = p2[i], p2[i] = t; } } } if (req_comp && req_comp != target) { out = convert_format(out, target, req_comp, s->img_x, s->img_y); if (out == NULL) return out; // convert_format frees input on failure } *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; return out; } static stbi_uc *stbi_bmp_load(stbi *s,int *x, int *y, int *comp, int req_comp) { return bmp_load(s, x,y,comp,req_comp); } // Targa Truevision - TGA // by Jonathan Dummer static int tga_info(stbi *s, int *x, int *y, int *comp) { int tga_w, tga_h, tga_comp; int sz; get8u(s); // discard Offset sz = get8u(s); // color type if( sz > 1 ) { stbi_rewind(s); return 0; // only RGB or indexed allowed } sz = get8u(s); // image type // only RGB or grey allowed, +/- RLE if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; skip(s,9); tga_w = get16le(s); if( tga_w < 1 ) { stbi_rewind(s); return 0; // test width } tga_h = get16le(s); if( tga_h < 1 ) { stbi_rewind(s); return 0; // test height } sz = get8(s); // bits per pixel // only RGB or RGBA or grey allowed if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { stbi_rewind(s); return 0; } tga_comp = sz; if (x) *x = tga_w; if (y) *y = tga_h; if (comp) *comp = tga_comp / 8; return 1; // seems to have passed everything } int stbi_tga_info(stbi *s, int *x, int *y, int *comp) { return tga_info(s, x, y, comp); } static int tga_test(stbi *s) { int sz; get8u(s); // discard Offset sz = get8u(s); // color type if ( sz > 1 ) return 0; // only RGB or indexed allowed sz = get8u(s); // image type if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE get16(s); // discard palette start get16(s); // discard palette length get8(s); // discard bits per palette color entry get16(s); // discard x origin get16(s); // discard y origin if ( get16(s) < 1 ) return 0; // test width if ( get16(s) < 1 ) return 0; // test height sz = get8(s); // bits per pixel if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed return 1; // seems to have passed everything } static int stbi_tga_test(stbi *s) { int res = tga_test(s); stbi_rewind(s); return res; } static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) { // read in the TGA header stuff int tga_offset = get8u(s); int tga_indexed = get8u(s); int tga_image_type = get8u(s); int tga_is_RLE = 0; int tga_palette_start = get16le(s); int tga_palette_len = get16le(s); int tga_palette_bits = get8u(s); int tga_x_origin = get16le(s); int tga_y_origin = get16le(s); int tga_width = get16le(s); int tga_height = get16le(s); int tga_bits_per_pixel = get8u(s); int tga_inverted = get8u(s); // image data unsigned char *tga_data; unsigned char *tga_palette = NULL; int i, j; unsigned char raw_data[4]; unsigned char trans_data[4]; int RLE_count = 0; int RLE_repeating = 0; int read_next_pixel = 1; // do a tiny bit of precessing if ( tga_image_type >= 8 ) { tga_image_type -= 8; tga_is_RLE = 1; } /* int tga_alpha_bits = tga_inverted & 15; */ tga_inverted = 1 - ((tga_inverted >> 5) & 1); // error check if ( //(tga_indexed) || (tga_width < 1) || (tga_height < 1) || (tga_image_type < 1) || (tga_image_type > 3) || ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) ) { return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA } // If I'm paletted, then I'll use the number of bits from the palette if ( tga_indexed ) { tga_bits_per_pixel = tga_palette_bits; } // tga info *x = tga_width; *y = tga_height; if ( (req_comp < 1) || (req_comp > 4) ) { // just use whatever the file was req_comp = tga_bits_per_pixel / 8; *comp = req_comp; } else { // force a new number of components *comp = tga_bits_per_pixel/8; } tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); if (!tga_data) return epuc("outofmem", "Out of memory"); // skip to the data's starting position (offset usually = 0) skip(s, tga_offset ); // do I need to load a palette? if ( tga_indexed ) { // any data to skip? (offset usually = 0) skip(s, tga_palette_start ); // load the palette tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); if (!tga_palette) return epuc("outofmem", "Out of memory"); if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { free(tga_data); free(tga_palette); return epuc("bad palette", "Corrupt TGA"); } } // load the data trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0; for (i=0; i < tga_width * tga_height; ++i) { // if I'm in RLE mode, do I need to get a RLE chunk? if ( tga_is_RLE ) { if ( RLE_count == 0 ) { // yep, get the next byte as a RLE command int RLE_cmd = get8u(s); RLE_count = 1 + (RLE_cmd & 127); RLE_repeating = RLE_cmd >> 7; read_next_pixel = 1; } else if ( !RLE_repeating ) { read_next_pixel = 1; } } else { read_next_pixel = 1; } // OK, if I need to read a pixel, do it now if ( read_next_pixel ) { // load however much data we did have if ( tga_indexed ) { // read in 1 byte, then perform the lookup int pal_idx = get8u(s); if ( pal_idx >= tga_palette_len ) { // invalid index pal_idx = 0; } pal_idx *= tga_bits_per_pixel / 8; for (j = 0; j*8 < tga_bits_per_pixel; ++j) { raw_data[j] = tga_palette[pal_idx+j]; } } else { // read in the data raw for (j = 0; j*8 < tga_bits_per_pixel; ++j) { raw_data[j] = get8u(s); } } // convert raw to the intermediate format switch (tga_bits_per_pixel) { case 8: // Luminous => RGBA trans_data[0] = raw_data[0]; trans_data[1] = raw_data[0]; trans_data[2] = raw_data[0]; trans_data[3] = 255; break; case 16: // Luminous,Alpha => RGBA trans_data[0] = raw_data[0]; trans_data[1] = raw_data[0]; trans_data[2] = raw_data[0]; trans_data[3] = raw_data[1]; break; case 24: // BGR => RGBA trans_data[0] = raw_data[2]; trans_data[1] = raw_data[1]; trans_data[2] = raw_data[0]; trans_data[3] = 255; break; case 32: // BGRA => RGBA trans_data[0] = raw_data[2]; trans_data[1] = raw_data[1]; trans_data[2] = raw_data[0]; trans_data[3] = raw_data[3]; break; } // clear the reading flag for the next pixel read_next_pixel = 0; } // end of reading a pixel // convert to final format switch (req_comp) { case 1: // RGBA => Luminance tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); break; case 2: // RGBA => Luminance,Alpha tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); tga_data[i*req_comp+1] = trans_data[3]; break; case 3: // RGBA => RGB tga_data[i*req_comp+0] = trans_data[0]; tga_data[i*req_comp+1] = trans_data[1]; tga_data[i*req_comp+2] = trans_data[2]; break; case 4: // RGBA => RGBA tga_data[i*req_comp+0] = trans_data[0]; tga_data[i*req_comp+1] = trans_data[1]; tga_data[i*req_comp+2] = trans_data[2]; tga_data[i*req_comp+3] = trans_data[3]; break; } // in case we're in RLE mode, keep counting down --RLE_count; } // do I need to invert the image? if ( tga_inverted ) { for (j = 0; j*2 < tga_height; ++j) { int index1 = j * tga_width * req_comp; int index2 = (tga_height - 1 - j) * tga_width * req_comp; for (i = tga_width * req_comp; i > 0; --i) { unsigned char temp = tga_data[index1]; tga_data[index1] = tga_data[index2]; tga_data[index2] = temp; ++index1; ++index2; } } } // clear my palette, if I had one if ( tga_palette != NULL ) { free( tga_palette ); } // the things I do to get rid of an error message, and yet keep // Microsoft's C compilers happy... [8^( tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; // OK, done return tga_data; } static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) { return tga_load(s,x,y,comp,req_comp); } // ************************************************************************************************* // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB static int psd_test(stbi *s) { if (get32(s) != 0x38425053) return 0; // "8BPS" else return 1; } static int stbi_psd_test(stbi *s) { int r = psd_test(s); stbi_rewind(s); return r; } static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) { int pixelCount; int channelCount, compression; int channel, i, count, len; int w,h; uint8 *out; // Check identifier if (get32(s) != 0x38425053) // "8BPS" return epuc("not PSD", "Corrupt PSD image"); // Check file type version. if (get16(s) != 1) return epuc("wrong version", "Unsupported version of PSD image"); // Skip 6 reserved bytes. skip(s, 6 ); // Read the number of channels (R, G, B, A, etc). channelCount = get16(s); if (channelCount < 0 || channelCount > 16) return epuc("wrong channel count", "Unsupported number of channels in PSD image"); // Read the rows and columns of the image. h = get32(s); w = get32(s); // Make sure the depth is 8 bits. if (get16(s) != 8) return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); // Make sure the color mode is RGB. // Valid options are: // 0: Bitmap // 1: Grayscale // 2: Indexed color // 3: RGB color // 4: CMYK color // 7: Multichannel // 8: Duotone // 9: Lab color if (get16(s) != 3) return epuc("wrong color format", "PSD is not in RGB color format"); // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) skip(s,get32(s) ); // Skip the image resources. (resolution, pen tool paths, etc) skip(s, get32(s) ); // Skip the reserved data. skip(s, get32(s) ); // Find out if the data is compressed. // Known values: // 0: no compression // 1: RLE compressed compression = get16(s); if (compression > 1) return epuc("bad compression", "PSD has an unknown compression format"); // Create the destination image. out = (stbi_uc *) malloc(4 * w*h); if (!out) return epuc("outofmem", "Out of memory"); pixelCount = w*h; // Initialize the data to zero. //memset( out, 0, pixelCount * 4 ); // Finally, the image data. if (compression) { // RLE as used by .PSD and .TIFF // Loop until you get the number of unpacked bytes you are expecting: // Read the next source byte into n. // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. // Else if n is 128, noop. // Endloop // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, // which we're going to just skip. skip(s, h * channelCount * 2 ); // Read the RLE data by channel. for (channel = 0; channel < 4; channel++) { uint8 *p; p = out+channel; if (channel >= channelCount) { // Fill this channel with default data. for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; } else { // Read the RLE data. count = 0; while (count < pixelCount) { len = get8(s); if (len == 128) { // No-op. } else if (len < 128) { // Copy next len+1 bytes literally. len++; count += len; while (len) { *p = get8u(s); p += 4; len--; } } else if (len > 128) { uint8 val; // Next -len+1 bytes in the dest are replicated from next source byte. // (Interpret len as a negative 8-bit int.) len ^= 0x0FF; len += 2; val = get8u(s); count += len; while (len) { *p = val; p += 4; len--; } } } } } } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) // where each channel consists of an 8-bit value for each pixel in the image. // Read the data by channel. for (channel = 0; channel < 4; channel++) { uint8 *p; p = out + channel; if (channel > channelCount) { // Fill this channel with default data. for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; } else { // Read the data. for (i = 0; i < pixelCount; i++) *p = get8u(s), p += 4; } } } if (req_comp && req_comp != 4) { out = convert_format(out, 4, req_comp, w, h); if (out == NULL) return out; // convert_format frees input on failure } if (comp) *comp = channelCount; *y = h; *x = w; return out; } static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) { return psd_load(s,x,y,comp,req_comp); } // ************************************************************************************************* // Softimage PIC loader // by Tom Seddon // // See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ static int pic_is4(stbi *s,const char *str) { int i; for (i=0; i<4; ++i) if (get8(s) != (stbi_uc)str[i]) return 0; return 1; } static int pic_test(stbi *s) { int i; if (!pic_is4(s,"\x53\x80\xF6\x34")) return 0; for(i=0;i<84;++i) get8(s); if (!pic_is4(s,"PICT")) return 0; return 1; } typedef struct { stbi_uc size,type,channel; } pic_packet_t; static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest) { int mask=0x80, i; for (i=0; i<4; ++i, mask>>=1) { if (channel & mask) { if (at_eof(s)) return epuc("bad file","PIC file too short"); dest[i]=get8u(s); } } return dest; } static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src) { int mask=0x80,i; for (i=0;i<4; ++i, mask>>=1) if (channel&mask) dest[i]=src[i]; } static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result) { int act_comp=0,num_packets=0,y,chained; pic_packet_t packets[10]; // this will (should...) cater for even some bizarre stuff like having data // for the same channel in multiple packets. do { pic_packet_t *packet; if (num_packets==sizeof(packets)/sizeof(packets[0])) return epuc("bad format","too many packets"); packet = &packets[num_packets++]; chained = get8(s); packet->size = get8u(s); packet->type = get8u(s); packet->channel = get8u(s); act_comp |= packet->channel; if (at_eof(s)) return epuc("bad file","file too short (reading packets)"); if (packet->size != 8) return epuc("bad format","packet isn't 8bpp"); } while (chained); *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? for(y=0; ytype) { default: return epuc("bad format","packet has bad compression type"); case 0: {//uncompressed int x; for(x=0;xchannel,dest)) return 0; break; } case 1://Pure RLE { int left=width, i; while (left>0) { stbi_uc count,value[4]; count=get8u(s); if (at_eof(s)) return epuc("bad file","file too short (pure read count)"); if (count > left) count = (uint8) left; if (!pic_readval(s,packet->channel,value)) return 0; for(i=0; ichannel,dest,value); left -= count; } } break; case 2: {//Mixed RLE int left=width; while (left>0) { int count = get8(s), i; if (at_eof(s)) return epuc("bad file","file too short (mixed read count)"); if (count >= 128) { // Repeated stbi_uc value[4]; int i; if (count==128) count = get16(s); else count -= 127; if (count > left) return epuc("bad file","scanline overrun"); if (!pic_readval(s,packet->channel,value)) return 0; for(i=0;ichannel,dest,value); } else { // Raw ++count; if (count>left) return epuc("bad file","scanline overrun"); for(i=0;ichannel,dest)) return 0; } left-=count; } break; } } } } return result; } static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp) { stbi_uc *result; int i, x,y; for (i=0; i<92; ++i) get8(s); x = get16(s); y = get16(s); if (at_eof(s)) return epuc("bad file","file too short (pic header)"); if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode"); get32(s); //skip `ratio' get16(s); //skip `fields' get16(s); //skip `pad' // intermediate buffer is RGBA result = (stbi_uc *) malloc(x*y*4); memset(result, 0xff, x*y*4); if (!pic_load2(s,x,y,comp, result)) { free(result); result=0; } *px = x; *py = y; if (req_comp == 0) req_comp = *comp; result=convert_format(result,4,req_comp,x,y); return result; } static int stbi_pic_test(stbi *s) { int r = pic_test(s); stbi_rewind(s); return r; } static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp) { return pic_load(s,x,y,comp,req_comp); } // ************************************************************************************************* // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb typedef struct stbi_gif_lzw_struct { int16 prefix; uint8 first; uint8 suffix; } stbi_gif_lzw; typedef struct stbi_gif_struct { int w,h; stbi_uc *out; // output buffer (always 4 components) int flags, bgindex, ratio, transparent, eflags; uint8 pal[256][4]; uint8 lpal[256][4]; stbi_gif_lzw codes[4096]; uint8 *color_table; int parse, step; int lflags; int start_x, start_y; int max_x, max_y; int cur_x, cur_y; int line_size; } stbi_gif; static int gif_test(stbi *s) { int sz; if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0; sz = get8(s); if (sz != '9' && sz != '7') return 0; if (get8(s) != 'a') return 0; return 1; } static int stbi_gif_test(stbi *s) { int r = gif_test(s); stbi_rewind(s); return r; } static void stbi_gif_parse_colortable(stbi *s, uint8 pal[256][4], int num_entries, int transp) { int i; for (i=0; i < num_entries; ++i) { pal[i][2] = get8u(s); pal[i][1] = get8u(s); pal[i][0] = get8u(s); pal[i][3] = transp ? 0 : 255; } } static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info) { uint8 version; if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return e("not GIF", "Corrupt GIF"); version = get8u(s); if (version != '7' && version != '9') return e("not GIF", "Corrupt GIF"); if (get8(s) != 'a') return e("not GIF", "Corrupt GIF"); failure_reason = ""; g->w = get16le(s); g->h = get16le(s); g->flags = get8(s); g->bgindex = get8(s); g->ratio = get8(s); g->transparent = -1; if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; if (g->flags & 0x80) stbi_gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); return 1; } static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp) { stbi_gif g; if (!stbi_gif_header(s, &g, comp, 1)) { stbi_rewind( s ); return 0; } if (x) *x = g.w; if (y) *y = g.h; return 1; } static void stbi_out_gif_code(stbi_gif *g, uint16 code) { uint8 *p, *c; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty if (g->codes[code].prefix >= 0) stbi_out_gif_code(g, g->codes[code].prefix); if (g->cur_y >= g->max_y) return; p = &g->out[g->cur_x + g->cur_y]; c = &g->color_table[g->codes[code].suffix * 4]; if (c[3] >= 128) { p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; p[3] = c[3]; } g->cur_x += 4; if (g->cur_x >= g->max_x) { g->cur_x = g->start_x; g->cur_y += g->step; while (g->cur_y >= g->max_y && g->parse > 0) { g->step = (1 << g->parse) * g->line_size; g->cur_y = g->start_y + (g->step >> 1); --g->parse; } } } static uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g) { uint8 lzw_cs; int32 len, code; uint32 first; int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; stbi_gif_lzw *p; lzw_cs = get8u(s); clear = 1 << lzw_cs; first = 1; codesize = lzw_cs + 1; codemask = (1 << codesize) - 1; bits = 0; valid_bits = 0; for (code = 0; code < clear; code++) { g->codes[code].prefix = -1; g->codes[code].first = (uint8) code; g->codes[code].suffix = (uint8) code; } // support no starting clear code avail = clear+2; oldcode = -1; len = 0; for(;;) { if (valid_bits < codesize) { if (len == 0) { len = get8(s); // start new block if (len == 0) return g->out; } --len; bits |= (int32) get8(s) << valid_bits; valid_bits += 8; } else { int32 code = bits & codemask; bits >>= codesize; valid_bits -= codesize; // @OPTIMIZE: is there some way we can accelerate the non-clear path? if (code == clear) { // clear code codesize = lzw_cs + 1; codemask = (1 << codesize) - 1; avail = clear + 2; oldcode = -1; first = 0; } else if (code == clear + 1) { // end of stream code skip(s, len); while ((len = get8(s)) > 0) skip(s,len); return g->out; } else if (code <= avail) { if (first) return epuc("no clear code", "Corrupt GIF"); if (oldcode >= 0) { p = &g->codes[avail++]; if (avail > 4096) return epuc("too many codes", "Corrupt GIF"); p->prefix = (int16) oldcode; p->first = g->codes[oldcode].first; p->suffix = (code == avail) ? p->first : g->codes[code].first; } else if (code == avail) return epuc("illegal code in raster", "Corrupt GIF"); stbi_out_gif_code(g, (uint16) code); if ((avail & codemask) == 0 && avail <= 0x0FFF) { codesize++; codemask = (1 << codesize) - 1; } oldcode = code; } else { return epuc("illegal code in raster", "Corrupt GIF"); } } } } static void stbi_fill_gif_background(stbi_gif *g) { int i; uint8 *c = g->pal[g->bgindex]; // @OPTIMIZE: write a dword at a time for (i = 0; i < g->w * g->h * 4; i += 4) { uint8 *p = &g->out[i]; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; p[3] = c[3]; } } // this function is designed to support animated gifs, although stb_image doesn't support it static uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp) { int i; uint8 *old_out = 0; if (g->out == 0) { if (!stbi_gif_header(s, g, comp,0)) return 0; // failure_reason set by stbi_gif_header g->out = (uint8 *) malloc(4 * g->w * g->h); if (g->out == 0) return epuc("outofmem", "Out of memory"); stbi_fill_gif_background(g); } else { // animated-gif-only path if (((g->eflags & 0x1C) >> 2) == 3) { old_out = g->out; g->out = (uint8 *) malloc(4 * g->w * g->h); if (g->out == 0) return epuc("outofmem", "Out of memory"); memcpy(g->out, old_out, g->w*g->h*4); } } for (;;) { switch (get8(s)) { case 0x2C: /* Image Descriptor */ { int32 x, y, w, h; uint8 *o; x = get16le(s); y = get16le(s); w = get16le(s); h = get16le(s); if (((x + w) > (g->w)) || ((y + h) > (g->h))) return epuc("bad Image Descriptor", "Corrupt GIF"); g->line_size = g->w * 4; g->start_x = x * 4; g->start_y = y * g->line_size; g->max_x = g->start_x + w * 4; g->max_y = g->start_y + h * g->line_size; g->cur_x = g->start_x; g->cur_y = g->start_y; g->lflags = get8(s); if (g->lflags & 0x40) { g->step = 8 * g->line_size; // first interlaced spacing g->parse = 3; } else { g->step = g->line_size; g->parse = 0; } if (g->lflags & 0x80) { stbi_gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); g->color_table = (uint8 *) g->lpal; } else if (g->flags & 0x80) { for (i=0; i < 256; ++i) // @OPTIMIZE: reset only the previous transparent g->pal[i][3] = 255; if (g->transparent >= 0 && (g->eflags & 0x01)) g->pal[g->transparent][3] = 0; g->color_table = (uint8 *) g->pal; } else return epuc("missing color table", "Corrupt GIF"); o = stbi_process_gif_raster(s, g); if (o == NULL) return NULL; if (req_comp && req_comp != 4) o = convert_format(o, 4, req_comp, g->w, g->h); return o; } case 0x21: // Comment Extension. { int len; if (get8(s) == 0xF9) { // Graphic Control Extension. len = get8(s); if (len == 4) { g->eflags = get8(s); get16le(s); // delay g->transparent = get8(s); } else { skip(s, len); break; } } while ((len = get8(s)) != 0) skip(s, len); break; } case 0x3B: // gif stream termination code return (uint8 *) 1; default: return epuc("unknown code", "Corrupt GIF"); } } } static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp) { uint8 *u = 0; stbi_gif g={0}; u = stbi_gif_load_next(s, &g, comp, req_comp); if (u == (void *) 1) u = 0; // end of animated gif marker if (u) { *x = g.w; *y = g.h; } return u; } static int stbi_gif_info(stbi *s, int *x, int *y, int *comp) { return stbi_gif_info_raw(s,x,y,comp); } // ************************************************************************************************* // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR static int hdr_test(stbi *s) { const char *signature = "#?RADIANCE\n"; int i; for (i=0; signature[i]; ++i) if (get8(s) != signature[i]) return 0; return 1; } static int stbi_hdr_test(stbi* s) { int r = hdr_test(s); stbi_rewind(s); return r; } #define HDR_BUFLEN 1024 static char *hdr_gettoken(stbi *z, char *buffer) { int len=0; char c = '\0'; c = (char) get8(z); while (!at_eof(z) && c != '\n') { buffer[len++] = c; if (len == HDR_BUFLEN-1) { // flush to end of line while (!at_eof(z) && get8(z) != '\n') ; break; } c = (char) get8(z); } buffer[len] = 0; return buffer; } static void hdr_convert(float *output, stbi_uc *input, int req_comp) { if ( input[3] != 0 ) { float f1; // Exponent f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); if (req_comp <= 2) output[0] = (input[0] + input[1] + input[2]) * f1 / 3; else { output[0] = input[0] * f1; output[1] = input[1] * f1; output[2] = input[2] * f1; } if (req_comp == 2) output[1] = 1; if (req_comp == 4) output[3] = 1; } else { switch (req_comp) { case 4: output[3] = 1; /* fallthrough */ case 3: output[0] = output[1] = output[2] = 0; break; case 2: output[1] = 1; /* fallthrough */ case 1: output[0] = 0; break; } } } static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) { char buffer[HDR_BUFLEN]; char *token; int valid = 0; int width, height; stbi_uc *scanline; float *hdr_data; int len; unsigned char count, value; int i, j, k, c1,c2, z; // Check identifier if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) return epf("not HDR", "Corrupt HDR image"); // Parse header for(;;) { token = hdr_gettoken(s,buffer); if (token[0] == 0) break; if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; } if (!valid) return epf("unsupported format", "Unsupported HDR format"); // Parse width and height // can't use sscanf() if we're not using stdio! token = hdr_gettoken(s,buffer); if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); token += 3; height = strtol(token, &token, 10); while (*token == ' ') ++token; if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); token += 3; width = strtol(token, NULL, 10); *x = width; *y = height; *comp = 3; if (req_comp == 0) req_comp = 3; // Read data hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); // Load image data // image data is stored as some number of sca if ( width < 8 || width >= 32768) { // Read flat data for (j=0; j < height; ++j) { for (i=0; i < width; ++i) { stbi_uc rgbe[4]; main_decode_loop: getn(s, rgbe, 4); hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); } } } else { // Read RLE-encoded data scanline = NULL; for (j = 0; j < height; ++j) { c1 = get8(s); c2 = get8(s); len = get8(s); if (c1 != 2 || c2 != 2 || (len & 0x80)) { // not run-length encoded, so we have to actually use THIS data as a decoded // pixel (note this can't be a valid pixel--one of RGB must be >= 128) uint8 rgbe[4]; rgbe[0] = (uint8) c1; rgbe[1] = (uint8) c2; rgbe[2] = (uint8) len; rgbe[3] = (uint8) get8u(s); hdr_convert(hdr_data, rgbe, req_comp); i = 1; j = 0; free(scanline); goto main_decode_loop; // yes, this makes no sense } len <<= 8; len |= get8(s); if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); for (k = 0; k < 4; ++k) { i = 0; while (i < width) { count = get8u(s); if (count > 128) { // Run value = get8u(s); count -= 128; for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = get8u(s); } } } for (i=0; i < width; ++i) hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } free(scanline); } return hdr_data; } static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) { return hdr_load(s,x,y,comp,req_comp); } static int stbi_hdr_info(stbi *s, int *x, int *y, int *comp) { char buffer[HDR_BUFLEN]; char *token; int valid = 0; if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { stbi_rewind( s ); return 0; } for(;;) { token = hdr_gettoken(s,buffer); if (token[0] == 0) break; if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; } if (!valid) { stbi_rewind( s ); return 0; } token = hdr_gettoken(s,buffer); if (strncmp(token, "-Y ", 3)) { stbi_rewind( s ); return 0; } token += 3; *y = strtol(token, &token, 10); while (*token == ' ') ++token; if (strncmp(token, "+X ", 3)) { stbi_rewind( s ); return 0; } token += 3; *x = strtol(token, NULL, 10); *comp = 3; return 1; } #endif // STBI_NO_HDR static int stbi_bmp_info(stbi *s, int *x, int *y, int *comp) { int hsz; if (get8(s) != 'B' || get8(s) != 'M') { stbi_rewind( s ); return 0; } skip(s,12); hsz = get32le(s); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) { stbi_rewind( s ); return 0; } if (hsz == 12) { *x = get16le(s); *y = get16le(s); } else { *x = get32le(s); *y = get32le(s); } if (get16le(s) != 1) { stbi_rewind( s ); return 0; } *comp = get16le(s) / 8; return 1; } static int stbi_psd_info(stbi *s, int *x, int *y, int *comp) { int channelCount; if (get32(s) != 0x38425053) { stbi_rewind( s ); return 0; } if (get16(s) != 1) { stbi_rewind( s ); return 0; } skip(s, 6); channelCount = get16(s); if (channelCount < 0 || channelCount > 16) { stbi_rewind( s ); return 0; } *y = get32(s); *x = get32(s); if (get16(s) != 8) { stbi_rewind( s ); return 0; } if (get16(s) != 3) { stbi_rewind( s ); return 0; } *comp = 4; return 1; } static int stbi_pic_info(stbi *s, int *x, int *y, int *comp) { int act_comp=0,num_packets=0,chained; pic_packet_t packets[10]; skip(s, 92); *x = get16(s); *y = get16(s); if (at_eof(s)) return 0; if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { stbi_rewind( s ); return 0; } skip(s, 8); do { pic_packet_t *packet; if (num_packets==sizeof(packets)/sizeof(packets[0])) return 0; packet = &packets[num_packets++]; chained = get8(s); packet->size = get8u(s); packet->type = get8u(s); packet->channel = get8u(s); act_comp |= packet->channel; if (at_eof(s)) { stbi_rewind( s ); return 0; } if (packet->size != 8) { stbi_rewind( s ); return 0; } } while (chained); *comp = (act_comp & 0x10 ? 4 : 3); return 1; } static int stbi_info_main(stbi *s, int *x, int *y, int *comp) { if (stbi_jpeg_info(s, x, y, comp)) return 1; if (stbi_png_info(s, x, y, comp)) return 1; if (stbi_gif_info(s, x, y, comp)) return 1; if (stbi_bmp_info(s, x, y, comp)) return 1; if (stbi_psd_info(s, x, y, comp)) return 1; if (stbi_pic_info(s, x, y, comp)) return 1; #ifndef STBI_NO_HDR if (stbi_hdr_info(s, x, y, comp)) return 1; #endif // test tga last because it's a crappy test! if (stbi_tga_info(s, x, y, comp)) return 1; return e("unknown image type", "Image not of any known type, or corrupt"); } #ifndef STBI_NO_STDIO int stbi_info(char const *filename, int *x, int *y, int *comp) { FILE *f = fopen(filename, "rb"); int result; if (!f) return e("can't fopen", "Unable to open file"); result = stbi_info_from_file(f, x, y, comp); fclose(f); return result; } int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) { int r; stbi s; long pos = ftell(f); start_file(&s, f); r = stbi_info_main(&s,x,y,comp); fseek(f,pos,SEEK_SET); return r; } #endif // !STBI_NO_STDIO int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) { stbi s; start_mem(&s,buffer,len); return stbi_info_main(&s,x,y,comp); } int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) { stbi s; start_callbacks(&s, (stbi_io_callbacks *) c, user); return stbi_info_main(&s,x,y,comp); } #endif // STBI_HEADER_FILE_ONLY /* revision history: 1.33 (2011-07-14) make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements 1.32 (2011-07-13) support for "info" function for all supported filetypes (SpartanJ) 1.31 (2011-06-20) a few more leak fixes, bug in PNG handling (SpartanJ) 1.30 (2011-06-11) added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) removed deprecated format-specific test/load functions removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) cast-to-uint8 to fix warnings 1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ 1.25 (2010-07-17) refix trans_data warning (Won Chun) 1.24 (2010-07-12) perf improvements reading from files on platforms with lock-heavy fgetc() minor perf improvements for jpeg deprecated type-specific functions so we'll get feedback if they're needed attempt to fix trans_data warning (Won Chun) 1.23 fixed bug in iPhone support 1.22 (2010-07-10) removed image *writing* support stbi_info support from Jetro Lauha GIF support from Jean-Marc Lienher iPhone PNG-extensions from James Brown warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva) 1.21 fix use of 'uint8' in header (reported by jon blow) 1.20 added support for Softimage PIC, by Tom Seddon 1.19 bug in interlaced PNG corruption check (found by ryg) 1.18 2008-08-02 fix a threading bug (local mutable static) 1.17 support interlaced PNG 1.16 major bugfix - convert_format converted one too many pixels 1.15 initialize some fields for thread safety 1.14 fix threadsafe conversion bug header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 1.13 threadsafe 1.12 const qualifiers in the API 1.11 Support installable IDCT, colorspace conversion routines 1.10 Fixes for 64-bit (don't use "unsigned long") optimized upsampling by Fabian "ryg" Giesen 1.09 Fix format-conversion for PSD code (bad global variables!) 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 1.07 attempt to fix C++ warning/errors again 1.06 attempt to fix C++ warning/errors again 1.05 fix TGA loading to return correct *comp and use good luminance calc 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR 1.02 support for (subset of) HDR files, float interface for preferred access to them 1.01 fix bug: possible bug in handling right-side up bmps... not sure fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all 1.00 interface to zlib that skips zlib header 0.99 correct handling of alpha in palette 0.98 TGA loader by lonesock; dynamically add loaders (untested) 0.97 jpeg errors on too large a file; also catch another malloc failure 0.96 fix detection of invalid v value - particleman@mollyrocket forum 0.95 during header scan, seek to markers in case of padding 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same 0.93 handle jpegtran output; verbose errors 0.92 read 4,8,16,24,32-bit BMP files of several formats 0.91 output 24-bit Windows 3.0 BMP files 0.90 fix a few more warnings; bump version number to approach 1.0 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd 0.60 fix compiling as c++ 0.59 fix warnings: merge Dave Moore's -Wall fixes 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available 0.56 fix bug: zlib uncompressed mode len vs. nlen 0.55 fix bug: restart_interval not initialized to 0 0.54 allow NULL for 'int *comp' 0.53 fix bug in png 3->4; speedup png decoding 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments 0.51 obey req_comp requests, 1-component jpegs return as 1-component, on 'test' only check type, not whether we support this variant 0.50 first released version */ repsnapper-2.3.2a5/libraries/amf/amftools-code/src/zip/000077500000000000000000000000001231531733200227675ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/amf/amftools-code/src/zip/unzip.cpp000066400000000000000000004437321231531733200246550ustar00rootroot00000000000000#ifdef WIN32 #include #include #include #include #include #include "zip/unzip.h" // THIS FILE is almost entirely based upon code by Jean-loup Gailly // and Mark Adler. It has been modified by Lucian Wischik. // The modifications were: incorporate the bugfixes of 1.1.4, allow // unzipping to/from handles/pipes/files/memory, encryption, unicode, // a windowsish api, and putting everything into a single .cpp file. // The original code may be found at http://www.gzip.org/zlib/ // The original copyright text follows. // // // // zlib.h -- interface of the 'zlib' general purpose compression library // version 1.1.3, July 9th, 1998 // // Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // Jean-loup Gailly Mark Adler // jloup@gzip.org madler@alumni.caltech.edu // // // The data format used by the zlib library is described by RFCs (Request for // Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt // (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). // // // The 'zlib' compression library provides in-memory compression and // decompression functions, including integrity checks of the uncompressed // data. This version of the library supports only one compression method // (deflation) but other algorithms will be added later and will have the same // stream interface. // // Compression can be done in a single step if the buffers are large // enough (for example if an input file is mmap'ed), or can be done by // repeated calls of the compression function. In the latter case, the // application must provide more input and/or consume the output // (providing more output space) before each call. // // The library also supports reading and writing files in gzip (.gz) format // with an interface similar to that of stdio. // // The library does not install any signal handler. The decoder checks // the consistency of the compressed data, so the library should never // crash even in case of corrupted input. // // for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip // PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip #define ZIP_HANDLE 1 #define ZIP_FILENAME 2 #define ZIP_MEMORY 3 #define zmalloc(len) malloc(len) #define zfree(p) free(p) /* void *zmalloc(unsigned int len) { char *buf = new char[len+32]; for (int i=0; i<16; i++) { buf[i]=i; buf[len+31-i]=i; } *((unsigned int*)buf) = len; char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); OutputDebugString(c); return buf+16; } void zfree(void *buf) { char c[1000]; wsprintf(c,"free 0x%lx",buf); OutputDebugString(c); char *p = ((char*)buf)-16; unsigned int len = *((unsigned int*)p); bool blown=false; for (int i=0; i<16; i++) { char lo = p[i]; char hi = p[len+31-i]; if (hi!=i || (lo!=i && i>4)) blown=true; } if (blown) { OutputDebugString("BLOWN!!!"); } delete[] p; } */ typedef struct tm_unz_s { unsigned int tm_sec; // seconds after the minute - [0,59] unsigned int tm_min; // minutes after the hour - [0,59] unsigned int tm_hour; // hours since midnight - [0,23] unsigned int tm_mday; // day of the month - [1,31] unsigned int tm_mon; // months since January - [0,11] unsigned int tm_year; // years - [1980..2044] } tm_unz; // unz_global_info structure contain global data about the ZIPfile typedef struct unz_global_info_s { unsigned long number_entry; // total number of entries in the central dir on this disk unsigned long size_comment; // size of the global comment of the zipfile } unz_global_info; // unz_file_info contain information about a file in the zipfile typedef struct unz_file_info_s { unsigned long version; // version made by 2 bytes unsigned long version_needed; // version needed to extract 2 bytes unsigned long flag; // general purpose bit flag 2 bytes unsigned long compression_method; // compression method 2 bytes unsigned long dosDate; // last mod file date in Dos fmt 4 bytes unsigned long crc; // crc-32 4 bytes unsigned long compressed_size; // compressed size 4 bytes unsigned long uncompressed_size; // uncompressed size 4 bytes unsigned long size_filename; // filename length 2 bytes unsigned long size_file_extra; // extra field length 2 bytes unsigned long size_file_comment; // file comment length 2 bytes unsigned long disk_num_start; // disk number start 2 bytes unsigned long internal_fa; // internal file attributes 2 bytes unsigned long external_fa; // external file attributes 4 bytes tm_unz tmu_date; } unz_file_info; #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) #define UNZ_PASSWORD (-106) #define ZLIB_VERSION "1.1.3" // Allowed flush values; see deflate() for details #define Z_NO_FLUSH 0 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 // compression levels #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) // compression strategy; see deflateInit2() for details #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_DEFAULT_STRATEGY 0 // Possible values of the data_type field #define Z_BINARY 0 #define Z_ASCII 1 #define Z_UNKNOWN 2 // The deflate compression method (the only one supported in this version) #define Z_DEFLATED 8 // for initializing zalloc, zfree, opaque #define Z_NULL 0 // case sensitivity when searching for filenames #define CASE_SENSITIVE 1 #define CASE_INSENSITIVE 2 // Return codes for the compression/decompression functions. Negative // values are errors, positive values are used for special but normal events. #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) // Basic data types typedef unsigned char Byte; // 8 bits typedef unsigned int uInt; // 16 bits or more typedef unsigned long uLong; // 32 bits or more typedef void *voidpf; typedef void *voidp; typedef long z_off_t; typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); typedef void (*free_func) (voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { Byte *next_in; // next input byte uInt avail_in; // number of bytes available at next_in uLong total_in; // total nb of input bytes read so far Byte *next_out; // next output byte should be put there uInt avail_out; // remaining free space at next_out uLong total_out; // total nb of bytes output so far char *msg; // last error message, NULL if no error struct internal_state *state; // not visible by applications alloc_func zalloc; // used to allocate the internal state free_func zfree; // used to free the internal state voidpf opaque; // private data object passed to zalloc and zfree int data_type; // best guess about the data type: ascii or binary uLong adler; // adler32 value of the uncompressed data uLong reserved; // reserved for future use } z_stream; typedef z_stream *z_streamp; // The application must update next_in and avail_in when avail_in has // dropped to zero. It must update next_out and avail_out when avail_out // has dropped to zero. The application must initialize zalloc, zfree and // opaque before calling the init function. All other fields are set by the // compression library and must not be updated by the application. // // The opaque value provided by the application will be passed as the first // parameter for calls of zalloc and zfree. This can be useful for custom // memory management. The compression library attaches no meaning to the // opaque value. // // zalloc must return Z_NULL if there is not enough memory for the object. // If zlib is used in a multi-threaded application, zalloc and zfree must be // thread safe. // // The fields total_in and total_out can be used for statistics or // progress reports. After compression, total_in holds the total size of // the uncompressed data and may be saved for use in the decompressor // (particularly if the decompressor wants to decompress everything in // a single step). // // basic functions const char *zlibVersion (); // The application can compare zlibVersion and ZLIB_VERSION for consistency. // If the first character differs, the library code actually used is // not compatible with the zlib.h header file used by the application. // This check is automatically made by inflateInit. int inflate (z_streamp strm, int flush); // // inflate decompresses as much data as possible, and stops when the input // buffer becomes empty or the output buffer becomes full. It may some // introduce some output latency (reading input without producing any output) // except when forced to flush. // // The detailed semantics are as follows. inflate performs one or both of the // following actions: // // - Decompress more input starting at next_in and update next_in and avail_in // accordingly. If not all input can be processed (because there is not // enough room in the output buffer), next_in is updated and processing // will resume at this point for the next call of inflate(). // // - Provide more output starting at next_out and update next_out and avail_out // accordingly. inflate() provides as much output as possible, until there // is no more input data or no more space in the output buffer (see below // about the flush parameter). // // Before the call of inflate(), the application should ensure that at least // one of the actions is possible, by providing more input and/or consuming // more output, and updating the next_* and avail_* values accordingly. // The application can consume the uncompressed output when it wants, for // example when the output buffer is full (avail_out == 0), or after each // call of inflate(). If inflate returns Z_OK and with zero avail_out, it // must be called again after making room in the output buffer because there // might be more output pending. // // If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much // output as possible to the output buffer. The flushing behavior of inflate is // not specified for values of the flush parameter other than Z_SYNC_FLUSH // and Z_FINISH, but the current implementation actually flushes as much output // as possible anyway. // // inflate() should normally be called until it returns Z_STREAM_END or an // error. However if all decompression is to be performed in a single step // (a single call of inflate), the parameter flush should be set to // Z_FINISH. In this case all pending input is processed and all pending // output is flushed; avail_out must be large enough to hold all the // uncompressed data. (The size of the uncompressed data may have been saved // by the compressor for this purpose.) The next operation on this stream must // be inflateEnd to deallocate the decompression state. The use of Z_FINISH // is never required, but can be used to inform inflate that a faster routine // may be used for the single inflate() call. // // If a preset dictionary is needed at this point (see inflateSetDictionary // below), inflate sets strm-adler to the adler32 checksum of the // dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise // it sets strm->adler to the adler32 checksum of all output produced // so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or // an error code as described below. At the end of the stream, inflate() // checks that its computed adler32 checksum is equal to that saved by the // compressor and returns Z_STREAM_END only if the checksum is correct. // // inflate() returns Z_OK if some progress has been made (more input processed // or more output produced), Z_STREAM_END if the end of the compressed data has // been reached and all uncompressed output has been produced, Z_NEED_DICT if a // preset dictionary is needed at this point, Z_DATA_ERROR if the input data was // corrupted (input stream not conforming to the zlib format or incorrect // adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent // (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if no progress is possible or if there was not // enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR // case, the application may then call inflateSync to look for a good // compression block. // int inflateEnd (z_streamp strm); // // All dynamically allocated data structures for this stream are freed. // This function discards any unprocessed input and does not flush any // pending output. // // inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state // was inconsistent. In the error case, msg may be set but then points to a // static string (which must not be deallocated). // Advanced functions // The following functions are needed only in some special applications. int inflateSetDictionary (z_streamp strm, const Byte *dictionary, uInt dictLength); // // Initializes the decompression dictionary from the given uncompressed byte // sequence. This function must be called immediately after a call of inflate // if this call returned Z_NEED_DICT. The dictionary chosen by the compressor // can be determined from the Adler32 value returned by this call of // inflate. The compressor and decompressor must use exactly the same // dictionary. // // inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a // parameter is invalid (such as NULL dictionary) or the stream state is // inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the // expected one (incorrect Adler32 value). inflateSetDictionary does not // perform any decompression: this will be done by subsequent calls of // inflate(). int inflateSync (z_streamp strm); // // Skips invalid compressed data until a full flush point can be found, or until all // available input is skipped. No output is provided. // // inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR // if no more input was provided, Z_DATA_ERROR if no flush point has been found, // or Z_STREAM_ERROR if the stream structure was inconsistent. In the success // case, the application may save the current current value of total_in which // indicates where valid compressed data was found. In the error case, the // application may repeatedly call inflateSync, providing more input each time, // until success or end of the input data. int inflateReset (z_streamp strm); // This function is equivalent to inflateEnd followed by inflateInit, // but does not free and reallocate all the internal decompression state. // The stream will keep attributes that may have been set by inflateInit2. // // inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent (such as zalloc or state being NULL). // // checksum functions // These functions are not related to compression but are exported // anyway because they might be useful in applications using the // compression library. uLong adler32 (uLong adler, const Byte *buf, uInt len); // Update a running Adler-32 checksum with the bytes buf[0..len-1] and // return the updated checksum. If buf is NULL, this function returns // the required initial value for the checksum. // An Adler-32 checksum is almost as reliable as a CRC32 but can be computed // much faster. Usage example: // // uLong adler = adler32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // adler = adler32(adler, buffer, length); // } // if (adler != original_adler) error(); uLong ucrc32 (uLong crc, const Byte *buf, uInt len); // Update a running crc with the bytes buf[0..len-1] and return the updated // crc. If buf is NULL, this function returns the required initial value // for the crc. Pre- and post-conditioning (one's complement) is performed // within this function so it shouldn't be done by the application. // Usage example: // // uLong crc = crc32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // crc = crc32(crc, buffer, length); // } // if (crc != original_crc) error(); const char *zError (int err); int inflateSyncPoint (z_streamp z); const uLong *get_crc_table (void); typedef unsigned char uch; typedef uch uchf; typedef unsigned short ush; typedef ush ushf; typedef unsigned long ulg; const char * const z_errmsg[10] = { // indexed by 2-zlib_error "need dictionary", // Z_NEED_DICT 2 "stream end", // Z_STREAM_END 1 "", // Z_OK 0 "file error", // Z_ERRNO (-1) "stream error", // Z_STREAM_ERROR (-2) "data error", // Z_DATA_ERROR (-3) "insufficient memory", // Z_MEM_ERROR (-4) "buffer error", // Z_BUF_ERROR (-5) "incompatible version",// Z_VERSION_ERROR (-6) ""}; #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = (char*)ERR_MSG(err), (err)) // To be used only when the state is known to be valid // common constants #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 // The three kinds of block type #define MIN_MATCH 3 #define MAX_MATCH 258 // The minimum and maximum match lengths #define PRESET_DICT 0x20 // preset dictionary flag in zlib header // target dependencies #define OS_CODE 0x0b // Window 95 & Windows NT // functions #define zmemzero(dest, len) memset(dest, 0, len) // Diagnostic functions #define LuAssert(cond,msg) #define LuTrace(x) #define LuTracev(x) #define LuTracevv(x) #define LuTracec(c,x) #define LuTracecv(c,x) typedef uLong (*check_func) (uLong check, const Byte *buf, uInt len); voidpf zcalloc (voidpf opaque, unsigned items, unsigned size); void zcfree (voidpf opaque, voidpf ptr); #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) //void ZFREE(z_streamp strm,voidpf addr) //{ *((strm)->zfree))((strm)->opaque, addr); //} #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} // Huffman code lookup table entry--this entry is four bytes for machines // that have 16-bit pointers (e.g. PC's in the small or medium model). typedef struct inflate_huft_s inflate_huft; struct inflate_huft_s { union { struct { Byte Exop; // number of extra bits or operation Byte Bits; // number of bits in this code or subcode } what; uInt pad; // pad structure to a power of 2 (4 bytes for } word; // 16-bit, 8 bytes for 32-bit int's) uInt base; // literal, length base, distance base, or table offset }; // Maximum size of dynamic tree. The maximum found in a long but non- // exhaustive search was 1004 huft structures (850 for length/literals // and 154 for distances, the latter actually the result of an // exhaustive search). The actual maximum is not known, but the // value below is more than safe. #define MANY 1440 int inflate_trees_bits ( uInt *, // 19 code lengths uInt *, // bits tree desired/actual depth inflate_huft * *, // bits tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_dynamic ( uInt, // number of literal/length codes uInt, // number of distance codes uInt *, // that many (total) code lengths uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth inflate_huft * *, // literal/length tree result inflate_huft * *, // distance tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_fixed ( uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth const inflate_huft * *, // literal/length tree result const inflate_huft * *, // distance tree result z_streamp); // for memory allocation struct inflate_blocks_state; typedef struct inflate_blocks_state inflate_blocks_statef; inflate_blocks_statef * inflate_blocks_new ( z_streamp z, check_func c, // check function uInt w); // window size int inflate_blocks ( inflate_blocks_statef *, z_streamp , int); // initial return code void inflate_blocks_reset ( inflate_blocks_statef *, z_streamp , uLong *); // check value on output int inflate_blocks_free ( inflate_blocks_statef *, z_streamp); void inflate_set_dictionary ( inflate_blocks_statef *s, const Byte *d, // dictionary uInt n); // dictionary length int inflate_blocks_sync_point ( inflate_blocks_statef *s); struct inflate_codes_state; typedef struct inflate_codes_state inflate_codes_statef; inflate_codes_statef *inflate_codes_new ( uInt, uInt, const inflate_huft *, const inflate_huft *, z_streamp ); int inflate_codes ( inflate_blocks_statef *, z_streamp , int); void inflate_codes_free ( inflate_codes_statef *, z_streamp ); typedef enum { IBM_TYPE, // get type bits (3, including end bit) IBM_LENS, // get lengths for stored IBM_STORED, // processing stored block IBM_TABLE, // get table lengths IBM_BTREE, // get bit lengths tree for a dynamic block IBM_DTREE, // get length, distance trees for a dynamic block IBM_CODES, // processing fixed or dynamic block IBM_DRY, // output remaining window bytes IBM_DONE, // finished last block, done IBM_BAD} // got a data error--stuck here inflate_block_mode; // inflate blocks semi-private state struct inflate_blocks_state { // mode inflate_block_mode mode; // current inflate_block mode // mode dependent information union { uInt left; // if STORED, bytes left to copy struct { uInt table; // table lengths (14 bits) uInt index; // index into blens (or border) uInt *blens; // bit lengths of codes uInt bb; // bit length tree depth inflate_huft *tb; // bit length decoding tree } trees; // if DTREE, decoding info for trees struct { inflate_codes_statef *codes; } decode; // if CODES, current state } sub; // submode uInt last; // true if this block is the last block // mode independent information uInt bitk; // bits in bit buffer uLong bitb; // bit buffer inflate_huft *hufts; // single malloc for tree space Byte *window; // sliding window Byte *end; // one byte after sliding window Byte *read; // window read pointer Byte *write; // window write pointer check_func checkfn; // check function uLong check; // check on output }; // defines for inflate input/output // update pointers and return #define UPDBITS {s->bitb=b;s->bitk=k;} #define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} #define UPDOUT {s->write=q;} #define UPDATE {UPDBITS UPDIN UPDOUT} #define LEAVE {UPDATE return inflate_flush(s,z,r);} // get bytes and bits #define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} #define NEEDBYTE {if(n)r=Z_OK;else LEAVE} #define NEXTBYTE (n--,*p++) #define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} // output bytes #define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) #define LOADOUT {q=s->write;m=(uInt)WAVAIL;m;} #define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} #define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} #define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} #define OUTBYTE(a) {*q++=(Byte)(a);m--;} // load local pointers #define LOAD {LOADIN LOADOUT} // masks for lower bits (size given to avoid silly warnings with Visual C++) // And'ing with mask[n] masks the lower n bits const uInt inflate_mask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; // copy as much as possible from the sliding window to the output area int inflate_flush (inflate_blocks_statef *, z_streamp, int); int inflate_fast (uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp ); const uInt fixed_bl = 9; const uInt fixed_bd = 5; const inflate_huft fixed_tl[] = { {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} }; const inflate_huft fixed_td[] = { {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} }; // copy as much as possible from the sliding window to the output area int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r) { uInt n; Byte *p; Byte *q; // local copies of source and destination pointers p = z->next_out; q = s->read; // compute number of bytes to copy as far as end of window n = (uInt)((q <= s->write ? s->write : s->end) - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy as far as end of window if (n!=0) // check for n!=0 to avoid waking up CodeGuard { memcpy(p, q, n); p += n; q += n; } // see if more to copy at beginning of window if (q == s->end) { // wrap pointers q = s->window; if (s->write == s->end) s->write = s->window; // compute bytes to copy n = (uInt)(s->write - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy if (n!=0) {memcpy(p,q,n); p+=n; q+=n;} } // update pointers z->next_out = p; s->read = q; // done return r; } // simplify the use of the inflate_huft type with some defines #define exop word.what.Exop #define bits word.what.Bits typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing START, // x: set up for LEN LEN, // i: get length/literal/eob next LENEXT, // i: getting length extra (have base) DIST, // i: get distance next DISTEXT, // i: getting distance extra COPY, // o: copying bytes in window, waiting for space LIT, // o: got literal, waiting for output space WASH, // o: got eob, possibly still output waiting END, // x: got eob and all data flushed BADCODE} // x: got error inflate_codes_mode; // inflate codes private state struct inflate_codes_state { // mode inflate_codes_mode mode; // current inflate_codes mode // mode dependent information uInt len; union { struct { const inflate_huft *tree; // pointer into tree uInt need; // bits needed } code; // if LEN or DIST, where in tree uInt lit; // if LIT, literal struct { uInt get; // bits to get for extra uInt dist; // distance back to copy from } copy; // if EXT or COPY, where and how much } sub; // submode // mode independent information Byte lbits; // ltree bits decoded per branch Byte dbits; // dtree bits decoder per branch const inflate_huft *ltree; // literal/length/eob tree const inflate_huft *dtree; // distance tree }; inflate_codes_statef *inflate_codes_new( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ z_streamp z) { inflate_codes_statef *c; if ((c = (inflate_codes_statef *) ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) { c->mode = START; c->lbits = (Byte)bl; c->dbits = (Byte)bd; c->ltree = tl; c->dtree = td; LuTracev((stderr, "inflate: codes new\n")); } return c; } int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) { uInt j; // temporary storage const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer Byte *f; // pointer to copy strings from inflate_codes_statef *c = s->sub.decode.codes; // codes state // copy input/output information to locals (UPDATE macro restores) LOAD // process input and output based on current state for(;;) switch (c->mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN #ifndef SLOW if (m >= 258 && n >= 10) { UPDATE r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); LOAD if (r != Z_OK) { c->mode = r == Z_STREAM_END ? WASH : BADCODE; break; } } #endif // !SLOW c->sub.code.need = c->lbits; c->sub.code.tree = c->ltree; c->mode = LEN; case LEN: // i: get length/literal/eob next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e == 0) // literal { c->sub.lit = t->base; LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", t->base)); c->mode = LIT; break; } if (e & 16) // length { c->sub.copy.get = e & 15; c->len = t->base; c->mode = LENEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } if (e & 32) // end of block { LuTracevv((stderr, "inflate: end of block\n")); c->mode = WASH; break; } c->mode = BADCODE; // invalid code z->msg = (char*)"invalid literal/length code"; r = Z_DATA_ERROR; LEAVE case LENEXT: // i: getting length extra (have base) j = c->sub.copy.get; NEEDBITS(j) c->len += (uInt)b & inflate_mask[j]; DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; LuTracevv((stderr, "inflate: length %u\n", c->len)); c->mode = DIST; case DIST: // i: get distance next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e & 16) // distance { c->sub.copy.get = e & 15; c->sub.copy.dist = t->base; c->mode = DISTEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } c->mode = BADCODE; // invalid code z->msg = (char*)"invalid distance code"; r = Z_DATA_ERROR; LEAVE case DISTEXT: // i: getting distance extra j = c->sub.copy.get; NEEDBITS(j) c->sub.copy.dist += (uInt)b & inflate_mask[j]; DUMPBITS(j) LuTracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: // o: copying bytes in window, waiting for space f = q - c->sub.copy.dist; while (f < s->window) // modulo window size-"while" instead f += s->end - s->window; // of "if" handles invalid distances while (c->len) { NEEDOUT OUTBYTE(*f++) if (f == s->end) f = s->window; c->len--; } c->mode = START; break; case LIT: // o: got literal, waiting for output space NEEDOUT OUTBYTE(c->sub.lit) c->mode = START; break; case WASH: // o: got eob, possibly more output if (k > 7) // return unused byte, if any { //Assert(k < 16, "inflate_codes grabbed too many bytes") k -= 8; n++; p--; // can always return one } FLUSH if (s->read != s->write) LEAVE c->mode = END; case END: r = Z_STREAM_END; LEAVE case BADCODE: // x: got error r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } void inflate_codes_free(inflate_codes_statef *c,z_streamp z) { ZFREE(z, c); LuTracev((stderr, "inflate: codes free\n")); } // infblock.c -- interpret and process block types to last block // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h //struct inflate_codes_state {int dummy;}; // for buggy compilers // Table for deflate from PKZIP's appnote.txt. const uInt border[] = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; // // Notes beyond the 1.93a appnote.txt: // // 1. Distance pointers never point before the beginning of the output stream. // 2. Distance pointers can point back across blocks, up to 32k away. // 3. There is an implied maximum of 7 bits for the bit length table and // 15 bits for the actual data. // 4. If only one code exists, then it is encoded using one bit. (Zero // would be more efficient, but perhaps a little confusing.) If two // codes exist, they are coded using one bit each (0 and 1). // 5. There is no way of sending zero distance codes--a dummy must be // sent if there are none. (History: a pre 2.0 version of PKZIP would // store blocks with no distance codes, but this was discovered to be // too harsh a criterion.) Valid only for 1.93a. 2.04c does allow // zero distance codes, which is sent as one code of zero bits in // length. // 6. There are up to 286 literal/length codes. Code 256 represents the // end-of-block. Note however that the static length tree defines // 288 codes just to fill out the Huffman codes. Codes 286 and 287 // cannot be used though, since there is no length base or extra bits // defined for them. Similarily, there are up to 30 distance codes. // However, static trees define 32 codes (all 5 bits) to fill out the // Huffman codes, but the last two had better not show up in the data. // 7. Unzip can check dynamic Huffman blocks for complete code sets. // The exception is that a single code would not be complete (see #4). // 8. The five bits following the block type is really the number of // literal codes sent minus 257. // 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits // (1+6+6). Therefore, to output three times the length, you output // three codes (1+1+1), whereas to output four times the same length, // you only need two codes (1+3). Hmm. //10. In the tree reconstruction algorithm, Code = Code + Increment // only if BitLength(i) is not zero. (Pretty obvious.) //11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) //12. Note: length code 284 can represent 227-258, but length code 285 // really is 258. The last length deserves its own, short code // since it gets used a lot in very redundant files. The length // 258 is special since 258 - 3 (the min match length) is 255. //13. The literal/length and distance code bit lengths are read as a // single stream of lengths. It is possible (and advantageous) for // a repeat code (16, 17, or 18) to go across the boundary between // the two sets of lengths. void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) { if (c != Z_NULL) *c = s->check; if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) ZFREE(z, s->sub.trees.blens); if (s->mode == IBM_CODES) inflate_codes_free(s->sub.decode.codes, z); s->mode = IBM_TYPE; s->bitk = 0; s->bitb = 0; s->read = s->write = s->window; if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); LuTracev((stderr, "inflate: blocks reset\n")); } inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) { inflate_blocks_statef *s; if ((s = (inflate_blocks_statef *)ZALLOC (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) return s; if ((s->hufts = (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) { ZFREE(z, s); return Z_NULL; } if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) { ZFREE(z, s->hufts); ZFREE(z, s); return Z_NULL; } s->end = s->window + w; s->checkfn = c; s->mode = IBM_TYPE; LuTracev((stderr, "inflate: blocks allocated\n")); inflate_blocks_reset(s, z, Z_NULL); return s; } int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) { uInt t; // temporary storage uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer // copy input/output information to locals (UPDATE macro restores) LOAD // process input based on current state for(;;) switch (s->mode) { case IBM_TYPE: NEEDBITS(3) t = (uInt)b & 7; s->last = t & 1; switch (t >> 1) { case 0: // stored LuTracev((stderr, "inflate: stored block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; // go to byte boundary DUMPBITS(t) s->mode = IBM_LENS; // get length of stored block break; case 1: // fixed LuTracev((stderr, "inflate: fixed codes block%s\n", s->last ? " (last)" : "")); { uInt bl, bd; const inflate_huft *tl, *td; inflate_trees_fixed(&bl, &bd, &tl, &td, z); s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); if (s->sub.decode.codes == Z_NULL) { r = Z_MEM_ERROR; LEAVE } } DUMPBITS(3) s->mode = IBM_CODES; break; case 2: // dynamic LuTracev((stderr, "inflate: dynamic codes block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) s->mode = IBM_TABLE; break; case 3: // illegal DUMPBITS(3) s->mode = IBM_BAD; z->msg = (char*)"invalid block type"; r = Z_DATA_ERROR; LEAVE } break; case IBM_LENS: NEEDBITS(32) if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) { s->mode = IBM_BAD; z->msg = (char*)"invalid stored block lengths"; r = Z_DATA_ERROR; LEAVE } s->sub.left = (uInt)b & 0xffff; b = k = 0; // dump bits LuTracev((stderr, "inflate: stored length %u\n", s->sub.left)); s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); break; case IBM_STORED: if (n == 0) LEAVE NEEDOUT t = s->sub.left; if (t > n) t = n; if (t > m) t = m; memcpy(q, p, t); p += t; n -= t; q += t; m -= t; if ((s->sub.left -= t) != 0) break; LuTracev((stderr, "inflate: stored end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); s->mode = s->last ? IBM_DRY : IBM_TYPE; break; case IBM_TABLE: NEEDBITS(14) s->sub.trees.table = t = (uInt)b & 0x3fff; // remove this section to workaround bug in pkzip if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) { s->mode = IBM_BAD; z->msg = (char*)"too many length or distance symbols"; r = Z_DATA_ERROR; LEAVE } // end remove t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } DUMPBITS(14) s->sub.trees.index = 0; LuTracev((stderr, "inflate: table sizes ok\n")); s->mode = IBM_BTREE; case IBM_BTREE: while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) { NEEDBITS(3) s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; DUMPBITS(3) } while (s->sub.trees.index < 19) s->sub.trees.blens[border[s->sub.trees.index++]] = 0; s->sub.trees.bb = 7; t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { r = t; if (r == Z_DATA_ERROR) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; } LEAVE } s->sub.trees.index = 0; LuTracev((stderr, "inflate: bits tree ok\n")); s->mode = IBM_DTREE; case IBM_DTREE: while (t = s->sub.trees.table, s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) { inflate_huft *h; uInt i, j, c; t = s->sub.trees.bb; NEEDBITS(t) h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); t = h->bits; c = h->base; if (c < 16) { DUMPBITS(t) s->sub.trees.blens[s->sub.trees.index++] = c; } else // c == 16..18 { i = c == 18 ? 7 : c - 14; j = c == 18 ? 11 : 3; NEEDBITS(t + i) DUMPBITS(t) j += (uInt)b & inflate_mask[i]; DUMPBITS(i) i = s->sub.trees.index; t = s->sub.trees.table; if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; z->msg = (char*)"invalid bit length repeat"; r = Z_DATA_ERROR; LEAVE } c = c == 16 ? s->sub.trees.blens[i - 1] : 0; do { s->sub.trees.blens[i++] = c; } while (--j); s->sub.trees.index = i; } } s->sub.trees.tb = Z_NULL; { uInt bl, bd; inflate_huft *tl, *td; inflate_codes_statef *c; bl = 9; // must be <= 9 for lookahead assumptions bd = 6; // must be <= 9 for lookahead assumptions t = s->sub.trees.table; t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, s->hufts, z); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; } r = t; LEAVE } LuTracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } s->sub.decode.codes = c; } ZFREE(z, s->sub.trees.blens); s->mode = IBM_CODES; case IBM_CODES: UPDATE if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) return inflate_flush(s, z, r); r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); LOAD LuTracev((stderr, "inflate: codes end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); if (!s->last) { s->mode = IBM_TYPE; break; } s->mode = IBM_DRY; case IBM_DRY: FLUSH if (s->read != s->write) LEAVE s->mode = IBM_DONE; case IBM_DONE: r = Z_STREAM_END; LEAVE case IBM_BAD: r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) { inflate_blocks_reset(s, z, Z_NULL); ZFREE(z, s->window); ZFREE(z, s->hufts); ZFREE(z, s); LuTracev((stderr, "inflate: blocks freed\n")); return Z_OK; } // inftrees.c -- generate Huffman trees for efficient decoding // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // extern const char inflate_copyright[] = " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; // If you use the zlib library in a product, an acknowledgment is welcome // in the documentation of your product. If for some reason you cannot // include such an acknowledgment, I would appreciate that you keep this // copyright string in the executable of your product. int huft_build ( uInt *, // code lengths in bits uInt, // number of codes uInt, // number of "simple" codes const uInt *, // list of base values for non-simple codes const uInt *, // list of extra bits for non-simple codes inflate_huft **,// result: starting table uInt *, // maximum lookup bits (returns actual) inflate_huft *, // space for trees uInt *, // hufts used in space uInt * ); // space for values // Tables for deflate from PKZIP's appnote.txt. const uInt cplens[31] = { // Copy lengths for literal codes 257..285 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; // see note #13 above about 258 const uInt cplext[31] = { // Extra bits for literal codes 257..285 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; const uInt cpdext[30] = { // Extra bits for distance codes 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; // // Huffman code decoding is performed using a multi-level table lookup. // The fastest way to decode is to simply build a lookup table whose // size is determined by the longest code. However, the time it takes // to build this table can also be a factor if the data being decoded // is not very long. The most common codes are necessarily the // shortest codes, so those codes dominate the decoding time, and hence // the speed. The idea is you can have a shorter table that decodes the // shorter, more probable codes, and then point to subsidiary tables for // the longer codes. The time it costs to decode the longer codes is // then traded against the time it takes to make longer tables. // // This results of this trade are in the variables lbits and dbits // below. lbits is the number of bits the first level table for literal/ // length codes can decode in one step, and dbits is the same thing for // the distance codes. Subsequent tables are also less than or equal to // those sizes. These values may be adjusted either when all of the // codes are shorter than that, in which case the longest code length in // bits is used, or when the shortest code is *longer* than the requested // table size, in which case the length of the shortest code in bits is // used. // // There are two different values for the two tables, since they code a // different number of possibilities each. The literal/length table // codes 286 possible values, or in a flat code, a little over eight // bits. The distance table codes 30 possible values, or a little less // than five bits, flat. The optimum values for speed end up being // about one bit more than those, so lbits is 8+1 and dbits is 5+1. // The optimum values may differ though from machine to machine, and // possibly even between compilers. Your mileage may vary. // // If BMAX needs to be larger than 16, then h and x[] should be uLong. #define BMAX 15 // maximum bit length of any code int huft_build( uInt *b, // code lengths in bits (all assumed <= BMAX) uInt n, // number of codes (assumed <= 288) uInt s, // number of simple-valued codes (0..s-1) const uInt *d, // list of base values for non-simple codes const uInt *e, // list of extra bits for non-simple codes inflate_huft * *t, // result: starting table uInt *m, // maximum lookup bits, returns actual inflate_huft *hp, // space for trees uInt *hn, // hufts used in space uInt *v) // working area: values in order of bit length // Given a list of code lengths and a maximum table size, make a set of // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR // if the given code set is incomplete (the tables are still built in this // case), or Z_DATA_ERROR if the input is invalid. { uInt a; // counter for codes of length k uInt c[BMAX+1]; // bit length count table uInt f; // i repeats in table every f entries int g; // maximum code length int h; // table level register uInt i; // counter, current code register uInt j; // counter register int k; // number of bits in current code int l; // bits per table (returned in m) uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP register uInt *p; // pointer into c[], b[], or v[] inflate_huft *q; // points to current table struct inflate_huft_s r; // table entry for structure assignment inflate_huft *u[BMAX]; // table stack register int w; // bits before this table == (l * h) uInt x[BMAX+1]; // bit offsets, then code stack uInt *xp; // pointer into x int y; // number of dummy codes added uInt z; // number of entries in current table // Generate counts for each bit length p = c; #define C0 *p++ = 0; #define C2 C0 C0 C0 C0 #define C4 C2 C2 C2 C2 C4; p; // clear c[]--assume BMAX+1 is 16 p = b; i = n; do { c[*p++]++; // assume all entries <= BMAX } while (--i); if (c[0] == n) // null input--all zero length codes { *t = (inflate_huft *)Z_NULL; *m = 0; return Z_OK; } // Find minimum and maximum length, bound *m by those l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; // minimum code length if ((uInt)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; // maximum code length if ((uInt)l > i) l = i; *m = l; // Adjust last length count to fill out codes, if needed for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return Z_DATA_ERROR; if ((y -= c[i]) < 0) return Z_DATA_ERROR; c[i] += y; // Generate starting offsets into the value table for each length x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { // note that i == g from above *xp++ = (j += *p++); } // Make a table of values in order of bit lengths p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); n = x[g]; // set n to length of v // Generate the Huffman codes and for each, make the table entries x[0] = i = 0; // first Huffman code is zero p = v; // grab values in bit order h = -1; // no tables yet--level -1 w = -l; // bits decoded == (l * h) u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy q = (inflate_huft *)Z_NULL; // ditto z = 0; // ditto // go through the bit lengths (k already is bits in shortest code) for (; k <= g; k++) { a = c[k]; while (a--) { // here i is the Huffman code of length k bits for value *p // make tables up to required level while (k > w + l) { h++; w += l; // previous table always l bits // compute minimum size table less than or equal to l bits z = g - w; z = z > (uInt)l ? l : z; // table size upper limit if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table { // too few codes for k-w bit table f -= a + 1; // deduct codes from patterns left xp = c + k; if (j < z) while (++j < z) // try smaller tables up to z bits { if ((f <<= 1) <= *++xp) break; // enough codes to use up j bits f -= *xp; // else deduct codes from patterns } } z = 1 << j; // table entries for j-bit table // allocate new table if (*hn + z > MANY) // (note: doesn't matter for fixed) return Z_DATA_ERROR; // overflow of MANY u[h] = q = hp + *hn; *hn += z; // connect to last table, if there is one if (h) { x[h] = i; // save pattern for backing up r.bits = (Byte)l; // bits to dump before this table r.exop = (Byte)j; // bits in this table j = i >> (w - l); r.base = (uInt)(q - u[h-1] - j); // offset to this table u[h-1][j] = r; // connect to last table } else *t = q; // first table is returned result } // set up table entry in r r.bits = (Byte)(k - w); if (p >= v + n) r.exop = 128 + 64; // out of values--invalid code else if (*p < s) { r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block r.base = *p++; // simple code is just the value } else { r.exop = (Byte)(e[*p - s] + 16 + 64);// non-simple--look up in lists r.base = d[*p++ - s]; } // fill code-like entries with r f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; // backwards increment the k-bit code i for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; // backup over finished tables mask = (1 << w) - 1; // needed on HP, cc -O bug while ((i & mask) != x[h]) { h--; // don't need to update q w -= l; mask = (1 << w) - 1; } } } // Return Z_BUF_ERROR if we were given an incomplete table return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; } int inflate_trees_bits( uInt *c, // 19 code lengths uInt *bb, // bits tree desired/actual depth inflate_huft * *tb, // bits tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, tb, bb, hp, &hn, v); if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed dynamic bit lengths tree"; else if (r == Z_BUF_ERROR || *bb == 0) { z->msg = (char*)"incomplete dynamic bit lengths tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } int inflate_trees_dynamic( uInt nl, // number of literal/length codes uInt nd, // number of distance codes uInt *c, // that many (total) code lengths uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth inflate_huft * *tl, // literal/length tree result inflate_huft * *td, // distance tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build // allocate work area if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; // build literal/length tree r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); if (r != Z_OK || *bl == 0) { if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed literal/length tree"; else if (r != Z_MEM_ERROR) { z->msg = (char*)"incomplete literal/length tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // build distance tree r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); if (r != Z_OK || (*bd == 0 && nl > 257)) { if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed distance tree"; else if (r == Z_BUF_ERROR) { z->msg = (char*)"incomplete distance tree"; r = Z_DATA_ERROR; } else if (r != Z_MEM_ERROR) { z->msg = (char*)"empty distance tree with lengths"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // done ZFREE(z, v); return Z_OK; } int inflate_trees_fixed( uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth const inflate_huft * * tl, // literal/length tree result const inflate_huft * *td, // distance tree result z_streamp ) // for memory allocation { *bl = fixed_bl; *bd = fixed_bd; *tl = fixed_tl; *td = fixed_td; return Z_OK; } // inffast.c -- process literals and length/distance pairs fast // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // //struct inflate_codes_state {int dummy;}; // for buggy compilers // macros for bit input with no checking and for returning unused bytes #define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} // Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. int inflate_fast( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ inflate_blocks_statef *s, z_streamp z) { const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer uInt ml; // mask for literal/length tree uInt md; // mask for distance tree uInt c; // bytes to copy uInt d; // distance back to copy from Byte *r; // copy source pointer // load input, output, bit values LOAD // initialize masks ml = inflate_mask[bl]; md = inflate_mask[bd]; // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code GRABBITS(20) // max bits for literal/length code if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) { DUMPBITS(t->bits) LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; continue; } for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits for length e &= 15; c = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) LuTracevv((stderr, "inflate: * length %u\n", c)); // decode distance base of block to copy GRABBITS(15); // max bits for distance code e = (t = td + ((uInt)b & md))->exop; for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits to add to distance base e &= 15; GRABBITS(e) // get extra bits (up to 13) d = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) LuTracevv((stderr, "inflate: * distance %u\n", d)); // do the copy m -= c; r = q - d; if (r < s->window) // wrap if needed { do { r += s->end - s->window; // force pointer in window } while (r < s->window); // covers invalid distances e = (uInt) (s->end - r); if (c > e) { c -= e; // wrapped copy do { *q++ = *r++; } while (--e); r = s->window; do { *q++ = *r++; } while (--c); } else // normal copy { *q++ = *r++; c--; *q++ = *r++; c--; do { *q++ = *r++; } while (--c); } } else /* normal copy */ { *q++ = *r++; c--; *q++ = *r++; c--; do { *q++ = *r++; } while (--c); } break; } else if ((e & 64) == 0) { t += t->base; e = (t += ((uInt)b & inflate_mask[e]))->exop; } else { z->msg = (char*)"invalid distance code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; break; } if ((e & 64) == 0) { t += t->base; if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; break; } } else if (e & 32) { LuTracevv((stderr, "inflate: * end of block\n")); UNGRAB UPDATE return Z_STREAM_END; } else { z->msg = (char*)"invalid literal/length code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; } while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return UNGRAB UPDATE return Z_OK; } // crc32.c -- compute the CRC-32 of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ // Table of CRC-32's of all single-byte values (made by make_crc_table) const uLong crc_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; const uLong * get_crc_table() { return (const uLong *)crc_table; } #define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf); #define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf); #define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf); uLong ucrc32(uLong crc, const Byte *buf, uInt len) { if (buf == Z_NULL) return 0L; crc = crc ^ 0xffffffffL; while (len >= 8) {CRC_DO8(buf); len -= 8;} if (len) do {CRC_DO1(buf);} while (--len); return crc ^ 0xffffffffL; } // ============================================================= // some decryption routines #define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8)) void Uupdate_keys(unsigned long *keys, char c) { keys[0] = CRC32(keys[0],c); keys[1] += keys[0] & 0xFF; keys[1] = keys[1]*134775813L +1; keys[2] = CRC32(keys[2], keys[1] >> 24); } char Udecrypt_byte(unsigned long *keys) { unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); } char zdecode(unsigned long *keys, char c) { c^=Udecrypt_byte(keys); Uupdate_keys(keys,c); return c; } // adler32.c -- compute the Adler-32 checksum of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ #define BASE 65521L // largest prime smaller than 65536 #define NMAX 5552 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 #define AD_DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1); #define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2); #define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4); #define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8); // ========================================================================= uLong adler32(uLong adler, const Byte *buf, uInt len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == Z_NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { AD_DO16(buf); buf += 16; k -= 16; } if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } // zutil.c -- target dependent utility functions for the compression library // Copyright (C) 1995-1998 Jean-loup Gailly. // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ const char * zlibVersion() { return ZLIB_VERSION; } // exported to allow conversion of error code to string for compress() and // uncompress() const char * zError(int err) { return ERR_MSG(err); } voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) { if (opaque) items += size - size; // make compiler happy return (voidpf)calloc(items, size); } void zcfree (voidpf opaque, voidpf ptr) { zfree(ptr); if (opaque) return; // make compiler happy } // inflate.c -- zlib interface to inflate modules // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h //struct inflate_blocks_state {int dummy;}; // for buggy compilers typedef enum { IM_METHOD, // waiting for method byte IM_FLAG, // waiting for flag byte IM_DICT4, // four dictionary check bytes to go IM_DICT3, // three dictionary check bytes to go IM_DICT2, // two dictionary check bytes to go IM_DICT1, // one dictionary check byte to go IM_DICT0, // waiting for inflateSetDictionary IM_BLOCKS, // decompressing blocks IM_CHECK4, // four check bytes to go IM_CHECK3, // three check bytes to go IM_CHECK2, // two check bytes to go IM_CHECK1, // one check byte to go IM_DONE, // finished check, done IM_BAD} // got an error--stay here inflate_mode; // inflate private state struct internal_state { // mode inflate_mode mode; // current inflate mode // mode dependent information union { uInt method; // if IM_FLAGS, method byte struct { uLong was; // computed check value uLong need; // stream check value } check; // if CHECK, check values to compare uInt marker; // if IM_BAD, inflateSync's marker bytes count } sub; // submode // mode independent information int nowrap; // flag for no wrapper uInt wbits; // log2(window size) (8..15, defaults to 15) inflate_blocks_statef *blocks; // current inflate_blocks state }; int inflateReset(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL) return Z_STREAM_ERROR; z->total_in = z->total_out = 0; z->msg = Z_NULL; z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; inflate_blocks_reset(z->state->blocks, z, Z_NULL); LuTracev((stderr, "inflate: reset\n")); return Z_OK; } int inflateEnd(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) return Z_STREAM_ERROR; if (z->state->blocks != Z_NULL) inflate_blocks_free(z->state->blocks, z); ZFREE(z, z->state); z->state = Z_NULL; LuTracev((stderr, "inflate: end\n")); return Z_OK; } int inflateInit2(z_streamp z) { const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; int w = -15; // MAX_WBITS: 32K LZ77 window. // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files created by gzip. // The memory requirements for deflate are (in bytes): // (1 << (windowBits+2)) + (1 << (memLevel+9)) // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) // plus a few kilobytes for small objects. For example, if you want to reduce // the default memory requirements from 256K to 128K, compile with // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" // Of course this will generally degrade compression (there's no free lunch). // // The memory requirements for inflate are (in bytes) 1 << windowBits // that is, 32K for windowBits=15 (default value) plus a few kilobytes // for small objects. // initialize state if (z == Z_NULL) return Z_STREAM_ERROR; z->msg = Z_NULL; if (z->zalloc == Z_NULL) { z->zalloc = zcalloc; z->opaque = (voidpf)0; } if (z->zfree == Z_NULL) z->zfree = zcfree; if ((z->state = (struct internal_state *) ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) return Z_MEM_ERROR; z->state->blocks = Z_NULL; // handle undocumented nowrap option (no zlib header or check) z->state->nowrap = 0; if (w < 0) { w = - w; z->state->nowrap = 1; } // set window size if (w < 8 || w > 15) { inflateEnd(z); return Z_STREAM_ERROR; } z->state->wbits = (uInt)w; // create inflate_blocks state if ((z->state->blocks = inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) == Z_NULL) { inflateEnd(z); return Z_MEM_ERROR; } LuTracev((stderr, "inflate: allocated\n")); // reset state inflateReset(z); return Z_OK; } #define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;} #define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) int inflate(z_streamp z, int f) { int r; uInt b; if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) return Z_STREAM_ERROR; f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; r = Z_BUF_ERROR; for (;;) switch (z->state->mode) { case IM_METHOD: IM_NEEDBYTE if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) { z->state->mode = IM_BAD; z->msg = (char*)"unknown compression method"; z->state->sub.marker = 5; // can't try inflateSync break; } if ((z->state->sub.method >> 4) + 8 > z->state->wbits) { z->state->mode = IM_BAD; z->msg = (char*)"invalid window size"; z->state->sub.marker = 5; // can't try inflateSync break; } z->state->mode = IM_FLAG; case IM_FLAG: IM_NEEDBYTE b = IM_NEXTBYTE; if (((z->state->sub.method << 8) + b) % 31) { z->state->mode = IM_BAD; z->msg = (char*)"incorrect header check"; z->state->sub.marker = 5; // can't try inflateSync break; } LuTracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { z->state->mode = IM_BLOCKS; break; } z->state->mode = IM_DICT4; case IM_DICT4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_DICT3; case IM_DICT3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_DICT2; case IM_DICT2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_DICT1; case IM_DICT1: IM_NEEDBYTE; r; z->state->sub.check.need += (uLong)IM_NEXTBYTE; z->adler = z->state->sub.check.need; z->state->mode = IM_DICT0; return Z_NEED_DICT; case IM_DICT0: z->state->mode = IM_BAD; z->msg = (char*)"need dictionary"; z->state->sub.marker = 0; // can try inflateSync return Z_STREAM_ERROR; case IM_BLOCKS: r = inflate_blocks(z->state->blocks, z, r); if (r == Z_DATA_ERROR) { z->state->mode = IM_BAD; z->state->sub.marker = 0; // can try inflateSync break; } if (r == Z_OK) r = f; if (r != Z_STREAM_END) return r; r = f; inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); if (z->state->nowrap) { z->state->mode = IM_DONE; break; } z->state->mode = IM_CHECK4; case IM_CHECK4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_CHECK3; case IM_CHECK3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_CHECK2; case IM_CHECK2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_CHECK1; case IM_CHECK1: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE; if (z->state->sub.check.was != z->state->sub.check.need) { z->state->mode = IM_BAD; z->msg = (char*)"incorrect data check"; z->state->sub.marker = 5; // can't try inflateSync break; } LuTracev((stderr, "inflate: zlib check ok\n")); z->state->mode = IM_DONE; case IM_DONE: return Z_STREAM_END; case IM_BAD: return Z_DATA_ERROR; default: return Z_STREAM_ERROR; } } // unzip.c -- IO on .zip files using zlib // Version 0.15 beta, Mar 19th, 1998, // Read unzip.h for more info #define UNZ_BUFSIZE (16384) #define UNZ_MAXFILENAMEINZIP (256) #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; // unz_file_info_interntal contain internal info about a file in zipfile typedef struct unz_file_info_internal_s { uLong offset_curfile;// relative offset of local header 4 bytes } unz_file_info_internal; typedef struct { bool is_handle; // either a handle or memory bool canseek; // for handles: HANDLE h; bool herr; unsigned long initial_offset; bool mustclosehandle; // for memory: void *buf; unsigned int len,pos; // if it's a memory block } LUFILE; LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) { if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) {*err=ZR_ARGS; return NULL;} // HANDLE h=0; bool canseek=false; *err=ZR_OK; bool mustclosehandle=false; if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) { if (flags==ZIP_HANDLE) { HANDLE hf = z; h=hf; mustclosehandle=false; #ifdef DuplicateHandle BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS); if (!res) mustclosehandle=true; #endif } else { h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (h==INVALID_HANDLE_VALUE) {*err=ZR_NOFILE; return NULL;} mustclosehandle=true; } // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. DWORD res = SetFilePointer(h,0,0,FILE_CURRENT); canseek = (res!=0xFFFFFFFF); } LUFILE *lf = new LUFILE; if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) { lf->is_handle=true; lf->mustclosehandle=mustclosehandle; lf->canseek=canseek; lf->h=h; lf->herr=false; lf->initial_offset=0; if (canseek) lf->initial_offset = SetFilePointer(h,0,NULL,FILE_CURRENT); } else { lf->is_handle=false; lf->canseek=true; lf->mustclosehandle=false; lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0; } *err=ZR_OK; return lf; } int lufclose(LUFILE *stream) { if (stream==NULL) return EOF; if (stream->mustclosehandle) CloseHandle(stream->h); delete stream; return 0; } int luferror(LUFILE *stream) { if (stream->is_handle && stream->herr) return 1; else return 0; } long int luftell(LUFILE *stream) { if (stream->is_handle && stream->canseek) return SetFilePointer(stream->h,0,NULL,FILE_CURRENT)-stream->initial_offset; else if (stream->is_handle) return 0; else return stream->pos; } int lufseek(LUFILE *stream, long offset, int whence) { if (stream->is_handle && stream->canseek) { if (whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN); else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT); else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END); else return 19; // EINVAL return 0; } else if (stream->is_handle) return 29; // ESPIPE else { if (whence==SEEK_SET) stream->pos=offset; else if (whence==SEEK_CUR) stream->pos+=offset; else if (whence==SEEK_END) stream->pos=stream->len+offset; return 0; } } size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream) { unsigned int toread = (unsigned int)(size*n); if (stream->is_handle) { DWORD red; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL); if (!res) stream->herr=true; return red/size; } if (stream->pos+toread > stream->len) toread = stream->len-stream->pos; memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread; stream->pos += red; return red/size; } // file_in_zip_read_info_s contain internal information about a file in zipfile, // when reading and decompress it typedef struct { char *read_buffer; // internal buffer for compressed data z_stream stream; // zLib stream structure for inflate uLong pos_in_zipfile; // position in byte on the zipfile, for fseek uLong stream_initialised; // flag set if stream structure is initialised uLong offset_local_extrafield;// offset of the local extra field uInt size_local_extrafield;// size of the local extra field uLong pos_local_extrafield; // position in the local extra field in read uLong crc32; // crc32 of all data uncompressed uLong crc32_wait; // crc32 we must obtain after decompress all uLong rest_read_compressed; // number of byte to be decompressed uLong rest_read_uncompressed;//number of byte to be obtained after decomp LUFILE* file; // io structore of the zipfile uLong compression_method; // compression method (0==store) uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) bool encrypted; // is it encrypted? unsigned long keys[3]; // decryption keys, initialized by unzOpenCurrentFile int encheadleft; // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first char crcenctest; // if encrypted, we'll check the encryption buffer against this } file_in_zip_read_info_s; // unz_s contain internal information about the zipfile typedef struct { LUFILE* file; // io structore of the zipfile unz_global_info gi; // public global information uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) uLong num_file; // number of the current file in the zipfile uLong pos_in_central_dir; // pos of the current file in the central dir uLong current_file_ok; // flag about the usability of the current file uLong central_pos; // position of the beginning of the central dir uLong size_central_dir; // size of the central directory uLong offset_central_dir; // offset of start of central directory with respect to the starting disk number unz_file_info cur_file_info; // public info about the current file in zip unz_file_info_internal cur_file_info_internal; // private info about it file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it } unz_s, *unzFile; int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity); // Compare two filename (fileName1,fileName2). z_off_t unztell (unzFile file); // Give the current position in uncompressed data int unzeof (unzFile file); // return 1 if the end of file was reached, 0 elsewhere int unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len); // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // // if buf==NULL, it return the size of the local extra field // // if buf!=NULL, len is the size of the buffer, the extra header is copied in // buf. // the return value is the number of bytes copied in buf, or (if <0) // the error code // =========================================================================== // Read a byte from a gz_stream; update next_in and avail_in. Return EOF // for end of file. // IN assertion: the stream s has been sucessfully opened for reading. int unzlocal_getByte(LUFILE *fin,int *pi) { unsigned char c; int err = (int)lufread(&c, 1, 1, fin); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (luferror(fin)) return UNZ_ERRNO; else return UNZ_EOF; } } // =========================================================================== // Reads a long in LSB order from the given gz_stream. Sets int unzlocal_getShort (LUFILE *fin,uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } int unzlocal_getLong (LUFILE *fin,uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(fin,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<16; if (err==UNZ_OK) err = unzlocal_getByte(fin,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } // My own strcmpi / strcasecmp int strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= (char)0x20; if ((c2>='a') && (c2<='z')) c2 -= (char)0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } // // Compare two filename (fileName1,fileName2). // If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) // If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) // int unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity) { if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); else return strcmpcasenosensitive_internal(fileName1,fileName2); } #define BUFREADCOMMENT (0x400) // Locate the Central directory of a zipfile (at the end, just before // the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found, // rather than 0, since 0 is a valid central-dir-location for an empty zipfile. uLong unzlocal_SearchCentralDir(LUFILE *fin) { if (lufseek(fin,0,SEEK_END) != 0) return 0xFFFFFFFF; uLong uSizeFile = luftell(fin); uLong uMaxBack=0xffff; // maximum size of global comment if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4); if (buf==NULL) return 0xFFFFFFFF; uLong uPosFound=0xFFFFFFFF; uLong uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (lufseek(fin,uReadPos,SEEK_SET)!=0) break; if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break; for (i=(int)uReadSize-3; (i--)>=0;) { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } } if (uPosFound!=0) break; } if (buf) zfree(buf); return uPosFound; } int unzGoToFirstFile (unzFile file); int unzCloseCurrentFile (unzFile file); // Open a Zip file. // If the zipfile cannot be opened (file don't exist or in not valid), return NULL. // Otherwise, the return value is a unzFile Handle, usable with other unzip functions unzFile unzOpenInternal(LUFILE *fin) { if (fin==NULL) return NULL; if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;} int err=UNZ_OK; unz_s us; uLong central_pos,uL; central_pos = unzlocal_SearchCentralDir(fin); if (central_pos==0xFFFFFFFF) err=UNZ_ERRNO; if (lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; // the signature, already checked if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; // number of this disk uLong number_disk; // number of the current dist, used for spanning ZIP, unsupported, always 0 if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; // number of the disk with the start of the central directory uLong number_disk_with_CD; // number the the disk with central dir, used for spaning ZIP, unsupported, always 0 if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; // total number of entries in the central dir on this disk if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; // total number of entries in the central dir uLong number_entry_CD; // total number of entries in the central dir (same than number_entry on nospan) if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; // size of the central directory if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; // offset of start of central directory with respect to the starting disk number if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; // zipfile comment length if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; if ((central_pos+fin->initial_offsetinitial_offset - (us.offset_central_dir+us.size_central_dir); us.central_pos = central_pos; us.pfile_in_zip_read = NULL; fin->initial_offset = 0; // since the zipfile itself is expected to handle this unz_s *s = (unz_s*)zmalloc(sizeof(unz_s)); *s=us; unzGoToFirstFile((unzFile)s); return (unzFile)s; } // Close a ZipFile opened with unzipOpen. // If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), // these files MUST be closed with unzipCloseCurrentFile before call unzipClose. // return UNZ_OK if there is no problem. int unzClose (unzFile file) { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (s->pfile_in_zip_read!=NULL) unzCloseCurrentFile(file); lufclose(s->file); if (s) zfree(s); // unused s=0; return UNZ_OK; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; *pglobal_info=s->gi; return UNZ_OK; } // Translate date/time from Dos format to tm_unz (readable more easilty) void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) { uLong uDate; uDate = (uLong)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } // Get Info about the current file in the zipfile, with internal only info int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize); int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz_s* s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) err=UNZ_ERRNO; // we check the magic if (err==UNZ_OK) if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek -= uSizeRead; } if ((err==UNZ_OK) && (extraField!=NULL)) { uLong uSizeRead ; if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - uSizeRead; } else lSeek+=file_info.size_file_extra; if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) {} // unused lSeek=0; else err=UNZ_ERRNO; if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1) err=UNZ_ERRNO; //unused lSeek+=file_info.size_file_comment - uSizeRead; } else {} //unused lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } // Set the current file of the zipfile to the first file. // return UNZ_OK if there is no problem int unzGoToFirstFile (unzFile file) { int err; unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } // Set the current file of the zipfile to the next file. // return UNZ_OK if there is no problem // return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. int unzGoToNextFile (unzFile file) { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } // Try locate the file szFileName in the zipfile. // For the iCaseSensitivity signification, see unzStringFileNameCompare // return value : // UNZ_OK if the file is found. It becomes the current file. // UNZ_END_OF_LIST_OF_FILE if the file is not found int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz_s* s; int err; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; unzGetCurrentFileInfo(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (unzStringFileNameCompare(szCurrentFileName,szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; return err; } // Read the local header of the current zipfile // Check the coherency of the local header and info in the end of central // directory about this file // store in *piSizeVar the size of extra info in local header // (filename and size of extra field data) int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s,uInt *piSizeVar, uLong *poffset_local_extrafield, uInt *psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; // else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) // err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time err=UNZ_ERRNO; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } // Open for reading data the current file in the zipfile. // If there is no error and the file is opened, the return value is UNZ_OK. int unzOpenCurrentFile (unzFile file, const char *password) { int err; int Store; uInt iSizeVar; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uLong offset_local_extrafield; // offset of the local extra field uInt size_local_extrafield; // size of the local extra field if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; if (pfile_in_zip_read_info->read_buffer==NULL) { if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0; return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) { // unused err=UNZ_BADZIPFILE; } Store = s->cur_file_info.compression_method==0; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->file=s->file; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if (!Store) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; err=inflateInit2(&pfile_in_zip_read_info->stream); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; // windowBits is passed < 0 to tell that there is no zlib header. // Note that in this case inflate *requires* an extra "dummy" byte // after the compressed stream in order to complete decompression and // return Z_STREAM_END. // In unzip, i don't wait absolutely Z_STREAM_END because I known the // size of both compressed and uncompressed data } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0; bool extlochead = (s->cur_file_info.flag&8)!=0; if (extlochead) pfile_in_zip_read_info->crcenctest = (char)((s->cur_file_info.dosDate>>8)&0xff); else pfile_in_zip_read_info->crcenctest = (char)(s->cur_file_info.crc >> 24); pfile_in_zip_read_info->encheadleft = (pfile_in_zip_read_info->encrypted?12:0); pfile_in_zip_read_info->keys[0] = 305419896L; pfile_in_zip_read_info->keys[1] = 591751049L; pfile_in_zip_read_info->keys[2] = 878082192L; for (const char *cp=password; cp!=0 && *cp!=0; cp++) Uupdate_keys(pfile_in_zip_read_info->keys,*cp); pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; return UNZ_OK; } // Read bytes from the current file. // buf contain buffer where data must be copied // len the size of buf. // return the number of byte copied if somes bytes are copied (and also sets *reached_eof) // return 0 if the end of file was reached. (and also sets *reached_eof). // return <0 with error code if there is an error. (in which case *reached_eof is meaningless) // (UNZ_ERRNO for IO error, or zLib error for uncompress error) int unzReadCurrentFile (unzFile file, voidp buf, unsigned len, bool *reached_eof) { int err=UNZ_OK; uInt iRead = 0; if (reached_eof!=0) *reached_eof=false; unz_s *s = (unz_s*)file; if (s==NULL) return UNZ_PARAMERROR; file_in_zip_read_info_s* pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Byte*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if (len>pfile_in_zip_read_info->rest_read_uncompressed) { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; } while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) {if (reached_eof!=0) *reached_eof=true; return UNZ_EOF;} if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Byte*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; // if (pfile_in_zip_read_info->encrypted) { char *buf = (char*)pfile_in_zip_read_info->stream.next_in; for (unsigned int i=0; ikeys,buf[i]); } } unsigned int uDoEncHead = pfile_in_zip_read_info->encheadleft; if (uDoEncHead>pfile_in_zip_read_info->stream.avail_in) uDoEncHead=pfile_in_zip_read_info->stream.avail_in; if (uDoEncHead>0) { char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1]; pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead; pfile_in_zip_read_info->stream.avail_in -= uDoEncHead; pfile_in_zip_read_info->stream.next_in += uDoEncHead; pfile_in_zip_read_info->encheadleft -= uDoEncHead; if (pfile_in_zip_read_info->encheadleft==0) { if (bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD; } } if (pfile_in_zip_read_info->compression_method==0) { uInt uDoCopy,i ; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) { uDoCopy = pfile_in_zip_read_info->stream.avail_out ; } else { uDoCopy = pfile_in_zip_read_info->stream.avail_in ; } for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; if (pfile_in_zip_read_info->rest_read_uncompressed==0) {if (reached_eof!=0) *reached_eof=true;} } else { uLong uTotalOutBefore,uTotalOutAfter; const Byte *bufBefore; uLong uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; // err=inflate(&pfile_in_zip_read_info->stream,flush); // uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END || pfile_in_zip_read_info->rest_read_uncompressed==0) { if (reached_eof!=0) *reached_eof=true; return iRead; } if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } // Give the current position in uncompressed data z_off_t unztell (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } // return 1 if the end of file was reached, 0 elsewhere int unzeof (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // if buf==NULL, it return the size of the local extra field that can be read // if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. // the return value is the number of bytes copied in buf, or (if <0) the error code int unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) return UNZ_ERRNO; if (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; return (int)read_now; } // Close the file in zip opened with unzipOpenCurrentFile // Return UNZ_CRCERROR if all the file was read but the CRC is not good int unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } if (pfile_in_zip_read_info->read_buffer!=0) { void *buf = pfile_in_zip_read_info->read_buffer; zfree(buf); pfile_in_zip_read_info->read_buffer=0; } pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; s->pfile_in_zip_read=NULL; return err; } // Get the global comment string of the ZipFile, in the szComment buffer. // uSizeBuf is the size of the szComment buffer. // return the number of byte copied or an error code <0 int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) { //int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } int unzOpenCurrentFile (unzFile file, const char *password); int unzReadCurrentFile (unzFile file, void *buf, unsigned len); int unzCloseCurrentFile (unzFile file); typedef unsigned __int32 lutime_t; // define it ourselves since we don't include time.h FILETIME timet2filetime(const lutime_t t) { LONGLONG i = Int32x32To64(t,10000000) + 116444736000000000LL; FILETIME ft; ft.dwLowDateTime = (DWORD) i; ft.dwHighDateTime = (DWORD)(i >>32); return ft; } FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) { // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 SYSTEMTIME st; st.wYear = (WORD)(((dosdate>>9)&0x7f) + 1980); st.wMonth = (WORD)((dosdate>>5)&0xf); st.wDay = (WORD)(dosdate&0x1f); st.wHour = (WORD)((dostime>>11)&0x1f); st.wMinute = (WORD)((dostime>>5)&0x3f); st.wSecond = (WORD)((dostime&0x1f)*2); st.wMilliseconds = 0; FILETIME ft; SystemTimeToFileTime(&st,&ft); return ft; } class TUnzip { public: TUnzip(const char *pwd) : uf(0), unzbuf(0), currentfile(-1), czei(-1), password(0) {if (pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} ~TUnzip() {if (password!=0) delete[] password; password=0; if (unzbuf!=0) delete[] unzbuf; unzbuf=0;} unzFile uf; int currentfile; ZIPENTRY cze; int czei; char *password; char *unzbuf; // lazily created and destroyed, used by Unzip TCHAR rootdir[MAX_PATH]; // includes a trailing slash ZRESULT Open(void *z,unsigned int len,DWORD flags); ZRESULT Get(int index,ZIPENTRY *ze); ZRESULT Find(const TCHAR *name,bool ic,int *index,ZIPENTRY *ze); ZRESULT Unzip(int index,void *dst,unsigned int len,DWORD flags); ZRESULT SetUnzipBaseDir(const TCHAR *dir); ZRESULT Close(); }; ZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags) { if (uf!=0 || currentfile!=-1) return ZR_NOTINITED; // #ifdef GetCurrentDirectory GetCurrentDirectory(MAX_PATH,rootdir); #else _tcscpy(rootdir,_T("\\")); #endif TCHAR lastchar = rootdir[_tcslen(rootdir)-1]; if (lastchar!='\\' && lastchar!='/') _tcscat(rootdir,_T("\\")); // if (flags==ZIP_HANDLE) { // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. DWORD res = SetFilePointer(z,0,0,FILE_CURRENT); bool canseek = (res!=0xFFFFFFFF); if (!canseek) return ZR_SEEK; } ZRESULT e; LUFILE *f = lufopen(z,len,flags,&e); if (f==NULL) return e; uf = unzOpenInternal(f); if (uf==0) return ZR_NOFILE; return ZR_OK; } ZRESULT TUnzip::SetUnzipBaseDir(const TCHAR *dir) { _tcscpy(rootdir,dir); TCHAR lastchar = rootdir[_tcslen(rootdir)-1]; if (lastchar!='\\' && lastchar!='/') _tcscat(rootdir,_T("\\")); return ZR_OK; } ZRESULT TUnzip::Get(int index,ZIPENTRY *ze) { if (index<-1 || index>=(int)uf->gi.number_entry) return ZR_ARGS; if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;} if (index==-1) { ze->index = uf->gi.number_entry; ze->name[0]=0; ze->attr=0; ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0; ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0; ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0; ze->comp_size=0; ze->unc_size=0; return ZR_OK; } if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_filefile,offset,SEEK_SET)!=0) return ZR_READ; unsigned char *extra = new unsigned char[extralen]; if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;} // ze->index=uf->num_file; TCHAR tfn[MAX_PATH]; #ifdef UNICODE MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH); #else strcpy(tfn,fn); #endif // As a safety feature: if the zip filename had sneaky stuff // like "c:\windows\file.txt" or "\windows\file.txt" or "fred\..\..\..\windows\file.txt" // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name), // it won't be a problem. (If the programmer really did want to get the full evil information, // then they can edit out this security feature from here). // In particular, we chop off any prefixes that are "c:\" or "\" or "/" or "[stuff]\.." or "[stuff]/.." const TCHAR *sfn=tfn; for (;;) { if (sfn[0]!=0 && sfn[1]==':') {sfn+=2; continue;} if (sfn[0]=='\\') {sfn++; continue;} if (sfn[0]=='/') {sfn++; continue;} const TCHAR *c; c=_tcsstr(sfn,_T("\\..\\")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("\\../")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("/../")); if (c!=0) {sfn=c+4; continue;} c=_tcsstr(sfn,_T("/..\\")); if (c!=0) {sfn=c+4; continue;} break; } _tcscpy(ze->name, sfn); // zip has an 'attribute' 32bit value. Its lower half is windows stuff // its upper half is standard unix stat.st_mode. We'll start trying // to read it in unix mode unsigned long a = ufi.external_fa; bool isdir = (a&0x40000000)!=0; bool readonly= (a&0x00800000)==0; //bool readable= (a&0x01000000)!=0; // unused //bool executable=(a&0x00400000)!=0; // unused bool hidden=false, system=false, archive=true; // but in normal hostmodes these are overridden by the lower half... int host = ufi.version>>8; if (host==0 || host==7 || host==11 || host==14) { readonly= (a&0x00000001)!=0; hidden= (a&0x00000002)!=0; system= (a&0x00000004)!=0; isdir= (a&0x00000010)!=0; archive= (a&0x00000020)!=0; } ze->attr=0; if (isdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; if (archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE; if (hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN; if (readonly) ze->attr|=FILE_ATTRIBUTE_READONLY; if (system) ze->attr|=FILE_ATTRIBUTE_SYSTEM; ze->comp_size = ufi.compressed_size; ze->unc_size = ufi.uncompressed_size; // WORD dostime = (WORD)(ufi.dosDate&0xFFFF); WORD dosdate = (WORD)((ufi.dosDate>>16)&0xFFFF); FILETIME ftd = dosdatetime2filetime(dosdate,dostime); FILETIME ft; LocalFileTimeToFileTime(&ftd,&ft); ze->atime=ft; ze->ctime=ft; ze->mtime=ft; // the zip will always have at least that dostime. But if it also has // an extra header, then we'll instead get the info from that. unsigned int epos=0; while (epos+4mtime = timet2filetime(mtime); } if (hasatime) { lutime_t atime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); epos+=4; ze->atime = timet2filetime(atime); } if (hasctime) { lutime_t ctime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); epos+=4; ze->ctime = timet2filetime(ctime); } break; } // if (extra!=0) delete[] extra; memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index; return ZR_OK; } ZRESULT TUnzip::Find(const TCHAR *tname,bool ic,int *index,ZIPENTRY *ze) { char name[MAX_PATH]; #ifdef UNICODE WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0); #else strcpy(name,tname); #endif int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE); if (res!=UNZ_OK) { if (index!=0) *index=-1; if (ze!=NULL) {ZeroMemory(ze,sizeof(ZIPENTRY)); ze->index=-1;} return ZR_NOTFOUND; } if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; int i = (int)uf->num_file; if (index!=NULL) *index=i; if (ze!=NULL) { ZRESULT zres = Get(i,ze); if (zres!=ZR_OK) return zres; } return ZR_OK; } void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) { if (rootdir!=0 && GetFileAttributes(rootdir)==0xFFFFFFFF) CreateDirectory(rootdir,0); if (*dir==0) return; const TCHAR *lastslash=dir, *c=lastslash; while (*c!=0) {if (*c=='/' || *c=='\\') lastslash=c; c++;} const TCHAR *name=lastslash; if (lastslash!=dir) { TCHAR tmp[MAX_PATH]; memcpy(tmp,dir,sizeof(TCHAR)*(lastslash-dir)); tmp[lastslash-dir]=0; EnsureDirectory(rootdir,tmp); name++; } TCHAR cd[MAX_PATH]; *cd=0; if (rootdir!=0) _tcscpy(cd,rootdir); _tcscat(cd,dir); if (GetFileAttributes(cd)==0xFFFFFFFF) CreateDirectory(cd,NULL); } ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) { if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) return ZR_ARGS; if (flags==ZIP_MEMORY) { if (index!=currentfile) { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index>=(int)uf->gi.number_entry) return ZR_ARGS; if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file0) return ZR_MORE; if (res==UNZ_PASSWORD) return ZR_PASSWORD; return ZR_FLATE; } // otherwise we're writing to a handle or a file if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (index>=(int)uf->gi.number_entry) return ZR_ARGS; if (index<(int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file0) {DWORD writ; BOOL bres=WriteFile(h,unzbuf,res,&writ,NULL); if (!bres) {haderr=ZR_WRITE; break;}} if (reached_eof) break; if (res==0) {haderr=ZR_FLATE; break;} } if (!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe if (flags!=ZIP_HANDLE) CloseHandle(h); unzCloseCurrentFile(uf); if (haderr!=0) return haderr; return ZR_OK; } ZRESULT TUnzip::Close() { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; if (uf!=0) unzClose(uf); uf=0; return ZR_OK; } ZRESULT lasterrorU=ZR_OK; unsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len) { if (code==ZR_RECENT) code=lasterrorU; const TCHAR *msg=_T("unknown zip result code"); switch (code) { case ZR_OK: msg=_T("Success"); break; case ZR_NODUPH: msg=_T("Culdn't duplicate handle"); break; case ZR_NOFILE: msg=_T("Couldn't create/open file"); break; case ZR_NOALLOC: msg=_T("Failed to allocate memory"); break; case ZR_WRITE: msg=_T("Error writing to file"); break; case ZR_NOTFOUND: msg=_T("File not found in the zipfile"); break; case ZR_MORE: msg=_T("Still more data to unzip"); break; case ZR_CORRUPT: msg=_T("Zipfile is corrupt or not a zipfile"); break; case ZR_READ: msg=_T("Error reading file"); break; case ZR_PASSWORD: msg=_T("Correct password required"); break; case ZR_ARGS: msg=_T("Caller: faulty arguments"); break; case ZR_PARTIALUNZ: msg=_T("Caller: the file had already been partially unzipped"); break; case ZR_NOTMMAP: msg=_T("Caller: can only get memory of a memory zipfile"); break; case ZR_MEMSIZE: msg=_T("Caller: not enough space allocated for memory zipfile"); break; case ZR_FAILED: msg=_T("Caller: there was a previous error"); break; case ZR_ENDED: msg=_T("Caller: additions to the zip have already been ended"); break; case ZR_ZMODE: msg=_T("Caller: mixing creation and opening of zip"); break; case ZR_NOTINITED: msg=_T("Zip-bug: internal initialisation not completed"); break; case ZR_SEEK: msg=_T("Zip-bug: trying to seek the unseekable"); break; case ZR_MISSIZE: msg=_T("Zip-bug: the anticipated size turned out wrong"); break; case ZR_NOCHANGE: msg=_T("Zip-bug: tried to change mind, but not allowed"); break; case ZR_FLATE: msg=_T("Zip-bug: an internal error during flation"); break; } unsigned int mlen=(unsigned int)_tcslen(msg); if (buf==0 || len==0) return mlen; unsigned int n=mlen; if (n+1>len) n=len-1; _tcsncpy(buf,msg,n); buf[n]=0; return mlen; } typedef struct { DWORD flag; TUnzip *unz; } TUnzipHandleData; HZIP OpenZipInternal(void *z,unsigned int len,DWORD flags, const char *password) { TUnzip *unz = new TUnzip(password); lasterrorU = unz->Open(z,len,flags); if (lasterrorU!=ZR_OK) {delete unz; return 0;} TUnzipHandleData *han = new TUnzipHandleData; han->flag=1; han->unz=unz; return (HZIP)han; } HZIP OpenZipHandle(HANDLE h, const char *password) {return OpenZipInternal((void*)h,0,ZIP_HANDLE,password);} HZIP OpenZip(const TCHAR *fn, const char *password) {return OpenZipInternal((void*)fn,0,ZIP_FILENAME,password);} HZIP OpenZip(void *z,unsigned int len, const char *password) {return OpenZipInternal(z,len,ZIP_MEMORY,password);} ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze) { ze->index=0; *ze->name=0; ze->unc_size=0; if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Get(index,ze); return lasterrorU; } ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Find(name,ic,index,ze); return lasterrorU; } ZRESULT UnzipItemInternal(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Unzip(index,dst,len,flags); return lasterrorU; } ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h) {return UnzipItemInternal(hz,index,(void*)h,0,ZIP_HANDLE);} ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn) {return UnzipItemInternal(hz,index,(void*)fn,0,ZIP_FILENAME);} ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len) {return UnzipItemInternal(hz,index,z,len,ZIP_MEMORY);} ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->SetUnzipBaseDir(dir); return lasterrorU; } ZRESULT CloseZipU(HZIP hz) { if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} TUnzipHandleData *han = (TUnzipHandleData*)hz; if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} TUnzip *unz = han->unz; lasterrorU = unz->Close(); delete unz; delete han; return lasterrorU; } bool IsZipHandleU(HZIP hz) { if (hz==0) return false; TUnzipHandleData *han = (TUnzipHandleData*)hz; return (han->flag==1); } #endif //WIN32 repsnapper-2.3.2a5/libraries/amf/amftools-code/src/zip/zip.cpp000066400000000000000000003420621231531733200243040ustar00rootroot00000000000000#ifdef WIN32 #include #include #include #include "zip/zip.h" // THIS FILE is almost entirely based upon code by info-zip. // It has been modified by Lucian Wischik. The modifications // were a complete rewrite of the bit of code that generates the // layout of the zipfile, and support for zipping to/from memory // or handles or pipes or pagefile or diskfiles, encryption, unicode. // The original code may be found at http://www.info-zip.org // The original copyright text follows. // // // // This is version 1999-Oct-05 of the Info-ZIP copyright and license. // The definitive version of this document should be available at // ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely. // // Copyright (c) 1990-1999 Info-ZIP. All rights reserved. // // For the purposes of this copyright and license, "Info-ZIP" is defined as // the following set of individuals: // // Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, // Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, // Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum, // Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller, // Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel, // Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen, // Paul von Behren, Rich Wales, Mike White // // This software is provided "as is," without warranty of any kind, express // or implied. In no event shall Info-ZIP or its contributors be held liable // for any direct, indirect, incidental, special or consequential damages // arising out of the use of or inability to use this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. Redistributions of source code must retain the above copyright notice, // definition, disclaimer, and this list of conditions. // // 2. Redistributions in binary form must reproduce the above copyright // notice, definition, disclaimer, and this list of conditions in // documentation and/or other materials provided with the distribution. // // 3. Altered versions--including, but not limited to, ports to new operating // systems, existing ports with new graphical interfaces, and dynamic, // shared, or static library versions--must be plainly marked as such // and must not be misrepresented as being the original source. Such // altered versions also must not be misrepresented as being Info-ZIP // releases--including, but not limited to, labeling of the altered // versions with the names "Info-ZIP" (or any variation thereof, including, // but not limited to, different capitalizations), "Pocket UnZip," "WiZ" // or "MacZip" without the explicit permission of Info-ZIP. Such altered // versions are further prohibited from misrepresentative use of the // Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). // // 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," // "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and // binary releases. // typedef unsigned char uch; // unsigned 8-bit value typedef unsigned short ush; // unsigned 16-bit value typedef unsigned long ulg; // unsigned 32-bit value typedef size_t extent; // file size typedef unsigned Pos; // must be at least 32 bits typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing #ifndef EOF #define EOF (-1) #endif // Error return values. The values 0..4 and 12..18 follow the conventions // of PKZIP. The values 4..10 are all assigned to "insufficient memory" // by PKZIP, so the codes 5..10 are used here for other purposes. #define ZE_MISS -1 // used by procname(), zipbare() #define ZE_OK 0 // success #define ZE_EOF 2 // unexpected end of zip file #define ZE_FORM 3 // zip file structure error #define ZE_MEM 4 // out of memory #define ZE_LOGIC 5 // internal logic error #define ZE_BIG 6 // entry too large to split #define ZE_NOTE 7 // invalid comment format #define ZE_TEST 8 // zip test (-T) failed or out of memory #define ZE_ABORT 9 // user interrupt or termination #define ZE_TEMP 10 // error using a temp file #define ZE_READ 11 // read or seek error #define ZE_NONE 12 // nothing to do #define ZE_NAME 13 // missing or empty zip file #define ZE_WRITE 14 // error writing to a file #define ZE_CREAT 15 // couldn't open to write #define ZE_PARMS 16 // bad command line #define ZE_OPEN 18 // could not open a specified file to read #define ZE_MAXERR 18 // the highest error number // internal file attribute #define UNKNOWN (-1) #define BINARY 0 #define ASCII 1 #define BEST -1 // Use best method (deflation or store) #define STORE 0 // Store method #define DEFLATE 8 // Deflation method #define CRCVAL_INITIAL 0L // MSDOS file or directory attributes #define MSDOS_HIDDEN_ATTR 0x02 #define MSDOS_DIR_ATTR 0x10 // Lengths of headers after signatures in bytes #define LOCHEAD 26 #define CENHEAD 42 #define ENDHEAD 18 // Definitions for extra field handling: #define EB_HEADSIZE 4 /* length of a extra field block header */ #define EB_LEN 2 /* offset of data length field in header */ #define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */ #define EB_UT_FLAGS 0 /* byte offset of Flags field */ #define EB_UT_TIME1 1 /* byte offset of 1st time value */ #define EB_UT_FL_MTIME (1 << 0) /* mtime present */ #define EB_UT_FL_ATIME (1 << 1) /* atime present */ #define EB_UT_FL_CTIME (1 << 2) /* ctime present */ #define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n)) #define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3)) #define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) // Macros for writing machine integers to little-endian format #define PUTSH(a,f) {char _putsh_c=(char)((a)&0xff); wfunc(param,&_putsh_c,1); _putsh_c=(char)((a)>>8); wfunc(param,&_putsh_c,1);} #define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))} // -- Structure of a ZIP file -- // Signatures for zip file information headers #define LOCSIG 0x04034b50L #define CENSIG 0x02014b50L #define ENDSIG 0x06054b50L #define EXTLOCSIG 0x08074b50L #define MIN_MATCH 3 #define MAX_MATCH 258 // The minimum and maximum match lengths #define WSIZE (0x8000) // Maximum window size = 32K. If you are really short of memory, compile // with a smaller WSIZE but this reduces the compression ratio for files // of size > WSIZE. WSIZE must be a power of two in the current implementation. // #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) // Minimum amount of lookahead, except at the end of the input file. // See deflate.c for comments about the MIN_MATCH+1. // #define MAX_DIST (WSIZE-MIN_LOOKAHEAD) // In order to simplify the code, particularly on 16 bit machines, match // distances are limited to MAX_DIST instead of WSIZE. // #define ZIP_HANDLE 1 #define ZIP_FILENAME 2 #define ZIP_MEMORY 3 #define ZIP_FOLDER 4 // =========================================================================== // Constants // #define MAX_BITS 15 // All codes must not exceed MAX_BITS bits #define MAX_BL_BITS 7 // Bit length codes must not exceed MAX_BL_BITS bits #define LENGTH_CODES 29 // number of length codes, not counting the special END_BLOCK code #define LITERALS 256 // number of literal bytes 0..255 #define END_BLOCK 256 // end of block literal code #define L_CODES (LITERALS+1+LENGTH_CODES) // number of Literal or Length codes, including the END_BLOCK code #define D_CODES 30 // number of distance codes #define BL_CODES 19 // number of codes used to transfer the bit lengths #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 // The three kinds of block type #define LIT_BUFSIZE 0x8000 #define DIST_BUFSIZE LIT_BUFSIZE // Sizes of match buffers for literals/lengths and distances. There are // 4 reasons for limiting LIT_BUFSIZE to 64K: // - frequencies can be kept in 16 bit counters // - if compression is not successful for the first block, all input data is // still in the window so we can still emit a stored block even when input // comes from standard input. (This can also be done for all blocks if // LIT_BUFSIZE is not greater than 32K.) // - if compression is not successful for a file smaller than 64K, we can // even emit a stored file instead of a stored block (saving 5 bytes). // - creating new Huffman trees less frequently may not provide fast // adaptation to changes in the input data statistics. (Take for // example a binary file with poorly compressible code followed by // a highly compressible string table.) Smaller buffer sizes give // fast adaptation but have of course the overhead of transmitting trees // more frequently. // - I can't count above 4 // The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save // memory at the expense of compression). Some optimizations would be possible // if we rely on DIST_BUFSIZE == LIT_BUFSIZE. // #define REP_3_6 16 // repeat previous bit length 3-6 times (2 bits of repeat count) #define REPZ_3_10 17 // repeat a zero length 3-10 times (3 bits of repeat count) #define REPZ_11_138 18 // repeat a zero length 11-138 times (7 bits of repeat count) #define HEAP_SIZE (2*L_CODES+1) // maximum heap size // =========================================================================== // Local data used by the "bit string" routines. // #define Buf_size (8 * 2*sizeof(char)) // Number of bits used within bi_buf. (bi_buf may be implemented on // more than 16 bits on some systems.) // Output a 16 bit value to the bit stream, lower (oldest) byte first #define PUTSHORT(state,w) \ { if (state.bs.out_offset >= state.bs.out_size-1) \ state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \ state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \ } #define PUTBYTE(state,b) \ { if (state.bs.out_offset >= state.bs.out_size) \ state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ state.bs.out_buf[state.bs.out_offset++] = (char) (b); \ } // DEFLATE.CPP HEADER #define HASH_BITS 15 // For portability to 16 bit machines, do not use values above 15. #define HASH_SIZE (unsigned)(1<= HASH_BITS #define max_insert_length max_lazy_match // Insert new strings in the hash table only if the match length // is not greater than this length. This saves time but degrades compression. // max_insert_length is used only for compression levels <= 3. const int extra_lbits[LENGTH_CODES] // extra bits for each length code = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; const int extra_dbits[D_CODES] // extra bits for each distance code = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; const int extra_blbits[BL_CODES]// extra bits for each bit length code = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; // The lengths of the bit length codes are sent in order of decreasing // probability, to avoid transmitting the lengths for unused bit length codes. typedef struct config { ush good_length; // reduce lazy search above this match length ush max_lazy; // do not perform lazy search above this match length ush nice_length; // quit search above this match length ush max_chain; } config; // Values for max_lazy_match, good_match, nice_match and max_chain_length, // depending on the desired pack level (0..9). The values given below have // been tuned to exclude worst case performance for pathological files. // Better values may be found for specific files. // const config configuration_table[10] = { // good lazy nice chain {0, 0, 0, 0}, // 0 store only {4, 4, 8, 4}, // 1 maximum speed, no lazy matches {4, 5, 16, 8}, // 2 {4, 6, 32, 32}, // 3 {4, 4, 16, 16}, // 4 lazy matches */ {8, 16, 32, 32}, // 5 {8, 16, 128, 128}, // 6 {8, 32, 128, 256}, // 7 {32, 128, 258, 1024}, // 8 {32, 258, 258, 4096}};// 9 maximum compression */ // Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 // For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning. // Data structure describing a single value and its code string. typedef struct ct_data { union { ush freq; // frequency count ush code; // bit string } fc; union { ush dad; // father node in Huffman tree ush len; // length of bit string } dl; } ct_data; typedef struct tree_desc { ct_data *dyn_tree; // the dynamic tree ct_data *static_tree; // corresponding static tree or NULL const int *extra_bits; // extra bits for each code or NULL int extra_base; // base index for extra_bits int elems; // max number of elements in the tree int max_length; // max bit length for the codes int max_code; // largest code with non zero frequency } tree_desc; class TTreeState { public: TTreeState(); ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree ct_data dyn_dtree[2*D_CODES+1]; // distance tree ct_data static_ltree[L_CODES+2]; // the static literal tree... // ... Since the bit lengths are imposed, there is no need for the L_CODES // extra codes used during heap construction. However the codes 286 and 287 // are needed to build a canonical tree (see ct_init below). ct_data static_dtree[D_CODES]; // the static distance tree... // ... (Actually a trivial tree since all codes use 5 bits.) ct_data bl_tree[2*BL_CODES+1]; // Huffman tree for the bit lengths tree_desc l_desc; tree_desc d_desc; tree_desc bl_desc; ush bl_count[MAX_BITS+1]; // number of codes at each bit length for an optimal tree int heap[2*L_CODES+1]; // heap used to build the Huffman trees int heap_len; // number of elements in the heap int heap_max; // element of largest frequency // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. // The same heap array is used to build all trees. uch depth[2*L_CODES+1]; // Depth of each subtree used as tie breaker for trees of equal frequency uch length_code[MAX_MATCH-MIN_MATCH+1]; // length code for each normalized match length (0 == MIN_MATCH) uch dist_code[512]; // distance codes. The first 256 values correspond to the distances // 3 .. 258, the last 256 values correspond to the top 8 bits of // the 15 bit distances. int base_length[LENGTH_CODES]; // First normalized length for each code (0 = MIN_MATCH) int base_dist[D_CODES]; // First normalized distance for each code (0 = distance of 1) uch far l_buf[LIT_BUFSIZE]; // buffer for literals/lengths ush far d_buf[DIST_BUFSIZE]; // buffer for distances uch flag_buf[(LIT_BUFSIZE/8)]; // flag_buf is a bit array distinguishing literals from lengths in // l_buf, and thus indicating the presence or absence of a distance. unsigned last_lit; // running index in l_buf unsigned last_dist; // running index in d_buf unsigned last_flags; // running index in flag_buf uch flags; // current flags not yet saved in flag_buf uch flag_bit; // current bit used in flags // bits are filled in flags starting at bit 0 (least significant). // Note: these flags are overkill in the current code since we don't // take advantage of DIST_BUFSIZE == LIT_BUFSIZE. ulg opt_len; // bit length of current block with optimal trees ulg static_len; // bit length of current block with static trees ulg cmpr_bytelen; // total byte length of compressed file ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen' ulg input_len; // total byte length of input file // input_len is for debugging only since we can get it by other means. ush *file_type; // pointer to UNKNOWN, BINARY or ASCII // int *file_method; // pointer to DEFLATE or STORE }; TTreeState::TTreeState() { tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0}; l_desc = a; tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; d_desc = b; tree_desc c = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; bl_desc = c; last_lit=0; last_dist=0; last_flags=0; } class TBitState { public: int flush_flg; // unsigned bi_buf; // Output buffer. bits are inserted starting at the bottom (least significant // bits). The width of bi_buf must be at least 16 bits. int bi_valid; // Number of valid bits in bi_buf. All bits above the last valid bit // are always zero. char *out_buf; // Current output buffer. unsigned out_offset; // Current offset in output buffer. // On 16 bit machines, the buffer is limited to 64K. unsigned out_size; // Size of current output buffer ulg bits_sent; // bit length of the compressed data only needed for debugging??? }; class TDeflateState { public: TDeflateState() {window_size=0;} uch window[2L*WSIZE]; // Sliding window. Input bytes are read into the second half of the window, // and move to the first half later to keep a dictionary of at least WSIZE // bytes. With this organization, matches are limited to a distance of // WSIZE-MAX_MATCH bytes, but this ensures that IO is always // performed with a length multiple of the block size. Also, it limits // the window size to 64K, which is quite useful on MSDOS. // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would // be less efficient since the data would have to be copied WSIZE/CBSZ times) Pos prev[WSIZE]; // Link to older string with same hash index. To limit the size of this // array to 64K, this link is maintained only for the last 32K strings. // An index in this array is thus a window index modulo 32K. Pos head[HASH_SIZE]; // Heads of the hash chains or NIL. If your compiler thinks that // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC. ulg window_size; // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the // input file length plus MIN_LOOKAHEAD. long block_start; // window position at the beginning of the current output block. Gets // negative when the window is moved backwards. int sliding; // Set to false when the input file is already in memory unsigned ins_h; // hash index of string to be inserted unsigned int prev_length; // Length of the best match at previous step. Matches not greater than this // are discarded. This is used in the lazy match evaluation. unsigned strstart; // start of string to insert unsigned match_start; // start of matching string int eofile; // flag set at end of input file unsigned lookahead; // number of valid bytes ahead in window unsigned max_chain_length; // To speed up deflation, hash chains are never searched beyond this length. // A higher limit improves compression ratio but degrades the speed. unsigned int max_lazy_match; // Attempt to find a better match only when the current match is strictly // smaller than this value. This mechanism is used only for compression // levels >= 4. unsigned good_match; // Use a faster search when the previous match is longer than this int nice_match; // Stop searching when current match exceeds this }; typedef __int64 lutime_t; // define it ourselves since we don't include time.h typedef struct iztimes { lutime_t atime,mtime,ctime; } iztimes; // access, modify, create times typedef struct zlist { ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are ulg tim, crc, siz, len; extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD ulg atx, off; char name[MAX_PATH]; // File name in zip file char *extra; // Extra field (set only if ext != 0) char *cextra; // Extra in central (set only if cext != 0) char *comment; // Comment (set only if com != 0) char iname[MAX_PATH]; // Internal file name after cleanup char zname[MAX_PATH]; // External version of internal name int mark; // Marker for files to operate on int trash; // Marker for files to delete int dosflag; // Set to force MSDOS file attributes struct zlist far *nxt; // Pointer to next header in list } TZipFileInfo; struct TState; typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size); typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size); typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size); struct TState { void *param; int level; bool seekable; READFUNC readfunc; FLUSHFUNC flush_outbuf; TTreeState ts; TBitState bs; TDeflateState ds; const char *err; }; void Assert(TState &state,bool cond, const char *msg) { if (cond) return; state.err=msg; } void __cdecl Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} void __cdecl Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} // =========================================================================== // Local (static) routines in this file. // void init_block (TState &); void pqdownheap (TState &,ct_data *tree, int k); void gen_bitlen (TState &,tree_desc *desc); void gen_codes (TState &state,ct_data *tree, int max_code); void build_tree (TState &,tree_desc *desc); void scan_tree (TState &,ct_data *tree, int max_code); void send_tree (TState &state,ct_data *tree, int max_code); int build_bl_tree (TState &); void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes); void compress_block (TState &state,ct_data *ltree, ct_data *dtree); void set_file_type (TState &); void send_bits (TState &state, int value, int length); unsigned bi_reverse (unsigned code, int len); void bi_windup (TState &state); void copy_block (TState &state,char *buf, unsigned len, int header); #define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len) // Send a code of the given tree. c and tree must not have side effects // alternatively... //#define send_code(state, c, tree) // { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c)); // send_bits(state, tree[c].fc.code, tree[c].dl.len); } #define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)]) // Mapping from a distance to a distance code. dist is the distance - 1 and // must not have side effects. dist_code[256] and dist_code[257] are never used. #define Max(a,b) (a >= b ? a : b) /* the arguments must not have side effects */ /* =========================================================================== * Allocate the match buffer, initialize the various tables and save the * location of the internal file attribute (ascii/binary) and method * (DEFLATE/STORE). */ void ct_init(TState &state, ush *attr) { int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ state.ts.file_type = attr; //state.ts.file_method = method; state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L; state.ts.input_len = 0L; if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */ /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { state.ts.base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { state.ts.base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { state.ts.base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { state.ts.dist_code[256 + dist++] = (uch)code; } } Assert(state,dist == 256, "ct_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; n = 0; while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++; while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++; while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; /* fc.codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { state.ts.static_dtree[n].dl.len = 5; state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5); } /* Initialize the first block of the first file: */ init_block(state); } /* =========================================================================== * Initialize a new block. */ void init_block(TState &state) { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0; for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0; for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0; state.ts.dyn_ltree[END_BLOCK].fc.freq = 1; state.ts.opt_len = state.ts.static_len = 0L; state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0; state.ts.flags = 0; state.ts.flag_bit = 1; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(tree, top) \ {\ top = state.ts.heap[SMALLEST]; \ state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \ pqdownheap(state,tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m) \ (tree[n].fc.freq < tree[m].fc.freq || \ (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ void pqdownheap(TState &state,ct_data *tree, int k) { int v = state.ts.heap[k]; int j = k << 1; /* left son of k */ int htemp; /* required because of bug in SASC compiler */ while (j <= state.ts.heap_len) { /* Set j to the smallest of the two sons: */ if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++; /* Exit if v is smaller than both sons */ htemp = state.ts.heap[j]; if (smaller(tree, v, htemp)) break; /* Exchange v with the smallest son */ state.ts.heap[k] = htemp; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } state.ts.heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ void gen_bitlen(TState &state,tree_desc *desc) { ct_data *tree = desc->dyn_tree; const int *extra = desc->extra_bits; int base = desc->extra_base; int max_code = desc->max_code; int max_length = desc->max_length; ct_data *stree = desc->static_tree; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */ for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) { n = state.ts.heap[h]; bits = tree[tree[n].dl.dad].dl.len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].dl.len = (ush)bits; /* We overwrite tree[n].dl.dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ state.ts.bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].fc.freq; state.ts.opt_len += (ulg)f * (bits + xbits); if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits); } if (overflow == 0) return; Trace("\nbit length overflow\n"); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (state.ts.bl_count[bits] == 0) bits--; state.ts.bl_count[bits]--; /* move one leaf down the tree */ state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */ state.ts.bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = state.ts.bl_count[bits]; while (n != 0) { m = state.ts.heap[--h]; if (m > max_code) continue; if (tree[m].dl.len != (ush)bits) { Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits); state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; tree[m].dl.len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ void gen_codes (TState &state, ct_data *tree, int max_code) { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1); } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1, "inconsistent bit counts"); Trace("\ngen_codes: max_code %d ", max_code); for (n = 0; n <= max_code; n++) { int len = tree[n].dl.len; if (len == 0) continue; /* Now reverse the bits */ tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len); //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1); } } /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ void build_tree(TState &state,tree_desc *desc) { ct_data *tree = desc->dyn_tree; ct_data *stree = desc->static_tree; int elems = desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node = elems; /* next internal node of the tree */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].fc.freq != 0) { state.ts.heap[++state.ts.heap_len] = max_code = n; state.ts.depth[n] = 0; } else { tree[n].dl.len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (state.ts.heap_len < 2) { int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0); tree[newcp].fc.freq = 1; state.ts.depth[newcp] = 0; state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len; /* new is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ do { pqremove(tree, n); /* n = node of least frequency */ m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */ state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */ state.ts.heap[--state.ts.heap_max] = m; /* Create a new node father of n and m */ tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq); state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1); tree[n].dl.dad = tree[m].dl.dad = (ush)node; /* and insert the new node in the heap */ state.ts.heap[SMALLEST] = node++; pqdownheap(state,tree, SMALLEST); } while (state.ts.heap_len >= 2); state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(state,(tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes (state,(ct_data *)tree, max_code); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. Updates opt_len to take into account the repeat * counts. (The contribution of the bit length codes will be added later * during the construction of bl_tree.) */ void scan_tree (TState &state,ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].dl.len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].dl.len = (ush)-1; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].dl.len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count); } else if (curlen != 0) { if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++; state.ts.bl_tree[REP_3_6].fc.freq++; } else if (count <= 10) { state.ts.bl_tree[REPZ_3_10].fc.freq++; } else { state.ts.bl_tree[REPZ_11_138].fc.freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ void send_tree (TState &state, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].dl.len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].dl.len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].dl.len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(state, curlen, state.ts.bl_tree); count--; } Assert(state,count >= 3 && count <= 6, " 3_6?"); send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2); } else if (count <= 10) { send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3); } else { send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ int build_bl_tree(TState &state) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code); scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code); /* Build the bit length tree: */ build_tree(state,(tree_desc *)(&state.ts.bl_desc)); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break; } /* Update opt_len to include the bit length tree and counts */ state.ts.opt_len += 3*(max_blindex+1) + 5+5+4; Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes) { int rank; /* index in bl_order */ Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Trace("\nbl counts: "); send_bits(state,lcodes-257, 5); /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */ send_bits(state,dcodes-1, 5); send_bits(state,blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Trace("\nbl code %2d ", bl_order[rank]); send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3); } Trace("\nbl tree: sent %ld", state.bs.bits_sent); send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */ Trace("\nlit tree: sent %ld", state.bs.bits_sent); send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */ Trace("\ndist tree: sent %ld", state.bs.bits_sent); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. This function * returns the total compressed length (in bytes) for the file so far. */ ulg flush_block(TState &state,char *buf, ulg stored_len, int eof) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex; /* index of last bit length code of non zero freq */ state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */ /* Check if the file is ascii or binary */ if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state); /* Construct the literal and distance trees */ build_tree(state,(tree_desc *)(&state.ts.l_desc)); Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); build_tree(state,(tree_desc *)(&state.ts.d_desc)); Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(state); /* Determine the best encoding. Compute first the block length in bytes */ opt_lenb = (state.ts.opt_len+3+7)>>3; static_lenb = (state.ts.static_len+3+7)>>3; state.ts.input_len += stored_len; /* for debugging only */ Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len, state.ts.last_lit, state.ts.last_dist); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; // Originally, zip allowed the file to be transformed from a compressed // into a stored file in the case where compression failed, there // was only one block, and it was allowed to change. I've removed this // possibility since the code's cleaner if no changes are allowed. //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L // && state.ts.cmpr_len_bits == 0L && state.seekable) //{ // && state.ts.file_method != NULL // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: // Assert(state,buf!=NULL,"block vanished"); // copy_block(state,buf, (unsigned)stored_len, 0); // without header // state.ts.cmpr_bytelen = stored_len; // Assert(state,false,"unimplemented *state.ts.file_method = STORE;"); // //*state.ts.file_method = STORE; //} //else if (stored_len+4 <= opt_lenb && buf != (char*)NULL) { /* 4: two words for the lengths */ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ send_bits(state,(STORED_BLOCK<<1)+eof, 3); /* send block type */ state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4; state.ts.cmpr_len_bits = 0L; copy_block(state,buf, (unsigned)stored_len, 1); /* with header */ } else if (static_lenb == opt_lenb) { send_bits(state,(STATIC_TREES<<1)+eof, 3); compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree); state.ts.cmpr_len_bits += 3 + state.ts.static_len; state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; state.ts.cmpr_len_bits &= 7L; } else { send_bits(state,(DYN_TREES<<1)+eof, 3); send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1); compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree); state.ts.cmpr_len_bits += 3 + state.ts.opt_len; state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; state.ts.cmpr_len_bits &= 7L; } Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size"); init_block(state); if (eof) { // Assert(state,input_len == isize, "bad input size"); bi_windup(state); state.ts.cmpr_len_bits += 7; /* align on byte boundary */ } Trace("\n"); return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ct_tally (TState &state,int dist, int lc) { state.ts.l_buf[state.ts.last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ state.ts.dyn_ltree[lc].fc.freq++; } else { /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert(state,(ush)dist < (ush)MAX_DIST && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match"); state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++; state.ts.dyn_dtree[d_code(dist)].fc.freq++; state.ts.d_buf[state.ts.last_dist++] = (ush)dist; state.ts.flags |= state.ts.flag_bit; } state.ts.flag_bit <<= 1; /* Output the flags if they fill a byte: */ if ((state.ts.last_lit & 7) == 0) { state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags; state.ts.flags = 0, state.ts.flag_bit = 1; } /* Try to guess if it is profitable to stop the current block here */ if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)state.ts.last_lit*8L; ulg in_length = (ulg)state.ds.strstart-state.ds.block_start; int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]); } out_length >>= 3; Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", state.ts.last_lit, state.ts.last_dist, in_length, out_length, 100L - out_length*100L/in_length); if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1; } return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE); /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ void compress_block(TState &state,ct_data *ltree, ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned dx = 0; /* running index in d_buf */ unsigned fx = 0; /* running index in flag_buf */ uch flag = 0; /* current flags */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (state.ts.last_lit != 0) do { if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++]; lc = state.ts.l_buf[lx++]; if ((flag & 1) == 0) { send_code(state,lc, ltree); /* send a literal byte */ } else { /* Here, lc is the match length - MIN_MATCH */ code = state.ts.length_code[lc]; send_code(state,code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= state.ts.base_length[code]; send_bits(state,lc, extra); /* send the extra length bits */ } dist = state.ts.d_buf[dx++]; /* Here, dist is the match distance - 1 */ code = d_code(dist); Assert(state,code < D_CODES, "bad d_code"); send_code(state,code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= state.ts.base_dist[code]; send_bits(state,dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ flag >>= 1; } while (lx < state.ts.last_lit); send_code(state,END_BLOCK, ltree); } /* =========================================================================== * Set the file type to ASCII or BINARY, using a crude approximation: * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. * IN assertion: the fields freq of dyn_ltree are set and the total of all * frequencies does not exceed 64K (to fit in an int on 16 bit machines). */ void set_file_type(TState &state) { int n = 0; unsigned ascii_freq = 0; unsigned bin_freq = 0; while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq; while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq; while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq; *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); } /* =========================================================================== * Initialize the bit string routines. */ void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed) { state.bs.out_buf = tgt_buf; state.bs.out_size = tgt_size; state.bs.out_offset = 0; state.bs.flush_flg = flsh_allowed; state.bs.bi_buf = 0; state.bs.bi_valid = 0; state.bs.bits_sent = 0L; } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ void send_bits(TState &state,int value, int length) { Assert(state,length > 0 && length <= 15, "invalid length"); state.bs.bits_sent += (ulg)length; /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and * (Buf_size - bi_valid) bits from value to flush the filled bi_buf, * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid)) * unused bits in bi_buf. */ state.bs.bi_buf |= (value << state.bs.bi_valid); state.bs.bi_valid += length; if (state.bs.bi_valid > (int)Buf_size) { PUTSHORT(state,state.bs.bi_buf); state.bs.bi_valid -= Buf_size; state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid); } } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ unsigned bi_reverse(unsigned code, int len) { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Write out any remaining bits in an incomplete byte. */ void bi_windup(TState &state) { if (state.bs.bi_valid > 8) { PUTSHORT(state,state.bs.bi_buf); } else if (state.bs.bi_valid > 0) { PUTBYTE(state,state.bs.bi_buf); } if (state.bs.flush_flg) { state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); } state.bs.bi_buf = 0; state.bs.bi_valid = 0; state.bs.bits_sent = (state.bs.bits_sent+7) & ~7; } /* =========================================================================== * Copy a stored block to the zip file, storing first the length and its * one's complement if requested. */ void copy_block(TState &state, char *block, unsigned len, int header) { bi_windup(state); /* align on byte boundary */ if (header) { PUTSHORT(state,(ush)len); PUTSHORT(state,(ush)~len); state.bs.bits_sent += 2*16; } if (state.bs.flush_flg) { state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); state.bs.out_offset = len; state.flush_outbuf(state.param,block, &state.bs.out_offset); } else if (state.bs.out_offset + len > state.bs.out_size) { Assert(state,false,"output buffer too small for in-memory compression"); } else { memcpy(state.bs.out_buf + state.bs.out_offset, block, len); state.bs.out_offset += len; } state.bs.bits_sent += (ulg)len<<3; } /* =========================================================================== * Prototypes for functions. */ void fill_window (TState &state); ulg deflate_fast (TState &state); int longest_match (TState &state,IPos cur_match); /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or * mmap'ed in the window[] array, 0 otherwise. In the first case, * window_size is sufficient to contain the whole input file plus * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end * of window[] when looking for matches towards the end). */ void lm_init (TState &state, int pack_level, ush *flags) { register unsigned j; Assert(state,pack_level>=1 && pack_level<=8,"bad pack level"); /* Do not slide the window if the whole input is already in memory * (window_size > 0) */ state.ds.sliding = 0; if (state.ds.window_size == 0L) { state.ds.sliding = 1; state.ds.window_size = (ulg)2L*WSIZE; } /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ state.ds.head[HASH_SIZE-1] = NIL; memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head)); /* Set the default configuration parameters: */ state.ds.max_lazy_match = configuration_table[pack_level].max_lazy; state.ds.good_match = configuration_table[pack_level].good_length; state.ds.nice_match = configuration_table[pack_level].nice_length; state.ds.max_chain_length = configuration_table[pack_level].max_chain; if (pack_level <= 2) { *flags |= FAST; } else if (pack_level >= 8) { *flags |= SLOW; } /* ??? reduce max_chain_length for binary files */ state.ds.strstart = 0; state.ds.block_start = 0L; j = WSIZE; j <<= 1; // Can read 64K in one step state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j); if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) { state.ds.eofile = 1, state.ds.lookahead = 0; return; } state.ds.eofile = 0; /* Make sure that we always have enough lookahead. This is important * if input comes from a device such as a tty. */ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); state.ds.ins_h = 0; for (j=0; j= 1 */ // For 80x86 and 680x0 and ARM, an optimized version is in match.asm or // match.S. The code is functionally equivalent, so you can use the C version // if desired. Which I do so desire! int longest_match(TState &state,IPos cur_match) { unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */ register uch far *scan = state.ds.window + state.ds.strstart; /* current string */ register uch far *match; /* matched string */ register int len; /* length of current match */ int best_len = state.ds.prev_length; /* best match length so far */ IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. // It is easy to get rid of this optimization if necessary. Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever"); register uch far *strend = state.ds.window + state.ds.strstart + MAX_MATCH; register uch scan_end1 = scan[best_len-1]; register uch scan_end = scan[best_len]; /* Do not waste too much time if we already have a good match: */ if (state.ds.prev_length >= state.ds.good_match) { chain_length >>= 2; } Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead"); do { Assert(state,cur_match < state.ds.strstart, "no future"); match = state.ds.window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2: */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; if (len > best_len) { state.ds.match_start = cur_match; best_len = len; if (len >= state.ds.nice_match) break; scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; } } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit && --chain_length != 0); return best_len; } #define check_match(state,start, match, length) // or alternatively... //void check_match(TState &state,IPos start, IPos match, int length) //{ // check that the match is indeed a match // if (memcmp((char*)state.ds.window + match, // (char*)state.ds.window + start, length) != EQUAL) { // fprintf(stderr, // " start %d, match %d, length %d\n", // start, match, length); // error("invalid match"); // } // if (state.verbose > 1) { // fprintf(stderr,"\\[%d,%d]", start-match, length); // do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0); // } //} /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead, and sets eofile if end of input file. * * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or eofile is set; file reads are * performed for at least two bytes (required for the translate_eol option). */ void fill_window(TState &state) { register unsigned n, m; unsigned more; /* Amount of free space at the end of the window. */ do { more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart); /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (more == (unsigned)EOF) { /* Very unlikely, but possible on 16 bit machine if strstart == 0 * and lookahead == 1 (input done one byte at time) */ more--; /* For MMAP or BIG_MEM, the whole input file is already in memory so * we must not perform sliding. We must however call (*read_buf)() in * order to compute the crc, update lookahead and possibly set eofile. */ } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) { /* By the IN assertion, the window is not empty so we can't confuse * more == 0 with more == 64K on a 16 bit machine. */ memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE); state.ds.match_start -= WSIZE; state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ state.ds.block_start -= (long) WSIZE; for (n = 0; n < HASH_SIZE; n++) { m = state.ds.head[n]; state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); } for (n = 0; n < WSIZE; n++) { m = state.ds.prev[n]; state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } more += WSIZE; } if (state.ds.eofile) return; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the MMAP or BIG_MEM case (not yet supported in gzip), * window_size == input_size + MIN_LOOKAHEAD && * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(state,more >= 2, "more < 2"); n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more); if (n == 0 || n == (unsigned)EOF) { state.ds.eofile = 1; } else { state.ds.lookahead += n; } } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK(state,eof) \ flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \ (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof)) /* =========================================================================== * Processes a new input file and return its compressed length. This * function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ ulg deflate_fast(TState &state) { IPos hash_head = NIL; /* head of the hash chain */ int flush; /* set if current block must be flushed */ unsigned match_length = 0; /* length of best match */ state.ds.prev_length = MIN_MATCH-1; while (state.ds.lookahead != 0) { /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ if (state.ds.lookahead >= MIN_MATCH) INSERT_STRING(state.ds.strstart, hash_head); /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ /* Do not look for matches beyond the end of the input. * This is necessary to make deflate deterministic. */ if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; match_length = longest_match (state,hash_head); /* longest_match() sets match_start */ if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; } if (match_length >= MIN_MATCH) { check_match(state,state.ds.strstart, state.ds.match_start, match_length); flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH); state.ds.lookahead -= match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ if (match_length <= state.ds.max_insert_length && state.ds.lookahead >= MIN_MATCH) { match_length--; /* string at strstart already in hash table */ do { state.ds.strstart++; INSERT_STRING(state.ds.strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--match_length != 0); state.ds.strstart++; } else { state.ds.strstart += match_length; match_length = 0; state.ds.ins_h = state.ds.window[state.ds.strstart]; UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]); Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times"); } } else { /* No match, output a literal byte */ flush = ct_tally (state,0, state.ds.window[state.ds.strstart]); state.ds.lookahead--; state.ds.strstart++; } if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); } return FLUSH_BLOCK(state,1); /* eof */ } /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ ulg deflate(TState &state) { IPos hash_head = NIL; /* head of hash chain */ IPos prev_match; /* previous match */ int flush; /* set if current block must be flushed */ int match_available = 0; /* set if previous match exists */ register unsigned match_length = MIN_MATCH-1; /* length of best match */ if (state.level <= 3) return deflate_fast(state); /* optimized for speed */ /* Process the input block. */ while (state.ds.lookahead != 0) { /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ if (state.ds.lookahead >= MIN_MATCH) INSERT_STRING(state.ds.strstart, hash_head); /* Find the longest match, discarding those <= prev_length. */ state.ds.prev_length = match_length, prev_match = state.ds.match_start; match_length = MIN_MATCH-1; if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match && state.ds.strstart - hash_head <= MAX_DIST) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ /* Do not look for matches beyond the end of the input. * This is necessary to make deflate deterministic. */ if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; match_length = longest_match (state,hash_head); /* longest_match() sets match_start */ if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; /* Ignore a length 3 match if it is too distant: */ if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){ /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) { unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH; check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length); flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. */ state.ds.lookahead -= state.ds.prev_length-1; state.ds.prev_length -= 2; do { if (++state.ds.strstart <= max_insert) { INSERT_STRING(state.ds.strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } } while (--state.ds.prev_length != 0); state.ds.strstart++; match_available = 0; match_length = MIN_MATCH-1; if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; } else if (match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) { FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; } state.ds.strstart++; state.ds.lookahead--; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ match_available = 1; state.ds.strstart++; state.ds.lookahead--; } // Assert(state,strstart <= isize && lookahead <= isize, "a bit too far"); /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); } if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]); return FLUSH_BLOCK(state,1); /* eof */ } int putlocal(struct zlist far *z, WRITEFUNC wfunc,void *param) { // Write a local header described by *z to file *f. Return a ZE_ error code. PUTLG(LOCSIG, f); PUTSH(z->ver, f); PUTSH(z->lflg, f); PUTSH(z->how, f); PUTLG(z->tim, f); PUTLG(z->crc, f); PUTLG(z->siz, f); PUTLG(z->len, f); PUTSH(z->nam, f); PUTSH(z->ext, f); size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam); if (res!=z->nam) return ZE_TEMP; if (z->ext) { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext); if (res!=z->ext) return ZE_TEMP; } return ZE_OK; } int putextended(struct zlist far *z, WRITEFUNC wfunc, void *param) { // Write an extended local header described by *z to file *f. Returns a ZE_ code PUTLG(EXTLOCSIG, f); PUTLG(z->crc, f); PUTLG(z->siz, f); PUTLG(z->len, f); return ZE_OK; } int putcentral(struct zlist far *z, WRITEFUNC wfunc, void *param) { // Write a central header entry of *z to file *f. Returns a ZE_ code. PUTLG(CENSIG, f); PUTSH(z->vem, f); PUTSH(z->ver, f); PUTSH(z->flg, f); PUTSH(z->how, f); PUTLG(z->tim, f); PUTLG(z->crc, f); PUTLG(z->siz, f); PUTLG(z->len, f); PUTSH(z->nam, f); PUTSH(z->cext, f); PUTSH(z->com, f); PUTSH(z->dsk, f); PUTSH(z->att, f); PUTLG(z->atx, f); PUTLG(z->off, f); if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam || (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) || (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com)) return ZE_TEMP; return ZE_OK; } int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param) { // write the end of the central-directory-data to file *f. PUTLG(ENDSIG, f); PUTSH(0, f); PUTSH(0, f); PUTSH(n, f); PUTSH(n, f); PUTLG(s, f); PUTLG(c, f); PUTSH(m, f); // Write the comment, if any if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP; return ZE_OK; } const ulg crc_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; #define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) #define DO1(buf) crc = CRC32(crc, *buf++) #define DO2(buf) DO1(buf); DO1(buf) #define DO4(buf) DO2(buf); DO2(buf) #define DO8(buf) DO4(buf); DO4(buf) ulg crc32(ulg crc, const uch *buf, extent len) { if (buf==NULL) return 0L; crc = crc ^ 0xffffffffL; while (len >= 8) {DO8(buf); len -= 8;} if (len) do {DO1(buf);} while (--len); return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines) } void update_keys(unsigned long *keys, char c) { keys[0] = CRC32(keys[0],c); keys[1] += keys[0] & 0xFF; keys[1] = keys[1]*134775813L +1; keys[2] = CRC32(keys[2], keys[1] >> 24); } char decrypt_byte(unsigned long *keys) { unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); } char zencode(unsigned long *keys, char c) { int t=decrypt_byte(keys); update_keys(keys,c); return (char)(t^c); } bool HasZipSuffix(const TCHAR *fn) { const TCHAR *ext = fn+_tcslen(fn); while (ext>fn && *ext!='.') ext--; if (ext==fn && *ext!='.') return false; if (_tcsicmp(ext,_T(".Z"))==0) return true; if (_tcsicmp(ext,_T(".zip"))==0) return true; if (_tcsicmp(ext,_T(".zoo"))==0) return true; if (_tcsicmp(ext,_T(".arc"))==0) return true; if (_tcsicmp(ext,_T(".lzh"))==0) return true; if (_tcsicmp(ext,_T(".arj"))==0) return true; if (_tcsicmp(ext,_T(".gz"))==0) return true; if (_tcsicmp(ext,_T(".tgz"))==0) return true; return false; } lutime_t filetime2timet(const FILETIME ft) { __int64 i = *(__int64*)&ft; return (lutime_t)((i-116444736000000000LL)/10000000); } void filetime2dosdatetime(const FILETIME ft, WORD *dosdate,WORD *dostime) { // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 SYSTEMTIME st; FileTimeToSystemTime(&ft,&st); *dosdate = (WORD)(((st.wYear-1980)&0x7f) << 9); *dosdate |= (WORD)((st.wMonth&0xf) << 5); *dosdate |= (WORD)((st.wDay&0x1f)); *dostime = (WORD)((st.wHour&0x1f) << 11); *dostime |= (WORD)((st.wMinute&0x3f) << 5); *dostime |= (WORD)((st.wSecond*2)&0x1f); } ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp) { // The handle must be a handle to a file // The date and time is returned in a long with the date most significant to allow // unsigned integer comparison of absolute times. The attributes have two // high bytes unix attr, and two low bytes a mapping of that to DOS attr. //struct stat s; int res=stat(fn,&s); if (res!=0) return false; // translate windows file attributes into zip ones. BY_HANDLE_FILE_INFORMATION bhi; BOOL res=GetFileInformationByHandle(hf,&bhi); if (!res) return ZR_NOFILE; DWORD fa=bhi.dwFileAttributes; ulg a=0; // Zip uses the lower word for its interpretation of windows stuff if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01; if (fa&FILE_ATTRIBUTE_HIDDEN) a|=0x02; if (fa&FILE_ATTRIBUTE_SYSTEM) a|=0x04; if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10; if (fa&FILE_ATTRIBUTE_ARCHIVE) a|=0x20; // It uses the upper word for standard unix attr, which we manually construct if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000; // directory else a|=0x80000000; // normal file a|=0x01000000; // readable if (fa&FILE_ATTRIBUTE_READONLY) {} else a|=0x00800000; // writeable // now just a small heuristic to check if it's an executable: DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40) { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL); SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos; ReadFile(hf,&hpos,sizeof(hpos),&red,NULL); if (magic==0x54AD && hsize>hpos+4+20+28) { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL); if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE) { a |= 0x00400000; // executable } } } // if (attr!=NULL) *attr = a; if (size!=NULL) *size = hsize; if (times!=NULL) { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970. // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601 times->atime = filetime2timet(bhi.ftLastAccessTime); times->mtime = filetime2timet(bhi.ftLastWriteTime); times->ctime = filetime2timet(bhi.ftCreationTime); } if (timestamp!=NULL) { WORD dosdate,dostime; filetime2dosdatetime(bhi.ftLastWriteTime,&dosdate,&dostime); *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); } return ZR_OK; } class TZip { public: TZip(const char *pwd) : hfout(0),mustclosehfout(false),hmapout(0),zfis(0),obuf(0),hfin(0),writ(0),oerr(false),hasputcen(false),ooffset(0),encwriting(false),encbuf(0),password(0), state(0) {if (pwd!=0 && *pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} ~TZip() {if (state!=0) delete state; state=0; if (encbuf!=0) delete[] encbuf; encbuf=0; if (password!=0) delete[] password; password=0;} // These variables say about the file we're writing into // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile char *password; // keep a copy of the password HANDLE hfout; // if valid, we'll write here (for files or pipes) bool mustclosehfout; // if true, we are responsible for closing hfout HANDLE hmapout; // otherwise, we'll write here (for memmap) unsigned ooffset; // for hfout, this is where the pointer was initially ZRESULT oerr; // did a write operation give rise to an error? unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks bool ocanseek; // can we seek? char *obuf; // this is where we've locked mmap to view. unsigned int opos; // current pos in the mmap unsigned int mapsize; // the size of the map we created bool hasputcen; // have we yet placed the central directory? bool encwriting; // if true, then we'll encrypt stuff using 'keys' before we write it to disk unsigned long keys[3]; // keys are initialised inside Add() char *encbuf; // if encrypting, then this is a temporary workspace for encrypting the data unsigned int encbufsize; // (to be used and resized inside write(), and deleted in the destructor) // TZipFileInfo *zfis; // each file gets added onto this list, for writing the table at the end TState *state; // we use just one state object per zip, because it's big (500k) ZRESULT Create(void *z,unsigned int len,DWORD flags); static unsigned sflush(void *param,const char *buf, unsigned *size); static unsigned swrite(void *param,const char *buf, unsigned size); unsigned int write(const char *buf,unsigned int size); bool oseek(unsigned int pos); ZRESULT GetMemory(void **pbuf, unsigned long *plen); ZRESULT Close(); // some variables to do with the file currently being read: // I haven't done it object-orientedly here, just put them all // together, since OO didn't seem to make the design any clearer. ulg attr; iztimes times; ulg timestamp; // all open_* methods set these bool iseekable; long isize,ired; // size is not set until close() on pips ulg crc; // crc is not set until close(). iwrit is cumulative HANDLE hfin; bool selfclosehf; // for input files and pipes const char *bufin; unsigned int lenin,posin; // for memory // and a variable for what we've done with the input: (i.e. compressed it!) ulg csize; // compressed size, set by the compression routines // and this is used by some of the compression routines char buf[16384]; ZRESULT open_file(const TCHAR *fn); ZRESULT open_handle(HANDLE hf,unsigned int len); ZRESULT open_mem(void *src,unsigned int len); ZRESULT open_dir(); static unsigned sread(TState &s,char *buf,unsigned size); unsigned read(char *buf, unsigned size); ZRESULT iclose(); ZRESULT ideflate(TZipFileInfo *zfi); ZRESULT istore(); ZRESULT Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags); ZRESULT AddCentral(); }; ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags) { if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) return ZR_NOTINITED; // if (flags==ZIP_HANDLE) { HANDLE hf = (HANDLE)z; hfout=hf; mustclosehfout=false; #ifdef DuplicateHandle BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS); if (res) mustclosehandle=true; #endif // now we have hfout. Either we duplicated the handle and we close it ourselves // (while the caller closes h themselves), or we couldn't duplicate it. DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT); ocanseek = (res!=0xFFFFFFFF); if (ocanseek) ooffset=res; else ooffset=0; return ZR_OK; } else if (flags==ZIP_FILENAME) { const TCHAR *fn = (const TCHAR*)z; hfout = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (hfout==INVALID_HANDLE_VALUE) {hfout=0; return ZR_NOFILE;} ocanseek=true; ooffset=0; mustclosehfout=true; return ZR_OK; } else if (flags==ZIP_MEMORY) { unsigned int size = len; if (size==0) return ZR_MEMSIZE; if (z!=0) obuf=(char*)z; else { hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,NULL); if (hmapout==NULL) return ZR_NOALLOC; obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,size); if (obuf==0) {CloseHandle(hmapout); hmapout=0; return ZR_NOALLOC;} } ocanseek=true; opos=0; mapsize=size; return ZR_OK; } else return ZR_ARGS; } unsigned TZip::sflush(void *param,const char *buf, unsigned *size) { // static if (*size==0) return 0; TZip *zip = (TZip*)param; unsigned int writ = zip->write(buf,*size); if (writ!=0) *size=0; return writ; } unsigned TZip::swrite(void *param,const char *buf, unsigned size) { // static if (size==0) return 0; TZip *zip=(TZip*)param; return zip->write(buf,size); } unsigned int TZip::write(const char *buf,unsigned int size) { const char *srcbuf=buf; if (encwriting) { if (encbuf!=0 && encbufsize=mapsize) {oerr=ZR_MEMSIZE; return 0;} memcpy(obuf+opos, srcbuf, size); opos+=size; return size; } else if (hfout!=0) { DWORD writ; WriteFile(hfout,srcbuf,size,&writ,NULL); return writ; } oerr=ZR_NOTINITED; return 0; } bool TZip::oseek(unsigned int pos) { if (!ocanseek) {oerr=ZR_SEEK; return false;} if (obuf!=0) { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;} opos=pos; return true; } else if (hfout!=0) { SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN); return true; } oerr=ZR_NOTINITED; return 0; } ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen) { // When the user calls GetMemory, they're presumably at the end // of all their adding. In any case, we have to add the central // directory now, otherwise the memory we tell them won't be complete. if (!hasputcen) AddCentral(); hasputcen=true; if (pbuf!=NULL) *pbuf=(void*)obuf; if (plen!=NULL) *plen=writ; if (obuf==NULL) return ZR_NOTMMAP; return ZR_OK; } ZRESULT TZip::Close() { // if the directory hadn't already been added through a call to GetMemory, // then we do it now ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true; if (obuf!=0 && hmapout!=0) UnmapViewOfFile(obuf); obuf=0; if (hmapout!=0) CloseHandle(hmapout); hmapout=0; if (hfout!=0 && mustclosehfout) CloseHandle(hfout); hfout=0; mustclosehfout=false; return res; } ZRESULT TZip::open_file(const TCHAR *fn) { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; if (fn==0) return ZR_ARGS; HANDLE hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE; ZRESULT res = open_handle(hf,0); if (res!=ZR_OK) {CloseHandle(hf); return res;} selfclosehf=true; return ZR_OK; } ZRESULT TZip::open_handle(HANDLE hf,unsigned int len) { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS; DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT); if (res!=0xFFFFFFFF) { ZRESULT res = GetFileInfo(hf,&attr,&isize,×,×tamp); if (res!=ZR_OK) return res; SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up iseekable=true; hfin=hf; return ZR_OK; } else { attr= 0x80000000; // just a normal file isize = -1; // can't know size until at the end if (len!=0) isize=len; // unless we were told explicitly! iseekable=false; SYSTEMTIME st; GetLocalTime(&st); FILETIME ft; SystemTimeToFileTime(&st,&ft); WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); times.atime = filetime2timet(ft); times.mtime = times.atime; times.ctime = times.atime; timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); hfin=hf; return ZR_OK; } } ZRESULT TZip::open_mem(void *src,unsigned int len) { hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0; lenin=len; posin=0; if (src==0 || len==0) return ZR_ARGS; attr= 0x80000000; // just a normal file isize = len; iseekable=true; SYSTEMTIME st; GetLocalTime(&st); FILETIME ft; SystemTimeToFileTime(&st,&ft); WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); times.atime = filetime2timet(ft); times.mtime = times.atime; times.ctime = times.atime; timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); return ZR_OK; } ZRESULT TZip::open_dir() { hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; attr= 0x41C00010; // a readable writable directory, and again directory isize = 0; iseekable=false; SYSTEMTIME st; GetLocalTime(&st); FILETIME ft; SystemTimeToFileTime(&st,&ft); WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); times.atime = filetime2timet(ft); times.mtime = times.atime; times.ctime = times.atime; timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); return ZR_OK; } unsigned TZip::sread(TState &s,char *buf,unsigned size) { // static TZip *zip = (TZip*)s.param; return zip->read(buf,size); } unsigned TZip::read(char *buf, unsigned size) { if (bufin!=0) { if (posin>=lenin) return 0; // end of input ulg red = lenin-posin; if (red>size) red=size; memcpy(buf, bufin+posin, red); posin += red; ired += red; crc = crc32(crc, (uch*)buf, red); return red; } else if (hfin!=0) { DWORD red; BOOL ok = ReadFile(hfin,buf,size,&red,NULL); if (!ok) return 0; ired += red; crc = crc32(crc, (uch*)buf, red); return red; } else {oerr=ZR_NOTINITED; return 0;} } ZRESULT TZip::iclose() { if (selfclosehf && hfin!=0) CloseHandle(hfin); hfin=0; bool mismatch = (isize!=-1 && isize!=ired); isize=ired; // and crc has been being updated anyway if (mismatch) return ZR_MISSIZE; else return ZR_OK; } ZRESULT TZip::ideflate(TZipFileInfo *zfi) { if (state==0) state=new TState(); // It's a very big object! 500k! We allocate it on the heap, because PocketPC's // stack breaks if we try to put it all on the stack. It will be deleted lazily state->err=0; state->readfunc=sread; state->flush_outbuf=sflush; state->param=this; state->level=8; state->seekable=iseekable; state->err=NULL; // the following line will make ct_init realise it has to perform the init state->ts.static_dtree[0].dl.len = 0; // Thanks to Alvin77 for this crucial fix: state->ds.window_size=0; // I think that covers everything that needs to be initted. // bi_init(*state,buf, sizeof(buf), TRUE); // it used to be just 1024-size, not 16384 as here ct_init(*state,&zfi->att); lm_init(*state,state->level, &zfi->flg); ulg sz = deflate(*state); csize=sz; ZRESULT r=ZR_OK; if (state->err!=NULL) r=ZR_FLATE; return r; } ZRESULT TZip::istore() { ulg size=0; for (;;) { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break; unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE; size += cin; } csize=size; return ZR_OK; } bool has_seeded=false; ZRESULT TZip::Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags) { if (oerr) return ZR_FAILED; if (hasputcen) return ZR_ENDED; // if we use password encryption, then every isize and csize is 12 bytes bigger int passex=0; if (password!=0 && flags!=ZIP_FOLDER) passex=12; // zip has its own notion of what its names should look like: i.e. dir/file.stuff TCHAR dstzn[MAX_PATH]; _tcscpy(dstzn,odstzn); if (*dstzn==0) return ZR_ARGS; TCHAR *d=dstzn; while (*d!=0) {if (*d=='\\') *d='/'; d++;} bool isdir = (flags==ZIP_FOLDER); bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn)-1]!='/'); int method=DEFLATE; if (isdir || HasZipSuffix(dstzn)) method=STORE; // now open whatever was our input source: ZRESULT openres; if (flags==ZIP_FILENAME) openres=open_file((const TCHAR*)src); else if (flags==ZIP_HANDLE) openres=open_handle((HANDLE)src,len); else if (flags==ZIP_MEMORY) openres=open_mem(src,len); else if (flags==ZIP_FOLDER) openres=open_dir(); else return ZR_ARGS; if (openres!=ZR_OK) return openres; // A zip "entry" consists of a local header (which includes the file name), // then the compressed data, and possibly an extended local header. // Initialize the local header TZipFileInfo zfi; zfi.nxt=NULL; strcpy(zfi.name,""); #ifdef UNICODE WideCharToMultiByte(CP_UTF8,0,dstzn,-1,zfi.iname,MAX_PATH,0,0); #else strcpy(zfi.iname,dstzn); #endif zfi.nam=strlen(zfi.iname); if (needs_trailing_slash) {strcat(zfi.iname,"/"); zfi.nam++;} strcpy(zfi.zname,""); zfi.extra=NULL; zfi.ext=0; // extra header to go after this compressed data, and its length zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length zfi.comment=NULL; zfi.com=0; // comment, and its length zfi.mark = 1; zfi.dosflag = 0; zfi.att = (ush)BINARY; zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3 zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it zfi.tim = timestamp; // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. zfi.crc = 0; // to be updated later zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it. if (password!=0 && !isdir) zfi.flg=9; // and 1 means 'password-encrypted' zfi.lflg = zfi.flg; // to be updated later zfi.how = (ush)method; // to be updated later zfi.siz = (ulg)(method==STORE && isize>=0 ? isize+passex : 0); // to be updated later zfi.len = (ulg)(isize); // to be updated later zfi.dsk = 0; zfi.atx = attr; zfi.off = writ+ooffset; // offset within file of the start of this local record // stuff the 'times' structure into zfi.extra // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up. char xloc[EB_L_UT_SIZE]; zfi.extra=xloc; zfi.ext=EB_L_UT_SIZE; char xcen[EB_C_UT_SIZE]; zfi.cextra=xcen; zfi.cext=EB_C_UT_SIZE; xloc[0] = 'U'; xloc[1] = 'T'; xloc[2] = EB_UT_LEN(3); // length of data part of e.f. xloc[3] = 0; xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME; xloc[5] = (char)(times.mtime); xloc[6] = (char)(times.mtime >> 8); xloc[7] = (char)(times.mtime >> 16); xloc[8] = (char)(times.mtime >> 24); xloc[9] = (char)(times.atime); xloc[10] = (char)(times.atime >> 8); xloc[11] = (char)(times.atime >> 16); xloc[12] = (char)(times.atime >> 24); xloc[13] = (char)(times.ctime); xloc[14] = (char)(times.ctime >> 8); xloc[15] = (char)(times.ctime >> 16); xloc[16] = (char)(times.ctime >> 24); memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE); zfi.cextra[EB_LEN] = EB_UT_LEN(1); // (1) Start by writing the local header: int r = putlocal(&zfi,swrite,this); if (r!=ZE_OK) {iclose(); return ZR_WRITE;} writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext; if (oerr!=ZR_OK) {iclose(); return oerr;} // (1.5) if necessary, write the encryption header keys[0]=305419896L; keys[1]=591751049L; keys[2]=878082192L; for (const char *cp=password; cp!=0 && *cp!=0; cp++) update_keys(keys,*cp); // generate some random bytes if (!has_seeded) srand(GetTickCount()^(unsigned long)GetDesktopWindow()); char encbuf[12]; for (int i=0; i<12; i++) encbuf[i]=(char)((rand()>>7)&0xff); encbuf[11] = (char)((zfi.tim>>8)&0xff); for (int ei=0; ei<12; ei++) encbuf[ei]=zencode(keys,encbuf[ei]); if (password!=0 && !isdir) {swrite(this,encbuf,12); writ+=12;} //(2) Write deflated/stored file to zip file ZRESULT writeres=ZR_OK; encwriting = (password!=0 && !isdir); // an object member variable to say whether we write to disk encrypted if (!isdir && method==DEFLATE) writeres=ideflate(&zfi); else if (!isdir && method==STORE) writeres=istore(); else if (isdir) csize=0; encwriting = false; iclose(); writ += csize; if (oerr!=ZR_OK) return oerr; if (writeres!=ZR_OK) return ZR_WRITE; // (3) Either rewrite the local header with correct information... bool first_header_has_size_right = (zfi.siz==csize+passex); zfi.crc = crc; zfi.siz = csize+passex; zfi.len = isize; if (ocanseek && (password==0 || isdir)) { zfi.how = (ush)method; if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag zfi.lflg = zfi.flg; // rewrite the local header: if (!oseek(zfi.off-ooffset)) return ZR_SEEK; if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; if (!oseek(writ)) return ZR_SEEK; } else { // (4) ... or put an updated header at the end if (zfi.how != (ush) method) return ZR_NOCHANGE; if (method==STORE && !first_header_has_size_right) return ZR_NOCHANGE; if ((r = putextended(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; writ += 16L; zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index } if (oerr!=ZR_OK) return oerr; // Keep a copy of the zipfileinfo, for our end-of-zip directory char *cextra = new char[zfi.cext]; memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra; TZipFileInfo *pzfi = new TZipFileInfo; memcpy(pzfi,&zfi,sizeof(zfi)); if (zfis==NULL) zfis=pzfi; else {TZipFileInfo *z=zfis; while (z->nxt!=NULL) z=z->nxt; z->nxt=pzfi;} return ZR_OK; } ZRESULT TZip::AddCentral() { // write central directory int numentries = 0; ulg pos_at_start_of_central = writ; //ulg tot_unc_size=0, tot_compressed_size=0; bool okay=true; for (TZipFileInfo *zfi=zfis; zfi!=NULL; ) { if (okay) { int res = putcentral(zfi, swrite,this); if (res!=ZE_OK) okay=false; } writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com; //tot_unc_size += zfi->len; //tot_compressed_size += zfi->siz; numentries++; // TZipFileInfo *zfinext = zfi->nxt; if (zfi->cextra!=0) delete[] zfi->cextra; delete zfi; zfi = zfinext; } ulg center_size = writ - pos_at_start_of_central; if (okay) { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this); if (res!=ZE_OK) okay=false; writ += 4 + ENDHEAD + 0; } if (!okay) return ZR_WRITE; return ZR_OK; } ZRESULT lasterrorZ=ZR_OK; unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len) { if (code==ZR_RECENT) code=lasterrorZ; const char *msg="unknown zip result code"; switch (code) { case ZR_OK: msg="Success"; break; case ZR_NODUPH: msg="Culdn't duplicate handle"; break; case ZR_NOFILE: msg="Couldn't create/open file"; break; case ZR_NOALLOC: msg="Failed to allocate memory"; break; case ZR_WRITE: msg="Error writing to file"; break; case ZR_NOTFOUND: msg="File not found in the zipfile"; break; case ZR_MORE: msg="Still more data to unzip"; break; case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break; case ZR_READ: msg="Error reading file"; break; case ZR_ARGS: msg="Caller: faulty arguments"; break; case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break; case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break; case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break; case ZR_FAILED: msg="Caller: there was a previous error"; break; case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break; case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break; case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break; case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break; case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break; case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break; case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break; } unsigned int mlen=(unsigned int)strlen(msg); if (buf==0 || len==0) return mlen; unsigned int n=mlen; if (n+1>len) n=len-1; strncpy(buf,msg,n); buf[n]=0; return mlen; } typedef struct { DWORD flag; TZip *zip; } TZipHandleData; HZIP CreateZipInternal(void *z,unsigned int len,DWORD flags, const char *password) { TZip *zip = new TZip(password); lasterrorZ = zip->Create(z,len,flags); if (lasterrorZ!=ZR_OK) {delete zip; return 0;} TZipHandleData *han = new TZipHandleData; han->flag=2; han->zip=zip; return (HZIP)han; } HZIP CreateZipHandle(HANDLE h, const char *password) {return CreateZipInternal(h,0,ZIP_HANDLE,password);} HZIP CreateZip(const TCHAR *fn, const char *password) {return CreateZipInternal((void*)fn,0,ZIP_FILENAME,password);} HZIP CreateZip(void *z,unsigned int len, const char *password) {return CreateZipInternal(z,len,ZIP_MEMORY,password);} ZRESULT ZipAddInternal(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len, DWORD flags) { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} TZipHandleData *han = (TZipHandleData*)hz; if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} TZip *zip = han->zip; lasterrorZ = zip->Add(dstzn,src,len,flags); return lasterrorZ; } ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn) {return ZipAddInternal(hz,dstzn,(void*)fn,0,ZIP_FILENAME);} ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len) {return ZipAddInternal(hz,dstzn,src,len,ZIP_MEMORY);} ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h) {return ZipAddInternal(hz,dstzn,h,0,ZIP_HANDLE);} ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len) {return ZipAddInternal(hz,dstzn,h,len,ZIP_HANDLE);} ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn) {return ZipAddInternal(hz,dstzn,0,0,ZIP_FOLDER);} ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len) { if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;} TZipHandleData *han = (TZipHandleData*)hz; if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} TZip *zip = han->zip; lasterrorZ = zip->GetMemory(buf,len); return lasterrorZ; } ZRESULT CloseZipZ(HZIP hz) { if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} TZipHandleData *han = (TZipHandleData*)hz; if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} TZip *zip = han->zip; lasterrorZ = zip->Close(); delete zip; delete han; return lasterrorZ; } bool IsZipHandleZ(HZIP hz) { if (hz==0) return false; TZipHandleData *han = (TZipHandleData*)hz; return (han->flag==2); } #endif //WIN32 repsnapper-2.3.2a5/libraries/clipper/000077500000000000000000000000001231531733200175355ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/clipper/Makefile.am000066400000000000000000000005021231531733200215660ustar00rootroot00000000000000noinst_LTLIBRARIES += libclipper.la libclipper_la_CPPFLAGS = \ -I$(srcdir) \ -I$(top_srcdir)/libraries/clipper/clipper/polyclipping-code/cpp/ \ $(EXTRA_CFLAGS) libclipper_la_SOURCES = \ libraries/clipper/clipper/polyclipping-code/cpp/clipper.cpp \ libraries/clipper/clipper/polyclipping-code/cpp/clipper.hpp repsnapper-2.3.2a5/libraries/clipper/clipper/000077500000000000000000000000001231531733200211735ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/000077500000000000000000000000001231531733200246145ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/License.txt000066400000000000000000000030621231531733200267400ustar00rootroot00000000000000The Clipper Library (including Delphi, C++ & C# source code, other accompanying code, examples and documentation), hereafter called "the Software", has been released under the following license, terms and conditions: Boost Software License - Version 1.0 - August 17th, 2003 http://www.boost.org/LICENSE_1_0.txt Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the Software covered by this license to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/README000066400000000000000000000332211231531733200254750ustar00rootroot00000000000000============================================================ Clipper Change Log ============================================================ v6.0.0 (30 October 2013) * Added: Open path (polyline) clipping. A new 'Curves' demo application showcases this (see the 'Curves' directory). * Update: Major improvement in the merging of shared/collinear edges in clip solutions (see Execute). * Added: The IntPoint structure now has an optional 'Z' member. (See the precompiler directive use_xyz.) * Added: Users can now force Clipper to use 32bit integers (via the precompiler directive use_int32) instead of using 64bit integers. * Modified: To accommodate open paths, the Polygon and Polygons structures have been renamed Path and Paths respectively. The AddPolygon and AddPolygons methods of the ClipperBase class have been renamed AddPath and AddPaths respectively. Several other functions have been similarly renamed. * Modified: The PolyNode Class has a new IsOpen property. * Modified: The Clipper class has a new ZFillFunction property. * Added: MinkowskiSum and MinkowskiDiff functions added. * Added: Several other new functions have been added including PolyTreeToPaths, OpenPathsFromPolyTree and ClosedPathsFromPolyTree. * Added: The Clipper constructor now accepts an optional InitOptions parameter to simplify setting properties. * Bugfixes: Numerous minor bugs have been fixed. * Deprecated: Version 6 is a major upgrade from previous versions and quite a number of changes have been made to exposed structures and functions. To minimize inconvenience to existing library users, some code has been retained and some added to maintain backward compatibility. However, because this code will be removed in a future update, it has been marked as deprecated and a precompiler directive use_deprecated has been defined. v5.1.6 (23 May 2013) * BugFix: CleanPolygon function was buggy. * Changed: The behaviour of the 'miter' JoinType has been changed so that when squaring occurs, it's no longer extended up to the miter limit but is squared off at exactly 'delta' units. (This improves the look of mitering with larger limits at acute angles.) * Added: New OffsetPolyLines function * Update: Minor code refactoring and optimisations v5.1.5 (5 May 2013) * Added: ForceSimple property to Clipper class * Update: Improved documentation v5.1.4 (24 March 2013) * Update: CleanPolygon function enhanced. * Update: Documentation improved. v5.1.3 (14 March 2013) * Bugfix: Minor bugfixes. * Update: Documentation significantly improved. v5.1.2 (26 February 2013) * Bugfix: PolyNode class was missing a constructor. * Update: The MiterLimit parameter in the OffsetPolygons function has been renamed Limit and can now also be used to limit the number of vertices used to construct arcs when JoinType is set to jtRound. v5.1.0 (17 February 2013) * Update: ExPolygons has been replaced with the PolyTree & PolyNode classes to more fully represent the parent-child relationships of the polygons returned by Clipper. * Added: New CleanPolygon and CleanPolygons functions. * Bugfix: Another orientation bug fixed. v5.0.2 - 30 December 2012 * Bugfix: Significant fixes in and tidy of the internal Int128 class (which is used only when polygon coordinate values are greater than 0x3FFFFFFF (~1.07e9)). * Update: The Area algorithm has been updated and is faster. * Update: Documentation updates. The newish but undocumented 'CheckInputs' parameter of the OffsetPolygons function has been renamed 'AutoFix' and documented too. The comments on rounding have also been improved (ie clearer and expanded). v4.10.0 - 25 December 2012 * Bugfix: Orientation bugs should now be resolved (finally!). * Bugfix: Bug in Int128 class v4.9.8 - 2 December 2012 * Bugfix: Further fixes to rare Orientation bug. v4.9.7 - 29 November 2012 * Bugfix: Bug that very rarely returned the wrong polygon orientation. * Bugfix: Obscure bug affecting OffsetPolygons when using jtRound for the JoinType parameter and when polygons also contain very large coordinate values (> +/-100000000000). v4.9.6 - 9 November 2012 * Bugfix: Another obscure bug related to joining polygons. v4.9.4 - 2 November 2012 * Bugfix: Bugs in Int128 class occasionally causing wrong orientations. * Bugfix: Further fixes related to joining polygons. v4.9.0 - 9 October 2012 * Bugfix: Obscure bug related to joining polygons. v4.8.9 - 25 September 2012 * Bugfix: Obscure bug related to precision of intersections. v4.8.8 - 30 August 2012 * Bugfix: Fixed bug in OffsetPolygons function introduced in version 4.8.5. v4.8.7 - 24 August 2012 * Bugfix: ReversePolygon function in C++ translation was broken. * Bugfix: Two obscure bugs affecting orientation fixed too. v4.8.6 - 11 August 2012 * Bugfix: Potential for memory overflow errors when using ExPolygons structure. * Bugfix: The polygon coordinate range has been reduced to +/- 0x3FFFFFFFFFFFFFFF (4.6e18). * Update: ReversePolygons function was misnamed ReversePoints in C++. * Update: SimplifyPolygon function now takes a PolyFillType parameter. v4.8.5 - 15 July 2012 * Bugfix: Potential for memory overflow errors in OffsetPolygons(). v4.8.4 - 1 June 2012 * Bugfix: Another obscure bug affecting ExPolygons structure. v4.8.3 - 27 May 2012 * Bugfix: Obscure bug causing incorrect removal of a vertex. v4.8.2 - 21 May 2012 * Bugfix: Obscure bug could cause an exception when using ExPolygon structure. v4.8.1 - 12 May 2012 * Update: Cody tidy and minor bug fixes. v4.8.0 - 30 April 2012 * Bugfix: Occasional errors in orientation fixed. * Update: Added notes on rounding to the documentation. v4.7.6 - 11 April 2012 * Fixed a bug in Orientation function (affecting C# translations only). * Minor documentation update. v4.7.5 - 28 March 2012 * Bugfix: Fixed a recently introduced bug that occasionally caused an unhandled exception in C++ and C# translations. v4.7.4 - 15 March 2012 * Bugfix: Another minor bugfix. v4.7.2 - 4 March 2012 * Bugfix: Fixed bug introduced in ver 4.7 which sometimes caused an exception if ExPolygon structure was passed to Clipper's Execute method. v4.7.1 - 3 March 2012 * Bugfix: Rare crash when JoinCommonEdges joined polygons that 'cancelled' each other. * Bugfix: Clipper's internal Orientation method occasionally returned wrong result. * Update: Improved C# code (thanks to numerous excellent suggestions from David Piepgrass) v4.7 - 10 February 2012 * Improved the joining of output polygons sharing a common edge. v4.6.6 - 3 February 2012 * Bugfix: Another obscure bug occasionally causing incorrect polygon orientation. v4.6.5 - 17 January 2012 * Bugfix: Obscure bug occasionally causing incorrect hole assignment in ExPolygon structure. v4.6.4 - 8 November 2011 * Added: SimplifyPolygon and SimplifyPolygons functions. v4.6.3 - 11 November 2011 * Bugfix: Fixed another minor mitering bug in OffsetPolygons. v4.6.2 - 10 November 2011 * Bugfix: Fixed a rare bug in the orientation of polygons returned by Clipper's Execute() method. * Bugfix: Previous update introduced a mitering bug in the OffsetPolygons function. v4.6 - 29 October 2011 * Added: Support for Positive and Negative polygon fill types (in addition to the EvenOdd and NonZero fill types). * Bugfix: The OffsetPolygons function was generating the occasional artefact when 'shrinking' polygons. v4.5.5 - 8 October 2011 * Bugfix: Fixed an obscure bug in Clipper's JoinCommonEdges method. * Update: Replaced IsClockwise function with Orientation function. The orientation issues affecting OffsetPolygons should now be finally resolved. * Change: The Area function once again returns a signed value. v4.5.1 - 28 September 2011 * Deleted: The UseFullCoordinateRange property has been deleted since integer range is now managed implicitly. * BugFix: Minor bug in OffsetPolygon mitering. * Change: C# JoinType enum moved from Clipper class to ClipperLib namespace. * Change: The Area function now returns the absolute area (irrespective of orientation). * Change: The IsClockwise function now requires a second parameter - YAxisPositiveUpward - to accommodate displays with Y-axis oriented in either direction v4.4.4 - 10 September 2011 * Change: Deleted jtButt from JoinType (used by the OffsetPolygons function). * BugFix: Fixed another minor bug in OffsetPolygons function. * Update: Further improvements to the help file v4.4.3 - 29 August 2011 * BugFix: fixed a minor rounding issue in OffsetPolygons function (affected C++ & C# translations). * BugFix: fixed a minor bug in OffsetPolygons' function declaration (affected C++ translation only). * Change: 'clipper' namespace changed to 'ClipperLib' namespace in both C++ and C# code to remove the ambiguity between the Clipper class and the namespace. (This also required numerous updates to the accompanying demos.) v4.4.2 - 26 August 2011 * BugFix: minor bugfixes in Clipper. * Update: the OffsetPolygons function has been significantly improved by offering 4 different join styles. v4.4.0 - 6 August 2011 * BugFix: A number of minor bugs have been fixed that mostly affected the new ExPolygons structure. v4.3.0 - 17 June 2011 * New: ExPolygons structure that explicitly associates 'hole' polygons with their 'outer' container polygons. * New: Execute method overloaded so the solution parameter can now be either Polygons or ExPolygons. * BugFix: Fixed a rare bug in solution polygons orientation. v4.2.8 - 21 May 2011 * Update: JoinCommonEdges() improved once more. * BugFix: Several minor bugs fixed. v4.2.6 - 1 May 2011 * Bugfix: minor bug in SlopesEqual function. * Update: Merging of output polygons sharing common edges has been significantly inproved v4.2.4 - 26 April 2011 Input polygon coordinates can now contain the full range of signed 64bit integers (ie +/-9,223,372,036,854,775,807). This means that floating point values can be converted to and from Clipper's 64bit integer coordinates structure (IntPoint) and still retain a precision of up to 18 decimal places. However, since the large-integer math that supports this expanded range imposes a small cost on performance (~15%), a new property UseFullCoordinateRange has been added to the Clipper class to allow users the choice of whether or not to use this expanded coordinate range. If this property is disabled, coordinate values are restricted to +/-1,500,000,000. v4.2 - 12 April 2011 JoinCommonEdges() code significantly improved plus other minor improvements. v4.1.2 - 9 April 2011 * Update: Minor code tidy. * Bugfix: Possible endless loop in JoinCommonEdges() in clipper.pas. v4.1.1 - 8 April 2011 * Update: All polygon coordinates are now stored as 64bit integers (though they're still restricted to range -1.5e9 to +1.5e9 pending the inclusion of code supporting 64bit math). * Change: AddPolygon and AddPolygons methods now return boolean values. * Bugfix: Bug in JoinCommonEdges() caused potential endless loop. * Bugfix: Bug in IsClockwise(). (C++ code only) v4.0 - 5 April 2011 * Clipper 4 is a major rewrite of earlier versions. The biggest change is that floating point values are no longer used, except for the storing of edge slope values. The main benefit of this is the issue of numerical robustness has been addressed. Due to other major code improvements Clipper v4 is approximately 40% faster than Clipper v3. * The AddPolyPolygon method has been renamed to AddPolygons. * The IgnoreOrientation property has been removed. * The clipper_misc library has been merged back into the main clipper library. v3.1.0 - 17 February 2011 * Bugfix: Obscure bug in TClipperBase.SetDx method that caused problems with very small edges ( edges <1/1000th pixel in size). v3.0.3 - 9 February 2011 * Bugfix: Significant bug, but only in C# code. * Update: Minor refactoring. v3.0 - 31 January 2011 * Update: Major rewrite of the portion of code that calculates the output polygons' orientation. * Update: Help file significantly improved. * Change: Renamed ForceOrientation property to IgnoreOrientation. If the orientation of output polygons is not important, or can be managed separately, clipping routines can be sped up by about 60% by setting IgnoreOrientation to true. Defaults to false. * Change: The OffsetPolygon and Area functions have been moved to the new unit - clipper_misc. 2.99 - 15 January 2011 * Bugfix: Obscure bug in AddPolygon method could cause an endless loop. 2.8 - 20 November 2010 * Updated: Output polygons which previously shared a common edge are now merged. * Changed: The orientation of outer polygons is now clockwise when the display's Y axis is positive downwards (as is typical for most Windows applications). Inner polygons (holes) have the opposite orientation. * Added: Support module for Cairo Graphics Library (with demo). * Updated: C# and C++ demos. 2.522 - 15 October 2010 * Added C# translation (thanks to Olivier Lejeune) and a link to Ruby bindings (thanks to Mike Owens). 2.0 - 30 July 2010 * Clipper now clips using both the Even-Odd (alternate) and Non-Zero (winding) polygon filling rules. (Previously Clipper assumed the Even-Odd rule for polygon filling.) 1.4c - 16 June 2010 * Added C++ support for AGG graphics library 1.2s - 2 June 2010 * Added C++ translation of clipper.pas 1.0 - 9 May 2010repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/cpp/000077500000000000000000000000001231531733200253765ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/cpp/clipper.cpp000066400000000000000000004225641231531733200275550ustar00rootroot00000000000000/******************************************************************************* * * * Author : Angus Johnson * * Version : 6.1.3a * * Date : 22 January 2014 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2014 * * * * License: * * Use, modification & distribution is subject to Boost Software License Ver 1. * * http://www.boost.org/LICENSE_1_0.txt * * * * Attributions: * * The code in this library is an extension of Bala Vatti's clipping algorithm: * * "A generic solution to polygon clipping" * * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * * http://portal.acm.org/citation.cfm?id=129906 * * * * Computer graphics and geometric modeling: implementation and algorithms * * By Max K. Agoston * * Springer; 1 edition (January 4, 2005) * * http://books.google.com/books?q=vatti+clipping+agoston * * * * See also: * * "Polygon Offsetting by Computing Winding Numbers" * * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * * September 24-28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ /******************************************************************************* * * * This is a translation of the Delphi Clipper library and the naming style * * used has retained a Delphi flavour. * * * *******************************************************************************/ #include "clipper.hpp" #include #include #include #include #include #include #include #include namespace ClipperLib { #ifdef use_int32 static cInt const loRange = 46340; static cInt const hiRange = 46340; #else static cInt const loRange = 0x3FFFFFFF; static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; typedef unsigned long long ulong64; #endif static double const pi = 3.141592653589793238; static double const two_pi = pi *2; static double const def_arc_tolerance = 0.25; enum Direction { dRightToLeft, dLeftToRight }; static int const Unassigned = -1; //edge not currently 'owning' a solution static int const Skip = -2; //edge that would otherwise close a path #define HORIZONTAL (-1.0E+40) #define TOLERANCE (1.0e-20) #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) struct TEdge { IntPoint Bot; IntPoint Curr; IntPoint Top; IntPoint Delta; double Dx; PolyType PolyTyp; EdgeSide Side; int WindDelta; //1 or -1 depending on winding direction int WindCnt; int WindCnt2; //winding count of the opposite polytype int OutIdx; TEdge *Next; TEdge *Prev; TEdge *NextInLML; TEdge *NextInAEL; TEdge *PrevInAEL; TEdge *NextInSEL; TEdge *PrevInSEL; }; struct IntersectNode { TEdge *Edge1; TEdge *Edge2; IntPoint Pt; }; struct LocalMinima { cInt Y; TEdge *LeftBound; TEdge *RightBound; LocalMinima *Next; }; struct OutPt; struct OutRec { int Idx; bool IsHole; bool IsOpen; OutRec *FirstLeft; //see comments in clipper.pas PolyNode *PolyNd; OutPt *Pts; OutPt *BottomPt; }; struct OutPt { int Idx; IntPoint Pt; OutPt *Next; OutPt *Prev; }; struct Join { OutPt *OutPt1; OutPt *OutPt2; IntPoint OffPt; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ inline cInt Round(double val) { if ((val < 0)) return static_cast(val - 0.5); else return static_cast(val + 0.5); } //------------------------------------------------------------------------------ inline cInt Abs(cInt val) { return val < 0 ? -val : val; } //------------------------------------------------------------------------------ // PolyTree methods ... //------------------------------------------------------------------------------ void PolyTree::Clear() { for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) delete AllNodes[i]; AllNodes.resize(0); Childs.resize(0); } //------------------------------------------------------------------------------ PolyNode* PolyTree::GetFirst() const { if (!Childs.empty()) return Childs[0]; else return 0; } //------------------------------------------------------------------------------ int PolyTree::Total() const { return (int)AllNodes.size(); } //------------------------------------------------------------------------------ // PolyNode methods ... //------------------------------------------------------------------------------ PolyNode::PolyNode(): Childs(), Parent(0), Index(0), m_IsOpen(false) { } //------------------------------------------------------------------------------ int PolyNode::ChildCount() const { return (int)Childs.size(); } //------------------------------------------------------------------------------ void PolyNode::AddChild(PolyNode& child) { unsigned cnt = (unsigned)Childs.size(); Childs.push_back(&child); child.Parent = this; child.Index = cnt; } //------------------------------------------------------------------------------ PolyNode* PolyNode::GetNext() const { if (!Childs.empty()) return Childs[0]; else return GetNextSiblingUp(); } //------------------------------------------------------------------------------ PolyNode* PolyNode::GetNextSiblingUp() const { if (!Parent) //protects against PolyTree.GetNextSiblingUp() return 0; else if (Index == Parent->Childs.size() - 1) return Parent->GetNextSiblingUp(); else return Parent->Childs[Index + 1]; } //------------------------------------------------------------------------------ bool PolyNode::IsHole() const { bool result = true; PolyNode* node = Parent; while (node) { result = !result; node = node->Parent; } return result; } //------------------------------------------------------------------------------ bool PolyNode::IsOpen() const { return m_IsOpen; } //------------------------------------------------------------------------------ #ifndef use_int32 //------------------------------------------------------------------------------ // Int128 class (enables safe math on signed 64bit integers) // eg Int128 val1((cInt)9223372036854775807); //ie 2^63 -1 // Int128 val2((cInt)9223372036854775807); // Int128 val3 = val1 * val2; // val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) //------------------------------------------------------------------------------ class Int128 { public: cUInt lo; cInt hi; Int128(cInt _lo = 0) { lo = (cUInt)_lo; if (_lo < 0) hi = -1; else hi = 0; } Int128(const Int128 &val): lo(val.lo), hi(val.hi){} Int128(const cInt& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} Int128& operator = (const cInt &val) { lo = (ulong64)val; if (val < 0) hi = -1; else hi = 0; return *this; } bool operator == (const Int128 &val) const {return (hi == val.hi && lo == val.lo);} bool operator != (const Int128 &val) const { return !(*this == val);} bool operator > (const Int128 &val) const { if (hi != val.hi) return hi > val.hi; else return lo > val.lo; } bool operator < (const Int128 &val) const { if (hi != val.hi) return hi < val.hi; else return lo < val.lo; } bool operator >= (const Int128 &val) const { return !(*this < val);} bool operator <= (const Int128 &val) const { return !(*this > val);} Int128& operator += (const Int128 &rhs) { hi += rhs.hi; lo += rhs.lo; if (lo < rhs.lo) hi++; return *this; } Int128 operator + (const Int128 &rhs) const { Int128 result(*this); result+= rhs; return result; } Int128& operator -= (const Int128 &rhs) { *this += -rhs; return *this; } Int128 operator - (const Int128 &rhs) const { Int128 result(*this); result -= rhs; return result; } Int128 operator-() const //unary negation { if (lo == 0) return Int128(-hi,0); else return Int128(~hi,~lo +1); } Int128 operator/ (const Int128 &rhs) const { if (rhs.lo == 0 && rhs.hi == 0) throw "Int128 operator/: divide by zero"; bool negate = (rhs.hi < 0) != (hi < 0); Int128 dividend = *this; Int128 divisor = rhs; if (dividend.hi < 0) dividend = -dividend; if (divisor.hi < 0) divisor = -divisor; if (divisor < dividend) { Int128 result = Int128(0); Int128 cntr = Int128(1); while (divisor.hi >= 0 && !(divisor > dividend)) { divisor.hi <<= 1; if ((cInt)divisor.lo < 0) divisor.hi++; divisor.lo <<= 1; cntr.hi <<= 1; if ((cInt)cntr.lo < 0) cntr.hi++; cntr.lo <<= 1; } divisor.lo >>= 1; if ((divisor.hi & 1) == 1) divisor.lo |= 0x8000000000000000LL; divisor.hi = (ulong64)divisor.hi >> 1; cntr.lo >>= 1; if ((cntr.hi & 1) == 1) cntr.lo |= 0x8000000000000000LL; cntr.hi >>= 1; while (cntr.hi != 0 || cntr.lo != 0) { if (!(dividend < divisor)) { dividend -= divisor; result.hi |= cntr.hi; result.lo |= cntr.lo; } divisor.lo >>= 1; if ((divisor.hi & 1) == 1) divisor.lo |= 0x8000000000000000LL; divisor.hi >>= 1; cntr.lo >>= 1; if ((cntr.hi & 1) == 1) cntr.lo |= 0x8000000000000000LL; cntr.hi >>= 1; } if (negate) result = -result; return result; } else if (rhs.hi == this->hi && rhs.lo == this->lo) return Int128(negate ? -1: 1); else return Int128(0); } double AsDouble() const { const double shift64 = 18446744073709551616.0; //2^64 if (hi < 0) { cUInt lo_ = ~lo + 1; if (lo_ == 0) return (double)hi * shift64; else return -(double)(lo_ + ~hi * shift64); } else return (double)(lo + hi * shift64); } }; //------------------------------------------------------------------------------ Int128 Int128Mul (cInt lhs, cInt rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) lhs = -lhs; ulong64 int1Hi = ulong64(lhs) >> 32; ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); if (rhs < 0) rhs = -rhs; ulong64 int2Hi = ulong64(rhs) >> 32; ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); //nb: see comments in clipper.pas ulong64 a = int1Hi * int2Hi; ulong64 b = int1Lo * int2Lo; ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; Int128 tmp; tmp.hi = cInt(a + (c >> 32)); tmp.lo = cInt(c << 32); tmp.lo += cInt(b); if (tmp.lo < b) tmp.hi++; if (negate) tmp = -tmp; return tmp; }; #endif //------------------------------------------------------------------------------ // Miscellaneous global functions //------------------------------------------------------------------------------ bool Orientation(const Path &poly) { return Area(poly) >= 0; } //------------------------------------------------------------------------------ double Area(const Path &poly) { int size = (int)poly.size(); if (size < 3) return 0; double a = 0; for (int i = 0, j = size -1; i < size; ++i) { a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); j = i; } return -a * 0.5; } //------------------------------------------------------------------------------ double Area(const OutRec &outRec) { OutPt *op = outRec.Pts; if (!op) return 0; double a = 0; do { a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y); op = op->Next; } while (op != outRec.Pts); return a * 0.5; } //------------------------------------------------------------------------------ bool PointIsVertex(const IntPoint &Pt, OutPt *pp) { OutPt *pp2 = pp; do { if (pp2->Pt == Pt) return true; pp2 = pp2->Next; } while (pp2 != pp); return false; } //------------------------------------------------------------------------------ int PointInPolygon (const IntPoint &pt, const Path &path) { //returns 0 if false, +1 if true, -1 if pt ON polygon boundary //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf int result = 0; size_t cnt = path.size(); if (cnt < 3) return 0; IntPoint ip = path[0]; for(size_t i = 1; i <= cnt; ++i) { IntPoint ipNext = (i == cnt ? path[0] : path[i]); if (ipNext.Y == pt.Y) { if ((ipNext.X == pt.X) || (ip.Y == pt.Y && ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; } if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) { if (ip.X >= pt.X) { if (ipNext.X > pt.X) result = 1 - result; else { double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); if (!d) return -1; if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; } } else { if (ipNext.X > pt.X) { double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); if (!d) return -1; if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; } } } ip = ipNext; } return result; } //------------------------------------------------------------------------------ int PointInPolygon (const IntPoint &pt, OutPt *op) { //returns 0 if false, +1 if true, -1 if pt ON polygon boundary //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf int result = 0; OutPt* startOp = op; for(;;) { if (op->Next->Pt.Y == pt.Y) { if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y && ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1; } if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) { if (op->Pt.X >= pt.X) { if (op->Next->Pt.X > pt.X) result = 1 - result; else { double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); if (!d) return -1; if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; } } else { if (op->Next->Pt.X > pt.X) { double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); if (!d) return -1; if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; } } } op = op->Next; if (startOp == op) break; } return result; } //------------------------------------------------------------------------------ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) { OutPt* op = OutPt1; do { int res = PointInPolygon(op->Pt, OutPt2); if (res >= 0) return res != 0; op = op->Next; } while (op != OutPt1); return true; } //---------------------------------------------------------------------- bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) { #ifndef use_int32 if (UseFullInt64Range) return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y); else #endif return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y; } //------------------------------------------------------------------------------ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3, bool UseFullInt64Range) { #ifndef use_int32 if (UseFullInt64Range) return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); else #endif return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); } //------------------------------------------------------------------------------ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) { #ifndef use_int32 if (UseFullInt64Range) return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); else #endif return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); } //------------------------------------------------------------------------------ inline bool IsHorizontal(TEdge &e) { return e.Delta.Y == 0; } //------------------------------------------------------------------------------ inline double GetDx(const IntPoint pt1, const IntPoint pt2) { return (pt1.Y == pt2.Y) ? HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); } //--------------------------------------------------------------------------- inline void SetDx(TEdge &e) { e.Delta.X = (e.Top.X - e.Bot.X); e.Delta.Y = (e.Top.Y - e.Bot.Y); if (e.Delta.Y == 0) e.Dx = HORIZONTAL; else e.Dx = (double)(e.Delta.X) / e.Delta.Y; } //--------------------------------------------------------------------------- inline void SwapSides(TEdge &Edge1, TEdge &Edge2) { EdgeSide Side = Edge1.Side; Edge1.Side = Edge2.Side; Edge2.Side = Side; } //------------------------------------------------------------------------------ inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) { int OutIdx = Edge1.OutIdx; Edge1.OutIdx = Edge2.OutIdx; Edge2.OutIdx = OutIdx; } //------------------------------------------------------------------------------ inline cInt TopX(TEdge &edge, const cInt currentY) { return ( currentY == edge.Top.Y ) ? edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); } //------------------------------------------------------------------------------ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip, bool UseFullInt64Range) { #ifdef use_xyz ip.Z = 0; #endif double b1, b2; //nb: with very large coordinate values, it's possible for SlopesEqual() to //return false but for the edge.Dx value be equal due to double precision rounding. if (SlopesEqual(Edge1, Edge2, UseFullInt64Range) || Edge1.Dx == Edge2.Dx) { if (Edge2.Bot.Y > Edge1.Bot.Y) ip = Edge2.Bot; else ip = Edge1.Bot; return false; } else if (Edge1.Delta.X == 0) { ip.X = Edge1.Bot.X; if (IsHorizontal(Edge2)) ip.Y = Edge2.Bot.Y; else { b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx); ip.Y = Round(ip.X / Edge2.Dx + b2); } } else if (Edge2.Delta.X == 0) { ip.X = Edge2.Bot.X; if (IsHorizontal(Edge1)) ip.Y = Edge1.Bot.Y; else { b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx); ip.Y = Round(ip.X / Edge1.Dx + b1); } } else { b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx; b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); ip.Y = Round(q); if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ip.X = Round(Edge1.Dx * q + b1); else ip.X = Round(Edge2.Dx * q + b2); } if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) { if (Edge1.Top.Y > Edge2.Top.Y) ip.Y = Edge1.Top.Y; else ip.Y = Edge2.Top.Y; if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ip.X = TopX(Edge1, ip.Y); else ip.X = TopX(Edge2, ip.Y); } return true; } //------------------------------------------------------------------------------ void ReversePolyPtLinks(OutPt *pp) { if (!pp) return; OutPt *pp1, *pp2; pp1 = pp; do { pp2 = pp1->Next; pp1->Next = pp1->Prev; pp1->Prev = pp2; pp1 = pp2; } while( pp1 != pp ); } //------------------------------------------------------------------------------ void DisposeOutPts(OutPt*& pp) { if (pp == 0) return; pp->Prev->Next = 0; while( pp ) { OutPt *tmpPp = pp; pp = pp->Next; delete tmpPp; } } //------------------------------------------------------------------------------ inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) { std::memset(e, 0, sizeof(TEdge)); e->Next = eNext; e->Prev = ePrev; e->Curr = Pt; e->OutIdx = Unassigned; } //------------------------------------------------------------------------------ void InitEdge2(TEdge& e, PolyType Pt) { if (e.Curr.Y >= e.Next->Curr.Y) { e.Bot = e.Curr; e.Top = e.Next->Curr; } else { e.Top = e.Curr; e.Bot = e.Next->Curr; } SetDx(e); e.PolyTyp = Pt; } //------------------------------------------------------------------------------ TEdge* RemoveEdge(TEdge* e) { //removes e from double_linked_list (but without removing from memory) e->Prev->Next = e->Next; e->Next->Prev = e->Prev; TEdge* result = e->Next; e->Prev = 0; //flag as removed (see ClipperBase.Clear) return result; } //------------------------------------------------------------------------------ inline void ReverseHorizontal(TEdge &e) { //swap horizontal edges' Top and Bottom x's so they follow the natural //progression of the bounds - ie so their xbots will align with the //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] cInt tmp = e.Top.X; e.Top.X = e.Bot.X; e.Bot.X = tmp; #ifdef use_xyz tmp = e.Top.Z; e.Top.Z = e.Bot.Z; e.Bot.Z = tmp; #endif } //------------------------------------------------------------------------------ void SwapPoints(IntPoint &pt1, IntPoint &pt2) { IntPoint tmp = pt1; pt1 = pt2; pt2 = tmp; } //------------------------------------------------------------------------------ bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) { //precondition: segments are Collinear. if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) { if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; return pt1.X < pt2.X; } else { if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; return pt1.Y > pt2.Y; } } //------------------------------------------------------------------------------ bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) { OutPt *p = btmPt1->Prev; while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); p = btmPt1->Next; while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); p = btmPt2->Prev; while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); p = btmPt2->Next; while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); } //------------------------------------------------------------------------------ OutPt* GetBottomPt(OutPt *pp) { OutPt* dups = 0; OutPt* p = pp->Next; while (p != pp) { if (p->Pt.Y > pp->Pt.Y) { pp = p; dups = 0; } else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) { if (p->Pt.X < pp->Pt.X) { dups = 0; pp = p; } else { if (p->Next != pp && p->Prev != pp) dups = p; } } p = p->Next; } if (dups) { //there appears to be at least 2 vertices at BottomPt so ... while (dups != p) { if (!FirstIsBottomPt(p, dups)) pp = dups; dups = dups->Next; while (dups->Pt != pp->Pt) dups = dups->Next; } } return pp; } //------------------------------------------------------------------------------ bool FindSegment(OutPt* &pp, bool UseFullInt64Range, IntPoint &pt1, IntPoint &pt2) { //OutPt1 & OutPt2 => the overlap segment (if the function returns true) if (!pp) return false; OutPt* pp2 = pp; IntPoint pt1a = pt1, pt2a = pt2; do { if (SlopesEqual(pt1a, pt2a, pp->Pt, pp->Prev->Pt, UseFullInt64Range) && SlopesEqual(pt1a, pt2a, pp->Pt, UseFullInt64Range) && GetOverlapSegment(pt1a, pt2a, pp->Pt, pp->Prev->Pt, pt1, pt2)) return true; pp = pp->Next; } while (pp != pp2); return false; } //------------------------------------------------------------------------------ bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3) { if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) return false; else if (pt1.X != pt3.X) return (pt2.X > pt1.X) == (pt2.X < pt3.X); else return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); } //------------------------------------------------------------------------------ OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt) { if (p1 == p2) throw "JoinError"; OutPt* result = new OutPt; result->Pt = Pt; if (p2 == p1->Next) { p1->Next = result; p2->Prev = result; result->Next = p2; result->Prev = p1; } else { p2->Next = result; p1->Prev = result; result->Next = p1; result->Prev = p2; } return result; } //------------------------------------------------------------------------------ bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b, const IntPoint& pt2a, const IntPoint& pt2b) { //precondition: both segments are horizontal if ((pt1a.X > pt2a.X) == (pt1a.X < pt2b.X)) return true; else if ((pt1b.X > pt2a.X) == (pt1b.X < pt2b.X)) return true; else if ((pt2a.X > pt1a.X) == (pt2a.X < pt1b.X)) return true; else if ((pt2b.X > pt1a.X) == (pt2b.X < pt1b.X)) return true; else if ((pt1a.X == pt2a.X) && (pt1b.X == pt2b.X)) return true; else if ((pt1a.X == pt2b.X) && (pt1b.X == pt2a.X)) return true; else return false; } //------------------------------------------------------------------------------ // ClipperBase class methods ... //------------------------------------------------------------------------------ ClipperBase::ClipperBase() //constructor { m_MinimaList = 0; m_CurrentLM = 0; m_UseFullRange = false; } //------------------------------------------------------------------------------ ClipperBase::~ClipperBase() //destructor { Clear(); } //------------------------------------------------------------------------------ void RangeTest(const IntPoint& Pt, bool& useFullRange) { if (useFullRange) { if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) throw "Coordinate outside allowed range"; } else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) { useFullRange = true; RangeTest(Pt, useFullRange); } } //------------------------------------------------------------------------------ TEdge* FindNextLocMin(TEdge* E) { for (;;) { while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; while (IsHorizontal(*E->Prev)) E = E->Prev; TEdge* E2 = E; while (IsHorizontal(*E)) E = E->Next; if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz. if (E2->Prev->Bot.X < E->Bot.X) E = E2; break; } return E; } //------------------------------------------------------------------------------ TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise) { TEdge *EStart = E, *Result = E; TEdge *Horz = 0; cInt StartX; if (IsHorizontal(*E)) { //it's possible for adjacent overlapping horz edges to start heading left //before finishing right, so ... if (IsClockwise) StartX = E->Prev->Bot.X; else StartX = E->Next->Bot.X; if (E->Bot.X != StartX) ReverseHorizontal(*E); } if (Result->OutIdx != Skip) { if (IsClockwise) { while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip) Result = Result->Next; if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) { //nb: at the top of a bound, horizontals are added to the bound //only when the preceding edge attaches to the horizontal's left vertex //unless a Skip edge is encountered when that becomes the top divide Horz = Result; while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; if (Horz->Prev->Top.X == Result->Next->Top.X) { if (!IsClockwise) Result = Horz->Prev; } else if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev; } while (E != Result) { E->NextInLML = E->Next; if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); E = E->Next; } if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); Result = Result->Next; //move to the edge just beyond current bound } else { while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip) Result = Result->Prev; if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) { Horz = Result; while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; if (Horz->Next->Top.X == Result->Prev->Top.X) { if (!IsClockwise) Result = Horz->Next; } else if (Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next; } while (E != Result) { E->NextInLML = E->Prev; if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) ReverseHorizontal(*E); E = E->Prev; } if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) ReverseHorizontal(*E); Result = Result->Prev; //move to the edge just beyond current bound } } if (Result->OutIdx == Skip) { //if edges still remain in the current bound beyond the skip edge then //create another LocMin and call ProcessBound once more E = Result; if (IsClockwise) { while (E->Top.Y == E->Next->Bot.Y) E = E->Next; //don't include top horizontals when parsing a bound a second time, //they will be contained in the opposite bound ... while (E != Result && IsHorizontal(*E)) E = E->Prev; } else { while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev; while (E != Result && IsHorizontal(*E)) E = E->Next; } if (E == Result) { if (IsClockwise) Result = E->Next; else Result = E->Prev; } else { //there are more edges in the bound beyond result starting with E if (IsClockwise) E = Result->Next; else E = Result->Prev; LocalMinima* locMin = new LocalMinima; locMin->Next = 0; locMin->Y = E->Bot.Y; locMin->LeftBound = 0; locMin->RightBound = E; locMin->RightBound->WindDelta = 0; Result = ProcessBound(locMin->RightBound, IsClockwise); InsertLocalMinima(locMin); } } return Result; } //------------------------------------------------------------------------------ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) { #ifdef use_lines if (!Closed && PolyTyp == ptClip) throw clipperException("AddPath: Open paths must be subject."); #else if (!Closed) throw clipperException("AddPath: Open paths have been disabled."); #endif int highI = (int)pg.size() -1; if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; while (highI > 0 && (pg[highI] == pg[highI -1])) --highI; if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; //create a new edge array ... TEdge *edges = new TEdge [highI +1]; bool IsFlat = true; //1. Basic (first) edge initialization ... try { edges[1].Curr = pg[1]; RangeTest(pg[0], m_UseFullRange); RangeTest(pg[highI], m_UseFullRange); InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); for (int i = highI - 1; i >= 1; --i) { RangeTest(pg[i], m_UseFullRange); InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); } } catch(...) { delete [] edges; throw; //range test fails } TEdge *eStart = &edges[0]; //2. Remove duplicate vertices, and (when closed) collinear edges ... TEdge *E = eStart, *eLoopStop = eStart; for (;;) { if ((E->Curr == E->Next->Curr)) { if (E == E->Next) break; if (E == eStart) eStart = E->Next; E = RemoveEdge(E); eLoopStop = E; continue; } if (E->Prev == E->Next) break; //only two vertices else if (Closed && SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && (!m_PreserveCollinear || !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) { //Collinear edges are allowed for open paths but in closed paths //the default is to merge adjacent collinear edges into a single edge. //However, if the PreserveCollinear property is enabled, only overlapping //collinear edges (ie spikes) will be removed from closed paths. if (E == eStart) eStart = E->Next; E = RemoveEdge(E); E = E->Prev; eLoopStop = E; continue; } E = E->Next; if (E == eLoopStop) break; } if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) { delete [] edges; return false; } if (!Closed) { m_HasOpenPaths = true; eStart->Prev->OutIdx = Skip; } //3. Do second stage of edge initialization ... E = eStart; do { InitEdge2(*E, PolyTyp); E = E->Next; if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false; } while (E != eStart); //4. Finally, add edge bounds to LocalMinima list ... //Totally flat paths must be handled differently when adding them //to LocalMinima list to avoid endless loops etc ... if (IsFlat) { if (Closed) { delete [] edges; return false; } E->Prev->OutIdx = Skip; if (E->Prev->Bot.X < E->Prev->Top.X) ReverseHorizontal(*E->Prev); LocalMinima* locMin = new LocalMinima(); locMin->Next = 0; locMin->Y = E->Bot.Y; locMin->LeftBound = 0; locMin->RightBound = E; locMin->RightBound->Side = esRight; locMin->RightBound->WindDelta = 0; while (E->Next->OutIdx != Skip) { E->NextInLML = E->Next; if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); E = E->Next; } InsertLocalMinima(locMin); m_edges.push_back(edges); return true; } m_edges.push_back(edges); bool clockwise; TEdge* EMin = 0; for (;;) { E = FindNextLocMin(E); if (E == EMin) break; else if (!EMin) EMin = E; //E and E.Prev now share a local minima (left aligned if horizontal). //Compare their slopes to find which starts which bound ... LocalMinima* locMin = new LocalMinima; locMin->Next = 0; locMin->Y = E->Bot.Y; if (E->Dx < E->Prev->Dx) { locMin->LeftBound = E->Prev; locMin->RightBound = E; clockwise = false; //Q.nextInLML = Q.prev } else { locMin->LeftBound = E; locMin->RightBound = E->Prev; clockwise = true; //Q.nextInLML = Q.next } locMin->LeftBound->Side = esLeft; locMin->RightBound->Side = esRight; if (!Closed) locMin->LeftBound->WindDelta = 0; else if (locMin->LeftBound->Next == locMin->RightBound) locMin->LeftBound->WindDelta = -1; else locMin->LeftBound->WindDelta = 1; locMin->RightBound->WindDelta = -locMin->LeftBound->WindDelta; E = ProcessBound(locMin->LeftBound, clockwise); TEdge* E2 = ProcessBound(locMin->RightBound, !clockwise); if (locMin->LeftBound->OutIdx == Skip) locMin->LeftBound = 0; else if (locMin->RightBound->OutIdx == Skip) locMin->RightBound = 0; InsertLocalMinima(locMin); if (!clockwise) E = E2; } return true; } //------------------------------------------------------------------------------ bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) { bool result = false; for (Paths::size_type i = 0; i < ppg.size(); ++i) if (AddPath(ppg[i], PolyTyp, Closed)) result = true; return result; } //------------------------------------------------------------------------------ void ClipperBase::InsertLocalMinima(LocalMinima *newLm) { if( ! m_MinimaList ) { m_MinimaList = newLm; } else if( newLm->Y >= m_MinimaList->Y ) { newLm->Next = m_MinimaList; m_MinimaList = newLm; } else { LocalMinima* tmpLm = m_MinimaList; while( tmpLm->Next && ( newLm->Y < tmpLm->Next->Y ) ) tmpLm = tmpLm->Next; newLm->Next = tmpLm->Next; tmpLm->Next = newLm; } } //------------------------------------------------------------------------------ void ClipperBase::Clear() { DisposeLocalMinimaList(); for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) { //for each edge array in turn, find the first used edge and //check for and remove any hiddenPts in each edge in the array. TEdge* edges = m_edges[i]; delete [] edges; } m_edges.clear(); m_UseFullRange = false; m_HasOpenPaths = false; } //------------------------------------------------------------------------------ void ClipperBase::Reset() { m_CurrentLM = m_MinimaList; if( !m_CurrentLM ) return; //ie nothing to process //reset all edges ... LocalMinima* lm = m_MinimaList; while( lm ) { TEdge* e = lm->LeftBound; if (e) { e->Curr = e->Bot; e->Side = esLeft; e->OutIdx = Unassigned; } e = lm->RightBound; if (e) { e->Curr = e->Bot; e->Side = esRight; e->OutIdx = Unassigned; } lm = lm->Next; } } //------------------------------------------------------------------------------ void ClipperBase::DisposeLocalMinimaList() { while( m_MinimaList ) { LocalMinima* tmpLm = m_MinimaList->Next; delete m_MinimaList; m_MinimaList = tmpLm; } m_CurrentLM = 0; } //------------------------------------------------------------------------------ void ClipperBase::PopLocalMinima() { if( ! m_CurrentLM ) return; m_CurrentLM = m_CurrentLM->Next; } //------------------------------------------------------------------------------ IntRect ClipperBase::GetBounds() { IntRect result; LocalMinima* lm = m_MinimaList; if (!lm) { result.left = result.top = result.right = result.bottom = 0; return result; } result.left = lm->LeftBound->Bot.X; result.top = lm->LeftBound->Bot.Y; result.right = lm->LeftBound->Bot.X; result.bottom = lm->LeftBound->Bot.Y; while (lm) { if (lm->LeftBound->Bot.Y > result.bottom) result.bottom = lm->LeftBound->Bot.Y; TEdge* e = lm->LeftBound; for (;;) { TEdge* bottomE = e; while (e->NextInLML) { if (e->Bot.X < result.left) result.left = e->Bot.X; if (e->Bot.X > result.right) result.right = e->Bot.X; e = e->NextInLML; } if (e->Bot.X < result.left) result.left = e->Bot.X; if (e->Bot.X > result.right) result.right = e->Bot.X; if (e->Top.X < result.left) result.left = e->Top.X; if (e->Top.X > result.right) result.right = e->Top.X; if (e->Top.Y < result.top) result.top = e->Top.Y; if (bottomE == lm->LeftBound) e = lm->RightBound; else break; } lm = lm->Next; } return result; } //------------------------------------------------------------------------------ // TClipper methods ... //------------------------------------------------------------------------------ Clipper::Clipper(int initOptions) : ClipperBase() //constructor { m_ActiveEdges = 0; m_SortedEdges = 0; m_ExecuteLocked = false; m_UseFullRange = false; m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); m_HasOpenPaths = false; #ifdef use_xyz m_ZFill = 0; #endif } //------------------------------------------------------------------------------ Clipper::~Clipper() //destructor { Clear(); m_Scanbeam.clear(); } //------------------------------------------------------------------------------ #ifdef use_xyz void Clipper::ZFillFunction(TZFillCallback zFillFunc) { m_ZFill = zFillFunc; } //------------------------------------------------------------------------------ #endif void Clipper::Reset() { ClipperBase::Reset(); m_Scanbeam.clear(); m_ActiveEdges = 0; m_SortedEdges = 0; LocalMinima* lm = m_MinimaList; while (lm) { InsertScanbeam(lm->Y); lm = lm->Next; } } //------------------------------------------------------------------------------ bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType subjFillType, PolyFillType clipFillType) { if( m_ExecuteLocked ) return false; if (m_HasOpenPaths) throw clipperException("Error: PolyTree struct is need for open path clipping."); m_ExecuteLocked = true; solution.resize(0); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; m_UsingPolyTree = false; bool succeeded = ExecuteInternal(); if (succeeded) BuildResult(solution); DisposeAllOutRecs(); m_ExecuteLocked = false; return succeeded; } //------------------------------------------------------------------------------ bool Clipper::Execute(ClipType clipType, PolyTree& polytree, PolyFillType subjFillType, PolyFillType clipFillType) { if( m_ExecuteLocked ) return false; m_ExecuteLocked = true; m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; m_UsingPolyTree = true; bool succeeded = ExecuteInternal(); if (succeeded) BuildResult2(polytree); DisposeAllOutRecs(); m_ExecuteLocked = false; return succeeded; } //------------------------------------------------------------------------------ void Clipper::FixHoleLinkage(OutRec &outrec) { //skip OutRecs that (a) contain outermost polygons or //(b) already have the correct owner/child linkage ... if (!outrec.FirstLeft || (outrec.IsHole != outrec.FirstLeft->IsHole && outrec.FirstLeft->Pts)) return; OutRec* orfl = outrec.FirstLeft; while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts)) orfl = orfl->FirstLeft; outrec.FirstLeft = orfl; } //------------------------------------------------------------------------------ bool Clipper::ExecuteInternal() { bool succeeded = true; try { Reset(); if (!m_CurrentLM) return false; cInt botY = PopScanbeam(); do { InsertLocalMinimaIntoAEL(botY); ClearGhostJoins(); ProcessHorizontals(false); if (m_Scanbeam.empty()) break; cInt topY = PopScanbeam(); succeeded = ProcessIntersections(botY, topY); if (!succeeded) break; ProcessEdgesAtTopOfScanbeam(topY); botY = topY; } while (!m_Scanbeam.empty() || m_CurrentLM); } catch(...) { succeeded = false; } if (succeeded) { //fix orientations ... for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec *outRec = m_PolyOuts[i]; if (!outRec->Pts || outRec->IsOpen) continue; if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0)) ReversePolyPtLinks(outRec->Pts); } if (!m_Joins.empty()) JoinCommonEdges(); //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec *outRec = m_PolyOuts[i]; if (outRec->Pts && !outRec->IsOpen) FixupOutPolygon(*outRec); } if (m_StrictSimple) DoSimplePolygons(); } ClearJoins(); ClearGhostJoins(); return succeeded; } //------------------------------------------------------------------------------ void Clipper::InsertScanbeam(const cInt Y) { m_Scanbeam.insert(Y); } //------------------------------------------------------------------------------ cInt Clipper::PopScanbeam() { cInt Y = *m_Scanbeam.begin(); m_Scanbeam.erase(m_Scanbeam.begin()); return Y; } //------------------------------------------------------------------------------ void Clipper::DisposeAllOutRecs(){ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) DisposeOutRec(i); m_PolyOuts.clear(); } //------------------------------------------------------------------------------ void Clipper::DisposeOutRec(PolyOutList::size_type index) { OutRec *outRec = m_PolyOuts[index]; if (outRec->Pts) DisposeOutPts(outRec->Pts); delete outRec; m_PolyOuts[index] = 0; } //------------------------------------------------------------------------------ void Clipper::SetWindingCount(TEdge &edge) { TEdge *e = edge.PrevInAEL; //find the edge of the same polytype that immediately preceeds 'edge' in AEL while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; if (!e) { edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); edge.WindCnt2 = 0; e = m_ActiveEdges; //ie get ready to calc WindCnt2 } else if (edge.WindDelta == 0 && m_ClipType != ctUnion) { edge.WindCnt = 1; edge.WindCnt2 = e->WindCnt2; e = e->NextInAEL; //ie get ready to calc WindCnt2 } else if (IsEvenOddFillType(edge)) { //EvenOdd filling ... if (edge.WindDelta == 0) { //are we inside a subj polygon ... bool Inside = true; TEdge *e2 = e->PrevInAEL; while (e2) { if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) Inside = !Inside; e2 = e2->PrevInAEL; } edge.WindCnt = (Inside ? 0 : 1); } else { edge.WindCnt = edge.WindDelta; } edge.WindCnt2 = e->WindCnt2; e = e->NextInAEL; //ie get ready to calc WindCnt2 } else { //nonZero, Positive or Negative filling ... if (e->WindCnt * e->WindDelta < 0) { //prev edge is 'decreasing' WindCount (WC) toward zero //so we're outside the previous polygon ... if (Abs(e->WindCnt) > 1) { //outside prev poly but still inside another. //when reversing direction of prev poly use the same WC if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; //otherwise continue to 'decrease' WC ... else edge.WindCnt = e->WindCnt + edge.WindDelta; } else //now outside all polys of same polytype so set own WC ... edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); } else { //prev edge is 'increasing' WindCount (WC) away from zero //so we're inside the previous polygon ... if (edge.WindDelta == 0) edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); //if wind direction is reversing prev then use same WC else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; //otherwise add to WC ... else edge.WindCnt = e->WindCnt + edge.WindDelta; } edge.WindCnt2 = e->WindCnt2; e = e->NextInAEL; //ie get ready to calc WindCnt2 } //update WindCnt2 ... if (IsEvenOddAltFillType(edge)) { //EvenOdd filling ... while (e != &edge) { if (e->WindDelta != 0) edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); e = e->NextInAEL; } } else { //nonZero, Positive or Negative filling ... while ( e != &edge ) { edge.WindCnt2 += e->WindDelta; e = e->NextInAEL; } } } //------------------------------------------------------------------------------ bool Clipper::IsEvenOddFillType(const TEdge& edge) const { if (edge.PolyTyp == ptSubject) return m_SubjFillType == pftEvenOdd; else return m_ClipFillType == pftEvenOdd; } //------------------------------------------------------------------------------ bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const { if (edge.PolyTyp == ptSubject) return m_ClipFillType == pftEvenOdd; else return m_SubjFillType == pftEvenOdd; } //------------------------------------------------------------------------------ bool Clipper::IsContributing(const TEdge& edge) const { PolyFillType pft, pft2; if (edge.PolyTyp == ptSubject) { pft = m_SubjFillType; pft2 = m_ClipFillType; } else { pft = m_ClipFillType; pft2 = m_SubjFillType; } switch(pft) { case pftEvenOdd: //return false if a subj line has been flagged as inside a subj polygon if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; break; case pftNonZero: if (Abs(edge.WindCnt) != 1) return false; break; case pftPositive: if (edge.WindCnt != 1) return false; break; default: //pftNegative if (edge.WindCnt != -1) return false; } switch(m_ClipType) { case ctIntersection: switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.WindCnt2 != 0); case pftPositive: return (edge.WindCnt2 > 0); default: return (edge.WindCnt2 < 0); } break; case ctUnion: switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.WindCnt2 == 0); case pftPositive: return (edge.WindCnt2 <= 0); default: return (edge.WindCnt2 >= 0); } break; case ctDifference: if (edge.PolyTyp == ptSubject) switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.WindCnt2 == 0); case pftPositive: return (edge.WindCnt2 <= 0); default: return (edge.WindCnt2 >= 0); } else switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.WindCnt2 != 0); case pftPositive: return (edge.WindCnt2 > 0); default: return (edge.WindCnt2 < 0); } break; case ctXor: if (edge.WindDelta == 0) //XOr always contributing unless open switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.WindCnt2 == 0); case pftPositive: return (edge.WindCnt2 <= 0); default: return (edge.WindCnt2 >= 0); } else return true; break; default: return true; } } //------------------------------------------------------------------------------ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) { OutPt* result; TEdge *e, *prevE; if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) { result = AddOutPt(e1, Pt); e2->OutIdx = e1->OutIdx; e1->Side = esLeft; e2->Side = esRight; e = e1; if (e->PrevInAEL == e2) prevE = e2->PrevInAEL; else prevE = e->PrevInAEL; } else { result = AddOutPt(e2, Pt); e1->OutIdx = e2->OutIdx; e1->Side = esRight; e2->Side = esLeft; e = e2; if (e->PrevInAEL == e1) prevE = e1->PrevInAEL; else prevE = e->PrevInAEL; } if (prevE && prevE->OutIdx >= 0 && (TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) && SlopesEqual(*e, *prevE, m_UseFullRange) && (e->WindDelta != 0) && (prevE->WindDelta != 0)) { OutPt* outPt = AddOutPt(prevE, Pt); AddJoin(result, outPt, e->Top); } return result; } //------------------------------------------------------------------------------ void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) { AddOutPt( e1, Pt ); if (e2->WindDelta == 0) AddOutPt(e2, Pt); if( e1->OutIdx == e2->OutIdx ) { e1->OutIdx = Unassigned; e2->OutIdx = Unassigned; } else if (e1->OutIdx < e2->OutIdx) AppendPolygon(e1, e2); else AppendPolygon(e2, e1); } //------------------------------------------------------------------------------ void Clipper::AddEdgeToSEL(TEdge *edge) { //SEL pointers in PEdge are reused to build a list of horizontal edges. //However, we don't need to worry about order with horizontal edge processing. if( !m_SortedEdges ) { m_SortedEdges = edge; edge->PrevInSEL = 0; edge->NextInSEL = 0; } else { edge->NextInSEL = m_SortedEdges; edge->PrevInSEL = 0; m_SortedEdges->PrevInSEL = edge; m_SortedEdges = edge; } } //------------------------------------------------------------------------------ void Clipper::CopyAELToSEL() { TEdge* e = m_ActiveEdges; m_SortedEdges = e; while ( e ) { e->PrevInSEL = e->PrevInAEL; e->NextInSEL = e->NextInAEL; e = e->NextInAEL; } } //------------------------------------------------------------------------------ void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) { Join* j = new Join; j->OutPt1 = op1; j->OutPt2 = op2; j->OffPt = OffPt; m_Joins.push_back(j); } //------------------------------------------------------------------------------ void Clipper::ClearJoins() { for (JoinList::size_type i = 0; i < m_Joins.size(); i++) delete m_Joins[i]; m_Joins.resize(0); } //------------------------------------------------------------------------------ void Clipper::ClearGhostJoins() { for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++) delete m_GhostJoins[i]; m_GhostJoins.resize(0); } //------------------------------------------------------------------------------ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) { Join* j = new Join; j->OutPt1 = op; j->OutPt2 = 0; j->OffPt = OffPt; m_GhostJoins.push_back(j); } //------------------------------------------------------------------------------ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) { while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) { TEdge* lb = m_CurrentLM->LeftBound; TEdge* rb = m_CurrentLM->RightBound; PopLocalMinima(); OutPt *Op1 = 0; if (!lb) { //nb: don't insert LB into either AEL or SEL InsertEdgeIntoAEL(rb, 0); SetWindingCount(*rb); if (IsContributing(*rb)) Op1 = AddOutPt(rb, rb->Bot); } else if (!rb) { InsertEdgeIntoAEL(lb, 0); SetWindingCount(*lb); if (IsContributing(*lb)) Op1 = AddOutPt(lb, lb->Bot); InsertScanbeam(lb->Top.Y); } else { InsertEdgeIntoAEL(lb, 0); InsertEdgeIntoAEL(rb, lb); SetWindingCount( *lb ); rb->WindCnt = lb->WindCnt; rb->WindCnt2 = lb->WindCnt2; if (IsContributing(*lb)) Op1 = AddLocalMinPoly(lb, rb, lb->Bot); InsertScanbeam(lb->Top.Y); } if (rb) { if(IsHorizontal(*rb)) AddEdgeToSEL(rb); else InsertScanbeam( rb->Top.Y ); } if (!lb || !rb) continue; //if any output polygons share an edge, they'll need joining later ... if (Op1 && IsHorizontal(*rb) && m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) { for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) { Join* jr = m_GhostJoins[i]; //if the horizontal Rb and a 'ghost' horizontal overlap, then convert //the 'ghost' join to a real join ready for later ... if (HorzSegmentsOverlap(jr->OutPt1->Pt, jr->OffPt, rb->Bot, rb->Top)) AddJoin(jr->OutPt1, Op1, jr->OffPt); } } if (lb->OutIdx >= 0 && lb->PrevInAEL && lb->PrevInAEL->Curr.X == lb->Bot.X && lb->PrevInAEL->OutIdx >= 0 && SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) && (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) { OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); AddJoin(Op1, Op2, lb->Top); } if(lb->NextInAEL != rb) { if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) && (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) { OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); AddJoin(Op1, Op2, rb->Top); } TEdge* e = lb->NextInAEL; if (e) { while( e != rb ) { //nb: For calculating winding counts etc, IntersectEdges() assumes //that param1 will be to the Right of param2 ABOVE the intersection ... IntersectEdges(rb , e , lb->Curr); //order important here e = e->NextInAEL; } } } } } //------------------------------------------------------------------------------ void Clipper::DeleteFromAEL(TEdge *e) { TEdge* AelPrev = e->PrevInAEL; TEdge* AelNext = e->NextInAEL; if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted if( AelPrev ) AelPrev->NextInAEL = AelNext; else m_ActiveEdges = AelNext; if( AelNext ) AelNext->PrevInAEL = AelPrev; e->NextInAEL = 0; e->PrevInAEL = 0; } //------------------------------------------------------------------------------ void Clipper::DeleteFromSEL(TEdge *e) { TEdge* SelPrev = e->PrevInSEL; TEdge* SelNext = e->NextInSEL; if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted if( SelPrev ) SelPrev->NextInSEL = SelNext; else m_SortedEdges = SelNext; if( SelNext ) SelNext->PrevInSEL = SelPrev; e->NextInSEL = 0; e->PrevInSEL = 0; } //------------------------------------------------------------------------------ #ifdef use_xyz void Clipper::SetZ(IntPoint& pt, TEdge& e) { pt.Z = 0; if (m_ZFill) { //put the 'preferred' point as first parameter ... if (e.OutIdx < 0) (*m_ZFill)(e.Bot, e.Top, pt); //outside a path so presume entering else (*m_ZFill)(e.Top, e.Bot, pt); //inside a path so presume exiting } } //------------------------------------------------------------------------------ #endif void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, const IntPoint &Pt, bool protect) { //e1 will be to the Left of e2 BELOW the intersection. Therefore e1 is before //e2 in AEL except when e1 is being inserted at the intersection point ... bool e1stops = !protect && !e1->NextInLML && e1->Top.X == Pt.X && e1->Top.Y == Pt.Y; bool e2stops = !protect && !e2->NextInLML && e2->Top.X == Pt.X && e2->Top.Y == Pt.Y; bool e1Contributing = ( e1->OutIdx >= 0 ); bool e2Contributing = ( e2->OutIdx >= 0 ); #ifdef use_lines //if either edge is on an OPEN path ... if (e1->WindDelta == 0 || e2->WindDelta == 0) { //ignore subject-subject open path intersections UNLESS they //are both open paths, AND they are both 'contributing maximas' ... if (e1->WindDelta == 0 && e2->WindDelta == 0) { if ((e1stops || e2stops) && e1Contributing && e2Contributing) AddLocalMaxPoly(e1, e2, Pt); } //if intersecting a subj line with a subj poly ... else if (e1->PolyTyp == e2->PolyTyp && e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) { if (e1->WindDelta == 0) { if (e2Contributing) { AddOutPt(e1, Pt); if (e1Contributing) e1->OutIdx = Unassigned; } } else { if (e1Contributing) { AddOutPt(e2, Pt); if (e2Contributing) e2->OutIdx = Unassigned; } } } else if (e1->PolyTyp != e2->PolyTyp) { //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && (m_ClipType != ctUnion || e2->WindCnt2 == 0)) { AddOutPt(e1, Pt); if (e1Contributing) e1->OutIdx = Unassigned; } else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && (m_ClipType != ctUnion || e1->WindCnt2 == 0)) { AddOutPt(e2, Pt); if (e2Contributing) e2->OutIdx = Unassigned; } } if (e1stops) if (e1->OutIdx < 0) DeleteFromAEL(e1); else throw clipperException("Error intersecting polylines"); if (e2stops) if (e2->OutIdx < 0) DeleteFromAEL(e2); else throw clipperException("Error intersecting polylines"); return; } #endif //update winding counts... //assumes that e1 will be to the Right of e2 ABOVE the intersection if ( e1->PolyTyp == e2->PolyTyp ) { if ( IsEvenOddFillType( *e1) ) { int oldE1WindCnt = e1->WindCnt; e1->WindCnt = e2->WindCnt; e2->WindCnt = oldE1WindCnt; } else { if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; else e1->WindCnt += e2->WindDelta; if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; else e2->WindCnt -= e1->WindDelta; } } else { if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; } PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; if (e1->PolyTyp == ptSubject) { e1FillType = m_SubjFillType; e1FillType2 = m_ClipFillType; } else { e1FillType = m_ClipFillType; e1FillType2 = m_SubjFillType; } if (e2->PolyTyp == ptSubject) { e2FillType = m_SubjFillType; e2FillType2 = m_ClipFillType; } else { e2FillType = m_ClipFillType; e2FillType2 = m_SubjFillType; } cInt e1Wc, e2Wc; switch (e1FillType) { case pftPositive: e1Wc = e1->WindCnt; break; case pftNegative: e1Wc = -e1->WindCnt; break; default: e1Wc = Abs(e1->WindCnt); } switch(e2FillType) { case pftPositive: e2Wc = e2->WindCnt; break; case pftNegative: e2Wc = -e2->WindCnt; break; default: e2Wc = Abs(e2->WindCnt); } if ( e1Contributing && e2Contributing ) { if ( e1stops || e2stops || (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) AddLocalMaxPoly(e1, e2, Pt); else { AddOutPt(e1, Pt); AddOutPt(e2, Pt); SwapSides( *e1 , *e2 ); SwapPolyIndexes( *e1 , *e2 ); } } else if ( e1Contributing ) { if (e2Wc == 0 || e2Wc == 1) { AddOutPt(e1, Pt); SwapSides(*e1, *e2); SwapPolyIndexes(*e1, *e2); } } else if ( e2Contributing ) { if (e1Wc == 0 || e1Wc == 1) { AddOutPt(e2, Pt); SwapSides(*e1, *e2); SwapPolyIndexes(*e1, *e2); } } else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) { //neither edge is currently contributing ... cInt e1Wc2, e2Wc2; switch (e1FillType2) { case pftPositive: e1Wc2 = e1->WindCnt2; break; case pftNegative : e1Wc2 = -e1->WindCnt2; break; default: e1Wc2 = Abs(e1->WindCnt2); } switch (e2FillType2) { case pftPositive: e2Wc2 = e2->WindCnt2; break; case pftNegative: e2Wc2 = -e2->WindCnt2; break; default: e2Wc2 = Abs(e2->WindCnt2); } if (e1->PolyTyp != e2->PolyTyp) AddLocalMinPoly(e1, e2, Pt); else if (e1Wc == 1 && e2Wc == 1) switch( m_ClipType ) { case ctIntersection: if (e1Wc2 > 0 && e2Wc2 > 0) AddLocalMinPoly(e1, e2, Pt); break; case ctUnion: if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) AddLocalMinPoly(e1, e2, Pt); break; case ctDifference: if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) AddLocalMinPoly(e1, e2, Pt); break; case ctXor: AddLocalMinPoly(e1, e2, Pt); } else SwapSides( *e1, *e2 ); } if( (e1stops != e2stops) && ( (e1stops && (e1->OutIdx >= 0)) || (e2stops && (e2->OutIdx >= 0)) ) ) { SwapSides( *e1, *e2 ); SwapPolyIndexes( *e1, *e2 ); } //finally, delete any non-contributing maxima edges ... if( e1stops ) DeleteFromAEL( e1 ); if( e2stops ) DeleteFromAEL( e2 ); } //------------------------------------------------------------------------------ void Clipper::SetHoleState(TEdge *e, OutRec *outrec) { bool IsHole = false; TEdge *e2 = e->PrevInAEL; while (e2) { if (e2->OutIdx >= 0 && e2->WindDelta != 0) { IsHole = !IsHole; if (! outrec->FirstLeft) outrec->FirstLeft = m_PolyOuts[e2->OutIdx]; } e2 = e2->PrevInAEL; } if (IsHole) outrec->IsHole = true; } //------------------------------------------------------------------------------ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) { //work out which polygon fragment has the correct hole state ... if (!outRec1->BottomPt) outRec1->BottomPt = GetBottomPt(outRec1->Pts); if (!outRec2->BottomPt) outRec2->BottomPt = GetBottomPt(outRec2->Pts); OutPt *OutPt1 = outRec1->BottomPt; OutPt *OutPt2 = outRec2->BottomPt; if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1; else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2; else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1; else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2; else if (OutPt1->Next == OutPt1) return outRec2; else if (OutPt2->Next == OutPt2) return outRec1; else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; else return outRec2; } //------------------------------------------------------------------------------ bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2) { do { outRec1 = outRec1->FirstLeft; if (outRec1 == outRec2) return true; } while (outRec1); return false; } //------------------------------------------------------------------------------ OutRec* Clipper::GetOutRec(int Idx) { OutRec* outrec = m_PolyOuts[Idx]; while (outrec != m_PolyOuts[outrec->Idx]) outrec = m_PolyOuts[outrec->Idx]; return outrec; } //------------------------------------------------------------------------------ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) { //get the start and ends of both output polygons ... OutRec *outRec1 = m_PolyOuts[e1->OutIdx]; OutRec *outRec2 = m_PolyOuts[e2->OutIdx]; OutRec *holeStateRec; if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; else holeStateRec = GetLowermostRec(outRec1, outRec2); //get the start and ends of both output polygons and //join e2 poly onto e1 poly and delete pointers to e2 ... OutPt* p1_lft = outRec1->Pts; OutPt* p1_rt = p1_lft->Prev; OutPt* p2_lft = outRec2->Pts; OutPt* p2_rt = p2_lft->Prev; EdgeSide Side; //join e2 poly onto e1 poly and delete pointers to e2 ... if( e1->Side == esLeft ) { if( e2->Side == esLeft ) { //z y x a b c ReversePolyPtLinks(p2_lft); p2_lft->Next = p1_lft; p1_lft->Prev = p2_lft; p1_rt->Next = p2_rt; p2_rt->Prev = p1_rt; outRec1->Pts = p2_rt; } else { //x y z a b c p2_rt->Next = p1_lft; p1_lft->Prev = p2_rt; p2_lft->Prev = p1_rt; p1_rt->Next = p2_lft; outRec1->Pts = p2_lft; } Side = esLeft; } else { if( e2->Side == esRight ) { //a b c z y x ReversePolyPtLinks(p2_lft); p1_rt->Next = p2_rt; p2_rt->Prev = p1_rt; p2_lft->Next = p1_lft; p1_lft->Prev = p2_lft; } else { //a b c x y z p1_rt->Next = p2_lft; p2_lft->Prev = p1_rt; p1_lft->Prev = p2_rt; p2_rt->Next = p1_lft; } Side = esRight; } outRec1->BottomPt = 0; if (holeStateRec == outRec2) { if (outRec2->FirstLeft != outRec1) outRec1->FirstLeft = outRec2->FirstLeft; outRec1->IsHole = outRec2->IsHole; } outRec2->Pts = 0; outRec2->BottomPt = 0; outRec2->FirstLeft = outRec1; int OKIdx = e1->OutIdx; int ObsoleteIdx = e2->OutIdx; e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly e2->OutIdx = Unassigned; TEdge* e = m_ActiveEdges; while( e ) { if( e->OutIdx == ObsoleteIdx ) { e->OutIdx = OKIdx; e->Side = Side; break; } e = e->NextInAEL; } outRec2->Idx = outRec1->Idx; } //------------------------------------------------------------------------------ OutRec* Clipper::CreateOutRec() { OutRec* result = new OutRec; result->IsHole = false; result->IsOpen = false; result->FirstLeft = 0; result->Pts = 0; result->BottomPt = 0; result->PolyNd = 0; m_PolyOuts.push_back(result); result->Idx = (int)m_PolyOuts.size()-1; return result; } //------------------------------------------------------------------------------ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) { bool ToFront = (e->Side == esLeft); if( e->OutIdx < 0 ) { OutRec *outRec = CreateOutRec(); outRec->IsOpen = (e->WindDelta == 0); OutPt* newOp = new OutPt; outRec->Pts = newOp; newOp->Idx = outRec->Idx; newOp->Pt = pt; newOp->Next = newOp; newOp->Prev = newOp; if (!outRec->IsOpen) SetHoleState(e, outRec); #ifdef use_xyz if (pt == e->Bot) newOp->Pt = e->Bot; else if (pt == e->Top) newOp->Pt = e->Top; else SetZ(newOp->Pt, *e); #endif e->OutIdx = outRec->Idx; //nb: do this after SetZ ! return newOp; } else { OutRec *outRec = m_PolyOuts[e->OutIdx]; //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' OutPt* op = outRec->Pts; if (ToFront && (pt == op->Pt)) return op; else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; OutPt* newOp = new OutPt; newOp->Idx = outRec->Idx; newOp->Pt = pt; newOp->Next = op; newOp->Prev = op->Prev; newOp->Prev->Next = newOp; op->Prev = newOp; if (ToFront) outRec->Pts = newOp; #ifdef use_xyz if (pt == e->Bot) newOp->Pt = e->Bot; else if (pt == e->Top) newOp->Pt = e->Top; else SetZ(newOp->Pt, *e); #endif return newOp; } } //------------------------------------------------------------------------------ void Clipper::ProcessHorizontals(bool IsTopOfScanbeam) { TEdge* horzEdge = m_SortedEdges; while(horzEdge) { DeleteFromSEL(horzEdge); ProcessHorizontal(horzEdge, IsTopOfScanbeam); horzEdge = m_SortedEdges; } } //------------------------------------------------------------------------------ inline bool IsMinima(TEdge *e) { return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e); } //------------------------------------------------------------------------------ inline bool IsMaxima(TEdge *e, const cInt Y) { return e && e->Top.Y == Y && !e->NextInLML; } //------------------------------------------------------------------------------ inline bool IsIntermediate(TEdge *e, const cInt Y) { return e->Top.Y == Y && e->NextInLML; } //------------------------------------------------------------------------------ TEdge *GetMaximaPair(TEdge *e) { TEdge* result = 0; if ((e->Next->Top == e->Top) && !e->Next->NextInLML) result = e->Next; else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) result = e->Prev; if (result && (result->OutIdx == Skip || //result is false if both NextInAEL & PrevInAEL are nil & not horizontal ... (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0; return result; } //------------------------------------------------------------------------------ void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) { //check that one or other edge hasn't already been removed from AEL ... if (Edge1->NextInAEL == Edge1->PrevInAEL || Edge2->NextInAEL == Edge2->PrevInAEL) return; if( Edge1->NextInAEL == Edge2 ) { TEdge* Next = Edge2->NextInAEL; if( Next ) Next->PrevInAEL = Edge1; TEdge* Prev = Edge1->PrevInAEL; if( Prev ) Prev->NextInAEL = Edge2; Edge2->PrevInAEL = Prev; Edge2->NextInAEL = Edge1; Edge1->PrevInAEL = Edge2; Edge1->NextInAEL = Next; } else if( Edge2->NextInAEL == Edge1 ) { TEdge* Next = Edge1->NextInAEL; if( Next ) Next->PrevInAEL = Edge2; TEdge* Prev = Edge2->PrevInAEL; if( Prev ) Prev->NextInAEL = Edge1; Edge1->PrevInAEL = Prev; Edge1->NextInAEL = Edge2; Edge2->PrevInAEL = Edge1; Edge2->NextInAEL = Next; } else { TEdge* Next = Edge1->NextInAEL; TEdge* Prev = Edge1->PrevInAEL; Edge1->NextInAEL = Edge2->NextInAEL; if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1; Edge1->PrevInAEL = Edge2->PrevInAEL; if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1; Edge2->NextInAEL = Next; if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2; Edge2->PrevInAEL = Prev; if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2; } if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1; else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2; } //------------------------------------------------------------------------------ void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) { if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; if( Edge1->NextInSEL == Edge2 ) { TEdge* Next = Edge2->NextInSEL; if( Next ) Next->PrevInSEL = Edge1; TEdge* Prev = Edge1->PrevInSEL; if( Prev ) Prev->NextInSEL = Edge2; Edge2->PrevInSEL = Prev; Edge2->NextInSEL = Edge1; Edge1->PrevInSEL = Edge2; Edge1->NextInSEL = Next; } else if( Edge2->NextInSEL == Edge1 ) { TEdge* Next = Edge1->NextInSEL; if( Next ) Next->PrevInSEL = Edge2; TEdge* Prev = Edge2->PrevInSEL; if( Prev ) Prev->NextInSEL = Edge1; Edge1->PrevInSEL = Prev; Edge1->NextInSEL = Edge2; Edge2->PrevInSEL = Edge1; Edge2->NextInSEL = Next; } else { TEdge* Next = Edge1->NextInSEL; TEdge* Prev = Edge1->PrevInSEL; Edge1->NextInSEL = Edge2->NextInSEL; if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; Edge1->PrevInSEL = Edge2->PrevInSEL; if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; Edge2->NextInSEL = Next; if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; Edge2->PrevInSEL = Prev; if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; } if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; } //------------------------------------------------------------------------------ TEdge* GetNextInAEL(TEdge *e, Direction dir) { return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL; } //------------------------------------------------------------------------------ void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) { if (HorzEdge.Bot.X < HorzEdge.Top.X) { Left = HorzEdge.Bot.X; Right = HorzEdge.Top.X; Dir = dLeftToRight; } else { Left = HorzEdge.Top.X; Right = HorzEdge.Bot.X; Dir = dRightToLeft; } } //------------------------------------------------------------------------ void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam) { //get the last Op for this horizontal edge //the point may be anywhere along the horizontal ... OutPt* outPt = m_PolyOuts[horzEdge->OutIdx]->Pts; if (horzEdge->Side != esLeft) outPt = outPt->Prev; //First, match up overlapping horizontal edges (eg when one polygon's //intermediate horz edge overlaps an intermediate horz edge of another, or //when one polygon sits on top of another) ... //for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) //{ // Join* j = m_GhostJoins[i]; // if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top)) // AddJoin(j->OutPt1, outPt, j->OffPt); //} //Also, since horizontal edges at the top of one SB are often removed from //the AEL before we process the horizontal edges at the bottom of the next, //we need to create 'ghost' Join records of 'contrubuting' horizontals that //we can compare with horizontals at the bottom of the next SB. if (isTopOfScanbeam) { if (outPt->Pt == horzEdge->Top) AddGhostJoin(outPt, horzEdge->Bot); else AddGhostJoin(outPt, horzEdge->Top); } } //------------------------------------------------------------------------------ /******************************************************************************* * Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * * Bottom of a scanbeam) are processed as if layered. The order in which HEs * * are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] * * (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * * and with other non-horizontal edges [*]. Once these intersections are * * processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * * the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * *******************************************************************************/ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam) { Direction dir; cInt horzLeft, horzRight; GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); TEdge* eLastHorz = horzEdge, *eMaxPair = 0; while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) eLastHorz = eLastHorz->NextInLML; if (!eLastHorz->NextInLML) eMaxPair = GetMaximaPair(eLastHorz); for (;;) { bool IsLastHorz = (horzEdge == eLastHorz); TEdge* e = GetNextInAEL(horzEdge, dir); while(e) { //Break if we've got to the end of an intermediate horizontal edge ... //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML && e->Dx < horzEdge->NextInLML->Dx) break; TEdge* eNext = GetNextInAEL(e, dir); //saves eNext for later if ((dir == dLeftToRight && e->Curr.X <= horzRight) || (dir == dRightToLeft && e->Curr.X >= horzLeft)) { if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0) PrepareHorzJoins(horzEdge, isTopOfScanbeam); //so far we're still in range of the horizontal Edge but make sure //we're at the last of consec. horizontals when matching with eMaxPair if(e == eMaxPair && IsLastHorz) { if (dir == dLeftToRight) IntersectEdges(horzEdge, e, e->Top); else IntersectEdges(e, horzEdge, e->Top); if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error"); return; } else if(dir == dLeftToRight) { IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); IntersectEdges(horzEdge, e, Pt, true); } else { IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); IntersectEdges( e, horzEdge, Pt, true); } SwapPositionsInAEL( horzEdge, e ); } else if( (dir == dLeftToRight && e->Curr.X >= horzRight) || (dir == dRightToLeft && e->Curr.X <= horzLeft) ) break; e = eNext; } //end while if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0) PrepareHorzJoins(horzEdge, isTopOfScanbeam); if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML)) { UpdateEdgeIntoAEL(horzEdge); if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); } else break; } //end for (;;) if(horzEdge->NextInLML) { if(horzEdge->OutIdx >= 0) { OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top); UpdateEdgeIntoAEL(horzEdge); if (horzEdge->WindDelta == 0) return; //nb: HorzEdge is no longer horizontal here TEdge* ePrev = horzEdge->PrevInAEL; TEdge* eNext = horzEdge->NextInAEL; if (ePrev && ePrev->Curr.X == horzEdge->Bot.X && ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 && (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) { OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); AddJoin(op1, op2, horzEdge->Top); } else if (eNext && eNext->Curr.X == horzEdge->Bot.X && eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 && eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) { OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); AddJoin(op1, op2, horzEdge->Top); } } else UpdateEdgeIntoAEL(horzEdge); } else if (eMaxPair) { if (eMaxPair->OutIdx >= 0) { if (dir == dLeftToRight) IntersectEdges(horzEdge, eMaxPair, horzEdge->Top); else IntersectEdges(eMaxPair, horzEdge, horzEdge->Top); if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error"); } else { DeleteFromAEL(horzEdge); DeleteFromAEL(eMaxPair); } } else { if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); DeleteFromAEL(horzEdge); } } //------------------------------------------------------------------------------ void Clipper::UpdateEdgeIntoAEL(TEdge *&e) { if( !e->NextInLML ) throw clipperException("UpdateEdgeIntoAEL: invalid call"); e->NextInLML->OutIdx = e->OutIdx; TEdge* AelPrev = e->PrevInAEL; TEdge* AelNext = e->NextInAEL; if (AelPrev) AelPrev->NextInAEL = e->NextInLML; else m_ActiveEdges = e->NextInLML; if (AelNext) AelNext->PrevInAEL = e->NextInLML; e->NextInLML->Side = e->Side; e->NextInLML->WindDelta = e->WindDelta; e->NextInLML->WindCnt = e->WindCnt; e->NextInLML->WindCnt2 = e->WindCnt2; e = e->NextInLML; e->Curr = e->Bot; e->PrevInAEL = AelPrev; e->NextInAEL = AelNext; if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y); } //------------------------------------------------------------------------------ bool Clipper::ProcessIntersections(const cInt botY, const cInt topY) { if( !m_ActiveEdges ) return true; try { BuildIntersectList(botY, topY); size_t IlSize = m_IntersectList.size(); if (IlSize == 0) return true; if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); else return false; } catch(...) { m_SortedEdges = 0; DisposeIntersectNodes(); throw clipperException("ProcessIntersections error"); } m_SortedEdges = 0; return true; } //------------------------------------------------------------------------------ void Clipper::DisposeIntersectNodes() { for (size_t i = 0; i < m_IntersectList.size(); ++i ) delete m_IntersectList[i]; m_IntersectList.clear(); } //------------------------------------------------------------------------------ void Clipper::BuildIntersectList(const cInt botY, const cInt topY) { if ( !m_ActiveEdges ) return; //prepare for sorting ... TEdge* e = m_ActiveEdges; m_SortedEdges = e; while( e ) { e->PrevInSEL = e->PrevInAEL; e->NextInSEL = e->NextInAEL; e->Curr.X = TopX( *e, topY ); e = e->NextInAEL; } //bubblesort ... bool isModified; do { isModified = false; e = m_SortedEdges; while( e->NextInSEL ) { TEdge *eNext = e->NextInSEL; IntPoint Pt; if(e->Curr.X > eNext->Curr.X) { if (!IntersectPoint(*e, *eNext, Pt, m_UseFullRange) && e->Curr.X > eNext->Curr.X +1) throw clipperException("Intersection error"); if (Pt.Y > botY) { Pt.Y = botY; if (std::fabs(e->Dx) > std::fabs(eNext->Dx)) Pt.X = TopX(*eNext, botY); else Pt.X = TopX(*e, botY); } IntersectNode * newNode = new IntersectNode; newNode->Edge1 = e; newNode->Edge2 = eNext; newNode->Pt = Pt; m_IntersectList.push_back(newNode); SwapPositionsInSEL(e, eNext); isModified = true; } else e = eNext; } if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; else break; } while ( isModified ); m_SortedEdges = 0; //important } //------------------------------------------------------------------------------ void Clipper::ProcessIntersectList() { for (size_t i = 0; i < m_IntersectList.size(); ++i) { IntersectNode* iNode = m_IntersectList[i]; { IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt, true); SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 ); } delete iNode; } m_IntersectList.clear(); } //------------------------------------------------------------------------------ bool IntersectListSort(IntersectNode* node1, IntersectNode* node2) { return node2->Pt.Y < node1->Pt.Y; } //------------------------------------------------------------------------------ inline bool EdgesAdjacent(const IntersectNode &inode) { return (inode.Edge1->NextInSEL == inode.Edge2) || (inode.Edge1->PrevInSEL == inode.Edge2); } //------------------------------------------------------------------------------ bool Clipper::FixupIntersectionOrder() { //pre-condition: intersections are sorted Bottom-most first. //Now it's crucial that intersections are made only between adjacent edges, //so to ensure this the order of intersections may need adjusting ... CopyAELToSEL(); std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort); size_t cnt = m_IntersectList.size(); for (size_t i = 0; i < cnt; ++i) { if (!EdgesAdjacent(*m_IntersectList[i])) { size_t j = i + 1; while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++; if (j == cnt) return false; std::swap(m_IntersectList[i], m_IntersectList[j]); } SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2); } return true; } //------------------------------------------------------------------------------ void Clipper::DoMaxima(TEdge *e) { TEdge* eMaxPair = GetMaximaPair(e); if (!eMaxPair) { if (e->OutIdx >= 0) AddOutPt(e, e->Top); DeleteFromAEL(e); return; } TEdge* eNext = e->NextInAEL; while(eNext && eNext != eMaxPair) { IntersectEdges(e, eNext, e->Top, true); SwapPositionsInAEL(e, eNext); eNext = e->NextInAEL; } if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) { DeleteFromAEL(e); DeleteFromAEL(eMaxPair); } else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) { IntersectEdges( e, eMaxPair, e->Top); } #ifdef use_lines else if (e->WindDelta == 0) { if (e->OutIdx >= 0) { AddOutPt(e, e->Top); e->OutIdx = Unassigned; } DeleteFromAEL(e); if (eMaxPair->OutIdx >= 0) { AddOutPt(eMaxPair, e->Top); eMaxPair->OutIdx = Unassigned; } DeleteFromAEL(eMaxPair); } #endif else throw clipperException("DoMaxima error"); } //------------------------------------------------------------------------------ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) { TEdge* e = m_ActiveEdges; while( e ) { //1. process maxima, treating them as if they're 'bent' horizontal edges, // but exclude maxima with horizontal edges. nb: e can't be a horizontal. bool IsMaximaEdge = IsMaxima(e, topY); if(IsMaximaEdge) { TEdge* eMaxPair = GetMaximaPair(e); IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); } if(IsMaximaEdge) { TEdge* ePrev = e->PrevInAEL; DoMaxima(e); if( !ePrev ) e = m_ActiveEdges; else e = ePrev->NextInAEL; } else { //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) { UpdateEdgeIntoAEL(e); if (e->OutIdx >= 0) AddOutPt(e, e->Bot); AddEdgeToSEL(e); } else { e->Curr.X = TopX( *e, topY ); e->Curr.Y = topY; } if (m_StrictSimple) { TEdge* ePrev = e->PrevInAEL; if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0)) { OutPt* op = AddOutPt(ePrev, e->Curr); OutPt* op2 = AddOutPt(e, e->Curr); AddJoin(op, op2, e->Curr); //StrictlySimple (type-3) join } } e = e->NextInAEL; } } //3. Process horizontals at the Top of the scanbeam ... ProcessHorizontals(true); //4. Promote intermediate vertices ... e = m_ActiveEdges; while(e) { if(IsIntermediate(e, topY)) { OutPt* op = 0; if( e->OutIdx >= 0 ) op = AddOutPt(e, e->Top); UpdateEdgeIntoAEL(e); //if output polygons share an edge, they'll need joining later ... TEdge* ePrev = e->PrevInAEL; TEdge* eNext = e->NextInAEL; if (ePrev && ePrev->Curr.X == e->Bot.X && ePrev->Curr.Y == e->Bot.Y && op && ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && SlopesEqual(*e, *ePrev, m_UseFullRange) && (e->WindDelta != 0) && (ePrev->WindDelta != 0)) { OutPt* op2 = AddOutPt(ePrev, e->Bot); AddJoin(op, op2, e->Top); } else if (eNext && eNext->Curr.X == e->Bot.X && eNext->Curr.Y == e->Bot.Y && op && eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && SlopesEqual(*e, *eNext, m_UseFullRange) && (e->WindDelta != 0) && (eNext->WindDelta != 0)) { OutPt* op2 = AddOutPt(eNext, e->Bot); AddJoin(op, op2, e->Top); } } e = e->NextInAEL; } } //------------------------------------------------------------------------------ void Clipper::FixupOutPolygon(OutRec &outrec) { //FixupOutPolygon() - removes duplicate points and simplifies consecutive //parallel edges by removing the middle vertex. OutPt *lastOK = 0; outrec.BottomPt = 0; OutPt *pp = outrec.Pts; for (;;) { if (pp->Prev == pp || pp->Prev == pp->Next ) { DisposeOutPts(pp); outrec.Pts = 0; return; } //test for duplicate points and collinear edges ... if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && (!m_PreserveCollinear || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) { lastOK = 0; OutPt *tmp = pp; pp->Prev->Next = pp->Next; pp->Next->Prev = pp->Prev; pp = pp->Prev; delete tmp; } else if (pp == lastOK) break; else { if (!lastOK) lastOK = pp; pp = pp->Next; } } outrec.Pts = pp; } //------------------------------------------------------------------------------ int PointCount(OutPt *Pts) { if (!Pts) return 0; int result = 0; OutPt* p = Pts; do { result++; p = p->Next; } while (p != Pts); return result; } //------------------------------------------------------------------------------ void Clipper::BuildResult(Paths &polys) { polys.reserve(m_PolyOuts.size()); for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { if (!m_PolyOuts[i]->Pts) continue; Path pg; OutPt* p = m_PolyOuts[i]->Pts->Prev; int cnt = PointCount(p); if (cnt < 2) continue; pg.reserve(cnt); for (int i = 0; i < cnt; ++i) { pg.push_back(p->Pt); p = p->Prev; } polys.push_back(pg); } } //------------------------------------------------------------------------------ void Clipper::BuildResult2(PolyTree& polytree) { polytree.Clear(); polytree.AllNodes.reserve(m_PolyOuts.size()); //add each output polygon/contour to polytree ... for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) { OutRec* outRec = m_PolyOuts[i]; int cnt = PointCount(outRec->Pts); if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue; FixHoleLinkage(*outRec); PolyNode* pn = new PolyNode(); //nb: polytree takes ownership of all the PolyNodes polytree.AllNodes.push_back(pn); outRec->PolyNd = pn; pn->Parent = 0; pn->Index = 0; pn->Contour.reserve(cnt); OutPt *op = outRec->Pts->Prev; for (int j = 0; j < cnt; j++) { pn->Contour.push_back(op->Pt); op = op->Prev; } } //fixup PolyNode links etc ... polytree.Childs.reserve(m_PolyOuts.size()); for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) { OutRec* outRec = m_PolyOuts[i]; if (!outRec->PolyNd) continue; if (outRec->IsOpen) { outRec->PolyNd->m_IsOpen = true; polytree.AddChild(*outRec->PolyNd); } else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd) outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd); else polytree.AddChild(*outRec->PolyNd); } } //------------------------------------------------------------------------------ void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) { //just swap the contents (because fIntersectNodes is a single-linked-list) IntersectNode inode = int1; //gets a copy of Int1 int1.Edge1 = int2.Edge1; int1.Edge2 = int2.Edge2; int1.Pt = int2.Pt; int2.Edge1 = inode.Edge1; int2.Edge2 = inode.Edge2; int2.Pt = inode.Pt; } //------------------------------------------------------------------------------ inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) { if (e2.Curr.X == e1.Curr.X) { if (e2.Top.Y > e1.Top.Y) return e2.Top.X < TopX(e1, e2.Top.Y); else return e1.Top.X > TopX(e2, e1.Top.Y); } else return e2.Curr.X < e1.Curr.X; } //------------------------------------------------------------------------------ bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, cInt& Left, cInt& Right) { if (a1 < a2) { if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} else {Left = std::max(a1,b2); Right = std::min(a2,b1);} } else { if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} else {Left = std::max(a2,b2); Right = std::min(a1,b1);} } return Left < Right; } //------------------------------------------------------------------------------ inline void UpdateOutPtIdxs(OutRec& outrec) { OutPt* op = outrec.Pts; do { op->Idx = outrec.Idx; op = op->Prev; } while(op != outrec.Pts); } //------------------------------------------------------------------------------ void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) { if(!m_ActiveEdges) { edge->PrevInAEL = 0; edge->NextInAEL = 0; m_ActiveEdges = edge; } else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) { edge->PrevInAEL = 0; edge->NextInAEL = m_ActiveEdges; m_ActiveEdges->PrevInAEL = edge; m_ActiveEdges = edge; } else { if(!startEdge) startEdge = m_ActiveEdges; while(startEdge->NextInAEL && !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) startEdge = startEdge->NextInAEL; edge->NextInAEL = startEdge->NextInAEL; if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; edge->PrevInAEL = startEdge; startEdge->NextInAEL = edge; } } //---------------------------------------------------------------------- OutPt* DupOutPt(OutPt* outPt, bool InsertAfter) { OutPt* result = new OutPt; result->Pt = outPt->Pt; result->Idx = outPt->Idx; if (InsertAfter) { result->Next = outPt->Next; result->Prev = outPt; outPt->Next->Prev = result; outPt->Next = result; } else { result->Prev = outPt->Prev; result->Next = outPt; outPt->Prev->Next = result; outPt->Prev = result; } return result; } //------------------------------------------------------------------------------ bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, const IntPoint Pt, bool DiscardLeft) { Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight); Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight); if (Dir1 == Dir2) return false; //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) //So, to facilitate this while inserting Op1b and Op2b ... //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) if (Dir1 == dLeftToRight) { while (op1->Next->Pt.X <= Pt.X && op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) op1 = op1->Next; if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; op1b = DupOutPt(op1, !DiscardLeft); if (op1b->Pt != Pt) { op1 = op1b; op1->Pt = Pt; op1b = DupOutPt(op1, !DiscardLeft); } } else { while (op1->Next->Pt.X >= Pt.X && op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) op1 = op1->Next; if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; op1b = DupOutPt(op1, DiscardLeft); if (op1b->Pt != Pt) { op1 = op1b; op1->Pt = Pt; op1b = DupOutPt(op1, DiscardLeft); } } if (Dir2 == dLeftToRight) { while (op2->Next->Pt.X <= Pt.X && op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) op2 = op2->Next; if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; op2b = DupOutPt(op2, !DiscardLeft); if (op2b->Pt != Pt) { op2 = op2b; op2->Pt = Pt; op2b = DupOutPt(op2, !DiscardLeft); }; } else { while (op2->Next->Pt.X >= Pt.X && op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) op2 = op2->Next; if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; op2b = DupOutPt(op2, DiscardLeft); if (op2b->Pt != Pt) { op2 = op2b; op2->Pt = Pt; op2b = DupOutPt(op2, DiscardLeft); }; }; if ((Dir1 == dLeftToRight) == DiscardLeft) { op1->Prev = op2; op2->Next = op1; op1b->Next = op2b; op2b->Prev = op1b; } else { op1->Next = op2; op2->Prev = op1; op1b->Prev = op2b; op2b->Next = op1b; } return true; } //------------------------------------------------------------------------------ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) { OutPt *op1 = j->OutPt1, *op1b; OutPt *op2 = j->OutPt2, *op2b; //There are 3 kinds of joins for output polygons ... //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are a vertices anywhere //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same //location at the Bottom of the overlapping segment (& Join.OffPt is above). //3. StrictSimple joins where edges touch but are not collinear and where //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y); if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && (j->OffPt == j->OutPt2->Pt)) { //Strictly Simple join ... op1b = j->OutPt1->Next; while (op1b != op1 && (op1b->Pt == j->OffPt)) op1b = op1b->Next; bool reverse1 = (op1b->Pt.Y > j->OffPt.Y); op2b = j->OutPt2->Next; while (op2b != op2 && (op2b->Pt == j->OffPt)) op2b = op2b->Next; bool reverse2 = (op2b->Pt.Y > j->OffPt.Y); if (reverse1 == reverse2) return false; if (reverse1) { op1b = DupOutPt(op1, false); op2b = DupOutPt(op2, true); op1->Prev = op2; op2->Next = op1; op1b->Next = op2b; op2b->Prev = op1b; j->OutPt1 = op1; j->OutPt2 = op1b; return true; } else { op1b = DupOutPt(op1, true); op2b = DupOutPt(op2, false); op1->Next = op2; op2->Prev = op1; op1b->Prev = op2b; op2b->Next = op1b; j->OutPt1 = op1; j->OutPt2 = op1b; return true; } } else if (isHorizontal) { //treat horizontal joins differently to non-horizontal joins since with //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt //may be anywhere along the horizontal edge. op1b = op1; while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2) op1 = op1->Prev; while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2) op1b = op1b->Next; if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' op2b = op2; while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b) op2 = op2->Prev; while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1) op2b = op2b->Next; if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' cInt Left, Right; //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right)) return false; //DiscardLeftSide: when overlapping edges are joined, a spike will created //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up //on the discard Side as either may still be needed for other joins ... IntPoint Pt; bool DiscardLeftSide; if (op1->Pt.X >= Left && op1->Pt.X <= Right) { Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X); } else if (op2->Pt.X >= Left&& op2->Pt.X <= Right) { Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X); } else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) { Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X; } else { Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X); } j->OutPt1 = op1; j->OutPt2 = op2; return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); } else { //nb: For non-horizontal joins ... // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y // 2. Jr.OutPt1.Pt > Jr.OffPt.Y //make sure the polygons are correctly oriented ... op1b = op1->Next; while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) || !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); if (Reverse1) { op1b = op1->Prev; while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; if ((op1b->Pt.Y > op1->Pt.Y) || !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; }; op2b = op2->Next; while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) || !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); if (Reverse2) { op2b = op2->Prev; while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; if ((op2b->Pt.Y > op2->Pt.Y) || !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; } if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; if (Reverse1) { op1b = DupOutPt(op1, false); op2b = DupOutPt(op2, true); op1->Prev = op2; op2->Next = op1; op1b->Next = op2b; op2b->Prev = op1b; j->OutPt1 = op1; j->OutPt2 = op1b; return true; } else { op1b = DupOutPt(op1, true); op2b = DupOutPt(op2, false); op1->Next = op2; op2->Prev = op1; op1b->Prev = op2b; op2b->Next = op1b; j->OutPt1 = op1; j->OutPt2 = op1b; return true; } } } //---------------------------------------------------------------------- void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) { for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec* outRec = m_PolyOuts[i]; if (outRec->Pts && outRec->FirstLeft == OldOutRec) { if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) outRec->FirstLeft = NewOutRec; } } } //---------------------------------------------------------------------- void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) { for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec* outRec = m_PolyOuts[i]; if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec; } } //---------------------------------------------------------------------- static OutRec* ParseFirstLeft(OutRec* FirstLeft) { while (FirstLeft && !FirstLeft->Pts) FirstLeft = FirstLeft->FirstLeft; return FirstLeft; } //------------------------------------------------------------------------------ void Clipper::JoinCommonEdges() { for (JoinList::size_type i = 0; i < m_Joins.size(); i++) { Join* join = m_Joins[i]; OutRec *outRec1 = GetOutRec(join->OutPt1->Idx); OutRec *outRec2 = GetOutRec(join->OutPt2->Idx); if (!outRec1->Pts || !outRec2->Pts) continue; //get the polygon fragment with the correct hole state (FirstLeft) //before calling JoinPoints() ... OutRec *holeStateRec; if (outRec1 == outRec2) holeStateRec = outRec1; else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; else holeStateRec = GetLowermostRec(outRec1, outRec2); if (!JoinPoints(join, outRec1, outRec2)) continue; if (outRec1 == outRec2) { //instead of joining two polygons, we've just created a new one by //splitting one polygon into two. outRec1->Pts = join->OutPt1; outRec1->BottomPt = 0; outRec2 = CreateOutRec(); outRec2->Pts = join->OutPt2; //update all OutRec2.Pts Idx's ... UpdateOutPtIdxs(*outRec2); //We now need to check every OutRec.FirstLeft pointer. If it points //to OutRec1 it may need to point to OutRec2 instead ... if (m_UsingPolyTree) for (PolyOutList::size_type j = 0; j < m_PolyOuts.size() - 1; j++) { OutRec* oRec = m_PolyOuts[j]; if (!oRec->Pts || ParseFirstLeft(oRec->FirstLeft) != outRec1 || oRec->IsHole == outRec1->IsHole) continue; if (Poly2ContainsPoly1(oRec->Pts, join->OutPt2)) oRec->FirstLeft = outRec2; } if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) { //outRec2 is contained by outRec1 ... outRec2->IsHole = !outRec1->IsHole; outRec2->FirstLeft = outRec1; //fixup FirstLeft pointers that may need reassigning to OutRec1 if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) ReversePolyPtLinks(outRec2->Pts); } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) { //outRec1 is contained by outRec2 ... outRec2->IsHole = outRec1->IsHole; outRec1->IsHole = !outRec2->IsHole; outRec2->FirstLeft = outRec1->FirstLeft; outRec1->FirstLeft = outRec2; //fixup FirstLeft pointers that may need reassigning to OutRec1 if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) ReversePolyPtLinks(outRec1->Pts); } else { //the 2 polygons are completely separate ... outRec2->IsHole = outRec1->IsHole; outRec2->FirstLeft = outRec1->FirstLeft; //fixup FirstLeft pointers that may need reassigning to OutRec2 if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); } } else { //joined 2 polygons together ... outRec2->Pts = 0; outRec2->BottomPt = 0; outRec2->Idx = outRec1->Idx; outRec1->IsHole = holeStateRec->IsHole; if (holeStateRec == outRec2) outRec1->FirstLeft = outRec2->FirstLeft; outRec2->FirstLeft = outRec1; //fixup FirstLeft pointers that may need reassigning to OutRec1 if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); } } } //------------------------------------------------------------------------------ // ClipperOffset support functions ... //------------------------------------------------------------------------------ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) { if(pt2.X == pt1.X && pt2.Y == pt1.Y) return DoublePoint(0, 0); double Dx = (double)(pt2.X - pt1.X); double dy = (double)(pt2.Y - pt1.Y); double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy ); Dx *= f; dy *= f; return DoublePoint(dy, -Dx); } //------------------------------------------------------------------------------ // ClipperOffset class //------------------------------------------------------------------------------ ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) { this->MiterLimit = miterLimit; this->ArcTolerance = arcTolerance; m_lowest.X = -1; } //------------------------------------------------------------------------------ ClipperOffset::~ClipperOffset() { Clear(); } //------------------------------------------------------------------------------ void ClipperOffset::Clear() { for (int i = 0; i < m_polyNodes.ChildCount(); ++i) delete m_polyNodes.Childs[i]; m_polyNodes.Childs.clear(); m_lowest.X = -1; } //------------------------------------------------------------------------------ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) { int highI = (int)path.size() - 1; if (highI < 0) return; PolyNode* newNode = new PolyNode(); newNode->m_jointype = joinType; newNode->m_endtype = endType; //strip duplicate points from path and also get index to the lowest point ... if (endType == etClosedLine || endType == etClosedPolygon) while (highI > 0 && path[0] == path[highI]) highI--; newNode->Contour.reserve(highI + 1); newNode->Contour.push_back(path[0]); int j = 0, k = 0; for (int i = 1; i <= highI; i++) if (newNode->Contour[j] != path[i]) { j++; newNode->Contour.push_back(path[i]); if (path[i].Y > newNode->Contour[k].Y || (path[i].Y == newNode->Contour[k].Y && path[i].X < newNode->Contour[k].X)) k = j; } if ((endType == etClosedPolygon && j < 2) || (endType != etClosedPolygon && j < 0)) { delete newNode; return; } m_polyNodes.AddChild(*newNode); //if this path's lowest pt is lower than all the others then update m_lowest if (endType != etClosedPolygon) return; if (m_lowest.X < 0) m_lowest = IntPoint(0, k); else { IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y]; if (newNode->Contour[k].Y > ip.Y || (newNode->Contour[k].Y == ip.Y && newNode->Contour[k].X < ip.X)) m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); } } //------------------------------------------------------------------------------ void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) { for (Paths::size_type i = 0; i < paths.size(); ++i) AddPath(paths[i], joinType, endType); } //------------------------------------------------------------------------------ void ClipperOffset::FixOrientations() { //fixup orientations of all closed paths if the orientation of the //closed path with the lowermost vertex is wrong ... if (m_lowest.X >= 0 && !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) { for (int i = 0; i < m_polyNodes.ChildCount(); ++i) { PolyNode& node = *m_polyNodes.Childs[i]; if (node.m_endtype == etClosedPolygon || (node.m_endtype == etClosedLine && Orientation(node.Contour))) ReversePath(node.Contour); } } else { for (int i = 0; i < m_polyNodes.ChildCount(); ++i) { PolyNode& node = *m_polyNodes.Childs[i]; if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) ReversePath(node.Contour); } } } //------------------------------------------------------------------------------ void ClipperOffset::Execute(Paths& solution, double delta) { solution.clear(); FixOrientations(); DoOffset(delta); //now clean up 'corners' ... Clipper clpr; clpr.AddPaths(m_destPolys, ptSubject, true); if (delta > 0) { clpr.Execute(ctUnion, solution, pftPositive, pftPositive); } else { IntRect r = clpr.GetBounds(); Path outer(4); outer[0] = IntPoint(r.left - 10, r.bottom + 10); outer[1] = IntPoint(r.right + 10, r.bottom + 10); outer[2] = IntPoint(r.right + 10, r.top - 10); outer[3] = IntPoint(r.left - 10, r.top - 10); clpr.AddPath(outer, ptSubject, true); clpr.ReverseSolution(true); clpr.Execute(ctUnion, solution, pftNegative, pftNegative); if (solution.size() > 0) solution.erase(solution.begin()); } } //------------------------------------------------------------------------------ void ClipperOffset::Execute(PolyTree& solution, double delta) { solution.Clear(); FixOrientations(); DoOffset(delta); //now clean up 'corners' ... Clipper clpr; clpr.AddPaths(m_destPolys, ptSubject, true); if (delta > 0) { clpr.Execute(ctUnion, solution, pftPositive, pftPositive); } else { IntRect r = clpr.GetBounds(); Path outer(4); outer[0] = IntPoint(r.left - 10, r.bottom + 10); outer[1] = IntPoint(r.right + 10, r.bottom + 10); outer[2] = IntPoint(r.right + 10, r.top - 10); outer[3] = IntPoint(r.left - 10, r.top - 10); clpr.AddPath(outer, ptSubject, true); clpr.ReverseSolution(true); clpr.Execute(ctUnion, solution, pftNegative, pftNegative); //remove the outer PolyNode rectangle ... if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) { PolyNode* outerNode = solution.Childs[0]; solution.Childs.reserve(outerNode->ChildCount()); solution.Childs[0] = outerNode->Childs[0]; for (int i = 1; i < outerNode->ChildCount(); ++i) solution.AddChild(*outerNode->Childs[i]); } else solution.Clear(); } } //------------------------------------------------------------------------------ void ClipperOffset::DoOffset(double delta) { m_destPolys.clear(); m_delta = delta; //if Zero offset, just copy any CLOSED polygons to m_p and return ... if (NEAR_ZERO(delta)) { m_destPolys.reserve(m_polyNodes.ChildCount()); for (int i = 0; i < m_polyNodes.ChildCount(); i++) { PolyNode& node = *m_polyNodes.Childs[i]; if (node.m_endtype == etClosedPolygon) m_destPolys.push_back(node.Contour); } return; } //see offset_triginometry3.svg in the documentation folder ... if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit); else m_miterLim = 0.5; double y; if (ArcTolerance <= 0.0) y = def_arc_tolerance; else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) y = std::fabs(delta) * def_arc_tolerance; else y = ArcTolerance; //see offset_triginometry2.svg in the documentation folder ... double steps = pi / std::acos(1 - y / std::fabs(delta)); if (steps > std::fabs(delta) * pi) steps = std::fabs(delta) * pi; //ie excessive precision check m_sin = std::sin(two_pi / steps); m_cos = std::cos(two_pi / steps); m_StepsPerRad = steps / two_pi; if (delta < 0.0) m_sin = -m_sin; m_destPolys.reserve(m_polyNodes.ChildCount() * 2); for (int i = 0; i < m_polyNodes.ChildCount(); i++) { PolyNode& node = *m_polyNodes.Childs[i]; m_srcPoly = node.Contour; int len = (int)m_srcPoly.size(); if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) continue; m_destPoly.clear(); if (len == 1) { if (node.m_jointype == jtRound) { double X = 1.0, Y = 0.0; for (cInt j = 1; j <= steps; j++) { m_destPoly.push_back(IntPoint( Round(m_srcPoly[0].X + X * delta), Round(m_srcPoly[0].Y + Y * delta))); double X2 = X; X = X * m_cos - m_sin * Y; Y = X2 * m_sin + Y * m_cos; } } else { double X = -1.0, Y = -1.0; for (int j = 0; j < 4; ++j) { m_destPoly.push_back(IntPoint( Round(m_srcPoly[0].X + X * delta), Round(m_srcPoly[0].Y + Y * delta))); if (X < 0) X = 1; else if (Y < 0) Y = 1; else X = -1; } } m_destPolys.push_back(m_destPoly); continue; } //build m_normals ... m_normals.clear(); m_normals.reserve(len); for (int j = 0; j < len - 1; ++j) m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); else m_normals.push_back(DoublePoint(m_normals[len - 2])); if (node.m_endtype == etClosedPolygon) { int k = len - 1; for (int j = 0; j < len; ++j) OffsetPoint(j, k, node.m_jointype); m_destPolys.push_back(m_destPoly); } else if (node.m_endtype == etClosedLine) { int k = len - 1; for (int j = 0; j < len; ++j) OffsetPoint(j, k, node.m_jointype); m_destPolys.push_back(m_destPoly); m_destPoly.clear(); //re-build m_normals ... DoublePoint n = m_normals[len -1]; for (int j = len - 1; j > 0; j--) m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); m_normals[0] = DoublePoint(-n.X, -n.Y); k = 0; for (int j = len - 1; j >= 0; j--) OffsetPoint(j, k, node.m_jointype); m_destPolys.push_back(m_destPoly); } else { int k = 0; for (int j = 1; j < len - 1; ++j) OffsetPoint(j, k, node.m_jointype); IntPoint pt1; if (node.m_endtype == etOpenButt) { int j = len - 1; pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); m_destPoly.push_back(pt1); pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); m_destPoly.push_back(pt1); } else { int j = len - 1; k = len - 2; m_sinA = 0; m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y); if (node.m_endtype == etOpenSquare) DoSquare(j, k); else DoRound(j, k); } //re-build m_normals ... for (int j = len - 1; j > 0; j--) m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y); k = len - 1; for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); if (node.m_endtype == etOpenButt) { pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); m_destPoly.push_back(pt1); pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); m_destPoly.push_back(pt1); } else { k = 1; m_sinA = 0; if (node.m_endtype == etOpenSquare) DoSquare(0, 1); else DoRound(0, 1); } m_destPolys.push_back(m_destPoly); } } } //------------------------------------------------------------------------------ void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) { m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); if (m_sinA < 0.00005 && m_sinA > -0.00005) return; else if (m_sinA > 1.0) m_sinA = 1.0; else if (m_sinA < -1.0) m_sinA = -1.0; if (m_sinA * m_delta < 0) { m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); m_destPoly.push_back(m_srcPoly[j]); m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); } else switch (jointype) { case jtMiter: { double r = 1 + (m_normals[j].X * m_normals[k].X + m_normals[j].Y * m_normals[k].Y); if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); break; } case jtSquare: DoSquare(j, k); break; case jtRound: DoRound(j, k); break; } k = j; } //------------------------------------------------------------------------------ void ClipperOffset::DoSquare(int j, int k) { double dx = std::tan(std::atan2(m_sinA, m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); m_destPoly.push_back(IntPoint( Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); m_destPoly.push_back(IntPoint( Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); } //------------------------------------------------------------------------------ void ClipperOffset::DoMiter(int j, int k, double r) { double q = m_delta / r; m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); } //------------------------------------------------------------------------------ void ClipperOffset::DoRound(int j, int k) { double a = std::atan2(m_sinA, m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); int steps = (int)Round(m_StepsPerRad * std::fabs(a)); double X = m_normals[k].X, Y = m_normals[k].Y, X2; for (int i = 0; i < steps; ++i) { m_destPoly.push_back(IntPoint( Round(m_srcPoly[j].X + X * m_delta), Round(m_srcPoly[j].Y + Y * m_delta))); X2 = X; X = X * m_cos - m_sin * Y; Y = X2 * m_sin + Y * m_cos; } m_destPoly.push_back(IntPoint( Round(m_srcPoly[j].X + m_normals[j].X * m_delta), Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); } //------------------------------------------------------------------------------ // Miscellaneous public functions //------------------------------------------------------------------------------ void Clipper::DoSimplePolygons() { PolyOutList::size_type i = 0; while (i < m_PolyOuts.size()) { OutRec* outrec = m_PolyOuts[i++]; OutPt* op = outrec->Pts; if (!op) continue; do //for each Pt in Polygon until duplicate found do ... { OutPt* op2 = op->Next; while (op2 != outrec->Pts) { if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) { //split the polygon into two ... OutPt* op3 = op->Prev; OutPt* op4 = op2->Prev; op->Prev = op4; op4->Next = op; op2->Prev = op3; op3->Next = op2; outrec->Pts = op; OutRec* outrec2 = CreateOutRec(); outrec2->Pts = op2; UpdateOutPtIdxs(*outrec2); if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) { //OutRec2 is contained by OutRec1 ... outrec2->IsHole = !outrec->IsHole; outrec2->FirstLeft = outrec; } else if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) { //OutRec1 is contained by OutRec2 ... outrec2->IsHole = outrec->IsHole; outrec->IsHole = !outrec2->IsHole; outrec2->FirstLeft = outrec->FirstLeft; outrec->FirstLeft = outrec2; } else { //the 2 polygons are separate ... outrec2->IsHole = outrec->IsHole; outrec2->FirstLeft = outrec->FirstLeft; } op2 = op; //ie get ready for the Next iteration } op2 = op2->Next; } op = op->Next; } while (op != outrec->Pts); } } //------------------------------------------------------------------------------ void ReversePath(Path& p) { std::reverse(p.begin(), p.end()); } //------------------------------------------------------------------------------ void ReversePaths(Paths& p) { for (Paths::size_type i = 0; i < p.size(); ++i) ReversePath(p[i]); } //------------------------------------------------------------------------------ void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) { Clipper c; c.StrictlySimple(true); c.AddPath(in_poly, ptSubject, true); c.Execute(ctUnion, out_polys, fillType, fillType); } //------------------------------------------------------------------------------ void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) { Clipper c; c.StrictlySimple(true); c.AddPaths(in_polys, ptSubject, true); c.Execute(ctUnion, out_polys, fillType, fillType); } //------------------------------------------------------------------------------ void SimplifyPolygons(Paths &polys, PolyFillType fillType) { SimplifyPolygons(polys, polys, fillType); } //------------------------------------------------------------------------------ inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) { double Dx = ((double)pt1.X - pt2.X); double dy = ((double)pt1.Y - pt2.Y); return (Dx*Dx + dy*dy); } //------------------------------------------------------------------------------ double DistanceFromLineSqrd( const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) { //The equation of a line in general form (Ax + By + C = 0) //given 2 points (x,y) & (x,y) is ... //(y - y)x + (x - x)y + (y - y)x - (x - x)y = 0 //A = (y - y); B = (x - x); C = (y - y)x - (x - x)y //perpendicular distance of point (x,y) = (Ax + By + C)/Sqrt(A + B) //see http://en.wikipedia.org/wiki/Perpendicular_distance double A = double(ln1.Y - ln2.Y); double B = double(ln2.X - ln1.X); double C = A * ln1.X + B * ln1.Y; C = A * pt.X + B * pt.Y - C; return (C * C) / (A * A + B * B); } //--------------------------------------------------------------------------- bool SlopesNearCollinear(const IntPoint& pt1, const IntPoint& pt2, const IntPoint& pt3, double distSqrd) { return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; } //------------------------------------------------------------------------------ bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) { double Dx = (double)pt1.X - pt2.X; double dy = (double)pt1.Y - pt2.Y; return ((Dx * Dx) + (dy * dy) <= distSqrd); } //------------------------------------------------------------------------------ OutPt* ExcludeOp(OutPt* op) { OutPt* result = op->Prev; result->Next = op->Next; op->Next->Prev = result; result->Idx = 0; return result; } //------------------------------------------------------------------------------ void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) { //distance = proximity in units/pixels below which vertices //will be stripped. Default ~= sqrt(2). size_t size = in_poly.size(); if (size == 0) { out_poly.clear(); return; } OutPt* outPts = new OutPt[size]; for (size_t i = 0; i < size; ++i) { outPts[i].Pt = in_poly[i]; outPts[i].Next = &outPts[(i + 1) % size]; outPts[i].Next->Prev = &outPts[i]; outPts[i].Idx = 0; } double distSqrd = distance * distance; OutPt* op = &outPts[0]; while (op->Idx == 0 && op->Next != op->Prev) { if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) { op = ExcludeOp(op); size--; } else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) { ExcludeOp(op->Next); op = ExcludeOp(op); size -= 2; } else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) { op = ExcludeOp(op); size--; } else { op->Idx = 1; op = op->Next; } } if (size < 3) size = 0; out_poly.resize(size); for (size_t i = 0; i < size; ++i) { out_poly[i] = op->Pt; op = op->Next; } delete [] outPts; } //------------------------------------------------------------------------------ void CleanPolygon(Path& poly, double distance) { CleanPolygon(poly, poly, distance); } //------------------------------------------------------------------------------ void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) { for (Paths::size_type i = 0; i < in_polys.size(); ++i) CleanPolygon(in_polys[i], out_polys[i], distance); } //------------------------------------------------------------------------------ void CleanPolygons(Paths& polys, double distance) { CleanPolygons(polys, polys, distance); } //------------------------------------------------------------------------------ void Minkowski(const Path& poly, const Path& path, Paths& solution, bool isSum, bool isClosed) { int delta = (isClosed ? 1 : 0); size_t polyCnt = poly.size(); size_t pathCnt = path.size(); Paths pp; pp.reserve(pathCnt); if (isSum) for (size_t i = 0; i < pathCnt; ++i) { Path p; p.reserve(polyCnt); for (size_t j = 0; j < poly.size(); ++j) p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y)); pp.push_back(p); } else for (size_t i = 0; i < pathCnt; ++i) { Path p; p.reserve(polyCnt); for (size_t j = 0; j < poly.size(); ++j) p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y)); pp.push_back(p); } Paths quads; quads.reserve((pathCnt + delta) * (polyCnt + 1)); for (size_t i = 0; i < pathCnt - 1 + delta; ++i) for (size_t j = 0; j < polyCnt; ++j) { Path quad; quad.reserve(4); quad.push_back(pp[i % pathCnt][j % polyCnt]); quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]); quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]); if (!Orientation(quad)) ReversePath(quad); quads.push_back(quad); } Clipper c; c.AddPaths(quads, ptSubject, true); c.Execute(ctUnion, solution, pftNonZero, pftNonZero); } //------------------------------------------------------------------------------ void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) { Minkowski(pattern, path, solution, true, pathIsClosed); } //------------------------------------------------------------------------------ void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, PolyFillType pathFillType, bool pathIsClosed) { Clipper c; for (size_t i = 0; i < paths.size(); ++i) { Paths tmp; Minkowski(pattern, paths[i], tmp, true, pathIsClosed); c.AddPaths(tmp, ptSubject, true); } if (pathIsClosed) c.AddPaths(paths, ptClip, true); c.Execute(ctUnion, solution, pathFillType, pathFillType); } //------------------------------------------------------------------------------ void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) { Minkowski(poly1, poly2, solution, false, true); } //------------------------------------------------------------------------------ enum NodeType {ntAny, ntOpen, ntClosed}; void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& paths) { bool match = true; if (nodetype == ntClosed) match = !polynode.IsOpen(); else if (nodetype == ntOpen) return; if (!polynode.Contour.empty() && match) paths.push_back(polynode.Contour); for (int i = 0; i < polynode.ChildCount(); ++i) AddPolyNodeToPolygons(*polynode.Childs[i], nodetype, paths); } //------------------------------------------------------------------------------ void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) { paths.resize(0); paths.reserve(polytree.Total()); AddPolyNodeToPolygons(polytree, ntAny, paths); } //------------------------------------------------------------------------------ void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) { paths.resize(0); paths.reserve(polytree.Total()); AddPolyNodeToPolygons(polytree, ntClosed, paths); } //------------------------------------------------------------------------------ void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) { paths.resize(0); paths.reserve(polytree.Total()); //Open paths are top level only, so ... for (int i = 0; i < polytree.ChildCount(); ++i) if (polytree.Childs[i]->IsOpen()) paths.push_back(polytree.Childs[i]->Contour); } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, const IntPoint &p) { s << "(" << p.X << "," << p.Y << ")"; return s; } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, const Path &p) { if (p.empty()) return s; Path::size_type last = p.size() -1; for (Path::size_type i = 0; i < last; i++) s << "(" << p[i].X << "," << p[i].Y << "), "; s << "(" << p[last].X << "," << p[last].Y << ")\n"; return s; } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, const Paths &p) { for (Paths::size_type i = 0; i < p.size(); i++) s << p[i]; s << "\n"; return s; } //------------------------------------------------------------------------------ #ifdef use_deprecated void OffsetPaths(const Paths &in_polys, Paths &out_polys, double delta, JoinType jointype, EndType_ endtype, double limit) { ClipperOffset co(limit, limit); co.AddPaths(in_polys, jointype, (EndType)endtype); co.Execute(out_polys, delta); } //------------------------------------------------------------------------------ #endif } //ClipperLib namespace repsnapper-2.3.2a5/libraries/clipper/clipper/polyclipping-code/cpp/clipper.hpp000066400000000000000000000355241231531733200275560ustar00rootroot00000000000000/******************************************************************************* * * * Author : Angus Johnson * * Version : 6.1.3a * * Date : 22 January 2014 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2014 * * * * License: * * Use, modification & distribution is subject to Boost Software License Ver 1. * * http://www.boost.org/LICENSE_1_0.txt * * * * Attributions: * * The code in this library is an extension of Bala Vatti's clipping algorithm: * * "A generic solution to polygon clipping" * * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * * http://portal.acm.org/citation.cfm?id=129906 * * * * Computer graphics and geometric modeling: implementation and algorithms * * By Max K. Agoston * * Springer; 1 edition (January 4, 2005) * * http://books.google.com/books?q=vatti+clipping+agoston * * * * See also: * * "Polygon Offsetting by Computing Winding Numbers" * * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * * September 24-28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ #ifndef clipper_hpp #define clipper_hpp #define CLIPPER_VERSION "6.1.3" //use_int32: When enabled 32bit ints are used instead of 64bit ints. This //improve performance but coordinate values are limited to the range +/- 46340 //#define use_int32 //use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. //#define use_xyz //use_lines: Enables line clipping. Adds a very minor cost to performance. //#define use_lines //use_deprecated: Enables support for the obsolete OffsetPaths() function //which has been replace with the ClipperOffset class. #define use_deprecated #include #include #include #include #include #include #include namespace ClipperLib { enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; enum PolyType { ptSubject, ptClip }; //By far the most widely used winding rules for polygon filling are //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) //see http://glprogramming.com/red/chapter11.html enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; #ifdef use_int32 typedef int cInt; typedef unsigned int cUInt; #else typedef signed long long cInt; typedef unsigned long long cUInt; #endif struct IntPoint { cInt X; cInt Y; #ifdef use_xyz cInt Z; IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; #else IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; #endif friend inline bool operator== (const IntPoint& a, const IntPoint& b) { return a.X == b.X && a.Y == b.Y; } friend inline bool operator!= (const IntPoint& a, const IntPoint& b) { return a.X != b.X || a.Y != b.Y; } }; //------------------------------------------------------------------------------ typedef std::vector< IntPoint > Path; typedef std::vector< Path > Paths; inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} std::ostream& operator <<(std::ostream &s, const IntPoint &p); std::ostream& operator <<(std::ostream &s, const Path &p); std::ostream& operator <<(std::ostream &s, const Paths &p); struct DoublePoint { double X; double Y; DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} }; //------------------------------------------------------------------------------ #ifdef use_xyz typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt); #endif enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; enum JoinType {jtSquare, jtRound, jtMiter}; enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; #ifdef use_deprecated enum EndType_ {etClosed, etButt = 2, etSquare, etRound}; #endif class PolyNode; typedef std::vector< PolyNode* > PolyNodes; class PolyNode { public: PolyNode(); Path Contour; PolyNodes Childs; PolyNode* Parent; PolyNode* GetNext() const; bool IsHole() const; bool IsOpen() const; int ChildCount() const; private: unsigned Index; //node index in Parent.Childs bool m_IsOpen; JoinType m_jointype; EndType m_endtype; PolyNode* GetNextSiblingUp() const; void AddChild(PolyNode& child); friend class Clipper; //to access Index friend class ClipperOffset; }; class PolyTree: public PolyNode { public: ~PolyTree(){Clear();}; PolyNode* GetFirst() const; void Clear(); int Total() const; private: PolyNodes AllNodes; friend class Clipper; //to access AllNodes }; bool Orientation(const Path &poly); double Area(const Path &poly); int PointInPolygon(const IntPoint &pt, const Path &path); #ifdef use_deprecated void OffsetPaths(const Paths &in_polys, Paths &out_polys, double delta, JoinType jointype, EndType_ endtype, double limit = 0); #endif void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); void CleanPolygon(Path& poly, double distance = 1.415); void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); void CleanPolygons(Paths& polys, double distance = 1.415); void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, PolyFillType pathFillType, bool pathIsClosed); void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); void ReversePath(Path& p); void ReversePaths(Paths& p); struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; //enums that are used internally ... enum EdgeSide { esLeft = 1, esRight = 2}; //forward declarations (for stuff used internally) ... struct TEdge; struct IntersectNode; struct LocalMinima; struct Scanbeam; struct OutPt; struct OutRec; struct Join; typedef std::vector < OutRec* > PolyOutList; typedef std::vector < TEdge* > EdgeList; typedef std::vector < Join* > JoinList; typedef std::vector < IntersectNode* > IntersectList; //------------------------------------------------------------------------------ //ClipperBase is the ancestor to the Clipper class. It should not be //instantiated directly. This class simply abstracts the conversion of sets of //polygon coordinates into edge objects that are stored in a LocalMinima list. class ClipperBase { public: ClipperBase(); virtual ~ClipperBase(); bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); virtual void Clear(); IntRect GetBounds(); bool PreserveCollinear() {return m_PreserveCollinear;}; void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; protected: void DisposeLocalMinimaList(); TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); void PopLocalMinima(); virtual void Reset(); TEdge* ProcessBound(TEdge* E, bool IsClockwise); void InsertLocalMinima(LocalMinima *newLm); void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed); TEdge* DescendToMin(TEdge *&E); void AscendToMax(TEdge *&E, bool Appending, bool IsClosed); LocalMinima *m_CurrentLM; LocalMinima *m_MinimaList; bool m_UseFullRange; EdgeList m_edges; bool m_PreserveCollinear; bool m_HasOpenPaths; }; //------------------------------------------------------------------------------ class Clipper : public virtual ClipperBase { public: Clipper(int initOptions = 0); ~Clipper(); bool Execute(ClipType clipType, Paths &solution, PolyFillType subjFillType = pftEvenOdd, PolyFillType clipFillType = pftEvenOdd); bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType subjFillType = pftEvenOdd, PolyFillType clipFillType = pftEvenOdd); bool ReverseSolution() {return m_ReverseOutput;}; void ReverseSolution(bool value) {m_ReverseOutput = value;}; bool StrictlySimple() {return m_StrictSimple;}; void StrictlySimple(bool value) {m_StrictSimple = value;}; //set the callback function for z value filling on intersections (otherwise Z is 0) #ifdef use_xyz void ZFillFunction(TZFillCallback zFillFunc); #endif protected: void Reset(); virtual bool ExecuteInternal(); private: PolyOutList m_PolyOuts; JoinList m_Joins; JoinList m_GhostJoins; IntersectList m_IntersectList; ClipType m_ClipType; std::set< cInt, std::greater > m_Scanbeam; TEdge *m_ActiveEdges; TEdge *m_SortedEdges; bool m_ExecuteLocked; PolyFillType m_ClipFillType; PolyFillType m_SubjFillType; bool m_ReverseOutput; bool m_UsingPolyTree; bool m_StrictSimple; #ifdef use_xyz TZFillCallback m_ZFill; //custom callback #endif void SetWindingCount(TEdge& edge); bool IsEvenOddFillType(const TEdge& edge) const; bool IsEvenOddAltFillType(const TEdge& edge) const; void InsertScanbeam(const cInt Y); cInt PopScanbeam(); void InsertLocalMinimaIntoAEL(const cInt botY); void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); void AddEdgeToSEL(TEdge *edge); void CopyAELToSEL(); void DeleteFromSEL(TEdge *e); void DeleteFromAEL(TEdge *e); void UpdateEdgeIntoAEL(TEdge *&e); void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); bool IsContributing(const TEdge& edge) const; bool IsTopHorz(const cInt XPos); void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); void DoMaxima(TEdge *e); void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam); void ProcessHorizontals(bool IsTopOfScanbeam); void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam); void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); OutRec* GetOutRec(int idx); void AppendPolygon(TEdge *e1, TEdge *e2); void IntersectEdges(TEdge *e1, TEdge *e2, const IntPoint &pt, bool protect = false); OutRec* CreateOutRec(); OutPt* AddOutPt(TEdge *e, const IntPoint &pt); void DisposeAllOutRecs(); void DisposeOutRec(PolyOutList::size_type index); bool ProcessIntersections(const cInt botY, const cInt topY); void BuildIntersectList(const cInt botY, const cInt topY); void ProcessIntersectList(); void ProcessEdgesAtTopOfScanbeam(const cInt topY); void BuildResult(Paths& polys); void BuildResult2(PolyTree& polytree); void SetHoleState(TEdge *e, OutRec *outrec); void DisposeIntersectNodes(); bool FixupIntersectionOrder(); void FixupOutPolygon(OutRec &outrec); bool IsHole(TEdge *e); bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); void FixHoleLinkage(OutRec &outrec); void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); void ClearJoins(); void ClearGhostJoins(); void AddGhostJoin(OutPt *op, const IntPoint offPt); bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); void JoinCommonEdges(); void DoSimplePolygons(); void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec); #ifdef use_xyz void SetZ(IntPoint& pt, TEdge& e); #endif }; //------------------------------------------------------------------------------ class ClipperOffset { public: ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); ~ClipperOffset(); void AddPath(const Path& path, JoinType joinType, EndType endType); void AddPaths(const Paths& paths, JoinType joinType, EndType endType); void Execute(Paths& solution, double delta); void Execute(PolyTree& solution, double delta); void Clear(); double MiterLimit; double ArcTolerance; private: Paths m_destPolys; Path m_srcPoly; Path m_destPoly; std::vector m_normals; double m_delta, m_sinA, m_sin, m_cos; double m_miterLim, m_StepsPerRad; IntPoint m_lowest; PolyNode m_polyNodes; void FixOrientations(); void DoOffset(double delta); void OffsetPoint(int j, int& k, JoinType jointype); void DoSquare(int j, int k); void DoMiter(int j, int k, double r); void DoRound(int j, int k); }; //------------------------------------------------------------------------------ class clipperException : public std::exception { public: clipperException(const char* description): m_descr(description) {} virtual ~clipperException() throw() {} virtual const char* what() const throw() {return m_descr.c_str();} private: std::string m_descr; }; //------------------------------------------------------------------------------ } //ClipperLib namespace #endif //clipper_hpp repsnapper-2.3.2a5/libraries/lmfit/000077500000000000000000000000001231531733200172125ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/lmfit/Makefile.am000066400000000000000000000005231231531733200212460ustar00rootroot00000000000000noinst_LTLIBRARIES += liblmfit.la liblmfit_la_CPPFLAGS = \ -I$(srcdir) \ -I$(top_srcdir)/libraries/lmfit/lmfit-5.0/lib \ $(EXTRA_CFLAGS) liblmfit_la_SOURCES = \ libraries/lmfit/lmfit-5.0/lib/lmmin.c \ libraries/lmfit/lmfit-5.0/lib/lmmin.h \ libraries/lmfit/lmfit-5.0/lib/lmcurve.c \ libraries/lmfit/lmfit-5.0/lib/lmcurve.h repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/000077500000000000000000000000001231531733200206255ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/COPYING000066400000000000000000000010671231531733200216640ustar00rootroot00000000000000lmfit is released under the LMFIT-BEER-WARE licence: In writing this software, I borrowed heavily from the public domain, especially from work by Burton S. Garbow, Kenneth E. Hillstrom, Jorge J. Moré, Steve Moshier, and the authors of lapack. To avoid unneccessary complications, I put my additions and amendments also into the public domain. Please retain this notice. Otherwise feel free to do whatever you want with this stuff. If we meet some day, and you think this work is worth it, you can buy me a beer in return. - Joachim Wuttke repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/000077500000000000000000000000001231531733200213735ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/Makefile.am000066400000000000000000000002411231531733200234240ustar00rootroot00000000000000include_HEADERS = lmmin.h lib_LTLIBRARIES = liblmmin.la liblmmin_la_SOURCES = lmmin.c lmmin.h lmcurve.c lmcurve.h liblmmin_la_LDFLAGS = -version-info $(VERSION) repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/lmcurve.c000066400000000000000000000023251231531733200232160ustar00rootroot00000000000000/* * Library: lmfit (Levenberg-Marquardt least squares fitting) * * File: lmcurve.c * * Contents: Levenberg-Marquardt curve-fitting * * Copyright: Joachim Wuttke, Forschungszentrum Juelich GmbH (2004-2013) * * License: see ../COPYING (FreeBSD) * * Homepage: apps.jcns.fz-juelich.de/lmfit */ #include "lmmin.h" typedef struct { const double *t; const double *y; double (*f) (double t, const double *par); } lmcurve_data_struct; void lmcurve_evaluate( const double *par, int m_dat, const void *data, double *fvec, int *info ) { int i; for ( i = 0; i < m_dat; i++ ) fvec[i] = ((lmcurve_data_struct*)data)->y[i] - ((lmcurve_data_struct*)data)->f( ((lmcurve_data_struct*)data)->t[i], par ); } void lmcurve( int n_par, double *par, int m_dat, const double *t, const double *y, double (*f)( double t, const double *par ), const lm_control_struct *control, lm_status_struct *status ) { lmcurve_data_struct data; data.t = t; data.y = y; data.f = f; lmmin( n_par, par, m_dat, (const void*) &data, lmcurve_evaluate, control, status ); } repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/lmcurve.h000066400000000000000000000013341231531733200232220ustar00rootroot00000000000000/* * Library: lmfit (Levenberg-Marquardt least squares fitting) * * File: lmcurve.h * * Contents: Declarations for Levenberg-Marquardt curve fitting. * * Copyright: Joachim Wuttke, Forschungszentrum Juelich GmbH (2004-2013) * * License: see ../COPYING (FreeBSD) * * Homepage: apps.jcns.fz-juelich.de/lmfit */ #ifndef LMCURVE_H #define LMCURVE_H #include #ifdef __cplusplus extern "C" { #endif void lmcurve( int n_par, double *par, int m_dat, const double *t, const double *y, double (*f)( double t, const double *par ), const lm_control_struct *control, lm_status_struct *status ); #ifdef __cplusplus } #endif #endif /* LMCURVE_H */ repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/lmmin.c000066400000000000000000001136351231531733200226640ustar00rootroot00000000000000/* * Library: lmfit (Levenberg-Marquardt least squares fitting) * * File: lmmin.c * * Contents: Levenberg-Marquardt minimization. * * Copyright: MINPACK authors, The University of Chikago (1980-1999) * Joachim Wuttke, Forschungszentrum Juelich GmbH (2004-2013) * * License: see ../COPYING (FreeBSD) * * Homepage: apps.jcns.fz-juelich.de/lmfit */ #include #include #include #include #include "lmmin.h" #define MIN(a,b) (((a)<=(b)) ? (a) : (b)) #define MAX(a,b) (((a)>=(b)) ? (a) : (b)) #define SQR(x) (x)*(x) /* function declarations (implemented below). */ void lm_lmpar( int n, double *r, int ldr, int *ipvt, double *diag, double *qtb, double delta, double *par, double *x, double *sdiag, double *aux, double *xdi ); void lm_qrfac( int m, int n, double *a, int *ipvt, double *rdiag, double *acnorm, double *wa ); void lm_qrsolv( int n, double *r, int ldr, int *ipvt, double *diag, double *qtb, double *x, double *sdiag, double *wa ); /*****************************************************************************/ /* Numeric constants */ /*****************************************************************************/ /* machine-dependent constants from float.h */ #define LM_MACHEP DBL_EPSILON /* resolution of arithmetic */ #define LM_DWARF DBL_MIN /* smallest nonzero number */ #define LM_SQRT_DWARF sqrt(DBL_MIN) /* square should not underflow */ #define LM_SQRT_GIANT sqrt(DBL_MAX) /* square should not overflow */ #define LM_USERTOL 30*LM_MACHEP /* users are recommended to require this */ /* If the above values do not work, the following seem good for an x86: LM_MACHEP .555e-16 LM_DWARF 9.9e-324 LM_SQRT_DWARF 1.e-160 LM_SQRT_GIANT 1.e150 LM_USER_TOL 1.e-14 The following values should work on any machine: LM_MACHEP 1.2e-16 LM_DWARF 1.0e-38 LM_SQRT_DWARF 3.834e-20 LM_SQRT_GIANT 1.304e19 LM_USER_TOL 1.e-14 */ #ifndef WIN32 const lm_control_struct lm_control_double = { LM_USERTOL, LM_USERTOL, LM_USERTOL, LM_USERTOL, 100., 100, 1, &stdout, 0, -1, -1 }; const lm_control_struct lm_control_float = { 1.e-7, 1.e-7, 1.e-7, 1.e-7, 100., 100, 1, &stdout, 0, -1, -1 }; #else const lm_control_struct lm_control_double = { LM_USERTOL, LM_USERTOL, LM_USERTOL, LM_USERTOL, 100., 100, 1, NULL, 0, -1, -1 }; const lm_control_struct lm_control_float = { 1.e-7, 1.e-7, 1.e-7, 1.e-7, 100., 100, 1, NULL, 0, -1, -1 }; #endif /*****************************************************************************/ /* Message texts (indexed by status.info) */ /*****************************************************************************/ const char *lm_infmsg[] = { "found zero (sum of squares below underflow limit)", "converged (the relative error in the sum of squares is at most tol)", "converged (the relative error of the parameter vector is at most tol)", "converged (both errors are at most tol)", "trapped (by degeneracy; increasing epsilon might help)", "exhausted (number of function calls exceeding preset patience)", "failed (ftolstream), " %16.9g", par[i] ); fprintf( *(C->stream), " => %18.11g\n", fnorm ); } /*****************************************************************************/ /* lmmin (main minimization routine) */ /*****************************************************************************/ void lmmin( int n, double *x, int m, const void *data, void (*evaluate) (const double *par, int m_dat, const void *data, double *fvec, int *userbreak), const lm_control_struct *C, lm_status_struct *S ) { double *fvec, *diag, *fjac, *qtf, *wa1, *wa2, *wa3, *wf; int *ipvt; int j, i; double actred, dirder, fnorm, fnorm1, gnorm, pnorm, prered, ratio, step, sum, temp, temp1, temp2, temp3; static double p0001 = 1.0e-4; int maxfev = C->patience * (n+1); int outer, inner; /* loop counters, for monitoring */ int inner_success; /* flag for loop control */ double lmpar = 0; /* Levenberg-Marquardt parameter */ double delta = 0; double xnorm = 0; double eps = sqrt(MAX(C->epsilon, LM_MACHEP)); /* for forward differences */ int nout = C->n_maxpri==-1 ? n : MIN( C->n_maxpri, n ); S->outcome = 0; /* status code */ S->userbreak = 0; S->nfev = 0; /* function evaluation counter */ /*** Check input parameters for errors. ***/ if ( n <= 0 ) { fprintf( stderr, "lmmin: invalid number of parameters %i\n", n ); S->outcome = 10; /* invalid parameter */ return; } if (m < n) { fprintf( stderr, "lmmin: number of data points (%i) " "smaller than number of parameters (%i)\n", m, n ); S->outcome = 10; return; } if (C->ftol < 0. || C->xtol < 0. || C->gtol < 0.) { fprintf( stderr, "lmmin: negative tolerance (at least one of %g %g %g)\n", C->ftol, C->xtol, C->gtol ); S->outcome = 10; return; } if (maxfev <= 0) { fprintf( stderr, "lmmin: nonpositive function evaluations limit %i\n", maxfev ); S->outcome = 10; return; } if (C->stepbound <= 0.) { fprintf( stderr, "lmmin: nonpositive stepbound %g\n", C->stepbound ); S->outcome = 10; return; } if (C->scale_diag != 0 && C->scale_diag != 1) { fprintf( stderr, "lmmin: logical variable scale_diag=%i, " "should be 0 or 1\n", C->scale_diag ); S->outcome = 10; return; } /*** Allocate work space. ***/ if ( (fvec = (double *) malloc(m * sizeof(double))) == NULL || (diag = (double *) malloc(n * sizeof(double))) == NULL || (qtf = (double *) malloc(n * sizeof(double))) == NULL || (fjac = (double *) malloc(n*m*sizeof(double))) == NULL || (wa1 = (double *) malloc(n * sizeof(double))) == NULL || (wa2 = (double *) malloc(n * sizeof(double))) == NULL || (wa3 = (double *) malloc(n * sizeof(double))) == NULL || (wf = (double *) malloc(m * sizeof(double))) == NULL || (ipvt = (int *) malloc(n * sizeof(int) )) == NULL ) { S->outcome = 9; return; } if (!C->scale_diag) { for (j = 0; j < n; j++) diag[j] = 1.; } /*** Evaluate function at starting point and calculate norm. ***/ (*evaluate)( x, m, data, fvec, &(S->userbreak) ); S->nfev = 1; if ( S->userbreak ) goto terminate; fnorm = lm_enorm(m, fvec); if( C->verbosity ) { fprintf( *(C->stream), "lmmin start " ); lm_print_pars( nout, x, fnorm, C ); } if( fnorm <= LM_DWARF ){ S->outcome = 0; /* sum of squares almost zero, nothing to do */ goto terminate; } /*** The outer loop: compute gradient, then descend. ***/ for( outer=0; ; ++outer ) { /*** [outer] Calculate the Jacobian. ***/ for (j = 0; j < n; j++) { temp = x[j]; step = MAX(eps*eps, eps * fabs(temp)); x[j] += step; /* replace temporarily */ (*evaluate)( x, m, data, wf, &(S->userbreak) ); ++(S->nfev); if ( S->userbreak ) goto terminate; for (i = 0; i < m; i++) fjac[j*m+i] = (wf[i] - fvec[i]) / step; x[j] = temp; /* restore */ } if ( C->verbosity >=10 ) { /* print the entire matrix */ printf("\nlmmin Jacobian\n"); for (i = 0; i < m; i++) { printf(" "); for (j = 0; j < n; j++) printf("%.5e ", fjac[j*m+i]); printf("\n"); } } /*** [outer] Compute the QR factorization of the Jacobian. ***/ /* fjac is an m by n array. The upper n by n submatrix of fjac * is made to contain an upper triangular matrix r with diagonal * elements of nonincreasing magnitude such that * * p^T*(jac^T*jac)*p = r^T*r * * (NOTE: ^T stands for matrix transposition), * * where p is a permutation matrix and jac is the final calculated * Jacobian. Column j of p is column ipvt(j) of the identity matrix. * The lower trapezoidal part of fjac contains information generated * during the computation of r. * * ipvt is an integer array of length n. It defines a permutation * matrix p such that jac*p = q*r, where jac is the final calculated * Jacobian, q is orthogonal (not stored), and r is upper triangular * with diagonal elements of nonincreasing magnitude. Column j of p * is column ipvt(j) of the identity matrix. */ lm_qrfac(m, n, fjac, ipvt, wa1, wa2, wa3); /* return values are ipvt, wa1=rdiag, wa2=acnorm */ /*** [outer] Form q^T * fvec and store first n components in qtf. ***/ for (i = 0; i < m; i++) wf[i] = fvec[i]; for (j = 0; j < n; j++) { temp3 = fjac[j*m+j]; if (temp3 != 0.) { sum = 0; for (i = j; i < m; i++) sum += fjac[j*m+i] * wf[i]; temp = -sum / temp3; for (i = j; i < m; i++) wf[i] += fjac[j*m+i] * temp; } fjac[j*m+j] = wa1[j]; qtf[j] = wf[j]; } /*** [outer] Compute norm of scaled gradient and detect degeneracy. ***/ gnorm = 0; for (j = 0; j < n; j++) { if (wa2[ipvt[j]] == 0) continue; sum = 0.; for (i = 0; i <= j; i++) sum += fjac[j*m+i] * qtf[i]; gnorm = MAX( gnorm, fabs( sum / wa2[ipvt[j]] / fnorm ) ); } if (gnorm <= C->gtol) { S->outcome = 4; goto terminate; } /*** [outer] Initialize / update diag and delta. ***/ if ( !outer ) { /* first iteration only */ if (C->scale_diag) { /* diag := norms of the columns of the initial Jacobian */ for (j = 0; j < n; j++) diag[j] = wa2[j] ? wa2[j] : 1; /* xnorm := || D x || */ for (j = 0; j < n; j++) wa3[j] = diag[j] * x[j]; xnorm = lm_enorm(n, wa3); if( C->verbosity >= 2 ) { fprintf( *(C->stream), "lmmin diag " ); lm_print_pars( nout, x, xnorm, C ); } /* only now print the header for the loop table */ if( C->verbosity >=3 ) { fprintf( *(C->stream), " o i lmpar prered" " ratio dirder delta" " pnorm fnorm" ); for (i = 0; i < nout; ++i) fprintf( *(C->stream), " p%i", i ); fprintf( *(C->stream), "\n" ); } } else { xnorm = lm_enorm(n, x); } /* initialize the step bound delta. */ if ( xnorm ) delta = C->stepbound * xnorm; else delta = C->stepbound; } else { if (C->scale_diag) { for (j = 0; j < n; j++) diag[j] = MAX( diag[j], wa2[j] ); } } /*** The inner loop. ***/ inner = 0; do { /*** [inner] Determine the Levenberg-Marquardt parameter. ***/ lm_lmpar( n, fjac, m, ipvt, diag, qtf, delta, &lmpar, wa1, wa2, wf, wa3 ); /* used return values are fjac (partly), lmpar, wa1=x, wa3=diag*x */ /* predict scaled reduction */ pnorm = lm_enorm(n, wa3); temp2 = lmpar * SQR( pnorm / fnorm ); for (j = 0; j < n; j++) { wa3[j] = 0; for (i = 0; i <= j; i++) wa3[i] -= fjac[j*m+i] * wa1[ipvt[j]]; } temp1 = SQR( lm_enorm(n, wa3) / fnorm ); prered = temp1 + 2 * temp2; dirder = -temp1 + temp2; /* scaled directional derivative */ /* at first call, adjust the initial step bound. */ if ( !outer && pnorm < delta ) delta = pnorm; /*** [inner] Evaluate the function at x + p. ***/ for (j = 0; j < n; j++) wa2[j] = x[j] - wa1[j]; (*evaluate)( wa2, m, data, wf, &(S->userbreak) ); ++(S->nfev); if ( S->userbreak ) goto terminate; fnorm1 = lm_enorm(m, wf); /*** [inner] Evaluate the scaled reduction. ***/ /* actual scaled reduction */ actred = 1 - SQR(fnorm1/fnorm); /* ratio of actual to predicted reduction */ ratio = prered ? actred/prered : 0; if( C->verbosity == 2 ) { fprintf( *(C->stream), "lmmin (%i:%i) ", outer, inner ); lm_print_pars( nout, wa2, fnorm1, C ); } else if( C->verbosity >= 3 ) { printf( "%3i %2i %9.2g %9.2g %14.6g" " %9.2g %10.3e %10.3e %21.15e", outer, inner, lmpar, prered, ratio, dirder, delta, pnorm, fnorm1 ); for (i = 0; i < nout; ++i) fprintf( *(C->stream), " %16.9g", wa2[i] ); fprintf( *(C->stream), "\n" ); } /* update the step bound */ if ( ratio <= 0.25 ) { if ( actred >= 0 ) temp = 0.5; else if ( actred > -99 ) /* -99 = 1-1/0.1^2 */ temp = MAX( dirder / (2*dirder + actred), 0.1 ); else temp = 0.1; delta = temp * MIN(delta, pnorm / 0.1); lmpar /= temp; } else if ( ratio >= 0.75 ) { delta = 2*pnorm; lmpar *= 0.5; } else if ( !lmpar ) { delta = 2*pnorm; } /*** [inner] On success, update solution, and test for convergence. ***/ inner_success = ratio >= p0001; if ( inner_success ) { /* update x, fvec, and their norms */ if (C->scale_diag) { for (j = 0; j < n; j++) { x[j] = wa2[j]; wa2[j] = diag[j] * x[j]; } } else { for (j = 0; j < n; j++) x[j] = wa2[j]; } for (i = 0; i < m; i++) fvec[i] = wf[i]; xnorm = lm_enorm(n, wa2); fnorm = fnorm1; } /* convergence tests */ S->outcome = 0; if( fnorm<=LM_DWARF ) goto terminate; /* success: sum of squares almost zero */ /* test two criteria (both may be fulfilled) */ if (fabs(actred) <= C->ftol && prered <= C->ftol && ratio <= 2) S->outcome = 1; /* success: x almost stable */ if (delta <= C->xtol * xnorm) S->outcome += 2; /* success: sum of squares almost stable */ if (S->outcome != 0) { goto terminate; } /*** [inner] Tests for termination and stringent tolerances. ***/ if ( S->nfev >= maxfev ){ S->outcome = 5; goto terminate; } if ( fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && ratio <= 2 ){ S->outcome = 6; goto terminate; } if ( delta <= LM_MACHEP*xnorm ){ S->outcome = 7; goto terminate; } if ( gnorm <= LM_MACHEP ){ S->outcome = 8; goto terminate; } /*** [inner] End of the loop. Repeat if iteration unsuccessful. ***/ ++inner; } while ( !inner_success ); /*** [outer] End of the loop. ***/ }; terminate: S->fnorm = lm_enorm(m, fvec); if ( C->verbosity >= 2 ) printf("lmmin outcome (%i) xnorm %g ftol %g xtol %g\n", S->outcome, xnorm, C->ftol, C->xtol ); if( C->verbosity & 1 ) { fprintf( *(C->stream), "lmmin final " ); lm_print_pars( nout, x, S->fnorm, C ); } if ( S->userbreak ) /* user-requested break */ S->outcome = 11; /*** Deallocate the workspace. ***/ free(fvec); free(diag); free(qtf); free(fjac); free(wa1); free(wa2); free(wa3); free(wf); free(ipvt); } /*** lmmin. ***/ /*****************************************************************************/ /* lm_lmpar (determine Levenberg-Marquardt parameter) */ /*****************************************************************************/ void lm_lmpar(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb, double delta, double *par, double *x, double *sdiag, double *aux, double *xdi) { /* Given an m by n matrix a, an n by n nonsingular diagonal * matrix d, an m-vector b, and a positive number delta, * the problem is to determine a value for the parameter * par such that if x solves the system * * a*x = b and sqrt(par)*d*x = 0 * * in the least squares sense, and dxnorm is the euclidean * norm of d*x, then either par=0 and (dxnorm-delta) < 0.1*delta, * or par>0 and abs(dxnorm-delta) < 0.1*delta. * * Using lm_qrsolv, this subroutine completes the solution of the problem * if it is provided with the necessary information from the * qr factorization, with column pivoting, of a. That is, if * a*p = q*r, where p is a permutation matrix, q has orthogonal * columns, and r is an upper triangular matrix with diagonal * elements of nonincreasing magnitude, then lmpar expects * the full upper triangle of r, the permutation matrix p, * and the first n components of qT*b. On output * lmpar also provides an upper triangular matrix s such that * * p^T*(a^T*a + par*d*d)*p = s^T*s. * * s is employed within lmpar and may be of separate interest. * * Only a few iterations are generally needed for convergence * of the algorithm. If, however, the limit of 10 iterations * is reached, then the output par will contain the best * value obtained so far. * * parameters: * * n is a positive integer input variable set to the order of r. * * r is an n by n array. on input the full upper triangle * must contain the full upper triangle of the matrix r. * on OUTPUT the full upper triangle is unaltered, and the * strict lower triangle contains the strict upper triangle * (transposed) of the upper triangular matrix s. * * ldr is a positive integer input variable not less than n * which specifies the leading dimension of the array r. * * ipvt is an integer input array of length n which defines the * permutation matrix p such that a*p = q*r. column j of p * is column ipvt(j) of the identity matrix. * * diag is an input array of length n which must contain the * diagonal elements of the matrix d. * * qtb is an input array of length n which must contain the first * n elements of the vector (q transpose)*b. * * delta is a positive input variable which specifies an upper * bound on the euclidean norm of d*x. * * par is a nonnegative variable. on input par contains an * initial estimate of the levenberg-marquardt parameter. * on OUTPUT par contains the final estimate. * * x is an OUTPUT array of length n which contains the least * squares solution of the system a*x = b, sqrt(par)*d*x = 0, * for the output par. * * sdiag is an array of length n needed as workspace; on OUTPUT * it contains the diagonal elements of the upper triangular matrix s. * * aux is a multi-purpose work array of length n. * * xdi is a work array of length n. On OUTPUT: diag[j] * x[j]. * */ int i, iter, j, nsing; double dxnorm, fp, fp_old, gnorm, parc, parl, paru; double sum, temp; static double p1 = 0.1; /*** lmpar: compute and store in x the gauss-newton direction. if the jacobian is rank-deficient, obtain a least squares solution. ***/ nsing = n; for (j = 0; j < n; j++) { aux[j] = qtb[j]; if (r[j * ldr + j] == 0 && nsing == n) nsing = j; if (nsing < n) aux[j] = 0; } for (j = nsing - 1; j >= 0; j--) { aux[j] = aux[j] / r[j + ldr * j]; temp = aux[j]; for (i = 0; i < j; i++) aux[i] -= r[j * ldr + i] * temp; } for (j = 0; j < n; j++) x[ipvt[j]] = aux[j]; /*** lmpar: initialize the iteration counter, evaluate the function at the origin, and test for acceptance of the gauss-newton direction. ***/ for (j = 0; j < n; j++) xdi[j] = diag[j] * x[j]; dxnorm = lm_enorm(n, xdi); fp = dxnorm - delta; if (fp <= p1 * delta) { #ifdef LMFIT_DEBUG_MESSAGES printf("debug lmpar nsing %d n %d, terminate (fp= n) { for (j = 0; j < n; j++) aux[j] = diag[ipvt[j]] * xdi[ipvt[j]] / dxnorm; for (j = 0; j < n; j++) { sum = 0.; for (i = 0; i < j; i++) sum += r[j * ldr + i] * aux[i]; aux[j] = (aux[j] - sum) / r[j + ldr * j]; } temp = lm_enorm(n, aux); parl = fp / delta / temp / temp; } /*** lmpar: calculate an upper bound, paru, for the 0. of the function. ***/ for (j = 0; j < n; j++) { sum = 0; for (i = 0; i <= j; i++) sum += r[j * ldr + i] * qtb[i]; aux[j] = sum / diag[ipvt[j]]; } gnorm = lm_enorm(n, aux); paru = gnorm / delta; if (paru == 0.) paru = LM_DWARF / MIN(delta, p1); /*** lmpar: if the input par lies outside of the interval (parl,paru), set par to the closer endpoint. ***/ *par = MAX(*par, parl); *par = MIN(*par, paru); if (*par == 0.) *par = gnorm / dxnorm; /*** lmpar: iterate. ***/ for (iter=0; ; iter++) { /** evaluate the function at the current value of par. **/ if (*par == 0.) *par = MAX(LM_DWARF, 0.001 * paru); temp = sqrt(*par); for (j = 0; j < n; j++) aux[j] = temp * diag[j]; lm_qrsolv( n, r, ldr, ipvt, aux, qtb, x, sdiag, xdi ); /* return values are r, x, sdiag */ for (j = 0; j < n; j++) xdi[j] = diag[j] * x[j]; /* used as output */ dxnorm = lm_enorm(n, xdi); fp_old = fp; fp = dxnorm - delta; /** if the function is small enough, accept the current value of par. Also test for the exceptional cases where parl is zero or the number of iterations has reached 10. **/ if (fabs(fp) <= p1 * delta || (parl == 0. && fp <= fp_old && fp_old < 0.) || iter == 10) { #ifdef LMFIT_DEBUG_MESSAGES printf("debug lmpar nsing %d iter %d " "par %.4e [%.4e %.4e] delta %.4e fp %.4e\n", nsing, iter, *par, parl, paru, delta, fp); #endif break; /* the only exit from the iteration. */ } /** compute the Newton correction. **/ for (j = 0; j < n; j++) aux[j] = diag[ipvt[j]] * xdi[ipvt[j]] / dxnorm; for (j = 0; j < n; j++) { aux[j] = aux[j] / sdiag[j]; for (i = j + 1; i < n; i++) aux[i] -= r[j * ldr + i] * aux[j]; } temp = lm_enorm(n, aux); parc = fp / delta / temp / temp; /** depending on the sign of the function, update parl or paru. **/ if (fp > 0) parl = MAX(parl, *par); else if (fp < 0) paru = MIN(paru, *par); /* the case fp==0 is precluded by the break condition */ /** compute an improved estimate for par. **/ *par = MAX(parl, *par + parc); } } /*** lm_lmpar. ***/ /*****************************************************************************/ /* lm_qrfac (QR factorization, from lapack) */ /*****************************************************************************/ void lm_qrfac(int m, int n, double *a, int *ipvt, double *rdiag, double *acnorm, double *wa) { /* * This subroutine uses Householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix a. That is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that a*p = q*r. The Householder transformation for * column k, k = 1,2,...,min(m,n), is of the form * * i - (1/u(k))*u*uT * * where u has zeroes in the first k-1 positions. The form of * this transformation and the method of pivoting first * appeared in the corresponding linpack subroutine. * * Parameters: * * m is a positive integer input variable set to the number * of rows of a. * * n is a positive integer input variable set to the number * of columns of a. * * a is an m by n array. On input a contains the matrix for * which the qr factorization is to be computed. On OUTPUT * the strict upper trapezoidal part of a contains the strict * upper trapezoidal part of r, and the lower trapezoidal * part of a contains a factored form of q (the non-trivial * elements of the u vectors described above). * * ipvt is an integer OUTPUT array of length lipvt. This array * defines the permutation matrix p such that a*p = q*r. * Column j of p is column ipvt(j) of the identity matrix. * * rdiag is an OUTPUT array of length n which contains the * diagonal elements of r. * * acnorm is an OUTPUT array of length n which contains the * norms of the corresponding columns of the input matrix a. * If this information is not needed, then acnorm can coincide * with rdiag. * * wa is a work array of length n. * */ int i, j, k, kmax, minmn; double ajnorm, sum, temp; /*** qrfac: compute initial column norms and initialize several arrays. ***/ for (j = 0; j < n; j++) { acnorm[j] = lm_enorm(m, &a[j*m]); rdiag[j] = acnorm[j]; wa[j] = rdiag[j]; ipvt[j] = j; } #ifdef LMFIT_DEBUG_MESSAGES printf("debug qrfac\n"); #endif /*** qrfac: reduce a to r with Householder transformations. ***/ minmn = MIN(m, n); for (j = 0; j < minmn; j++) { /** bring the column of largest norm into the pivot position. **/ kmax = j; for (k = j + 1; k < n; k++) if (rdiag[k] > rdiag[kmax]) kmax = k; if (kmax == j) goto pivot_ok; for (i = 0; i < m; i++) { temp = a[j*m+i]; a[j*m+i] = a[kmax*m+i]; a[kmax*m+i] = temp; } rdiag[kmax] = rdiag[j]; wa[kmax] = wa[j]; k = ipvt[j]; ipvt[j] = ipvt[kmax]; ipvt[kmax] = k; pivot_ok: /** compute the Householder transformation to reduce the j-th column of a to a multiple of the j-th unit vector. **/ ajnorm = lm_enorm(m-j, &a[j*m+j]); if (ajnorm == 0.) { rdiag[j] = 0; continue; } if (a[j*m+j] < 0.) ajnorm = -ajnorm; for (i = j; i < m; i++) a[j*m+i] /= ajnorm; a[j*m+j] += 1; /** apply the transformation to the remaining columns and update the norms. **/ for (k = j + 1; k < n; k++) { sum = 0; for (i = j; i < m; i++) sum += a[j*m+i] * a[k*m+i]; temp = sum / a[j + m * j]; for (i = j; i < m; i++) a[k*m+i] -= temp * a[j*m+i]; if (rdiag[k] != 0.) { temp = a[m * k + j] / rdiag[k]; temp = MAX(0., 1 - temp * temp); rdiag[k] *= sqrt(temp); temp = rdiag[k] / wa[k]; if ( 0.05 * SQR(temp) <= LM_MACHEP ) { rdiag[k] = lm_enorm(m-j-1, &a[m*k+j+1]); wa[k] = rdiag[k]; } } } rdiag[j] = -ajnorm; } } /*** lm_qrfac. ***/ /*****************************************************************************/ /* lm_qrsolv (linear least-squares) */ /*****************************************************************************/ void lm_qrsolv(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb, double *x, double *sdiag, double *wa) { /* * Given an m by n matrix a, an n by n diagonal matrix d, * and an m-vector b, the problem is to determine an x which * solves the system * * a*x = b and d*x = 0 * * in the least squares sense. * * This subroutine completes the solution of the problem * if it is provided with the necessary information from the * qr factorization, with column pivoting, of a. That is, if * a*p = q*r, where p is a permutation matrix, q has orthogonal * columns, and r is an upper triangular matrix with diagonal * elements of nonincreasing magnitude, then qrsolv expects * the full upper triangle of r, the permutation matrix p, * and the first n components of (q transpose)*b. The system * a*x = b, d*x = 0, is then equivalent to * * r*z = q^T*b, p^T*d*p*z = 0, * * where x = p*z. If this system does not have full rank, * then a least squares solution is obtained. On output qrsolv * also provides an upper triangular matrix s such that * * p^T *(a^T *a + d*d)*p = s^T *s. * * s is computed within qrsolv and may be of separate interest. * * Parameters * * n is a positive integer input variable set to the order of r. * * r is an n by n array. On input the full upper triangle * must contain the full upper triangle of the matrix r. * On OUTPUT the full upper triangle is unaltered, and the * strict lower triangle contains the strict upper triangle * (transposed) of the upper triangular matrix s. * * ldr is a positive integer input variable not less than n * which specifies the leading dimension of the array r. * * ipvt is an integer input array of length n which defines the * permutation matrix p such that a*p = q*r. Column j of p * is column ipvt(j) of the identity matrix. * * diag is an input array of length n which must contain the * diagonal elements of the matrix d. * * qtb is an input array of length n which must contain the first * n elements of the vector (q transpose)*b. * * x is an OUTPUT array of length n which contains the least * squares solution of the system a*x = b, d*x = 0. * * sdiag is an OUTPUT array of length n which contains the * diagonal elements of the upper triangular matrix s. * * wa is a work array of length n. * */ int i, kk, j, k, nsing; double qtbpj, sum, temp; double _sin, _cos, _tan, _cot; /* local variables, not functions */ /*** qrsolv: copy r and q^T*b to preserve input and initialize s. in particular, save the diagonal elements of r in x. ***/ for (j = 0; j < n; j++) { for (i = j; i < n; i++) r[j * ldr + i] = r[i * ldr + j]; x[j] = r[j * ldr + j]; wa[j] = qtb[j]; } /*** qrsolv: eliminate the diagonal matrix d using a Givens rotation. ***/ for (j = 0; j < n; j++) { /*** qrsolv: prepare the row of d to be eliminated, locating the diagonal element using p from the qr factorization. ***/ if (diag[ipvt[j]] == 0.) goto L90; for (k = j; k < n; k++) sdiag[k] = 0.; sdiag[j] = diag[ipvt[j]]; /*** qrsolv: the transformations to eliminate the row of d modify only a single element of qT*b beyond the first n, which is initially 0. ***/ qtbpj = 0.; for (k = j; k < n; k++) { /** determine a Givens rotation which eliminates the appropriate element in the current row of d. **/ if (sdiag[k] == 0.) continue; kk = k + ldr * k; if (fabs(r[kk]) < fabs(sdiag[k])) { _cot = r[kk] / sdiag[k]; _sin = 1 / sqrt(1 + SQR(_cot)); _cos = _sin * _cot; } else { _tan = sdiag[k] / r[kk]; _cos = 1 / sqrt(1 + SQR(_tan)); _sin = _cos * _tan; } /** compute the modified diagonal element of r and the modified element of ((q^T)*b,0). **/ r[kk] = _cos * r[kk] + _sin * sdiag[k]; temp = _cos * wa[k] + _sin * qtbpj; qtbpj = -_sin * wa[k] + _cos * qtbpj; wa[k] = temp; /** accumulate the tranformation in the row of s. **/ for (i = k + 1; i < n; i++) { temp = _cos * r[k * ldr + i] + _sin * sdiag[i]; sdiag[i] = -_sin * r[k * ldr + i] + _cos * sdiag[i]; r[k * ldr + i] = temp; } } L90: /** store the diagonal element of s and restore the corresponding diagonal element of r. **/ sdiag[j] = r[j * ldr + j]; r[j * ldr + j] = x[j]; } /*** qrsolv: solve the triangular system for z. if the system is singular, then obtain a least squares solution. ***/ nsing = n; for (j = 0; j < n; j++) { if (sdiag[j] == 0. && nsing == n) nsing = j; if (nsing < n) wa[j] = 0; } for (j = nsing - 1; j >= 0; j--) { sum = 0; for (i = j + 1; i < nsing; i++) sum += r[j * ldr + i] * wa[i]; wa[j] = (wa[j] - sum) / sdiag[j]; } /*** qrsolv: permute the components of z back to components of x. ***/ for (j = 0; j < n; j++) x[ipvt[j]] = wa[j]; } /*** lm_qrsolv. ***/ /*****************************************************************************/ /* lm_enorm (Euclidean norm) */ /*****************************************************************************/ double lm_enorm(int n, const double *x) { /* Given an n-vector x, this function calculates the * euclidean norm of x. * * The euclidean norm is computed by accumulating the sum of * squares in three different sums. The sums of squares for the * small and large components are scaled so that no overflows * occur. Non-destructive underflows are permitted. Underflows * and overflows do not occur in the computation of the unscaled * sum of squares for the intermediate components. * The definitions of small, intermediate and large components * depend on two constants, LM_SQRT_DWARF and LM_SQRT_GIANT. The main * restrictions on these constants are that LM_SQRT_DWARF**2 not * underflow and LM_SQRT_GIANT**2 not overflow. * * Parameters * * n is a positive integer input variable. * * x is an input array of length n. */ int i; double agiant, s1, s2, s3, xabs, x1max, x3max, temp; s1 = 0; s2 = 0; s3 = 0; x1max = 0; x3max = 0; agiant = LM_SQRT_GIANT / n; /** sum squares. **/ for (i = 0; i < n; i++) { xabs = fabs(x[i]); if (xabs > LM_SQRT_DWARF) { if ( xabs < agiant ) { s2 += xabs * xabs; } else if ( xabs > x1max ) { temp = x1max / xabs; s1 = 1 + s1 * SQR(temp); x1max = xabs; } else { temp = xabs / x1max; s1 += SQR(temp); } } else if ( xabs > x3max ) { temp = x3max / xabs; s3 = 1 + s3 * SQR(temp); x3max = xabs; } else if (xabs != 0.) { temp = xabs / x3max; s3 += SQR(temp); } } /** calculation of norm. **/ if (s1 != 0) return x1max * sqrt(s1 + (s2 / x1max) / x1max); else if (s2 != 0) if (s2 >= x3max) return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3))); else return sqrt(x3max * ((s2 / x3max) + (x3max * s3))); else return x3max * sqrt(s3); } /*** lm_enorm. ***/ repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/lmmin.h000066400000000000000000000047211231531733200226640ustar00rootroot00000000000000/* * Library: lmfit (Levenberg-Marquardt least squares fitting) * * File: lmmin.h * * Contents: Declarations for Levenberg-Marquardt minimization. * * Copyright: Joachim Wuttke, Forschungszentrum Juelich GmbH (2004-2013) * * License: see ../COPYING (FreeBSD) * * Homepage: apps.jcns.fz-juelich.de/lmfit */ #ifndef LMMIN_H #define LMMIN_H #include "lmstruct.h" #ifdef __cplusplus extern "C" { #endif /* Levenberg-Marquardt minimization. */ void lmmin( int n_par, double *par, int m_dat, const void *data, void (*evaluate) (const double *par, int m_dat, const void *data, double *fvec, int *userbreak), const lm_control_struct *control, lm_status_struct *status ); /* * This routine contains the core algorithm of our library. * * It minimizes the sum of the squares of m nonlinear functions * in n variables by a modified Levenberg-Marquardt algorithm. * The function evaluation is done by the user-provided routine 'evaluate'. * The Jacobian is then calculated by a forward-difference approximation. * * Parameters: * * n is the number of variables (INPUT, positive integer). * * x is the solution vector (INPUT/OUTPUT, array of length n). * On input it must be set to an estimated solution. * On output it yields the final estimate of the solution. * * m is the number of functions to be minimized (INPUT, positive integer). * It must fulfill m>=n. * * data is a pointer that is ignored by lmmin; it is however forwarded * to the user-supplied functions evaluate and printout. * In a typical application, it contains experimental data to be fitted. * * evaluate is a user-supplied function that calculates the m functions. * Parameters: * n, x, m, data as above. * fvec is an array of length m; on OUTPUT, it must contain the * m function values for the parameter vector x. * userbreak is an integer pointer. When *userbreak is set to a * nonzero value, lmmin will terminate. * * control contains INPUT variables that control the fit algorithm, * as declared and explained in lmstruct.h * * status contains OUTPUT variables that inform about the fit result, * as declared and explained in lmstruct.h */ /* Refined calculation of Eucledian norm. */ double lm_enorm( int, const double * ); #ifdef __cplusplus } #endif #endif /* LMMIN_H */ repsnapper-2.3.2a5/libraries/lmfit/lmfit-5.0/lib/lmstruct.h000066400000000000000000000062421231531733200234250ustar00rootroot00000000000000/* * Library: lmfit (Levenberg-Marquardt least squares fitting) * * File: lmstruct.h * * Contents: Declarations of parameter records, used in lmmin.h and lmcurve.h * * Copyright: Joachim Wuttke, Forschungszentrum Juelich GmbH (2004-2013) * * License: see ../COPYING (FreeBSD) * * Homepage: apps.jcns.fz-juelich.de/lmfit */ #ifndef LMSTRUCT_H #define LMSTRUCT_H #ifdef __cplusplus extern "C" { #endif #include /* Collection of input parameters for fit control. */ typedef struct { double ftol; /* Relative error desired in the sum of squares. Termination occurs when both the actual and predicted relative reductions in the sum of squares are at most ftol. */ double xtol; /* Relative error between last two approximations. Termination occurs when the relative error between two consecutive iterates is at most xtol. */ double gtol; /* Orthogonality desired between fvec and its derivs. Termination occurs when the cosine of the angle between fvec and any column of the Jacobian is at most gtol in absolute value. */ double epsilon; /* Step used to calculate the Jacobian, should be slightly larger than the relative error in the user-supplied functions. */ double stepbound; /* Used in determining the initial step bound. This bound is set to the product of stepbound and the Euclidean norm of diag*x if nonzero, or else to stepbound itself. In most cases stepbound should lie in the interval (0.1,100.0). Generally, the value 100.0 is recommended. */ int patience; /* Used to set the maximum number of function evaluations to patience*(number_of_parameters+1). */ int scale_diag; /* If 1, the variables will be rescaled internally. Recommended value is 1. */ FILE** stream; /* Pointer to output stream to write to. */ int verbosity; /* OR'ed: 1: print some messages; 2: print Jacobian. */ int n_maxpri; /* -1, or max number of parameters to print. */ int m_maxpri; /* -1, or max number of residuals to print. */ } lm_control_struct; /* Collection of output parameters for status info. */ typedef struct { double fnorm; /* norm of the residue vector fvec. */ int nfev; /* actual number of iterations. */ int outcome; /* Status indicator. Nonnegative values are used as index for the message text lm_infmsg, set in lmmin.c. */ int userbreak; /* Set when function evaluation requests termination. */ } lm_status_struct; /* Preset (and recommended) control parameter settings. */ extern const lm_control_struct lm_control_double; extern const lm_control_struct lm_control_float; /* Preset message texts. */ extern const char *lm_infmsg[]; extern const char *lm_shortmsg[]; #ifdef __cplusplus } #endif #endif /* LMSTRUCT_H */ repsnapper-2.3.2a5/libraries/poly2tri/000077500000000000000000000000001231531733200176635ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/poly2tri/Makefile.am000066400000000000000000000015531231531733200217230ustar00rootroot00000000000000noinst_LTLIBRARIES += libpoly2tri.la libpoly2tri_la_CPPFLAGS = \ -I$(srcdir) \ -I$(top_srcdir)/libraries/poly2tri/poly2tri/poly2tri/ \ $(EXTRA_CFLAGS) libpoly2tri_la_SOURCES = \ libraries/poly2tri/poly2tri/poly2tri/common/shapes.cc \ libraries/poly2tri/poly2tri/poly2tri/sweep/advancing_front.cc \ libraries/poly2tri/poly2tri/poly2tri/sweep/cdt.cc \ libraries/poly2tri/poly2tri/poly2tri/sweep/sweep.cc \ libraries/poly2tri/poly2tri/poly2tri/sweep/sweep_context.cc \ libraries/poly2tri/poly2tri/poly2tri/sweep/sweep_context.h \ libraries/poly2tri/poly2tri/poly2tri/sweep/cdt.h \ libraries/poly2tri/poly2tri/poly2tri/sweep/advancing_front.h \ libraries/poly2tri/poly2tri/poly2tri/sweep/sweep.h \ libraries/poly2tri/poly2tri/poly2tri/common/shapes.h \ libraries/poly2tri/poly2tri/poly2tri/common/utils.h \ libraries/poly2tri/poly2tri/poly2tri/poly2tri.h repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/000077500000000000000000000000001231531733200214475ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/000077500000000000000000000000001231531733200232335ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/common/000077500000000000000000000000001231531733200245235ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/common/shapes.cc000066400000000000000000000216461231531733200263260ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "shapes.h" #include namespace p2t { Triangle::Triangle(Point& a, Point& b, Point& c) { points_[0] = &a; points_[1] = &b; points_[2] = &c; neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; constrained_edge[0] = constrained_edge[1] = constrained_edge[2] = false; delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; interior_ = false; } // Update neighbor pointers void Triangle::MarkNeighbor(Point* p1, Point* p2, Triangle* t) { if ((p1 == points_[2] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[2])) neighbors_[0] = t; else if ((p1 == points_[0] && p2 == points_[2]) || (p1 == points_[2] && p2 == points_[0])) neighbors_[1] = t; else if ((p1 == points_[0] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[0])) neighbors_[2] = t; else assert(0); } // Exhaustive search to update neighbor pointers void Triangle::MarkNeighbor(Triangle& t) { if (t.Contains(points_[1], points_[2])) { neighbors_[0] = &t; t.MarkNeighbor(points_[1], points_[2], this); } else if (t.Contains(points_[0], points_[2])) { neighbors_[1] = &t; t.MarkNeighbor(points_[0], points_[2], this); } else if (t.Contains(points_[0], points_[1])) { neighbors_[2] = &t; t.MarkNeighbor(points_[0], points_[1], this); } } /** * Clears all references to all other triangles and points */ void Triangle::Clear() { Triangle *t; for( int i=0; i<3; i++ ) { t = neighbors_[i]; if( t != NULL ) { t->ClearNeighbor( this ); } } ClearNeighbors(); points_[0]=points_[1]=points_[2] = NULL; } void Triangle::ClearNeighbor(Triangle *triangle ) { if( neighbors_[0] == triangle ) { neighbors_[0] = NULL; } else if( neighbors_[1] == triangle ) { neighbors_[1] = NULL; } else { neighbors_[2] = NULL; } } void Triangle::ClearNeighbors() { neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; } void Triangle::ClearDelunayEdges() { delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; } Point* Triangle::OppositePoint(Triangle& t, Point& p) { Point *cw = t.PointCW(p); double x = cw->x; double y = cw->y; x = p.x; y = p.y; return PointCW(*cw); } // Legalized triangle by rotating clockwise around point(0) void Triangle::Legalize(Point& point) { points_[1] = points_[0]; points_[0] = points_[2]; points_[2] = &point; } // Legalize triagnle by rotating clockwise around oPoint void Triangle::Legalize(Point& opoint, Point& npoint) { if (&opoint == points_[0]) { points_[1] = points_[0]; points_[0] = points_[2]; points_[2] = &npoint; } else if (&opoint == points_[1]) { points_[2] = points_[1]; points_[1] = points_[0]; points_[0] = &npoint; } else if (&opoint == points_[2]) { points_[0] = points_[2]; points_[2] = points_[1]; points_[1] = &npoint; } else { assert(0); } } int Triangle::Index(const Point* p) { if (p == points_[0]) { return 0; } else if (p == points_[1]) { return 1; } else if (p == points_[2]) { return 2; } assert(0); } int Triangle::EdgeIndex(const Point* p1, const Point* p2) { if (points_[0] == p1) { if (points_[1] == p2) { return 2; } else if (points_[2] == p2) { return 1; } } else if (points_[1] == p1) { if (points_[2] == p2) { return 0; } else if (points_[0] == p2) { return 2; } } else if (points_[2] == p1) { if (points_[0] == p2) { return 1; } else if (points_[1] == p2) { return 0; } } return -1; } void Triangle::MarkConstrainedEdge(const int index) { constrained_edge[index] = true; } void Triangle::MarkConstrainedEdge(Edge& edge) { MarkConstrainedEdge(edge.p, edge.q); } // Mark edge as constrained void Triangle::MarkConstrainedEdge(Point* p, Point* q) { if ((q == points_[0] && p == points_[1]) || (q == points_[1] && p == points_[0])) { constrained_edge[2] = true; } else if ((q == points_[0] && p == points_[2]) || (q == points_[2] && p == points_[0])) { constrained_edge[1] = true; } else if ((q == points_[1] && p == points_[2]) || (q == points_[2] && p == points_[1])) { constrained_edge[0] = true; } } // The point counter-clockwise to given point Point* Triangle::PointCW(Point& point) { if (&point == points_[0]) { return points_[2]; } else if (&point == points_[1]) { return points_[0]; } else if (&point == points_[2]) { return points_[1]; } assert(0); } // The point counter-clockwise to given point Point* Triangle::PointCCW(Point& point) { if (&point == points_[0]) { return points_[1]; } else if (&point == points_[1]) { return points_[2]; } else if (&point == points_[2]) { return points_[0]; } assert(0); } // The neighbor clockwise to given point Triangle* Triangle::NeighborCW(Point& point) { if (&point == points_[0]) { return neighbors_[1]; } else if (&point == points_[1]) { return neighbors_[2]; } return neighbors_[0]; } // The neighbor counter-clockwise to given point Triangle* Triangle::NeighborCCW(Point& point) { if (&point == points_[0]) { return neighbors_[2]; } else if (&point == points_[1]) { return neighbors_[0]; } return neighbors_[1]; } bool Triangle::GetConstrainedEdgeCCW(Point& p) { if (&p == points_[0]) { return constrained_edge[2]; } else if (&p == points_[1]) { return constrained_edge[0]; } return constrained_edge[1]; } bool Triangle::GetConstrainedEdgeCW(Point& p) { if (&p == points_[0]) { return constrained_edge[1]; } else if (&p == points_[1]) { return constrained_edge[2]; } return constrained_edge[0]; } void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[2] = ce; } else if (&p == points_[1]) { constrained_edge[0] = ce; } else { constrained_edge[1] = ce; } } void Triangle::SetConstrainedEdgeCW(Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[1] = ce; } else if (&p == points_[1]) { constrained_edge[2] = ce; } else { constrained_edge[0] = ce; } } bool Triangle::GetDelunayEdgeCCW(Point& p) { if (&p == points_[0]) { return delaunay_edge[2]; } else if (&p == points_[1]) { return delaunay_edge[0]; } return delaunay_edge[1]; } bool Triangle::GetDelunayEdgeCW(Point& p) { if (&p == points_[0]) { return delaunay_edge[1]; } else if (&p == points_[1]) { return delaunay_edge[2]; } return delaunay_edge[0]; } void Triangle::SetDelunayEdgeCCW(Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[2] = e; } else if (&p == points_[1]) { delaunay_edge[0] = e; } else { delaunay_edge[1] = e; } } void Triangle::SetDelunayEdgeCW(Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[1] = e; } else if (&p == points_[1]) { delaunay_edge[2] = e; } else { delaunay_edge[0] = e; } } // The neighbor across to given point Triangle& Triangle::NeighborAcross(Point& opoint) { if (&opoint == points_[0]) { return *neighbors_[0]; } else if (&opoint == points_[1]) { return *neighbors_[1]; } return *neighbors_[2]; } void Triangle::DebugPrint() { using namespace std; cout << points_[0]->x << "," << points_[0]->y << " "; cout << points_[1]->x << "," << points_[1]->y << " "; cout << points_[2]->x << "," << points_[2]->y << endl; } } repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/common/shapes.h000066400000000000000000000164401231531733200261640ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Include guard #ifndef SHAPES_H #define SHAPES_H #include #include #include #include namespace p2t { struct Edge; struct Point { double x, y; /// Default constructor does nothing (for performance). Point() { x = 0.0; y = 0.0; } /// The edges this point constitutes an upper ending point std::vector edge_list; /// Construct using coordinates. Point(double x, double y) : x(x), y(y) {} /// Set this point to all zeros. void set_zero() { x = 0.0; y = 0.0; } /// Set this point to some specified coordinates. void set(double x_, double y_) { x = x_; y = y_; } /// Negate this point. Point operator -() const { Point v; v.set(-x, -y); return v; } /// Add a point to this point. void operator +=(const Point& v) { x += v.x; y += v.y; } /// Subtract a point from this point. void operator -=(const Point& v) { x -= v.x; y -= v.y; } /// Multiply this point by a scalar. void operator *=(double a) { x *= a; y *= a; } /// Get the length of this point (the norm). double Length() const { return sqrt(x * x + y * y); } /// Convert this point into a unit point. Returns the Length. double Normalize() { double len = Length(); x /= len; y /= len; return len; } }; // Represents a simple polygon's edge struct Edge { Point* p, *q; /// Constructor Edge(Point& p1, Point& p2) : p(&p1), q(&p2) { if (p1.y > p2.y) { q = &p1; p = &p2; } else if (p1.y == p2.y) { if (p1.x > p2.x) { q = &p1; p = &p2; } else if (p1.x == p2.x) { // Repeat points assert(false); } } q->edge_list.push_back(this); } }; // Triangle-based data structures are know to have better performance than quad-edge structures // See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator" // "Triangulations in CGAL" class Triangle { public: /// Constructor Triangle(Point& a, Point& b, Point& c); /// Flags to determine if an edge is a Constrained edge bool constrained_edge[3]; /// Flags to determine if an edge is a Delauney edge bool delaunay_edge[3]; Point* GetPoint(const int& index); Point* PointCW(Point& point); Point* PointCCW(Point& point); Point* OppositePoint(Triangle& t, Point& p); Triangle* GetNeighbor(const int& index); void MarkNeighbor(Point* p1, Point* p2, Triangle* t); void MarkNeighbor(Triangle& t); void MarkConstrainedEdge(const int index); void MarkConstrainedEdge(Edge& edge); void MarkConstrainedEdge(Point* p, Point* q); int Index(const Point* p); int EdgeIndex(const Point* p1, const Point* p2); Triangle* NeighborCW(Point& point); Triangle* NeighborCCW(Point& point); bool GetConstrainedEdgeCCW(Point& p); bool GetConstrainedEdgeCW(Point& p); void SetConstrainedEdgeCCW(Point& p, bool ce); void SetConstrainedEdgeCW(Point& p, bool ce); bool GetDelunayEdgeCCW(Point& p); bool GetDelunayEdgeCW(Point& p); void SetDelunayEdgeCCW(Point& p, bool e); void SetDelunayEdgeCW(Point& p, bool e); bool Contains(Point* p); bool Contains(const Edge& e); bool Contains(Point* p, Point* q); void Legalize(Point& point); void Legalize(Point& opoint, Point& npoint); /** * Clears all references to all other triangles and points */ void Clear(); void ClearNeighbor(Triangle *triangle ); void ClearNeighbors(); void ClearDelunayEdges(); inline bool IsInterior(); inline void IsInterior(bool b); Triangle& NeighborAcross(Point& opoint); void DebugPrint(); private: /// Triangle points Point* points_[3]; /// Neighbor list Triangle* neighbors_[3]; /// Has this triangle been marked as an interior triangle? bool interior_; }; inline bool cmp(const Point* a, const Point* b) { if (a->y < b->y) { return true; } else if (a->y == b->y) { // Make sure q is point with greater x value if (a->x < b->x) { return true; } } return false; } /// Add two points_ component-wise. inline Point operator +(const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y); } /// Subtract two points_ component-wise. inline Point operator -(const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y); } /// Multiply point by scalar inline Point operator *(double s, const Point& a) { return Point(s * a.x, s * a.y); } inline bool operator ==(const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; } inline bool operator !=(const Point& a, const Point& b) { return a.x != b.x && a.y != b.y; } /// Peform the dot product on two vectors. inline double Dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; } /// Perform the cross product on two vectors. In 2D this produces a scalar. inline double Cross(const Point& a, const Point& b) { return a.x * b.y - a.y * b.x; } /// Perform the cross product on a point and a scalar. In 2D this produces /// a point. inline Point Cross(const Point& a, double s) { return Point(s * a.y, -s * a.x); } /// Perform the cross product on a scalar and a point. In 2D this produces /// a point. inline Point Cross(const double s, const Point& a) { return Point(-s * a.y, s * a.x); } inline Point* Triangle::GetPoint(const int& index) { return points_[index]; } inline Triangle* Triangle::GetNeighbor(const int& index) { return neighbors_[index]; } inline bool Triangle::Contains(Point* p) { return p == points_[0] || p == points_[1] || p == points_[2]; } inline bool Triangle::Contains(const Edge& e) { return Contains(e.p) && Contains(e.q); } inline bool Triangle::Contains(Point* p, Point* q) { return Contains(p) && Contains(q); } inline bool Triangle::IsInterior() { return interior_; } inline void Triangle::IsInterior(bool b) { interior_ = b; } } #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/common/utils.h000066400000000000000000000067641231531733200260510ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTILS_H #define UTILS_H // Otherwise #defines like M_PI are undeclared under Visual Studio #define _USE_MATH_DEFINES #include #include namespace p2t { const double PI_3div4 = 3 * M_PI / 4; const double PI_div2 = 1.57079632679489661923; const double EPSILON = 1e-12; enum Orientation { CW, CCW, COLLINEAR }; /** * Forumla to calculate signed area
* Positive if CCW
* Negative if CW
* 0 if collinear
*
 * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
 *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
 * 
*/ Orientation Orient2d(Point& pa, Point& pb, Point& pc) { double detleft = (pa.x - pc.x) * (pb.y - pc.y); double detright = (pa.y - pc.y) * (pb.x - pc.x); double val = detleft - detright; if (val > -EPSILON && val < EPSILON) { return COLLINEAR; } else if (val > 0) { return CCW; } return CW; } /* bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) { double pdx = pd.x; double pdy = pd.y; double adx = pa.x - pdx; double ady = pa.y - pdy; double bdx = pb.x - pdx; double bdy = pb.y - pdy; double adxbdy = adx * bdy; double bdxady = bdx * ady; double oabd = adxbdy - bdxady; if (oabd <= EPSILON) { return false; } double cdx = pc.x - pdx; double cdy = pc.y - pdy; double cdxady = cdx * ady; double adxcdy = adx * cdy; double ocad = cdxady - adxcdy; if (ocad <= EPSILON) { return false; } return true; } */ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) { double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y); if (oadb >= -EPSILON) { return false; } double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y); if (oadc <= EPSILON) { return false; } return true; } } #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/poly2tri.h000066400000000000000000000032711231531733200251730ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef POLY2TRI_H #define POLY2TRI_H #include "common/shapes.h" #include "sweep/cdt.h" #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/000077500000000000000000000000001231531733200243565ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/advancing_front.cc000066400000000000000000000061561231531733200300370ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "advancing_front.h" namespace p2t { AdvancingFront::AdvancingFront(Node& head, Node& tail) { head_ = &head; tail_ = &tail; search_node_ = &head; } Node* AdvancingFront::LocateNode(const double& x) { Node* node = search_node_; if (x < node->value) { while ((node = node->prev) != NULL) { if (x >= node->value) { search_node_ = node; return node; } } } else { while ((node = node->next) != NULL) { if (x < node->value) { search_node_ = node->prev; return node->prev; } } } return NULL; } Node* AdvancingFront::FindSearchNode(const double& x) { (void)x; // suppress compiler warnings "unused parameter 'x'" // TODO: implement BST index return search_node_; } Node* AdvancingFront::LocatePoint(const Point* point) { const double px = point->x; Node* node = FindSearchNode(px); const double nx = node->point->x; if (px == nx) { if (point != node->point) { // We might have two nodes with same x value for a short time if (point == node->prev->point) { node = node->prev; } else if (point == node->next->point) { node = node->next; } else { assert(0); } } } else if (px < nx) { while ((node = node->prev) != NULL) { if (point == node->point) { break; } } } else { while ((node = node->next) != NULL) { if (point == node->point) break; } } if(node) search_node_ = node; return node; } AdvancingFront::~AdvancingFront() { } } repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/advancing_front.h000066400000000000000000000055601231531733200276770ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ADVANCED_FRONT_H #define ADVANCED_FRONT_H #include "../common/shapes.h" namespace p2t { struct Node; // Advancing front node struct Node { Point* point; Triangle* triangle; Node* next; Node* prev; double value; Node(Point& p) : point(&p), triangle(NULL), next(NULL), prev(NULL), value(p.x) { } Node(Point& p, Triangle& t) : point(&p), triangle(&t), next(NULL), prev(NULL), value(p.x) { } }; // Advancing front class AdvancingFront { public: AdvancingFront(Node& head, Node& tail); // Destructor ~AdvancingFront(); Node* head(); void set_head(Node* node); Node* tail(); void set_tail(Node* node); Node* search(); void set_search(Node* node); /// Locate insertion point along advancing front Node* LocateNode(const double& x); Node* LocatePoint(const Point* point); private: Node* head_, *tail_, *search_node_; Node* FindSearchNode(const double& x); }; inline Node* AdvancingFront::head() { return head_; } inline void AdvancingFront::set_head(Node* node) { head_ = node; } inline Node* AdvancingFront::tail() { return tail_; } inline void AdvancingFront::set_tail(Node* node) { tail_ = node; } inline Node* AdvancingFront::search() { return search_node_; } inline void AdvancingFront::set_search(Node* node) { search_node_ = node; } } #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/cdt.cc000066400000000000000000000044061231531733200254430ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "cdt.h" namespace p2t { CDT::CDT(std::vector polyline) { sweep_context_ = new SweepContext(polyline); sweep_ = new Sweep; } void CDT::AddHole(std::vector polyline) { sweep_context_->AddHole(polyline); } void CDT::AddPoint(Point* point) { sweep_context_->AddPoint(point); } void CDT::Triangulate() { sweep_->Triangulate(*sweep_context_); } std::vector CDT::GetTriangles() { return sweep_context_->GetTriangles(); } std::list CDT::GetMap() { return sweep_context_->GetMap(); } CDT::~CDT() { delete sweep_context_; delete sweep_; } } repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/cdt.h000066400000000000000000000052251231531733200253050ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CDT_H #define CDT_H #include "advancing_front.h" #include "sweep_context.h" #include "sweep.h" /** * * @author Mason Green * */ namespace p2t { class CDT { public: /** * Constructor - add polyline with non repeating points * * @param polyline */ CDT(std::vector polyline); /** * Destructor - clean up memory */ ~CDT(); /** * Add a hole * * @param polyline */ void AddHole(std::vector polyline); /** * Add a steiner point * * @param point */ void AddPoint(Point* point); /** * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points */ void Triangulate(); /** * Get CDT triangles */ std::vector GetTriangles(); /** * Get triangle map */ std::list GetMap(); private: /** * Internals */ SweepContext* sweep_context_; Sweep* sweep_; }; } #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/sweep.cc000066400000000000000000000603341231531733200260160ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "sweep.h" #include "sweep_context.h" #include "advancing_front.h" #include "../common/utils.h" namespace p2t { // Triangulate simple polygon with holes void Sweep::Triangulate(SweepContext& tcx) { tcx.InitTriangulation(); tcx.CreateAdvancingFront(nodes_); // Sweep points; build mesh SweepPoints(tcx); // Clean up FinalizationPolygon(tcx); } void Sweep::SweepPoints(SweepContext& tcx) { for (int i = 1; i < tcx.point_count(); i++) { Point& point = *tcx.GetPoint(i); Node* node = &PointEvent(tcx, point); for (unsigned int i = 0; i < point.edge_list.size(); i++) { EdgeEvent(tcx, point.edge_list[i], node); } } } void Sweep::FinalizationPolygon(SweepContext& tcx) { // Get an Internal triangle to start with Triangle* t = tcx.front()->head()->next->triangle; Point* p = tcx.front()->head()->next->point; while (!t->GetConstrainedEdgeCW(*p)) { t = t->NeighborCCW(*p); } // Collect interior triangles constrained by edges tcx.MeshClean(*t); } Node& Sweep::PointEvent(SweepContext& tcx, Point& point) { Node& node = tcx.LocateNode(point); Node& new_node = NewFrontTriangle(tcx, point, node); // Only need to check +epsilon since point never have smaller // x value than node due to how we fetch nodes from the front if (point.x <= node.point->x + EPSILON) { Fill(tcx, node); } //tcx.AddNode(new_node); FillAdvancingFront(tcx, new_node); return new_node; } void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { tcx.edge_event.constrained_edge = edge; tcx.edge_event.right = (edge->p->x > edge->q->x); if (IsEdgeSideOfTriangle(*node->triangle, *edge->p, *edge->q)) { return; } // For now we will do all needed filling // TODO: integrate with flip process might give some better performance // but for now this avoid the issue with cases that needs both flips and fills FillEdgeEvent(tcx, edge, node); EdgeEvent(tcx, *edge->p, *edge->q, node->triangle, *edge->q); } void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) { if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { return; } Point* p1 = triangle->PointCCW(point); Orientation o1 = Orient2d(eq, *p1, ep); if (o1 == COLLINEAR) { if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p1, triangle, *p1 ); } else { std::runtime_error("EdgeEvent - collinear points not supported"); assert(0); } return; } Point* p2 = triangle->PointCW(point); Orientation o2 = Orient2d(eq, *p2, ep); if (o2 == COLLINEAR) { if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p2, triangle, *p2 ); } else { std::runtime_error("EdgeEvent - collinear points not supported"); assert(0); } return; } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == CW) { triangle = triangle->NeighborCCW(point); } else{ triangle = triangle->NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } } bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq) { int index = triangle.EdgeIndex(&ep, &eq); if (index != -1) { triangle.MarkConstrainedEdge(index); Triangle* t = triangle.GetNeighbor(index); if (t) { t->MarkConstrainedEdge(&ep, &eq); } return true; } return false; } Node& Sweep::NewFrontTriangle(SweepContext& tcx, Point& point, Node& node) { Triangle* triangle = new Triangle(point, *node.point, *node.next->point); triangle->MarkNeighbor(*node.triangle); tcx.AddToMap(triangle); Node* new_node = new Node(point); nodes_.push_back(new_node); new_node->next = node.next; new_node->prev = &node; node.next->prev = new_node; node.next = new_node; if (!Legalize(tcx, *triangle)) { tcx.MapTriangleToNodes(*triangle); } return *new_node; } void Sweep::Fill(SweepContext& tcx, Node& node) { Triangle* triangle = new Triangle(*node.prev->point, *node.point, *node.next->point); // TODO: should copy the constrained_edge value from neighbor triangles // for now constrained_edge values are copied during the legalize triangle->MarkNeighbor(*node.prev->triangle); triangle->MarkNeighbor(*node.triangle); tcx.AddToMap(triangle); // Update the advancing front node.prev->next = node.next; node.next->prev = node.prev; // If it was legalized the triangle has already been mapped if (!Legalize(tcx, *triangle)) { tcx.MapTriangleToNodes(*triangle); } } void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) { // Fill right holes Node* node = n.next; while (node->next) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->next; } // Fill left holes node = n.prev; while (node->prev) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->prev; } // Fill right basins if (n.next && n.next->next) { double angle = BasinAngle(n); if (angle < PI_3div4) { FillBasin(tcx, n); } } } // True if HoleAngle exceeds 90 degrees. bool Sweep::LargeHole_DontFill(Node* node) { Node* nextNode = node->next; Node* prevNode = node->prev; if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point)) return false; // Check additional points on front. Node* next2Node = nextNode->next; // "..Plus.." because only want angles on same side as point being added. if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) return false; Node* prev2Node = prevNode->prev; // "..Plus.." because only want angles on same side as point being added. if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) return false; return true; } bool Sweep::AngleExceeds90Degrees(Point* origin, Point* pa, Point* pb) { double angle = Angle(*origin, *pa, *pb); bool exceeds90Degrees = ((angle > PI_div2) || (angle < -PI_div2)); return exceeds90Degrees; } bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(Point* origin, Point* pa, Point* pb) { double angle = Angle(*origin, *pa, *pb); bool exceedsPlus90DegreesOrIsNegative = (angle > PI_div2) || (angle < 0); return exceedsPlus90DegreesOrIsNegative; } double Sweep::Angle(Point& origin, Point& pa, Point& pb) { /* Complex plane * ab = cosA +i*sinA * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) * atan2(y,x) computes the principal value of the argument function * applied to the complex number x+iy * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ double px = origin.x; double py = origin.y; double ax = pa.x- px; double ay = pa.y - py; double bx = pb.x - px; double by = pb.y - py; double x = ax * by - ay * bx; double y = ax * bx + ay * by; double angle = atan2(x, y); return angle; } double Sweep::BasinAngle(Node& node) { double ax = node.point->x - node.next->next->point->x; double ay = node.point->y - node.next->next->point->y; return atan2(ay, ax); } double Sweep::HoleAngle(Node& node) { /* Complex plane * ab = cosA +i*sinA * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) * atan2(y,x) computes the principal value of the argument function * applied to the complex number x+iy * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ double ax = node.next->point->x - node.point->x; double ay = node.next->point->y - node.point->y; double bx = node.prev->point->x - node.point->x; double by = node.prev->point->y - node.point->y; return atan2(ax * by - ay * bx, ax * bx + ay * by); } bool Sweep::Legalize(SweepContext& tcx, Triangle& t) { // To legalize a triangle we start by finding if any of the three edges // violate the Delaunay condition for (int i = 0; i < 3; i++) { if (t.delaunay_edge[i]) continue; Triangle* ot = t.GetNeighbor(i); if (ot) { Point* p = t.GetPoint(i); Point* op = ot->OppositePoint(t, *p); int oi = ot->Index(op); // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) // then we should not try to legalize if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) { t.constrained_edge[i] = ot->constrained_edge[oi]; continue; } bool inside = Incircle(*p, *t.PointCCW(*p), *t.PointCW(*p), *op); if (inside) { // Lets mark this shared edge as Delaunay t.delaunay_edge[i] = true; ot->delaunay_edge[oi] = true; // Lets rotate shared edge one vertex CW to legalize it RotateTrianglePair(t, *p, *ot, *op); // We now got one valid Delaunay Edge shared by two triangles // This gives us 4 new edges to check for Delaunay // Make sure that triangle to node mapping is done only one time for a specific triangle bool not_legalized = !Legalize(tcx, t); if (not_legalized) { tcx.MapTriangleToNodes(t); } not_legalized = !Legalize(tcx, *ot); if (not_legalized) tcx.MapTriangleToNodes(*ot); // Reset the Delaunay edges, since they only are valid Delaunay edges // until we add a new triangle or point. // XXX: need to think about this. Can these edges be tried after we // return to previous recursive level? t.delaunay_edge[i] = false; ot->delaunay_edge[oi] = false; // If triangle have been legalized no need to check the other edges since // the recursive legalization will handles those so we can end here. return true; } } } return false; } bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd) { double adx = pa.x - pd.x; double ady = pa.y - pd.y; double bdx = pb.x - pd.x; double bdy = pb.y - pd.y; double adxbdy = adx * bdy; double bdxady = bdx * ady; double oabd = adxbdy - bdxady; if (oabd <= 0) return false; double cdx = pc.x - pd.x; double cdy = pc.y - pd.y; double cdxady = cdx * ady; double adxcdy = adx * cdy; double ocad = cdxady - adxcdy; if (ocad <= 0) return false; double bdxcdy = bdx * cdy; double cdxbdy = cdx * bdy; double alift = adx * adx + ady * ady; double blift = bdx * bdx + bdy * bdy; double clift = cdx * cdx + cdy * cdy; double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; return det > 0; } void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) { Triangle* n1, *n2, *n3, *n4; n1 = t.NeighborCCW(p); n2 = t.NeighborCW(p); n3 = ot.NeighborCCW(op); n4 = ot.NeighborCW(op); bool ce1, ce2, ce3, ce4; ce1 = t.GetConstrainedEdgeCCW(p); ce2 = t.GetConstrainedEdgeCW(p); ce3 = ot.GetConstrainedEdgeCCW(op); ce4 = ot.GetConstrainedEdgeCW(op); bool de1, de2, de3, de4; de1 = t.GetDelunayEdgeCCW(p); de2 = t.GetDelunayEdgeCW(p); de3 = ot.GetDelunayEdgeCCW(op); de4 = ot.GetDelunayEdgeCW(op); t.Legalize(p, op); ot.Legalize(op, p); // Remap delaunay_edge ot.SetDelunayEdgeCCW(p, de1); t.SetDelunayEdgeCW(p, de2); t.SetDelunayEdgeCCW(op, de3); ot.SetDelunayEdgeCW(op, de4); // Remap constrained_edge ot.SetConstrainedEdgeCCW(p, ce1); t.SetConstrainedEdgeCW(p, ce2); t.SetConstrainedEdgeCCW(op, ce3); ot.SetConstrainedEdgeCW(op, ce4); // Remap neighbors // XXX: might optimize the markNeighbor by keeping track of // what side should be assigned to what neighbor after the // rotation. Now mark neighbor does lots of testing to find // the right side. t.ClearNeighbors(); ot.ClearNeighbors(); if (n1) ot.MarkNeighbor(*n1); if (n2) t.MarkNeighbor(*n2); if (n3) t.MarkNeighbor(*n3); if (n4) ot.MarkNeighbor(*n4); t.MarkNeighbor(ot); } void Sweep::FillBasin(SweepContext& tcx, Node& node) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { tcx.basin.left_node = node.next->next; } else { tcx.basin.left_node = node.next; } // Find the bottom and right node tcx.basin.bottom_node = tcx.basin.left_node; while (tcx.basin.bottom_node->next && tcx.basin.bottom_node->point->y >= tcx.basin.bottom_node->next->point->y) { tcx.basin.bottom_node = tcx.basin.bottom_node->next; } if (tcx.basin.bottom_node == tcx.basin.left_node) { // No valid basin return; } tcx.basin.right_node = tcx.basin.bottom_node; while (tcx.basin.right_node->next && tcx.basin.right_node->point->y < tcx.basin.right_node->next->point->y) { tcx.basin.right_node = tcx.basin.right_node->next; } if (tcx.basin.right_node == tcx.basin.bottom_node) { // No valid basins return; } tcx.basin.width = tcx.basin.right_node->point->x - tcx.basin.left_node->point->x; tcx.basin.left_highest = tcx.basin.left_node->point->y > tcx.basin.right_node->point->y; FillBasinReq(tcx, tcx.basin.bottom_node); } void Sweep::FillBasinReq(SweepContext& tcx, Node* node) { // if shallow stop filling if (IsShallow(tcx, *node)) { return; } Fill(tcx, *node); if (node->prev == tcx.basin.left_node && node->next == tcx.basin.right_node) { return; } else if (node->prev == tcx.basin.left_node) { Orientation o = Orient2d(*node->point, *node->next->point, *node->next->next->point); if (o == CW) { return; } node = node->next; } else if (node->next == tcx.basin.right_node) { Orientation o = Orient2d(*node->point, *node->prev->point, *node->prev->prev->point); if (o == CCW) { return; } node = node->prev; } else { // Continue with the neighbor node with lowest Y value if (node->prev->point->y < node->next->point->y) { node = node->prev; } else { node = node->next; } } FillBasinReq(tcx, node); } bool Sweep::IsShallow(SweepContext& tcx, Node& node) { double height; if (tcx.basin.left_highest) { height = tcx.basin.left_node->point->y - node.point->y; } else { height = tcx.basin.right_node->point->y - node.point->y; } // if shallow stop filling if (tcx.basin.width > height) { return true; } return false; } void Sweep::FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { if (tcx.edge_event.right) { FillRightAboveEdgeEvent(tcx, edge, node); } else { FillLeftAboveEdgeEvent(tcx, edge, node); } } void Sweep::FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { while (node->next->point->x < edge->p->x) { // Check if next node is below the edge if (Orient2d(*edge->q, *node->next->point, *edge->p) == CCW) { FillRightBelowEdgeEvent(tcx, edge, *node); } else { node = node->next; } } } void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { if (node.point->x < edge->p->x) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, node); } else{ // Convex FillRightConvexEdgeEvent(tcx, edge, node); // Retry this one FillRightBelowEdgeEvent(tcx, edge, node); } } } void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { Fill(tcx, *node.next); if (node.next->point != edge->p) { // Next above or below edge? if (Orient2d(*edge->q, *node.next->point, *edge->p) == CCW) { // Below if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { // Next is concave FillRightConcaveEdgeEvent(tcx, edge, node); } else { // Next is convex } } } } void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { // Next concave or convex? if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, *node.next); } else{ // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) { // Below FillRightConvexEdgeEvent(tcx, edge, *node.next); } else{ // Above } } } void Sweep::FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { while (node->prev->point->x > edge->p->x) { // Check if next node is below the edge if (Orient2d(*edge->q, *node->prev->point, *edge->p) == CW) { FillLeftBelowEdgeEvent(tcx, edge, *node); } else { node = node->prev; } } } void Sweep::FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { if (node.point->x > edge->p->x) { if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else { // Convex FillLeftConvexEdgeEvent(tcx, edge, node); // Retry this one FillLeftBelowEdgeEvent(tcx, edge, node); } } } void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { // Next concave or convex? if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); } else{ // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { // Below FillLeftConvexEdgeEvent(tcx, edge, *node.prev); } else{ // Above } } } void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { Fill(tcx, *node.prev); if (node.prev->point != edge->p) { // Next above or below edge? if (Orient2d(*edge->q, *node.prev->point, *edge->p) == CW) { // Below if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Next is concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else{ // Next is convex } } } } void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) { Triangle& ot = t->NeighborAcross(p); Point& op = *ot.OppositePoint(*t, p); if (&ot == NULL) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); assert(0); } if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { // Lets rotate shared edge one vertex CW RotateTrianglePair(*t, p, ot, op); tcx.MapTriangleToNodes(*t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == *tcx.edge_event.constrained_edge->q && ep == *tcx.edge_event.constrained_edge->p) { t->MarkConstrainedEdge(&ep, &eq); ot.MarkConstrainedEdge(&ep, &eq); Legalize(tcx, *t); Legalize(tcx, ot); } else { // XXX: I think one of the triangles should be legalized here? } } else { Orientation o = Orient2d(eq, op, ep); t = &NextFlipTriangle(tcx, (int)o, *t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, *t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } } Triangle& Sweep::NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op) { if (o == CCW) { // ot is not crossing edge after flip int edge_index = ot.EdgeIndex(&p, &op); ot.delaunay_edge[edge_index] = true; Legalize(tcx, ot); ot.ClearDelunayEdges(); return t; } // t is not crossing edge after flip int edge_index = t.EdgeIndex(&p, &op); t.delaunay_edge[edge_index] = true; Legalize(tcx, t); t.ClearDelunayEdges(); return ot; } Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) { Orientation o2d = Orient2d(eq, op, ep); if (o2d == CW) { // Right return *ot.PointCCW(op); } else if (o2d == CCW) { // Left return *ot.PointCW(op); } else{ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); assert(0); } } void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p) { Triangle& ot = t.NeighborAcross(p); Point& op = *ot.OppositePoint(t, p); if (&t.NeighborAcross(p) == NULL) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); assert(0); } if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, &ot, op); // TODO: Actually I just figured out that it should be possible to // improve this by getting the next ot and op before the the above // flip and continue the flipScanEdgeEvent here // set new ot and op here and loop back to inScanArea test // also need to set a new flip_triangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. } else{ Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); } } Sweep::~Sweep() { // Clean up memory for(int i = 0; i < nodes_.size(); i++) { delete nodes_[i]; } } } repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/sweep.h000066400000000000000000000206651231531733200256630ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science * * "FlipScan" Constrained Edge Algorithm invented by Thomas hln, thahlen@gmail.com */ #ifndef SWEEP_H #define SWEEP_H #include namespace p2t { class SweepContext; struct Node; struct Point; struct Edge; class Triangle; class Sweep { public: /** * Triangulate * * @param tcx */ void Triangulate(SweepContext& tcx); /** * Destructor - clean up memory */ ~Sweep(); private: /** * Start sweeping the Y-sorted point set from bottom to top * * @param tcx */ void SweepPoints(SweepContext& tcx); /** * Find closes node to the left of the new point and * create a new triangle. If needed new holes and basins * will be filled to. * * @param tcx * @param point * @return */ Node& PointEvent(SweepContext& tcx, Point& point); /** * * * @param tcx * @param edge * @param node */ void EdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point); /** * Creates a new front triangle and legalize it * * @param tcx * @param point * @param node * @return */ Node& NewFrontTriangle(SweepContext& tcx, Point& point, Node& node); /** * Adds a triangle to the advancing front to fill a hole. * @param tcx * @param node - middle node, that is the bottom of the hole */ void Fill(SweepContext& tcx, Node& node); /** * Returns true if triangle was legalized */ bool Legalize(SweepContext& tcx, Triangle& t); /** * Requirement:
* 1. a,b and c form a triangle.
* 2. a and d is know to be on opposite side of bc
*
   *                a
   *                +
   *               / \
   *              /   \
   *            b/     \c
   *            +-------+
   *           /    d    \
   *          /           \
   * 
* Fact: d has to be in area B to have a chance to be inside the circle formed by * a,b and c
* d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW
* This preknowledge gives us a way to optimize the incircle test * @param a - triangle point, opposite d * @param b - triangle point * @param c - triangle point * @param d - point opposite a * @return true if d is inside circle, false if on circle edge */ bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd); /** * Rotates a triangle pair one vertex CW *
   *       n2                    n2
   *  P +-----+             P +-----+
   *    | t  /|               |\  t |
   *    |   / |               | \   |
   *  n1|  /  |n3           n1|  \  |n3
   *    | /   |    after CW   |   \ |
   *    |/ oT |               | oT \|
   *    +-----+ oP            +-----+
   *       n4                    n4
   * 
*/ void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op); /** * Fills holes in the Advancing Front * * * @param tcx * @param n */ void FillAdvancingFront(SweepContext& tcx, Node& n); // Decision-making about when to Fill hole. // Contributed by ToolmakerSteve2 bool LargeHole_DontFill(Node* node); bool AngleExceeds90Degrees(Point* origin, Point* pa, Point* pb); bool AngleExceedsPlus90DegreesOrIsNegative(Point* origin, Point* pa, Point* pb); double Angle(Point& origin, Point& pa, Point& pb); /** * * @param node - middle node * @return the angle between 3 front nodes */ double HoleAngle(Node& node); /** * The basin angle is decided against the horizontal line [1,0] */ double BasinAngle(Node& node); /** * Fills a basin that has formed on the Advancing Front to the right * of given node.
* First we decide a left,bottom and right node that forms the * boundaries of the basin. Then we do a reqursive fill. * * @param tcx * @param node - starting node, this or next node will be left node */ void FillBasin(SweepContext& tcx, Node& node); /** * Recursive algorithm to fill a Basin with triangles * * @param tcx * @param node - bottom_node * @param cnt - counter used to alternate on even and odd numbers */ void FillBasinReq(SweepContext& tcx, Node* node); bool IsShallow(SweepContext& tcx, Node& node); bool IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq); void FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p); /** * After a flip we have two triangles and know that only one will still be * intersecting the edge. So decide which to contiune with and legalize the other * * @param tcx * @param o - should be the result of an orient2d( eq, op, ep ) * @param t - triangle 1 * @param ot - triangle 2 * @param p - a point shared by both triangles * @param op - another point shared by both triangles * @return returns the triangle still intersecting the edge */ Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op); /** * When we need to traverse from one triangle to the next we need * the point in current triangle that is the opposite point to the next * triangle. * * @param ep * @param eq * @param ot * @param op * @return */ Point& NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op); /** * Scan part of the FlipScan algorithm
* When a triangle pair isn't flippable we will scan for the next * point that is inside the flip triangle scan area. When found * we generate a new flipEdgeEvent * * @param tcx * @param ep - last point on the edge we are traversing * @param eq - first point on the edge we are traversing * @param flipTriangle - the current triangle sharing the point eq with edge * @param t * @param p */ void FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p); void FinalizationPolygon(SweepContext& tcx); std::vector nodes_; }; } #endif repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/sweep_context.cc000066400000000000000000000121711231531733200275560ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "sweep_context.h" #include #include "advancing_front.h" namespace p2t { SweepContext::SweepContext(std::vector polyline) { basin = Basin(); edge_event = EdgeEvent(); points_ = polyline; InitEdges(points_); } void SweepContext::AddHole(std::vector polyline) { InitEdges(polyline); for(unsigned int i = 0; i < polyline.size(); i++) { points_.push_back(polyline[i]); } } void SweepContext::AddPoint(Point* point) { points_.push_back(point); } std::vector SweepContext::GetTriangles() { return triangles_; } std::list SweepContext::GetMap() { return map_; } void SweepContext::InitTriangulation() { double xmax(points_[0]->x), xmin(points_[0]->x); double ymax(points_[0]->y), ymin(points_[0]->y); // Calculate bounds. for (unsigned int i = 0; i < points_.size(); i++) { Point& p = *points_[i]; if (p.x > xmax) xmax = p.x; if (p.x < xmin) xmin = p.x; if (p.y > ymax) ymax = p.y; if (p.y < ymin) ymin = p.y; } double dx = kAlpha * (xmax - xmin); double dy = kAlpha * (ymax - ymin); head_ = new Point(xmax + dx, ymin - dy); tail_ = new Point(xmin - dx, ymin - dy); // Sort points along y-axis std::sort(points_.begin(), points_.end(), cmp); } void SweepContext::InitEdges(std::vector polyline) { int num_points = polyline.size(); for (int i = 0; i < num_points; i++) { int j = i < num_points - 1 ? i + 1 : 0; edge_list.push_back(new Edge(*polyline[i], *polyline[j])); } } Point* SweepContext::GetPoint(const int& index) { return points_[index]; } void SweepContext::AddToMap(Triangle* triangle) { map_.push_back(triangle); } Node& SweepContext::LocateNode(Point& point) { // TODO implement search tree return *front_->LocateNode(point.x); } void SweepContext::CreateAdvancingFront(std::vector nodes) { (void) nodes; // Initial triangle Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); map_.push_back(triangle); af_head_ = new Node(*triangle->GetPoint(1), *triangle); af_middle_ = new Node(*triangle->GetPoint(0), *triangle); af_tail_ = new Node(*triangle->GetPoint(2)); front_ = new AdvancingFront(*af_head_, *af_tail_); // TODO: More intuitive if head is middles next and not previous? // so swap head and tail af_head_->next = af_middle_; af_middle_->next = af_tail_; af_middle_->prev = af_head_; af_tail_->prev = af_middle_; } void SweepContext::RemoveNode(Node* node) { delete node; } void SweepContext::MapTriangleToNodes(Triangle& t) { for (int i = 0; i < 3; i++) { if (!t.GetNeighbor(i)) { Node* n = front_->LocatePoint(t.PointCW(*t.GetPoint(i))); if (n) n->triangle = &t; } } } void SweepContext::RemoveFromMap(Triangle* triangle) { map_.remove(triangle); } void SweepContext::MeshClean(Triangle& triangle) { if (&triangle != NULL && !triangle.IsInterior()) { triangle.IsInterior(true); triangles_.push_back(&triangle); for (int i = 0; i < 3; i++) { if (!triangle.constrained_edge[i]) MeshClean(*triangle.GetNeighbor(i)); } } } SweepContext::~SweepContext() { // Clean up memory delete head_; delete tail_; delete front_; delete af_head_; delete af_middle_; delete af_tail_; typedef std::list type_list; for(type_list::iterator iter = map_.begin(); iter != map_.end(); ++iter) { Triangle* ptr = *iter; delete ptr; } for(unsigned int i = 0; i < edge_list.size(); i++) { delete edge_list[i]; } } } repsnapper-2.3.2a5/libraries/poly2tri/poly2tri/poly2tri/sweep/sweep_context.h000066400000000000000000000102631231531733200274200ustar00rootroot00000000000000/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Poly2Tri nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SWEEP_CONTEXT_H #define SWEEP_CONTEXT_H #include #include #include namespace p2t { // Inital triangle factor, seed triangle will extend 30% of // PointSet width to both left and right. const double kAlpha = 0.3; struct Point; class Triangle; struct Node; struct Edge; class AdvancingFront; class SweepContext { public: /// Constructor SweepContext(std::vector polyline); /// Destructor ~SweepContext(); void set_head(Point* p1); Point* head(); void set_tail(Point* p1); Point* tail(); int point_count(); Node& LocateNode(Point& point); void RemoveNode(Node* node); void CreateAdvancingFront(std::vector nodes); /// Try to map a node to all sides of this triangle that don't have a neighbor void MapTriangleToNodes(Triangle& t); void AddToMap(Triangle* triangle); Point* GetPoint(const int& index); Point* GetPoints(); void RemoveFromMap(Triangle* triangle); void AddHole(std::vector polyline); void AddPoint(Point* point); AdvancingFront* front(); void MeshClean(Triangle& triangle); std::vector GetTriangles(); std::list GetMap(); std::vector edge_list; struct Basin { Node* left_node; Node* bottom_node; Node* right_node; double width; bool left_highest; Basin() : left_node(NULL), bottom_node(NULL), right_node(NULL), width(0.0), left_highest(false) { } void Clear() { left_node = NULL; bottom_node = NULL; right_node = NULL; width = 0.0; left_highest = false; } }; struct EdgeEvent { Edge* constrained_edge; bool right; EdgeEvent() : constrained_edge(NULL), right(false) { } }; Basin basin; EdgeEvent edge_event; private: friend class Sweep; std::vector triangles_; std::list map_; std::vector points_; // Advancing front AdvancingFront* front_; // head point used with advancing front Point* head_; // tail point used with advancing front Point* tail_; Node *af_head_, *af_middle_, *af_tail_; void InitTriangulation(); void InitEdges(std::vector polyline); }; inline AdvancingFront* SweepContext::front() { return front_; } inline int SweepContext::point_count() { return points_.size(); } inline void SweepContext::set_head(Point* p1) { head_ = p1; } inline Point* SweepContext::head() { return head_; } inline void SweepContext::set_tail(Point* p1) { tail_ = p1; } inline Point* SweepContext::tail() { return tail_; } } #endif repsnapper-2.3.2a5/libraries/vmmlib/000077500000000000000000000000001231531733200173655ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/ACKNOWLEDGEMENTS000066400000000000000000000055431231531733200216510ustar00rootroot00000000000000=========================================================================== enable_if (http://www.boost.org/doc/libs/1_39_0/libs/utility/enable_if.html) =========================================================================== Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =========================================================================== Parts of vector and matrix code (http://www.cs.cmu.edu/~ajw/doc/vl.html) =========================================================================== Except where otherwise noted, Copyright (c) 2000 Andrew Willmott. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form have no conditions on them. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. repsnapper-2.3.2a5/libraries/vmmlib/AUTHORS000066400000000000000000000013321231531733200204340ustar00rootroot00000000000000VMMLib - Vector & Matrix Math Lib - AUTHORS Rafael Ballester (rballester@ifi.uzh.ch) Susanne Suter (susuter@ifi.uzh.ch) Jonas Boesch (boesch@ifi.uzh.ch) Stefan Eilemann (eile@eyescale.ch) Renato Pajarola (pajarola@ifi.uzh.ch) Philip Schlegel (schlegel@ifi.uzh.ch) With contributions from: Daniel Pfeifer (daniel@pfeifer-mail.de) - CMake Build System, Linux fixes Jaroslav Skarvada (jskarvad@redhat.com) - Red Hat packaging, RH compatibility fixes Bas Wijnen (wijnen@debian.org) - Debian packaging see ACKNOWLEDGEMENTS - Parts of the source code of VMMLib were inspired by David Eberly's Wild Magic and Andrew Willmott's VL. - enable_if was inspired by Boost (http://www.boost.org/doc/libs/1_39_0/libs/utility/enable_if.html) repsnapper-2.3.2a5/libraries/vmmlib/CHANGES000066400000000000000000000001151231531733200203550ustar00rootroot00000000000000 2012-02-21: validator class instead of matrix.is_valid(), vector.is_valid()repsnapper-2.3.2a5/libraries/vmmlib/CMakeLists.txt000066400000000000000000000136701231531733200221340ustar00rootroot00000000000000# Copyright (c) 2011 Daniel Pfeifer cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(vmmlib) set(VERSION_MAJOR 1) set(VERSION_MINOR 7) set(VERSION_PATCH 0) set(RELEASE_VERSION OFF) # OFF or ABI version set(LAST_RELEASE 1.6.1) option(VMMLIB_USE_BLAS "Disable to turn blas detection off" ON) mark_as_advanced(VMMLIB_USE_BLAS) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake) set(MACPORTS_DIR eyescalePorts) # override for now... include(Common) include(GitTargets) include(FindPackages) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-shadow -Wno-sign-compare -Wno-extra -Wno-strict-aliasing") endif() include_directories(BEFORE ${CMAKE_SOURCE_DIR}/include) if(APPLE) find_library(LAPACK_LIBRARIES Accelerate) if(LAPACK_LIBRARIES) set(LAPACK_FOUND TRUE) endif(LAPACK_LIBRARIES) elseif(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") # enable_language(Fortran OPTIONAL) # eile: Why needed? if (VMMLIB_USE_BLAS) find_package(BLAS) if(BLAS_FOUND) list(GET BLAS_LIBRARIES 0 BLAS_LIBRARY_DIR) get_filename_component(BLAS_LIBRARY_DIR ${BLAS_LIBRARY_DIR} PATH) find_path(BLAS_INCLUDE_DIR cblas.h ${BLAS_LIBRARY_DIR}/../include NO_DEFAULT_PATH) if(BLAS_INCLUDE_DIR) find_package(LAPACK) else() message(STATUS "Missing cblas.h in ${BLAS_LIBRARY_DIR}/../include, disabling BLAS support") set(BLAS_FOUND) endif() endif() endif() endif() set(DOCS README.md AUTHORS LICENSE.txt ACKNOWLEDGEMENTS) set(BLAS_LIBRARIES blas) update_file(${CMAKE_CURRENT_SOURCE_DIR}/include/vmmlib/version.in.hpp ${OUTPUT_INCLUDE_DIR}/vmmlib/version.hpp) set(HEADERS ${OUTPUT_INCLUDE_DIR}/vmmlib/version.hpp include/vmmlib/aabb.hpp include/vmmlib/blas_daxpy.hpp include/vmmlib/blas_dgemm.hpp include/vmmlib/blas_dot.hpp include/vmmlib/blas_includes.hpp include/vmmlib/blas_types.hpp include/vmmlib/cp3_tensor.hpp include/vmmlib/enable_if.hpp include/vmmlib/exception.hpp include/vmmlib/frustum.hpp include/vmmlib/frustum_culler.hpp include/vmmlib/intersection.hpp include/vmmlib/jacobi_solver.hpp include/vmmlib/lapack.hpp include/vmmlib/lapack/detail/clapack.h include/vmmlib/lapack/detail/f2c.h include/vmmlib/lapack_gaussian_elimination.hpp include/vmmlib/lapack_includes.hpp include/vmmlib/lapack_linear_least_squares.hpp include/vmmlib/lapack_svd.hpp include/vmmlib/lapack_sym_eigs.hpp include/vmmlib/lapack_types.hpp include/vmmlib/linear_least_squares.hpp include/vmmlib/lowpass_filter.hpp include/vmmlib/math.hpp include/vmmlib/matrix.hpp include/vmmlib/matrix_functors.hpp include/vmmlib/matrix_pseudoinverse.hpp include/vmmlib/matrix_traits.hpp include/vmmlib/qr_decomposition.hpp include/vmmlib/qtucker3_tensor.hpp include/vmmlib/quaternion.hpp include/vmmlib/svd.hpp include/vmmlib/t3_converter.hpp include/vmmlib/t3_hooi.hpp include/vmmlib/t3_hopm.hpp include/vmmlib/t3_hosvd.hpp include/vmmlib/t3_ihopm.hpp include/vmmlib/t3_ihooi.hpp include/vmmlib/t3_ttm.hpp include/vmmlib/tensor3.hpp include/vmmlib/tensor3_iterator.hpp include/vmmlib/tucker3_exporter.hpp include/vmmlib/tucker3_importer.hpp include/vmmlib/tucker3_tensor.hpp include/vmmlib/util.hpp include/vmmlib/validator.hpp include/vmmlib/vector.hpp include/vmmlib/vector_traits.hpp include/vmmlib/visibility.hpp include/vmmlib/vmmlib.hpp include/vmmlib/vmmlib_config.hpp include/vmmlib/tensor4.hpp include/vmmlib/t4_converter.hpp include/vmmlib/t4_hooi.hpp include/vmmlib/t4_hosvd.hpp include/vmmlib/t4_ttm.hpp include/vmmlib/tucker4_tensor.hpp ) set(TESTS tests/frustum_test.cpp tests/intersection_test.cpp tests/jacobi_test.cpp tests/matrix_test.cpp tests/perf_test.cpp tests/performance_test.cpp tests/qr_decomposition_test.cpp tests/quaternion_test.cpp tests/svd_test.cpp tests/timer.cpp tests/unit_test.cpp tests/unit_test_globals.cpp tests/lowpass_filter_test.cpp tests/vector_test.cpp tests/util_test.cpp tests/vmmlib_unit_tests_main.cpp # tests/matrix_compare_perf_test.cpp # tests/stringtests.cpp # tests/vmmlib_lapack_main.cpp # tests/vmmlib_performance_tests_main.cpp ) if(LAPACK_FOUND) add_definitions(-DVMMLIB_USE_LAPACK) list(APPEND TESTS tests/blas_daxpy_test.cpp tests/blas_dgemm_test.cpp tests/blas_dot_test.cpp tests/cp3_tensor_test.cpp tests/lapack_gaussian_elimination_test.cpp tests/lapack_linear_least_squares_test.cpp tests/lapack_svd_test.cpp tests/lapack_sym_eigs_test.cpp tests/matrix_pseudoinverse_test.cpp tests/qtucker3_tensor_test.cpp tests/svd_lapack_vs_old.cpp tests/t3_hooi_test.cpp tests/t3_hopm_test.cpp tests/t3_hosvd_test.cpp tests/t3_ihooi_test.cpp tests/t3_ihopm_test.cpp tests/t3_ttm_test.cpp tests/tensor3_iterator_test.cpp tests/tensor3_test.cpp tests/tucker3_exporter_importer_test.cpp tests/tucker3_tensor_test.cpp tests/t4_hooi_test.cpp tests/t4_converter_test.cpp tests/tensor4_test.cpp tests/t4_ttm_test.cpp ) endif() if(BLAS_FOUND) add_definitions(-DVMMLIB_USE_BLAS) endif() if(NOT MSVC) add_executable(vmmlib_test ${HEADERS} ${TESTS}) if(LAPACK_FOUND) target_link_libraries(vmmlib_test ${LAPACK_LIBRARIES}) endif() if(BLAS_FOUND) target_link_libraries(vmmlib_test ${BLAS_LIBRARIES}) endif() get_target_property(EXECUTABLE vmmlib_test LOCATION) STRING(REGEX REPLACE "\\$\\(.*\\)" "\${CTEST_CONFIGURATION_TYPE}" EXECUTABLE "${EXECUTABLE}") add_test(vmmlib_test ${EXECUTABLE}) # workaround: 'make test' does not build tests beforehand add_custom_target(tests COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS vmmlib_test) add_custom_target(vmmlib-test DEPENDS tests) # Travis CI hack endif() install(FILES ${HEADERS} DESTINATION include/vmmlib COMPONENT dev) install(FILES ${DOCS} DESTINATION share/vmmlib COMPONENT dev) include(DoxygenRule) # must be after all targets include(CPackConfig) include(CTest) include(PackageConfig) repsnapper-2.3.2a5/libraries/vmmlib/LICENSE.txt000066400000000000000000000030571231531733200212150ustar00rootroot00000000000000Copyright (c) 2006-2012, Visualization and Multimedia Lab, University of Zurich All rights reserved. (http://vmml.ifi.uzh.ch) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Visualization and Multimedia Lab, University of Zurich nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. repsnapper-2.3.2a5/libraries/vmmlib/Makefile.am000066400000000000000000000001241231531733200214160ustar00rootroot00000000000000EXTRA_DIST += libraries/vmmlib/README include libraries/vmmlib/include/Makefile.am repsnapper-2.3.2a5/libraries/vmmlib/Makefile.atlas000066400000000000000000000036351231531733200221370ustar00rootroot00000000000000 VMMLIB_UNIT_TESTS =\ tests/unit_test.cpp\ tests/unit_test_globals.cpp\ tests/vector_test.cpp\ tests/matrix_test.cpp\ tests/quaternion_test.cpp\ tests/qr_decomposition_test.cpp\ tests/svd_test.cpp\ tests/lapack_svd_test.cpp\ tests/lapack_linear_least_squares_test.cpp\ tests/lapack_gaussian_elimination_test.cpp\ tests/vmmlib_unit_tests_main.cpp\ tests/lapack_sym_eigs_test.cpp\ tests/tensor3_test.cpp \ tests/tensor3_iterator_test.cpp \ tests/tucker3_tensor_test.cpp \ tests/qtucker3_tensor_test.cpp \ tests/tucker3_exporter_importer_test.cpp \ tests/cp3_tensor_test.cpp \ tests/t3_hosvd_test.cpp \ tests/t3_hooi_test.cpp \ tests/t3_hopm_test.cpp \ tests/t3_ihopm_test.cpp \ tests/matrix_pseudoinverse_test.cpp \ tests/blas_dgemm_test.cpp \ tests/blas_dot_test.cpp \ VMMLIB_UNIT_TESTS_OBJECTS = ${VMMLIB_UNIT_TESTS:%.cpp=%.o} CXXFLAGS += -I. -Iinclude -Itests -include stdint.h # Mac OS X specific stuff # on mac we want to use the frameworks, not the unix style libs ARCH = $(shell uname) ifeq "$(ARCH)" "Darwin" CXXFLAGS += -framework Accelerate LDFLAGS += -framework Accelerate else # Linux specific stuff CXXFLAGS += -include f2c.h -include f2c_fix.h LBITS := $(shell getconf LONG_BIT) ifeq ($(LBITS),64) LIBDIR=$(DESTDIR)/usr/lib64 else LIBDIR=$(DESTDIR)/usr/lib endif LDFLAGS += -L$(LIBDIR)/atlas -u MAIN__ CXXFLAGS += -DVMMLIB_USE_LAPACK LDFLAGS += # adjust libs depending on your LAPACK and BLAS distribution LIBS += -lclapack -lf2c -lcblas -llapack # LIBS += -llapack -lblas endif all: vmmlib_unit_tests .cpp.o: $(CXX) $(CXXFLAGS) -c $< -o $@ vmmlib_unit_tests: $(VMMLIB_UNIT_TESTS_OBJECTS) ifeq "$(ARCH)" "Darwin" $(CXX) $(LDFLAGS) $(VMMLIB_UNIT_TESTS_OBJECTS) -o $@ else $(CXX) $(LDFLAGS) $(VMMLIB_UNIT_TESTS_OBJECTS) -o $@ $(LIBS) endif clean: rm -rf $(VMMLIB_UNIT_TESTS_OBJECTS) vmmlib_unit_tests repsnapper-2.3.2a5/libraries/vmmlib/Makefile.make000066400000000000000000000040301231531733200217360ustar00rootroot00000000000000 VMMLIB_UNIT_TESTS =\ tests/unit_test.cpp\ tests/unit_test_globals.cpp\ tests/vector_test.cpp\ tests/matrix_test.cpp\ tests/quaternion_test.cpp\ tests/qr_decomposition_test.cpp\ tests/svd_test.cpp\ tests/lapack_svd_test.cpp\ tests/lapack_linear_least_squares_test.cpp\ tests/lapack_gaussian_elimination_test.cpp\ tests/vmmlib_unit_tests_main.cpp\ tests/lapack_sym_eigs_test.cpp\ tests/tensor3_test.cpp \ tests/tensor3_iterator_test.cpp \ tests/tucker3_tensor_test.cpp \ tests/qtucker3_tensor_test.cpp \ tests/tucker3_exporter_importer_test.cpp \ tests/cp3_tensor_test.cpp \ tests/t3_hosvd_test.cpp \ tests/t3_hooi_test.cpp \ tests/t3_hopm_test.cpp \ tests/t3_ihopm_test.cpp \ tests/t3_ihooi_test.cpp \ tests/t3_ttm_test.cpp \ tests/t3_padder_test.cpp \ tests/matrix_pseudoinverse_test.cpp \ tests/blas_dgemm_test.cpp \ tests/blas_dot_test.cpp \ tests/blas_daxpy_test.cpp \ tests/tensor4_test.cpp \ tests/t4_converter_test.cpp \ VMMLIB_UNIT_TESTS_OBJECTS = ${VMMLIB_UNIT_TESTS:%.cpp=%.o} CXXFLAGS += -I. -Iinclude -Itests -include stdint.h # Mac OS X specific stuff # on mac we want to use the frameworks, not the unix style libs ARCH = $(shell uname) ifeq "$(ARCH)" "Darwin" CXXFLAGS += -DVMMLIB_USE_LAPACK LDFLAGS += -framework Accelerate -fopenmp else # Linux specific stuff CXXFLAGS += -include f2c.h -include f2c_fix.h LBITS := $(shell getconf LONG_BIT) ifeq ($(LBITS),64) LIBDIR=$(DESTDIR)/usr/lib64 else LIBDIR=$(DESTDIR)/usr/lib endif CXXFLAGS += -DVMMLIB_USE_LAPACK LDFLAGS += -fopenmp # adjust libs depending on your LAPACK and BLAS distribution LIBS += -lblas -llapack -lf2c endif all: vmmlib_unit_tests .cpp.o: $(CXX) $(CXXFLAGS) -c $< -o $@ vmmlib_unit_tests: $(VMMLIB_UNIT_TESTS_OBJECTS) ifeq "$(ARCH)" "Darwin" $(CXX) $(LDFLAGS) $(VMMLIB_UNIT_TESTS_OBJECTS) -o $@ else $(CXX) $(LDFLAGS) $(VMMLIB_UNIT_TESTS_OBJECTS) -o $@ $(LIBS) endif clean: rm -rf $(VMMLIB_UNIT_TESTS_OBJECTS) vmmlib_unit_tests repsnapper-2.3.2a5/libraries/vmmlib/README.md000066400000000000000000000004601231531733200206440ustar00rootroot00000000000000vmmlib ====== A templatized C++ vector and matrix math library. For more information please see http://vmml.github.com/vmmlib/ License: (revised) BSD VMMLib depends on LAPACK and BLAS, if you just want to use VMMLib basic without depending on LAPACK/BLAS, don't include the affected header files. repsnapper-2.3.2a5/libraries/vmmlib/RELNOTES.md000066400000000000000000000062661231531733200211540ustar00rootroot00000000000000# Release Notes 2013/05/02 vmmlib - a templatized C++ vector and matrix math library Its basic functionality includes a vector and a matrix class, with additional functionality for the often-used 3d and 4d vectors and 3x3 and 4x4 matrices. More advanced features include solvers, frustum computations and frustum culling classes, and spatial data structures. vmmlib also offers support for manipulating 3rd-order and 4th-order tensors, as well as several algorithms for tensor approximation. Vmmlib is implemented using C++ templates, making it versatile. Being a header library, it is very easy to integrate into other (your) libraries and programs. There is no need to build and install a library, just include the headers and you’re set. The BSD license allows the usage both in open source and commercial closed source software. # New in this release ###CMake * use now only CMake to create a Makefile ###Use Tensor Approximation Classes (based on LAPACK, BLAS) * define VMMLIB_USE_LAPACK in Makefile (changed from VMMLIB_BASIC_ONLY) ### Matrix * added matrix validators ###Tensor Approximation Classes * memory mapping classes for large tensor data structures (tensor_mmapper.hpp) * created t3_converter: used to import/export tensors; converting/reading/writing files; quantization * moved tensor3 reading/writing/quantization/tensor times matrix multiplications to t3_converter.hpp * added tensor times matrix multiplications (ttm) and tensor times vector multiplication (ttv): multiply tensors along various modes * use OpenMP for some parallel computations (tensor3, ttm) * added tensor4 data structure (including t4_converter for converting/reading/writing files) * added class for handling statistics on tensor algorithms: tensor_stats * updated incremental methods (added ihooi; updated ihopm) ###BLAS Wrapper * added BLAS DAXPY wrapper ###Filtering * added intersection, lowpass_filter class * updates in frustum_culler ###Unit Tests * boolean global results of every test are now consistent with every subtest ## Documentation The following have been added: * Tensor Approximation tutorial: www.ifi.uzh.ch/vmml/links/TutorTensorAprox.html * Tensor Approximation slides: http://files.ifi.uzh.ch/vmml/ta_tutorial/vmmlib_ta_classes.pdf * "toy" example project http://files.ifi.uzh.ch/vmml/ta_tutorial/vmmlib_play.zip ## Bug Fixes vmmlib 1.6 includes several fixes over the last release, such as: * various test fixes * precision bug of CP3 tensor reconstruction error measurement * tensor4 "<<" operator * computation of residual norm in HOOI * corrected formula for quaternion slerp ## Known Issues * memory mapping for windows to be tested * test for slerp and matrix validators are not yet implemented * tests that depend on rand() are deactivated: they may break with different stdlib versions * tests that depend on LAPACK and BLAS are not fully supported for Windows ## Planned Future Extensions * decomposition and reconstruction algorithms for 4D tensors # About ## Platform Support * Linux * Mac OS X * WIN64 operating systems ## Documentation ## Support * comments and requests can be issued at http://github.com/VMML/vmmlib/issues * contributions can be merged into vmmlib via a pull request # Errata repsnapper-2.3.2a5/libraries/vmmlib/doc/000077500000000000000000000000001231531733200201325ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/doc/Doxyfile000066400000000000000000002342241231531733200216470ustar00rootroot00000000000000# Doxyfile 1.8.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = vmmlib # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "Vector and Matrix Math Library" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @CMAKE_BINARY_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented classes, # or namespaces to their corresponding documentation. Such a link can be # prevented in individual cases by by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 5 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if section-label ... \endif # and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. Do not use # file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @CMAKE_INSTALL_PREFIX@/include/vmmlib \ @CMAKE_SOURCE_DIR@/doc # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h \ *.c \ *.cpp \ *.ipp \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page (index.html). # This can be useful if you have a project on for instance GitHub and want reuse # the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = @CMAKE_BINARY_DIR@/doc/html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 210 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 50 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = YES # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "VMMLib Documentation" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = net.sourceforge.vmmlib # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = net.sourceforge.vmmlib.documentation # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Eyescale # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NONE # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and # SVG. The default value is HTML-CSS, which is slower, but has the best # compatibility. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. # There are two flavours of web server based search depending on the # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # searching and an index file used by the script. When EXTERNAL_SEARCH is # enabled the indexing and searching needs to be provided by external tools. # See the manual for details. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain # the search results. Doxygen ships with an example indexer (doxyindexer) and # search engine (doxysearch.cgi) which are based on the open source search engine # library Xapian. See the manual for configuration details. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will returned the search results when EXTERNAL_SEARCH is enabled. # Doxygen ships with an example search engine (doxysearch) which is based on # the open source search engine library Xapian. See the manual for configuration # details. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. SEARCHDATA_FILE = searchdata.xml # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through other # doxygen projects that are not otherwise connected via tags files, but are # all added to the same search index. Each project needs to have a tag file set # via GENERATE_TAGFILE. The search mapping then maps the name of the tag file # to a relative location where the documentation can be found, # similar to the # TAGFILES option but without actually processing the tag file. # The format is: EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = pdf # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = pdflatex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = YES # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = @CMAKE_BINARY_DIR@/doc/man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Sans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 15 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 4 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES repsnapper-2.3.2a5/libraries/vmmlib/doc/DoxygenLayout.xml000066400000000000000000000130411231531733200234660ustar00rootroot00000000000000 repsnapper-2.3.2a5/libraries/vmmlib/include/000077500000000000000000000000001231531733200210105ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/include/Makefile.am000066400000000000000000000000651231531733200230450ustar00rootroot00000000000000include libraries/vmmlib/include/vmmlib/Makefile.am repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/000077500000000000000000000000001231531733200222765ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/Makefile.am000066400000000000000000000002261231531733200243320ustar00rootroot00000000000000EXTRA_DIST += \ libraries/vmmlib/LICENSE.txt \ $(wildcard libraries/vmmlib/include/vmmlib/*.h) \ $(wildcard libraries/vmmlib/include/vmmlib/*.hpp) repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/aabb.hpp000066400000000000000000000133001231531733200236710ustar00rootroot00000000000000#ifndef __VMML__AXIS_ALIGNED_BOUNDING_BOX__HPP__ #define __VMML__AXIS_ALIGNED_BOUNDING_BOX__HPP__ #include namespace vmml { template< typename T > class AxisAlignedBoundingBox { public: AxisAlignedBoundingBox(); AxisAlignedBoundingBox( const vector< 3, T >& pMin, const vector< 3, T >& pMax ); AxisAlignedBoundingBox( const vector< 4, T >& sphere ); AxisAlignedBoundingBox( T cx, T cy, T cz, T size ); inline bool isIn( const vector< 3, T >& pos ); inline bool isIn2d( const vector< 3, T >& pos ); // only x and y components are checked inline bool isIn( const vector< 4, T >& sphere ); inline void set( const vector< 3, T >& pMin, const vector< 3, T >& pMax ); inline void set( T cx, T cy, T cz, T size ); inline void setMin( const vector< 3, T >& pMin ); inline void setMax( const vector< 3, T >& pMax ); inline const vector< 3, T >& getMin() const; inline const vector< 3, T >& getMax() const; inline void merge( const AxisAlignedBoundingBox< T >& aabb ); inline void setEmpty( bool empty = true ); inline bool isEmpty() const; inline void setDirty( bool dirty = true ); inline bool isDirty() const; vector< 3, T > getCenter() const; vector< 3, T > getDimension() const; protected: vector< 3, T > _min; vector< 3, T > _max; bool _dirty; bool _empty; }; template< typename T > AxisAlignedBoundingBox< T >::AxisAlignedBoundingBox() : _dirty( false ) , _empty( true ) {} template< typename T > AxisAlignedBoundingBox< T >::AxisAlignedBoundingBox( const vector< 3, T >& pMin, const vector< 3, T >& pMax ) : _min( pMin ) , _max( pMax ) , _dirty( false ) , _empty( false ) {} template< typename T > AxisAlignedBoundingBox< T >::AxisAlignedBoundingBox( const vector< 4, T >& sphere ) : _dirty( false ) , _empty( false ) { _max = _min = sphere.getCenter(); _max += sphere.getRadius(); _min -= sphere.getRadius(); } template< typename T > AxisAlignedBoundingBox< T >::AxisAlignedBoundingBox( T cx, T cy, T cz, T size ) : _dirty( false ) , _empty( false ) { _max = _min = vector< 3, T >( cx, cy, cz ); _max += size; _min -= size; } template< typename T > inline bool AxisAlignedBoundingBox< T >::isIn( const vector< 4, T >& sphere ) { if ( _empty ) return false; vector< 3, T > sv ( sphere.getCenter() ); sv += sphere.getRadius(); if ( sv.x() > _max.x() || sv.y() > _max.y() || sv.z() > _max.z() ) return false; sv -= sphere.getRadius() * 2.0f; if ( sv.x() < _min.x() || sv.y() < _min.y() || sv.z() < _min.z() ) return false; return true; } template< typename T > inline bool AxisAlignedBoundingBox< T >::isIn( const vector< 3, T >& pos ) { if ( _empty ) return false; if ( pos.x() > _max.x() || pos.y() > _max.y() || pos.z() > _max.z() || pos.x() < _min.x() || pos.y() < _min.y() || pos.z() < _min.z() ) { return false; } return true; } template< typename T > inline bool AxisAlignedBoundingBox< T >::isIn2d( const vector< 3, T >& pos ) { if ( _empty ) return false; if ( pos.x() > _max.x() || pos.y() > _max.y() || pos.x() < _min.x() || pos.y() < _min.y() ) { return false; } return true; } template< typename T > inline void AxisAlignedBoundingBox< T >::set( const vector< 3, T >& pMin, const vector< 3, T >& pMax ) { _min = pMin; _max = pMax; _empty = false; } template< typename T > inline void AxisAlignedBoundingBox< T >::set( T cx, T cy, T cz, T size ) { vector< 3, T > center( cx, cy, cz ); _min = center - size; _max = center + size; _empty = false; } template< typename T > inline void AxisAlignedBoundingBox< T >::setMin( const vector< 3, T >& pMin ) { _min = pMin; } template< typename T > inline void AxisAlignedBoundingBox< T >::setMax( const vector< 3, T >& pMax ) { _max = pMax; } template< typename T > inline const vector< 3, T >& AxisAlignedBoundingBox< T >::getMin() const { return _min; } template< typename T > inline const vector< 3, T >& AxisAlignedBoundingBox< T >::getMax() const { return _max; } template< typename T > vector< 3, T > AxisAlignedBoundingBox< T >::getCenter() const { return _min + ( ( _max - _min ) * 0.5f ); } template< typename T > vector< 3, T > AxisAlignedBoundingBox< T >::getDimension() const { return _max - _min; } template< typename T > void AxisAlignedBoundingBox< T >::merge( const AxisAlignedBoundingBox< T >& aabb ) { if ( aabb._empty ) return; // nothing to do if ( _empty ) { // copy non-empty aabb _min = aabb._min; _max = aabb._max; _empty = _dirty = false; return; } // else merge the two aabbs const vector< 3, T >& min = aabb.getMin(); const vector< 3, T >& max = aabb.getMax(); if ( min.x() < _min.x() ) _min.x() = min.x(); if ( min.y() < _min.y() ) _min.y() = min.y(); if ( min.z() < _min.z() ) _min.z() = min.z(); if ( max.x() > _max.x() ) _max.x() = max.x(); if ( max.y() > _max.y() ) _max.y() = max.y(); if ( max.z() > _max.z() ) _max.z() = max.z(); } template< typename T > inline void AxisAlignedBoundingBox< T >::setEmpty( bool empty ) { _empty = empty; } template< typename T > inline bool AxisAlignedBoundingBox< T >::isEmpty() const { return _empty; } template< typename T > inline void AxisAlignedBoundingBox< T >::setDirty( bool dirty ) { _dirty = dirty; } template< typename T > inline bool AxisAlignedBoundingBox< T >::isDirty() const { return _dirty; } typedef AxisAlignedBoundingBox< float > Aabbf; }; //namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/blas_daxpy.hpp000066400000000000000000000123011231531733200251320ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_BLAS_DAXPY__HPP__ #define __VMML__VMMLIB_BLAS_DAXPY__HPP__ #include #include #include #include #include #ifdef VMMLIB_USE_OPENMP # include #endif /** * * a wrapper for blas's daxpy routine. * SUBROUTINE DAXPY(N,DA,DX,INCX,DY,INCY) * .. Scalar Arguments .. * DOUBLE PRECISION DA * INTEGER INCX,INCY,N * .. * .. Array Arguments .. * DOUBLE PRECISION DX(*),DY(*) * .. * * * Purpose * ======= * * DAXPY constant times a vector plus a vector. * uses unrolled loops for increments equal to one. * * more information in: http://netlib.org/blas/daxpy.f ** */ namespace vmml { namespace blas { #if 0 /* Subroutine */ void cblas_daxpy(const int N, const double alpha, const double *X, const int incX, double *Y, const int incY); #endif template< typename float_t > struct daxpy_params { blas_int n; float_t alpha; float_t* x; blas_int inc_x; float_t* y; blas_int inc_y; friend std::ostream& operator << ( std::ostream& os, const daxpy_params< float_t >& p ) { os << " (1)\tn " << p.n << std::endl << " (2)\talpha " << p.alpha << std::endl << " (3)\tx " << p.x << std::endl << " (4)\tincX " << p.inc_x << std::endl << " (5)\ty " << p.y << std::endl << " (6)\tincY " << p.inc_y << std::endl << std::endl; return os; } }; template< typename float_t > inline void daxpy_call( daxpy_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void daxpy_call( daxpy_params< float >& p ) { //std::cout << "calling blas saxpy (single precision) " << std::endl; cblas_saxpy( p.n, p.alpha, p.x, p.inc_x, p.y, p.inc_y ); } template<> inline void daxpy_call( daxpy_params< double >& p ) { //std::cout << "calling blas daxpy (double precision) " << std::endl; cblas_daxpy( p.n, p.alpha, p.x, p.inc_x, p.y, p.inc_y ); } } // namespace blas template< size_t M, typename float_t > struct blas_daxpy { typedef vector< M, float_t > vector_t; blas_daxpy(); ~blas_daxpy() {}; bool compute( const float_t a_, const vector_t& B_, vector_t& C_ ); template< size_t K, size_t N > bool compute_mmm( const matrix< M, K, float_t >& left_m_, const matrix< K, N, float_t >& right_m_, matrix< M, N, float_t >& res_m_ ); template< size_t K > bool compute_mmm( const matrix< M, K, float_t >& left_m_, matrix< M, M, float_t >& res_m_ ); blas::daxpy_params< float_t > p; const blas::daxpy_params< float_t >& get_params(){ return p; }; }; // struct blas_daxpy template< size_t M, typename float_t > blas_daxpy< M, float_t >::blas_daxpy() { p.n = M; p.alpha = 0; p.x = 0; p.inc_x = 1; p.y = 0; p.inc_y = 1; } template< size_t M, typename float_t > bool blas_daxpy< M, float_t >::compute( const float_t a_, const vector_t& B_, vector_t& C_ ) { // blas needs non-const data vector_t* BB = new vector_t( B_ ); C_.set(0); p.alpha = a_; p.x = BB->array; p.y = C_.array; blas::daxpy_call< float_t >( p ); //std::cout << p << std::endl; //debug delete BB; return true; } template< size_t M, typename float_t > template< size_t K, size_t N > bool blas_daxpy< M, float_t >::compute_mmm( const matrix< M, K, float_t >& left_m_, const matrix< K, N, float_t >& right_m_, matrix< M, N, float_t >& res_m_ ) { for ( int n = 0; n < (int)N; ++n ) { vector_t* final_col = new vector_t; final_col->set(0); for ( int k = 0; k < (int)K; ++k ) { vector_t* in_col = new vector_t; vector_t* out_col = new vector_t; float_t a_val = right_m_.at( k, n ); left_m_.get_column( k, *in_col ); compute( a_val, *in_col, *out_col ); *final_col += *out_col; delete in_col; delete out_col; } res_m_.set_column( n, *final_col ); delete final_col; } return true; } template< size_t M, typename float_t > template< size_t K > bool blas_daxpy< M, float_t >::compute_mmm( const matrix< M, K, float_t >& left_m_, matrix< M, M, float_t >& res_m_ ) { #pragma omp parallel for for ( int n = 0; n < (int)M; ++n ) { vector_t* final_col = new vector_t; final_col->set(0); #pragma omp parallel for for ( int k = 0; k < (int)K; ++k ) { vector_t* in_col = new vector_t; vector_t* out_col = new vector_t; float_t a_val = left_m_.at( n,k ); //reversed (k,n), because take value from transposed matrix left_m_ left_m_.get_column( k, *in_col ); compute( a_val, *in_col, *out_col ); *final_col += *out_col; delete in_col; delete out_col; } res_m_.set_column( n, *final_col ); delete final_col; } return true; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/blas_dgemm.hpp000066400000000000000000000241701231531733200251050ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_BLAS_DGEMM__HPP__ #define __VMML__VMMLIB_BLAS_DGEMM__HPP__ #include #include #include #include #include /** * * a wrapper for blas's DGEMM routine. SUBROUTINE DGEMM(TRANSA,TRANSB,M,N,K,ALPHA,A,LDA,B,LDB,BETA,C,LDC) * .. Scalar Arguments .. DOUBLE PRECISION ALPHA,BETA INTEGER K,LDA,LDB,LDC,M,N CHARACTER TRANSA,TRANSB * .. * .. Array Arguments .. DOUBLE PRECISION A(LDA,*),B(LDB,*),C(LDC,*) * .. * * Purpose * ======= * * DGEMM performs one of the matrix-matrix operations * * C := alpha*op( A )*op( B ) + beta*C, * * where op( X ) is one of * * op( X ) = X or op( X ) = X**T, * * alpha and beta are scalars, and A, B and C are matrices, with op( A ) * an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. * * * more information in: http://www.netlib.org/blas/dgemm.f * or http://www.netlib.org/clapack/cblas/dgemm.c ** */ namespace vmml { namespace blas { #if 0 /* Subroutine */ void cblas_dgemm(enum CBLAS_ORDER Order, enum CBLAS_TRANSPOSE TransA, enum CBLAS_TRANSPOSE TransB, blasint M, blasint N, blasint K, double alpha, double *A, blasint lda, double *B, blasint ldb, double beta, double *C, blasint ldc); #endif template< typename float_t > struct dgemm_params { CBLAS_ORDER order; CBLAS_TRANSPOSE trans_a; CBLAS_TRANSPOSE trans_b; blas_int m; blas_int n; blas_int k; float_t alpha; float_t* a; blas_int lda; //leading dimension of input array matrix left float_t* b; blas_int ldb; //leading dimension of input array matrix right float_t beta; float_t* c; blas_int ldc; //leading dimension of output array matrix right friend std::ostream& operator << ( std::ostream& os, const dgemm_params< float_t >& p ) { os << " (1)\torder " << p.order << std::endl << " (2)\ttrans_a " << p.trans_a << std::endl << " (3)\ttrans_b " << p.trans_b << std::endl << " (4)\tm " << p.m << std::endl << " (6)\tn " << p.n << std::endl << " (5)\tk " << p.k << std::endl << " (7)\talpha " << p.alpha << std::endl << " (8)\ta " << p.a << std::endl << " (9)\tlda " << p.lda << std::endl << " (10)\tb " << p.b << std::endl << " (11)\tldb " << p.ldb << std::endl << " (12)\tbeta " << p.beta << std::endl << " (13)\tc " << p.c << std::endl << " (14)\tldc " << p.ldc << std::endl << std::endl; return os; } }; template< typename float_t > inline void dgemm_call( dgemm_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void dgemm_call( dgemm_params< float >& p ) { //std::cout << "calling blas sgemm (single precision) " << std::endl; cblas_sgemm( p.order, p.trans_a, p.trans_b, p.m, p.n, p.k, p.alpha, p.a, p.lda, p.b, p.ldb, p.beta, p.c, p.ldc ); } template<> inline void dgemm_call( dgemm_params< double >& p ) { //std::cout << "calling blas dgemm (double precision) " << std::endl; cblas_dgemm( p.order, p.trans_a, p.trans_b, p.m, p.n, p.k, p.alpha, p.a, p.lda, p.b, p.ldb, p.beta, p.c, p.ldc ); } } // namespace blas template< size_t M, size_t K, size_t N, typename float_t > struct blas_dgemm { typedef matrix< M, K, float_t > matrix_left_t; typedef matrix< K, M, float_t > matrix_left_t_t; typedef matrix< K, N, float_t > matrix_right_t; typedef matrix< N, K, float_t > matrix_right_t_t; typedef matrix< M, N, float_t > matrix_out_t; typedef vector< M, float_t > vector_left_t; typedef vector< N, float_t > vector_right_t; blas_dgemm(); ~blas_dgemm() {}; bool compute( const matrix_left_t& A_, const matrix_right_t& B_, matrix_out_t& C_ ); bool compute( const matrix_left_t& A_, matrix_out_t& C_ ); // dgemms with tensor3 input works for frontal tensor unfolding //I2*I3 = K; template< size_t I2, size_t I3 > bool compute( const tensor3< M, I2, I3, float_t >& A_, const matrix_right_t& B_, matrix_out_t& C_ ); //I2*I3 = K; template< size_t I2, size_t I3 > bool compute( const tensor3< M, I2, I3, float_t >& A_, matrix_out_t& C_ ); bool compute_t( const matrix_right_t& B_, matrix_out_t& C_ ); bool compute_bt( const matrix_left_t& A_, const matrix_right_t_t& Bt_, matrix_out_t& C_ ); bool compute_t( const matrix_left_t_t& A_, const matrix_right_t_t& B_, matrix_out_t& C_ ); bool compute_vv_outer( const vector_left_t& A_, const vector_right_t& B_, matrix_out_t& C_ ); blas::dgemm_params< float_t > p; const blas::dgemm_params< float_t >& get_params(){ return p; }; }; // struct blas_dgemm template< size_t M, size_t K, size_t N, typename float_t > blas_dgemm< M, K, N, float_t >::blas_dgemm() { p.order = CblasColMajor; // p.trans_a = CblasNoTrans; p.trans_b = CblasNoTrans; p.m = M; p.n = N; p.k = K; p.alpha = 1; p.a = 0; p.lda = M; p.b = 0; p.ldb = K; //no transpose p.beta = 0; p.c = 0; p.ldc = M; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute( const matrix_left_t& A_, const matrix_right_t& B_, matrix_out_t& C_ ) { // blas needs non-const data matrix_left_t* AA = new matrix_left_t( A_ ); matrix_right_t* BB = new matrix_right_t( B_ ); C_.zero(); p.a = AA->array; p.b = BB->array; p.c = C_.array; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete AA; delete BB; return true; } template< size_t M, size_t K, size_t N, typename float_t > template< size_t I2, size_t I3 > bool blas_dgemm< M, K, N, float_t >::compute( const tensor3< M, I2, I3, float_t >& A_, const matrix_right_t& B_, matrix_out_t& C_ ) { // blas needs non-const data tensor3< M, I2, I3, float_t > AA( A_ ); matrix_right_t* BB = new matrix_right_t( B_ ); C_.zero(); p.a = AA.get_array_ptr(); p.b = BB->array; p.c = C_.array; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete BB; return true; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute( const matrix_left_t& A_, matrix_out_t& C_ ) { // blas needs non-const data matrix_left_t* AA = new matrix_left_t( A_ ); C_.zero(); p.trans_b = CblasTrans; p.a = AA->array; p.b = AA->array; p.ldb = N; p.c = C_.array; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete AA; return true; } template< size_t M, size_t K, size_t N, typename float_t > template< size_t I2, size_t I3 > bool blas_dgemm< M, K, N, float_t >::compute( const tensor3< M, I2, I3, float_t >& A_, matrix_out_t& C_ ) { // blas needs non-const data tensor3< M, I2, I3, float_t > AA( A_ ) ; C_.zero(); p.trans_b = CblasTrans; p.a = AA.get_array_ptr(); p.b = AA.get_array_ptr(); p.ldb = N; p.c = C_.array; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug return true; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute_t( const matrix_right_t& B_, matrix_out_t& C_ ) { // blas needs non-const data matrix_right_t* BB = new matrix_right_t( B_ ); C_.zero(); p.trans_a = CblasTrans; p.a = BB->array; p.b = BB->array; p.lda = K; p.c = C_.array; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete BB; return true; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute_bt( const matrix_left_t& A_, const matrix_right_t_t& Bt_, matrix_out_t& C_ ) { // blas needs non-const data matrix_left_t* AA = new matrix_left_t( A_ ); matrix_right_t_t* BB = new matrix_right_t_t( Bt_ ); C_.zero(); p.trans_b = CblasTrans; p.a = AA->array; p.b = BB->array; p.c = C_.array; p.ldb = N; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete AA; delete BB; return true; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute_t( const matrix_left_t_t& At_, const matrix_right_t_t& Bt_, matrix_out_t& C_ ) { // blas needs non-const data matrix_left_t_t* AA = new matrix_left_t_t( At_ ); matrix_right_t_t* BB = new matrix_right_t_t( Bt_ ); C_.zero(); p.trans_a = CblasTrans; p.trans_b = CblasTrans; p.a = AA->array; p.b = BB->array; p.c = C_.array; p.ldb = N; p.lda = K; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete AA; delete BB; return true; } template< size_t M, size_t K, size_t N, typename float_t > bool blas_dgemm< M, K, N, float_t >::compute_vv_outer( const vector_left_t& A_, const vector_right_t& B_, matrix_out_t& C_ ) { // blas needs non-const data vector_left_t* AA = new vector_left_t( A_ ); vector_right_t* BB = new vector_right_t( B_ ); C_.zero(); p.trans_a = CblasTrans; p.a = AA->array; p.b = BB->array; p.c = C_.array; p.lda = K; blas::dgemm_call< float_t >( p ); //std::cout << p << std::endl; //debug delete AA; delete BB; return true; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/blas_dot.hpp000066400000000000000000000064641231531733200246100ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_BLAS_DOT__HPP__ #define __VMML__VMMLIB_BLAS_DOT__HPP__ #include #include #include #include /** * * a wrapper for blas's DOT routine. * REAL FUNCTION SDOT(N,SX,INCX,SY,INCY) * .. Scalar Arguments .. * INTEGER INCX,INCY,N * * .. Array Arguments .. * REAL SX(*),SY(*) * * * Purpose * ======= * * SDOT forms the dot product of two vectors. * uses unrolled loops for increments equal to one. * * * more information in: http://netlib.org/blas/sdot.f ** */ namespace vmml { namespace blas { template< typename float_t > struct dot_params { blas_int n; float_t* x; blas_int inc_x; float_t* y; blas_int inc_y; friend std::ostream& operator << ( std::ostream& os, const dot_params< float_t >& p ) { os << " (1)\tn " << p.n << std::endl << " (2)\tx " << p.x << std::endl << " (3)\tincX " << p.inc_x << std::endl << " (4)\ty " << p.y << std::endl << " (5)\tincY " << p.inc_y << std::endl << std::endl; return os; } }; template< typename float_t > inline float_t dot_call( dot_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline float dot_call( dot_params< float >& p ) { //std::cout << "calling blas sdot (single precision) " << std::endl; float vvi = cblas_sdot( p.n, p.x, p.inc_x, p.y, p.inc_y ); return vvi; } template<> inline double dot_call( dot_params< double >& p ) { //std::cout << "calling blas ddot (double precision) " << std::endl; double vvi = cblas_ddot( p.n, p.x, p.inc_x, p.y, p.inc_y ); return vvi; } } // namespace blas template< size_t M, typename float_t > struct blas_dot { typedef vector< M, float_t > vector_t; blas_dot(); ~blas_dot() {}; bool compute( const vector_t& A_, const vector_t& B_, float_t& dot_prod_ ); blas::dot_params< float_t > p; const blas::dot_params< float_t >& get_params(){ return p; }; }; // struct blas_dot template< size_t M, typename float_t > blas_dot< M, float_t >::blas_dot() { p.n = M; p.x = 0; p.inc_x = 1; p.y = 0; p.inc_y = 1; } template< size_t M, typename float_t > bool blas_dot< M, float_t >::compute( const vector_t& A_, const vector_t& B_, float_t& dot_prod_ ) { // blas needs non-const data vector_t* AA = new vector_t( A_ ); vector_t* BB = new vector_t( B_ ); p.x = AA->array; p.y = BB->array; dot_prod_ = blas::dot_call< float_t >( p ); //std::cout << dot_prod_ << std::endl; //debug delete AA; delete BB; return true; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/blas_includes.hpp000066400000000000000000000003361231531733200256200ustar00rootroot00000000000000#ifndef __VMML__BLAS_INCLUDES__HPP__ #define __VMML__BLAS_INCLUDES__HPP__ #ifdef __APPLE__ #include #else extern "C" { #include } #endif #endif /* __VMML__BLAS_INCLUDES__HPP__ */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/blas_types.hpp000066400000000000000000000004071231531733200251550ustar00rootroot00000000000000#ifndef __VMML__BLAS_TYPES__HPP__ #define __VMML__BLAS_TYPES__HPP__ namespace vmml { namespace blas { #ifdef __APPLE__ typedef int blas_int; #else typedef int blas_int; #endif } // namespace blas } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/cp3_tensor.hpp000066400000000000000000000322651231531733200250760ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Jonas Boesch * @author Rafael Ballester * * The cp3 tensor class is consists of three basis matrices u1-u3 and R lambda values for a given rank-R approximation * CP stands for Candecomp/Parafac (1970) * - Carroll & Chang, 1970: Analysis of Individual Differences in Multidimensional Scaling via an N-way generalization of ``Eckart--Young'' decompositions, Psychometrika. * - Harshman, 1970: Foundations of the PARAFAC procedure: Models and conditions for an 'explanatory' multi-modal factor analysis,UCLA Working Papers in Phonetics. * - De Lathauwer, De Moor, Vandewalle, 2000: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * */ #ifndef __VMML__CP3_TENSOR__HPP__ #define __VMML__CP3_TENSOR__HPP__ #include #include #include #include namespace vmml { template< size_t R, size_t I1, size_t I2, size_t I3, typename T_value = double, typename T_coeff = float > class cp3_tensor { public: typedef float T_internal; typedef tensor3< I1, I2, I3, T_value > t3_type; typedef typename t3_type::iterator t3_iterator; typedef typename t3_type::const_iterator t3_const_iterator; typedef tensor3< I1, I2, I3, T_internal > t3_comp_type; typedef tensor3< I1, I2, I3, T_coeff > t3_coeff_type; typedef typename t3_coeff_type::iterator t3_coeff_iterator; typedef typename t3_coeff_type::const_iterator t3_coeff_const_iterator; typedef matrix< I1, R, T_coeff > u1_type; typedef typename u1_type::iterator u1_iterator; typedef typename u1_type::const_iterator u1_const_iterator; typedef matrix< I2, R, T_coeff > u2_type; typedef typename u2_type::iterator u2_iterator; typedef typename u2_type::const_iterator u2_const_iterator; typedef matrix< I3, R, T_coeff > u3_type; typedef typename u3_type::iterator u3_iterator; typedef typename u3_type::const_iterator u3_const_iterator; typedef matrix< I1, R, T_internal > u1_comp_type; typedef matrix< I2, R, T_internal > u2_comp_type; typedef matrix< I3, R, T_internal > u3_comp_type; typedef vector< R, T_internal > lambda_comp_type; typedef vector< R, T_coeff > lambda_type; cp3_tensor(u1_type& U1, u2_type& U2, u3_type& U3, lambda_type& lambdas_); cp3_tensor(); ~cp3_tensor(); void get_lambdas(lambda_type& data_) const { data_ = *_lambdas; }; void get_u1(u1_type& U1) const { U1 = *_u1; }; void get_u2(u2_type& U2) const { U2 = *_u2; }; void get_u3(u3_type& U3) const { U3 = *_u3; }; void set_lambdas(lambda_type& lambdas) { *_lambdas = lambdas; _lambdas_comp->cast_from(lambdas); }; void set_u1(u1_type& U1) { *_u1 = U1; _u1_comp->cast_from(U1); }; void set_u2(u2_type& U2) { *_u2 = U2; _u1_comp->cast_from(U2); }; void set_u3(u3_type& U3) { *_u3 = U3; _u1_comp->cast_from(U3); }; void set_lambda_comp(lambda_comp_type& lambdas) { *_lambdas_comp = lambdas; _lambdas->cast_from(lambdas); }; void set_u1_comp(u1_comp_type& U1) { *_u1_comp = U1; _u1->cast_from(U1); }; void set_u2_comp(u2_comp_type& U2) { *_u2_comp = U2; _u1->cast_from(U2); }; void set_u3_comp(u3_comp_type& U3) { *_u3_comp = U3; _u1->cast_from(U3); }; void get_lambda_comp(lambda_comp_type& data_) const { data_ = _lambdas_comp; }; void get_u1_comp(u1_comp_type& U1) const { U1 = *_u1_comp; }; void get_u2_comp(u2_comp_type& U2) const { U2 = *_u2_comp; }; void get_u3_comp(u3_comp_type& U3) const { U3 = *_u3_comp; }; void export_to(std::vector< T_coeff >& data_) const; void import_from(std::vector< T_coeff >& data_); void reconstruct(t3_type& data_) const; double error(t3_type& data_) const; size_t nnz() const; template< typename T_init > tensor_stats decompose(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); template< typename T_init > tensor_stats cp_als(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); template< size_t NBLOCKS, typename T_init > tensor_stats i_cp_als(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); template< size_t K > void reduce_ranks(const cp3_tensor< K, I1, I2, I3, T_value, T_coeff >& other); protected: cp3_tensor(const cp3_tensor< R, I1, I1, I1, T_value, T_coeff >& other) { }; cp3_tensor< R, I1, I1, I1, T_value, T_coeff > operator=(const cp3_tensor< R, I1, I1, I1, T_value, T_coeff >& other) { return *this; }; typedef cp3_tensor< R, I1, I2, I3, T_value, T_coeff > cp3_type; friend std::ostream& operator <<(std::ostream& os, const cp3_type& dec_ ) { lambda_type lambdas; dec_.get_lambdas(lambdas); u1_type* u1 = new u1_type; dec_.get_u1(*u1); u2_type* u2 = new u2_type; dec_.get_u2(*u2); u3_type* u3 = new u3_type; dec_.get_u3(*u3); os << "U1: " << std::endl << *u1 << std::endl << "U2: " << std::endl << *u2 << std::endl << "U3: " << std::endl << *u3 << std::endl << "lambdas: " << std::endl << lambdas << std::endl; delete u1; delete u2; delete u3; return os; } void cast_members(); void cast_comp_members(); private: lambda_type* _lambdas; u1_type* _u1; u2_type* _u2; u3_type* _u3; lambda_comp_type* _lambdas_comp; u1_comp_type* _u1_comp; u2_comp_type* _u2_comp; u3_comp_type* _u3_comp; }; // class cp3_tensor #define VMML_TEMPLATE_STRING template< size_t R, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME cp3_tensor< R, I1, I2, I3, T_value, T_coeff > VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::cp3_tensor(u1_type& U1, u2_type& U2, u3_type& U3, lambda_type& lambdas_) { set_lambdas(lambdas_); set_u1(U1); set_u2(U2); set_u3(U3); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::cp3_tensor() { _lambdas = new vector< R, T_coeff > (); _lambdas->set(0); _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _lambdas_comp = new vector< R, T_internal>; _lambdas_comp->set(0); _u1_comp = new u1_comp_type; _u1_comp->zero(); _u2_comp = new u2_comp_type; _u2_comp->zero(); _u3_comp = new u3_comp_type; _u3_comp->zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~cp3_tensor() { delete _u1; delete _u2; delete _u3; delete _lambdas; delete _u1_comp; delete _u2_comp; delete _u3_comp; delete _lambdas_comp; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_members() { _u1->cast_from(*_u1_comp); _u2->cast_from(*_u2_comp); _u3->cast_from(*_u3_comp); _lambdas->cast_from(*_lambdas_comp); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_comp_members() { _u1_comp->cast_from(*_u1); _u2_comp->cast_from(*_u2); _u3_comp->cast_from(*_u3); _lambdas_comp->cast_from(_lambdas); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct(t3_type& data_) const { //FIXME: check data types t3_comp_type data; data.cast_from(data_); typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type; hopm_type::reconstruct(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp); //convert reconstructed data, which is in type T_internal (double, float) to T_value (uint8 or uint16) if ((sizeof (T_value) == 1) || (sizeof (T_value) == 2)) { data_.float_t_to_uint_t(data); } else { data_.cast_from(data); } } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::error(t3_type& original) const { typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type; t3_comp_type data; hopm_type::reconstruct(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp); double err = data.frobenius_norm(original) / original.frobenius_norm() * 100; return err; } VMML_TEMPLATE_STRING template< typename T_init > tensor_stats VMML_TEMPLATE_CLASSNAME::decompose(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) { return cp_als(data_, init, max_iterations_, tolerance ); } VMML_TEMPLATE_STRING template< typename T_init > tensor_stats VMML_TEMPLATE_CLASSNAME::cp_als(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) { tensor_stats result; t3_comp_type data; data.cast_from(data_); typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type; result += hopm_type::als(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp, init, max_iterations_, tolerance); cast_members(); return result; } VMML_TEMPLATE_STRING template< size_t NBLOCKS, typename T_init > tensor_stats VMML_TEMPLATE_CLASSNAME::i_cp_als(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) { tensor_stats result; t3_comp_type data; data.cast_from(data_); typedef t3_ihopm< R, NBLOCKS, I1, I2, I3, T_internal > ihopm_type; result += ihopm_type::incremental_als(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp, init, max_iterations_, tolerance); cast_members(); return result; } VMML_TEMPLATE_STRING template< size_t K > void VMML_TEMPLATE_CLASSNAME::reduce_ranks(const cp3_tensor< K, I1, I2, I3, T_value, T_coeff >& other) // K -> R; I1, I2, I3 stay the same { assert(R <= K); //reduce basis matrices matrix< I1, K, T_coeff >* u1 = new matrix< I1, K, T_coeff > (); other.get_u1(*u1); matrix< I2, K, T_coeff >* u2 = new matrix< I2, K, T_coeff > (); other.get_u2(*u2); matrix< I3, K, T_coeff >* u3 = new matrix< I3, K, T_coeff > (); other.get_u3(*u3); for (size_t r = 0; r < R; ++r) { _u1->set_column(r, u1->get_column(r)); _u2->set_column(r, u2->get_column(r)); _u3->set_column(r, u3->get_column(r)); } // reduce vector of lambdas vector< K, T_coeff >* lambdas; other.get_lambdas(lambdas); _lambdas_comp->set(lambdas); cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::export_to(std::vector< T_coeff >& data_) const { u1_const_iterator it = _u1->begin(), it_end = _u1->end(); for (; it != it_end; ++it) { data_.push_back(*it); } u2_const_iterator u2_it = _u2->begin(), u2_it_end = _u2->end(); for (; u2_it != u2_it_end; ++u2_it) { data_.push_back(*u2_it); } u3_const_iterator u3_it = _u3->begin(), u3_it_end = _u3->end(); for (; u3_it != u3_it_end; ++u3_it) { data_.push_back(*u3_it); } //TODO: iterate over lambdas } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::import_from(std::vector< T_coeff >& data_) { size_t i = 0; //iterator over data_ u1_iterator it = _u1->begin(), it_end = _u1->end(); for (; it != it_end; ++it, ++i) { *it = data_.at(i); } u2_iterator u2_it = _u2->begin(), u2_it_end = _u2->end(); for (; u2_it != u2_it_end; ++u2_it, ++i) { *u2_it = data_.at(i); } u3_iterator u3_it = _u3->begin(), u3_it_end = _u3->end(); for (; u3_it != u3_it_end; ++u3_it, ++i) { *u3_it = data_.at(i); } //TODO: import lambdas } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz() const { size_t counter = 0; counter += _u1_comp->nnz(); counter += _u2_comp->nnz(); counter += _u3_comp->nnz(); counter += _lambdas_comp->nnz(); return counter; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/enable_if.hpp000066400000000000000000000007071231531733200247170ustar00rootroot00000000000000#ifndef __VMML__SFINAE__HPP__ #define __VMML__SFINAE__HPP__ #include /** * heavily inspired by boost::enable_if * http://www.boost.org, file: boost/utility/enable_if.hpp, * Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine */ namespace vmml { template < bool condition, typename T = void > struct enable_if { typedef T type; }; template< typename T > struct enable_if< false, T > {}; } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/exception.hpp000066400000000000000000000032051231531733200250050ustar00rootroot00000000000000#ifndef __VMMLIB__EXCEPTION__HPP__ #define __VMMLIB__EXCEPTION__HPP__ #include #include #include #include #include #include #define VMMLIB_HERE ( except_here( __FILE__, __LINE__ ) ) #ifdef VMMLIB_THROW_EXCEPTIONS #define VMMLIB_ERROR( desc, here ) throw( exception( desc, here ) ) #else #define VMMLIB_ERROR( desc, here ) error_noexcept( desc, here ) #endif namespace vmml { struct except_here { except_here( const char* file_, int line_ ) : file( file_ ), line( line_ ) {} const char* file; int line; }; // struct except_here inline void error_noexcept( const std::string& desc, const except_here& here ) { std::cerr << "vmmlib error at " << here.file << ":" << here.line << "\n" << desc << std::endl; assert( 0 ); } class exception : public std::exception { public: exception( const std::string& desc, const except_here& here ) : _description( desc ) , _here( here ) {} virtual ~exception() throw() {} virtual const char* what() const throw() { std::stringstream ss; ss << _here.file << "(" << _here.line << "): - " << _description << std::endl; return ss.str().c_str(); } protected: std::string _description; const except_here& _here; private: // disallow std ctor exception() : _here( *new except_here( "", 0 ) ){}; // disallow assignment operator virtual const exception& operator=( const exception& ){ return *this; } }; } // namespace stream_process #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/frustum.hpp000066400000000000000000000222101231531733200245110ustar00rootroot00000000000000/* * VMMLib - Vector & Matrix Math Lib * * @author Stefan Eilemann * * @license revised BSD license, check LICENSE */ #ifndef __VMML__FRUSTUM__HPP__ #define __VMML__FRUSTUM__HPP__ #include #include #include // - declaration - namespace vmml { template< typename T > class frustum { public: VMMLIB_ALIGN( T array[6] ); // contructors frustum(); // warning: components NOT initialised ( for performance ) frustum( const T left, const T right, const T bottom, const T top, const T near_plane, const T far_plane ); template< typename U > frustum( const frustum< U >& source_ ); //the pointer 'values' must be a valid 6 component c array of the resp. type template< typename U > frustum( const U* values ); ~frustum(); const frustum& operator=( const frustum& source_ ); template< typename U > void operator=( const frustum< U >& source_ ); void set( const T _left, const T _right, const T _bottom, const T _top, const T _near, const T _far ); // set the frustum using the same parameters as gluPerspective. void set_perspective( T field_of_view_y, T aspect_ratio, T near_plane_, T far_plane ); matrix< 4, 4, T > compute_matrix() const; matrix< 4, 4, T > compute_ortho_matrix() const; void compute_matrix( matrix< 4, 4, T >& matrix_ ) const; void compute_ortho_matrix( matrix< 4, 4, T >& matrix_ ) const; void apply_jitter( const vector< 2, T >& jitter_ ); // 'move' the frustum. this function changes the near_plane, and adjusts the // other parameters in a way that the 'perspective pyramid' stays the same. void adjust_near( const T near_plane ); inline T& left(); inline const T& left() const; inline T& right(); inline const T& right() const; inline T& bottom(); inline const T& bottom() const; inline T& top(); inline const T& top() const; inline T& near_plane(); inline const T& near_plane() const; inline T& far_plane(); inline const T& far_plane() const; inline T get_width() const; inline T get_height() const; friend std::ostream& operator << ( std::ostream& os, const frustum& f ) { const std::ios::fmtflags flags = os.flags(); const int prec = os.precision(); os.setf( std::ios::right, std::ios::adjustfield ); os.precision( 5 ); os << "[" << std::setw(10) << f.left() << " " << std::setw(10) << f.right() << " " << std::setw(10) << f.bottom() << " " << std::setw(10) << f.top() << " " << std::setw(10) << f.near_plane() << " " << std::setw(10) << f.far_plane() << "]"; os.precision( prec ); os.setf( flags ); return os; }; static const frustum DEFAULT; }; #ifndef VMMLIB_NO_TYPEDEFS typedef frustum< float > frustumf; typedef frustum< double > frustumd; #endif } // namespace vmml // - implementation - // namespace vmml { template< typename T > const frustum< T > frustum< T >::DEFAULT( static_cast< T >( -1.0 ), static_cast< T >( 1.0 ), static_cast< T >( -1.0 ), static_cast< T >( 1.0 ), static_cast< T >( 0.1 ), static_cast< T >( 100.0 ) ); template < typename T > frustum< T >::frustum() {} template < typename T > frustum::frustum( const T _left, const T _right, const T _bottom, const T _top, const T _near, const T _far ) { set( _left, _right, _bottom, _top, _near, _far ); } template < typename T > template< typename U > frustum< T >::frustum( const frustum< U >& source_ ) { (*this) = source_; } template < typename T > template< typename U > frustum< T >::frustum( const U* values ) { assert( values && "frustum: Nullpointer argument as source for initialisation!" ); left() = static_cast< T > ( values[0] ); right() = static_cast< T > ( values[1] ); bottom() = static_cast< T > ( values[2] ); top() = static_cast< T > ( values[3] ); near_plane() = static_cast< T > ( values[4] ); far_plane() = static_cast< T > ( values[5] ); } template < typename T > frustum< T >::~frustum() {} template< typename T > const frustum< T >& frustum< T >::operator=( const frustum& source_ ) { memcpy( array, source_.array, 6 * sizeof( T ) ); return *this; } template< typename T > template< typename U > void frustum< T >::operator = ( const frustum< U >& source_ ) { for( size_t index = 0; index < 6; ++index ) { array[ index ] = static_cast< T >( source_.array[ index ] ); } } template < typename T > void frustum< T >::set( const T _left, const T _right, const T _bottom, const T _top, const T _near, const T _far ) { left() = _left; right() = _right; bottom() = _bottom; top() = _top; near_plane() = _near; far_plane() = _far; } // 'move' the frustum. this function changes the near_plane, and adjusts the // other parameters in a way that the 'perspective pyramid' stays the same. template < typename T > void frustum::adjust_near( const T new_near ) { if( new_near == near_plane() ) return; const T ratio = new_near / near_plane(); right() *= ratio; left() *= ratio; top() *= ratio; bottom() *= ratio; near_plane() = new_near; } // set the frustum using the same parameters as gluPerspective. template < typename T > void frustum::set_perspective( T fov_y, T aspect_ratio, T near_plane_, T far_plane_ ) { near_plane() = near_plane_; far_plane() = far_plane_; top() = tan( 0.5 * fov_y * M_PI / 180.0 ) * 0.5; bottom() = - top(); left() = bottom() * aspect_ratio; right() = top() * aspect_ratio; } template < typename T > matrix< 4, 4, T > frustum::compute_matrix() const { matrix< 4, 4, T > matrix_; compute_matrix( matrix_ ); return matrix_; } template < typename T > void frustum::compute_matrix( matrix< 4, 4, T >& M ) const { M( 0,0 ) = 2.0 * near_plane() / ( right() - left() ); M( 0,1 ) = 0.0; M( 0,2 ) = ( right() + left() ) / ( right() - left() ); M( 0,3 ) = 0.0; M( 1,0 ) = 0.0; M( 1,1 ) = 2.0 * near_plane() / ( top() - bottom() ); M( 1,2 ) = ( top() + bottom() ) / ( top() - bottom() ); M( 1,3 ) = 0.0; M( 2,0 ) = 0.0; M( 2,1 ) = 0.0; // NOTE: Some glfrustum man pages say wrongly '(far + near) / (far - near)' M( 2,2 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() ); M( 2,3 ) = -2.0 * far_plane() * near_plane() / ( far_plane() - near_plane() ); M( 3,0 ) = 0.0; M( 3,1 ) = 0.0; M( 3,2 ) = -1.0; M( 3,3 ) = 0.0; } template < typename T > matrix< 4, 4, T > frustum< T >::compute_ortho_matrix() const { matrix< 4, 4, T > matrix_; compute_ortho_matrix( matrix_ ); return matrix_; } template < typename T > void frustum< T >::compute_ortho_matrix( matrix< 4, 4, T >& M ) const { M( 0,0 ) = 2.0 / ( right() - left() ); M( 0,1 ) = 0.0; M( 0,2 ) = 0.0; M( 0,3 ) = -( right() + left() ) / ( right() - left() ); M( 1,0 ) = 0.0; M( 1,1 ) = 2.0 / ( top() - bottom() ); M( 1,2 ) = 0.0f; M( 1,3 ) = -( top() + bottom() ) / ( top() - bottom() ); M( 2,0 ) = 0.0; M( 2,1 ) = 0.0; M( 2,2 ) = -2.0 / ( far_plane() - near_plane() ); M( 2,3 ) = -( far_plane() + near_plane() ) / ( far_plane() - near_plane() ); M( 3,0 ) = 0.0; M( 3,1 ) = 0.0; M( 3,2 ) = 0.0; M( 3,3 ) = 1.0f; } template < typename T > void frustum< T >::apply_jitter( const vector< 2, T >& jitter_ ) { left() = left() + jitter_.x(); right() = right() + jitter_.x(); bottom() = bottom() + jitter_.y(); top() = top() + jitter_.y(); } template< typename T > inline T& frustum< T >::left() { return array[ 0 ]; } template< typename T > inline const T& frustum< T >::left() const { return array[ 0 ]; } template< typename T > inline T& frustum< T >::right() { return array[ 1 ]; } template< typename T > inline const T& frustum< T >::right() const { return array[ 1 ]; } template< typename T > inline T& frustum< T >::bottom() { return array[ 2 ]; } template< typename T > inline const T& frustum< T >::bottom() const { return array[ 2 ]; } template< typename T > inline T& frustum< T >::top() { return array[ 3 ]; } template< typename T > inline const T& frustum< T >::top() const { return array[ 3 ]; } template< typename T > inline T& frustum< T >::near_plane() { return array[ 4 ]; } template< typename T > inline const T& frustum< T >::near_plane() const { return array[ 4 ]; } template< typename T > inline T& frustum< T >::far_plane() { return array[ 5 ]; } template< typename T > inline const T& frustum< T >::far_plane() const { return array[ 5 ]; } template< typename T > inline T frustum< T >::get_width() const { return fabs( right() - left( )); } template< typename T > inline T frustum< T >::get_height() const { return fabs( top() - bottom( )); } } //namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/frustum_culler.hpp000066400000000000000000000214121231531733200260620ustar00rootroot00000000000000/* * VMMLib - Vector & Matrix Math Lib * * @author Stefan Eilemann * * @license revised BSD license, check LICENSE */ #ifndef __VMML__FRUSTUM_CULLER__HPP__ #define __VMML__FRUSTUM_CULLER__HPP__ #include #include #include // - declaration - namespace vmml { /** Helper class for OpenGL view frustum culling. */ template< class T > class frustum_culler { public: typedef vector< 2, T > vec2; typedef vector< 3, T > vec3; typedef vector< 4, T > vec4; // contructors frustum_culler() {} // warning: components NOT initialised ~frustum_culler(){} /** Set up the culling state using a 4x4 projection*modelView matrix. */ void setup( const matrix< 4, 4, T >& proj_modelview ); /** * Set up the culling state using the eight frustum corner points. * Corner naming is n(ear)|f(ar), l(eft)|r(ight), t(op)|b(ottom) */ void setup( const vec3& nlt, const vec3& nrt, const vec3& nlb, const vec3& nrb, const vec3& flt, const vec3& frt, const vec3& flb, const vec3& frb ); Visibility test_sphere( const vec4& sphere ) const; Visibility test_aabb( const vec2& x, const vec2& y, const vec2& z ) const; friend std::ostream& operator << (std::ostream& os, const frustum_culler& f) { return os << "Frustum cull planes: " << std::endl << " left " << f._left_plane << std::endl << " right " << f._right_plane << std::endl << " top " << f._top_plane << std::endl << " bottom " << f._bottom_plane << std::endl << " near " << f._near_plane << std::endl << " far " << f._far_plane << std::endl; } private: inline void _normalize_plane( vec4& plane ) const; inline Visibility _test_aabb( const vec4& plane, const vec3& middle, const vec3& size_2 ) const; vec4 _left_plane; vec4 _right_plane; vec4 _bottom_plane; vec4 _top_plane; vec4 _near_plane; vec4 _far_plane; }; // class frustum_culler #ifndef VMMLIB_NO_TYPEDEFS typedef frustum_culler< float > frustum_cullerf; typedef frustum_culler< double > frustum_cullerd; #endif } // namespace vmml // - implementation - // namespace vmml { /** * Setup the culler by extracting the frustum planes from the projection * matrix. The projection matrix should contain the viewing transformation. */ template < class T > void frustum_culler< T >::setup( const matrix< 4, 4, T >& proj_modelview ) { // See http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf pp.5 const vec4& row0 = proj_modelview.get_row( 0 ); const vec4& row1 = proj_modelview.get_row( 1 ); const vec4& row2 = proj_modelview.get_row( 2 ); const vec4& row3 = proj_modelview.get_row( 3 ); _left_plane = row3 + row0; _right_plane = row3 - row0; _bottom_plane = row3 + row1; _top_plane = row3 - row1; _near_plane = row3 + row2; _far_plane = row3 - row2; _normalize_plane( _left_plane ); _normalize_plane( _right_plane ); _normalize_plane( _bottom_plane ); _normalize_plane( _top_plane ); _normalize_plane( _near_plane ); _normalize_plane( _far_plane ); } template < class T > void frustum_culler< T >::setup( const vec3& a, const vec3& b, const vec3& c, const vec3& d, const vec3& e, const vec3& f, const vec3& g, const vec3& h ) { // e_____f // /____ /| // | a b | | // | c d |/h // ----- // CCW winding _left_plane = compute_plane( c, a, e ); _right_plane = compute_plane( f, b, d ); _bottom_plane = compute_plane( h, d, c ); _top_plane = compute_plane( a, b, f ); _near_plane = compute_plane( b, a, c ); _far_plane = compute_plane( g, e, f ); } template < class T > inline void frustum_culler< T >::_normalize_plane( vector< 4, T >& plane ) const { const vec3& v3 = plane.template get_sub_vector< 3 >(); const T len_i = 1.0 / v3.length(); plane.x() *= len_i; plane.y() *= len_i; plane.z() *= len_i; plane.w() *= len_i; } template < class T > Visibility frustum_culler< T >::test_sphere( const vector< 4, T >& sphere ) const { Visibility visibility = VISIBILITY_FULL; // see http://www.flipcode.com/articles/article_frustumculling.shtml // distance = plane.normal . sphere.center + plane.distance // Test all planes: // - if sphere behind plane: not visible // - if sphere intersects one plane: partially visible // - else: fully visible T distance = _left_plane.x() * sphere.x() + _left_plane.y() * sphere.y() + _left_plane.z() * sphere.z() + _left_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; distance = _right_plane.x() * sphere.x() + _right_plane.y() * sphere.y() + _right_plane.z() * sphere.z() + _right_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; distance = _bottom_plane.x() * sphere.x() + _bottom_plane.y() * sphere.y() + _bottom_plane.z() * sphere.z() + _bottom_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; distance = _top_plane.x() * sphere.x() + _top_plane.y() * sphere.y() + _top_plane.z() * sphere.z() + _top_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; distance = _near_plane.x() * sphere.x() + _near_plane.y() * sphere.y() + _near_plane.z() * sphere.z() + _near_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; distance = _far_plane.x() * sphere.x() + _far_plane.y() * sphere.y() + _far_plane.z() * sphere.z() + _far_plane.w(); if( distance <= -sphere.w() ) return VISIBILITY_NONE; if( distance < sphere.w() ) visibility = VISIBILITY_PARTIAL; return visibility; } template < class T > Visibility frustum_culler< T >::_test_aabb( const vec4& plane, const vec3& middle, const vec3& extent ) const { // http://www.cescg.org/CESCG-2002/DSykoraJJelinek/index.html const T d = plane.dot( middle ); const T n = extent.x() * fabs( plane.x( )) + extent.y() * fabs( plane.y( )) + extent.z() * fabs( plane.z( )); if( d - n >= 0 ) return VISIBILITY_FULL; if( d + n > 0 ) return VISIBILITY_PARTIAL; return VISIBILITY_NONE; } template < class T > Visibility frustum_culler< T >::test_aabb( const vec2& x, const vec2& y, const vec2& z ) const { Visibility result = VISIBILITY_FULL; const vec3& middle = vec3( x[0] + x[1], y[0] + y[1], z[0] + z[1] ) * .5; const vec3& extent = vec3( fabs(x[1] - x[0]), fabs(y[1] - y[0]), fabs(z[1] - z[0]) ) * .5; switch( _test_aabb( _left_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } switch( _test_aabb( _right_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } switch( _test_aabb( _bottom_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } switch( _test_aabb( _top_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } switch( _test_aabb( _near_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } switch( _test_aabb( _far_plane, middle, extent )) { case VISIBILITY_FULL: break; case VISIBILITY_PARTIAL: result = VISIBILITY_PARTIAL; break; case VISIBILITY_NONE: return VISIBILITY_NONE; } return result; } } // namespace vmml #endif // include protection repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/intersection.hpp000066400000000000000000000043731231531733200255240ustar00rootroot00000000000000/* * VMMLib - Intersection classes * * @author Jafet Villafranca * * Implements ray-object intersection, storing the ray parameters as attributes * and implementing intersection tests against different types of objects * (e.g. sphere) * */ #ifndef __VMML__INTERSECTION__HPP__ #define __VMML__INTERSECTION__HPP__ #include namespace vmml { template< typename T > class intersection { public: typedef vector< 3, T > vec3; typedef vector< 4, T > vec4; /** Constructors @param[in] origin Ray origin @param[in] direction Ray direction */ intersection( const vec3& origin, const vec3& direction ) : _origin ( origin ) , _direction ( vmml::normalize( direction )) {} ~intersection() {} /** Ray Sphere Intersection - Optimized solution "Real-time Rendering 3rd Edition" @param[in] center Sphere center @param[in] radius Sphere radius @param[out] t Intersection distance @return Whether the ray intersects the sphere */ bool test_sphere( const vec4& sphere, T& t ) const; private: const vec3 _origin; const vec3 _direction; }; // class intersection template< typename T > bool intersection< T >::test_sphere( const vec4& sphere, T& t ) const { const vec3 center = vec3(sphere.x(), sphere.y(), sphere.z()); const T radius = sphere.w(); const vec3 centerVec = center - _origin; const T vecProjection = centerVec.dot(_direction); const T sqDistance = centerVec.squared_length(); const T sqRadius = radius * radius; /** Sphere behind the ray origin and ray origin outside the sphere */ if( vecProjection < 0 && sqDistance > sqRadius ) return false; /** Squared distance from sphere center to the projection */ const T sqCenterToProj = sqDistance - vecProjection * vecProjection; if( sqCenterToProj > sqRadius ) return false; /** Distance from the sphere center to the surface along the ray direction*/ const T distSurface = sqrt( sqRadius - sqCenterToProj ); if(sqDistance > sqRadius) t = vecProjection - distSurface; else t = vecProjection + distSurface; return true; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/jacobi_solver.hpp000066400000000000000000000122671231531733200256400ustar00rootroot00000000000000/* * VMMLib - Vector & Matrix Math Lib * * @author Jonas Boesch * @author Stefan Eilemann * @author Renato Pajarola * @author Andrew Willmott ( VL ) * * @license revised BSD license, check LICENSE * * parts of the source code of VMMLib were inspired by David Eberly's * Wild Magic and Andrew Willmott's VL. * */ #ifndef __VMML__JACOBI_SOLVER__HPP__ #define __VMML__JACOBI_SOLVER__HPP__ #include #include #include namespace vmml { /* * This function computes the eigenvalues and eigenvectors of a 3x3 matrix. * * @param a matrix to be diagonalized. * @param d eigenvalues of A. * @param v matrix whose columns are the normalized eigenvectors of A. * @param rotationCount number of Jacobi rotations required. * @return true if the transformation has been done. False if not. * * * modified from numerical recipies for n=3 and float values * */ template < typename T > bool solve_jacobi_3x3( matrix< 3, 3, T >& a, vector< 3, T >& d, matrix< 3, 3, T >& v, size_t& rotationCount ) { identity( v ); vector< 3, T > b, z; for ( size_t i = 0; i < 3; ++i ) { b[i] = d[i] = a( i,i ); z[i] = 0.0; } T t, theta, s, c, tau; size_t rot = 0; for ( size_t i = 1; i <= 150; ++i ) { T sm = 0.0; for ( size_t ip = 0; ip < 2; ++ip ) // < n-1 { for ( size_t iq = ip + 1; iq < 3; ++iq ) // < n { sm += fabs( a( iq, ip ) ); } } if ( sm == 0.0 ) { rotationCount = rot; return true; } T tresh = ( i < 4 ) ? 0.2 * sm / 9.0 : 0.0; for ( ssize_t ip = 0; ip < 2; ++ip ) // ip < n - 1 { for ( ssize_t iq = ip + 1; iq < 3; ++iq ) { T g = 100.0 * fabs( a( iq,ip ) ); // this has to be fabs( x ) + g == fabs( x ) and NOT // g == 0.0 because of floating point evilness // ( inaccuracies when comparing (anyfloat) to 0.0 ) if ( i > 4 && fabs( d[ip] ) + g == fabs( d[ip] ) && fabs( d[iq] ) + g == fabs( d[iq] ) ) { a( iq, ip ) = 0.0; } else { if ( fabs( a( iq, iq ) ) > tresh ) { T h = d[iq] - d[ip]; if ( fabs( h ) + g == fabs( h ) ) { if ( h != 0.0 ) t = ( a( iq, ip ) ) / h; else t = 0.0; } else { if( a( iq, ip ) != 0.0 ) theta = 0.5 * h / ( a( iq, ip ) ); else theta = 0.0; t = 1.0 / ( fabs( theta ) + sqrt( 1.0 + theta * theta ) ); if ( theta < 0.0 ) t = -t; } c = 1.0 / sqrt( 1 + t * t ); s = t * c; tau = s / ( 1.0 + c ); h = t * a( iq, ip ); z[ip] -= h; z[iq] += h; d[ip] -= h; d[iq] += h; a( iq, ip ) = 0.0; for ( ssize_t j = 0; j <= ip - 1; ++j ) { g = a( ip, j ); h = a( iq, j ); a( ip, j ) = g - s * ( h + g * tau ); a( iq, j ) = h + s * ( g - h * tau ); } for ( ssize_t j = ip + 1; j <= iq - 1; ++j ) { g = a( j, ip ); h = a( iq, j ); a( j, ip ) = g - s * ( h + g * tau ); a( iq, j ) = h + s * ( g - h * tau ); } for ( size_t j = iq + 1; j < 3; ++j ) { g = a( j, ip ); h = a( j, iq ); a( j, ip ) = g - s * ( h + g * tau ); a( j, iq ) = h + s * ( g - h * tau ); } for ( size_t j = 0; j < 3; ++j ) { g = v( ip, j ); h = v( iq, j ); v( ip, j ) = g - s * ( h + g * tau ); v( iq, j ) = h + s * ( g - h * tau ); } ++rot; } } } } for ( size_t ip = 0; ip < 3; ++ip ) { b[ip] += z[ip]; d[ip] = b[ip]; z[ip] = 0.0; } } return false; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack.hpp000066400000000000000000000002471231531733200242450ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_LAPACK__HPP__ #define __VMML__VMMLIB_LAPACK__HPP__ #include #include #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack/000077500000000000000000000000001231531733200235315ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack/detail/000077500000000000000000000000001231531733200247735ustar00rootroot00000000000000repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack/detail/clapack.h000066400000000000000000012365171231531733200265610ustar00rootroot00000000000000/* header file for clapack 3.2.1 */ #ifndef __CLAPACK_H #define __CLAPACK_H #ifdef __cplusplus extern "C" { #endif /* Subroutine */ int caxpy_(integer *n, complex *ca, complex *cx, integer * incx, complex *cy, integer *incy); /* Subroutine */ int ccopy_(integer *n, complex *cx, integer *incx, complex * cy, integer *incy); /* Complex */ VOID cdotc_(complex * ret_val, integer *n, complex *cx, integer *incx, complex *cy, integer *incy); /* Complex */ VOID cdotu_(complex * ret_val, integer *n, complex *cx, integer *incx, complex *cy, integer *incy); /* Subroutine */ int cgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, complex *alpha, complex *a, integer *lda, complex *x, integer *incx, complex *beta, complex *y, integer *incy); /* Subroutine */ int cgemm_(char *transa, char *transb, integer *m, integer * n, integer *k, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, complex *beta, complex *c__, integer *ldc); /* Subroutine */ int cgemv_(char *trans, integer *m, integer *n, complex * alpha, complex *a, integer *lda, complex *x, integer *incx, complex * beta, complex *y, integer *incy); /* Subroutine */ int cgerc_(integer *m, integer *n, complex *alpha, complex * x, integer *incx, complex *y, integer *incy, complex *a, integer *lda); /* Subroutine */ int cgeru_(integer *m, integer *n, complex *alpha, complex * x, integer *incx, complex *y, integer *incy, complex *a, integer *lda); /* Subroutine */ int chbmv_(char *uplo, integer *n, integer *k, complex * alpha, complex *a, integer *lda, complex *x, integer *incx, complex * beta, complex *y, integer *incy); /* Subroutine */ int chemm_(char *side, char *uplo, integer *m, integer *n, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, complex *beta, complex *c__, integer *ldc); /* Subroutine */ int chemv_(char *uplo, integer *n, complex *alpha, complex * a, integer *lda, complex *x, integer *incx, complex *beta, complex *y, integer *incy); /* Subroutine */ int cher_(char *uplo, integer *n, real *alpha, complex *x, integer *incx, complex *a, integer *lda); /* Subroutine */ int cher2_(char *uplo, integer *n, complex *alpha, complex * x, integer *incx, complex *y, integer *incy, complex *a, integer *lda); /* Subroutine */ int cher2k_(char *uplo, char *trans, integer *n, integer *k, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, real *beta, complex *c__, integer *ldc); /* Subroutine */ int cherk_(char *uplo, char *trans, integer *n, integer *k, real *alpha, complex *a, integer *lda, real *beta, complex *c__, integer *ldc); /* Subroutine */ int chpmv_(char *uplo, integer *n, complex *alpha, complex * ap, complex *x, integer *incx, complex *beta, complex *y, integer * incy); /* Subroutine */ int chpr_(char *uplo, integer *n, real *alpha, complex *x, integer *incx, complex *ap); /* Subroutine */ int chpr2_(char *uplo, integer *n, complex *alpha, complex * x, integer *incx, complex *y, integer *incy, complex *ap); /* Subroutine */ int crotg_(complex *ca, complex *cb, real *c__, complex *s); /* Subroutine */ int cscal_(integer *n, complex *ca, complex *cx, integer * incx); /* Subroutine */ int csrot_(integer *n, complex *cx, integer *incx, complex * cy, integer *incy, real *c__, real *s); /* Subroutine */ int csscal_(integer *n, real *sa, complex *cx, integer *incx); /* Subroutine */ int cswap_(integer *n, complex *cx, integer *incx, complex * cy, integer *incy); /* Subroutine */ int csymm_(char *side, char *uplo, integer *m, integer *n, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, complex *beta, complex *c__, integer *ldc); /* Subroutine */ int csyr2k_(char *uplo, char *trans, integer *n, integer *k, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb, complex *beta, complex *c__, integer *ldc); /* Subroutine */ int csyrk_(char *uplo, char *trans, integer *n, integer *k, complex *alpha, complex *a, integer *lda, complex *beta, complex *c__, integer *ldc); /* Subroutine */ int ctbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, complex *a, integer *lda, complex *x, integer *incx); /* Subroutine */ int ctbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, complex *a, integer *lda, complex *x, integer *incx); /* Subroutine */ int ctpmv_(char *uplo, char *trans, char *diag, integer *n, complex *ap, complex *x, integer *incx); /* Subroutine */ int ctpsv_(char *uplo, char *trans, char *diag, integer *n, complex *ap, complex *x, integer *incx); /* Subroutine */ int ctrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb); /* Subroutine */ int ctrmv_(char *uplo, char *trans, char *diag, integer *n, complex *a, integer *lda, complex *x, integer *incx); /* Subroutine */ int ctrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, complex *alpha, complex *a, integer *lda, complex *b, integer *ldb); /* Subroutine */ int ctrsv_(char *uplo, char *trans, char *diag, integer *n, complex *a, integer *lda, complex *x, integer *incx); doublereal dasum_(integer *n, doublereal *dx, integer *incx); /* Subroutine */ int daxpy_(integer *n, doublereal *da, doublereal *dx, integer *incx, doublereal *dy, integer *incy); doublereal dcabs1_(doublecomplex *z__); /* Subroutine */ int dcopy_(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy); doublereal ddot_(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy); /* Subroutine */ int dgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, doublereal *alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); /* Subroutine */ int dgemm_(char *transa, char *transb, integer *m, integer * n, integer *k, doublereal *alpha, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, integer *ldc); /* Subroutine */ int dgemv_(char *trans, integer *m, integer *n, doublereal * alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); /* Subroutine */ int dger_(integer *m, integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *a, integer *lda); doublereal dnrm2_(integer *n, doublereal *x, integer *incx); /* Subroutine */ int drot_(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy, doublereal *c__, doublereal *s); /* Subroutine */ int drotg_(doublereal *da, doublereal *db, doublereal *c__, doublereal *s); /* Subroutine */ int drotm_(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy, doublereal *dparam); /* Subroutine */ int drotmg_(doublereal *dd1, doublereal *dd2, doublereal * dx1, doublereal *dy1, doublereal *dparam); /* Subroutine */ int dsbmv_(char *uplo, integer *n, integer *k, doublereal * alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); /* Subroutine */ int dscal_(integer *n, doublereal *da, doublereal *dx, integer *incx); doublereal dsdot_(integer *n, real *sx, integer *incx, real *sy, integer * incy); /* Subroutine */ int dspmv_(char *uplo, integer *n, doublereal *alpha, doublereal *ap, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); /* Subroutine */ int dspr_(char *uplo, integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *ap); /* Subroutine */ int dspr2_(char *uplo, integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *ap); /* Subroutine */ int dswap_(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy); /* Subroutine */ int dsymm_(char *side, char *uplo, integer *m, integer *n, doublereal *alpha, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, integer *ldc); /* Subroutine */ int dsymv_(char *uplo, integer *n, doublereal *alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); /* Subroutine */ int dsyr_(char *uplo, integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *a, integer *lda); /* Subroutine */ int dsyr2_(char *uplo, integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *a, integer *lda); /* Subroutine */ int dsyr2k_(char *uplo, char *trans, integer *n, integer *k, doublereal *alpha, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *beta, doublereal *c__, integer *ldc); /* Subroutine */ int dsyrk_(char *uplo, char *trans, integer *n, integer *k, doublereal *alpha, doublereal *a, integer *lda, doublereal *beta, doublereal *c__, integer *ldc); /* Subroutine */ int dtbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, doublereal *a, integer *lda, doublereal *x, integer *incx); /* Subroutine */ int dtbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, doublereal *a, integer *lda, doublereal *x, integer *incx); /* Subroutine */ int dtpmv_(char *uplo, char *trans, char *diag, integer *n, doublereal *ap, doublereal *x, integer *incx); /* Subroutine */ int dtpsv_(char *uplo, char *trans, char *diag, integer *n, doublereal *ap, doublereal *x, integer *incx); /* Subroutine */ int dtrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, doublereal *alpha, doublereal *a, integer * lda, doublereal *b, integer *ldb); /* Subroutine */ int dtrmv_(char *uplo, char *trans, char *diag, integer *n, doublereal *a, integer *lda, doublereal *x, integer *incx); /* Subroutine */ int dtrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, doublereal *alpha, doublereal *a, integer * lda, doublereal *b, integer *ldb); /* Subroutine */ int dtrsv_(char *uplo, char *trans, char *diag, integer *n, doublereal *a, integer *lda, doublereal *x, integer *incx); doublereal dzasum_(integer *n, doublecomplex *zx, integer *incx); doublereal dznrm2_(integer *n, doublecomplex *x, integer *incx); integer icamax_(integer *n, complex *cx, integer *incx); integer idamax_(integer *n, doublereal *dx, integer *incx); integer isamax_(integer *n, real *sx, integer *incx); integer izamax_(integer *n, doublecomplex *zx, integer *incx); logical lsame_(char *ca, char *cb); doublereal sasum_(integer *n, real *sx, integer *incx); /* Subroutine */ int saxpy_(integer *n, real *sa, real *sx, integer *incx, real *sy, integer *incy); doublereal scabs1_(complex *z__); doublereal scasum_(integer *n, complex *cx, integer *incx); doublereal scnrm2_(integer *n, complex *x, integer *incx); /* Subroutine */ int scopy_(integer *n, real *sx, integer *incx, real *sy, integer *incy); doublereal sdot_(integer *n, real *sx, integer *incx, real *sy, integer *incy); doublereal sdsdot_(integer *n, real *sb, real *sx, integer *incx, real *sy, integer *incy); /* Subroutine */ int sgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, real *alpha, real *a, integer *lda, real *x, integer * incx, real *beta, real *y, integer *incy); /* Subroutine */ int sgemm_(char *transa, char *transb, integer *m, integer * n, integer *k, real *alpha, real *a, integer *lda, real *b, integer * ldb, real *beta, real *c__, integer *ldc); /* Subroutine */ int sgemv_(char *trans, integer *m, integer *n, real *alpha, real *a, integer *lda, real *x, integer *incx, real *beta, real *y, integer *incy); /* Subroutine */ int sger_(integer *m, integer *n, real *alpha, real *x, integer *incx, real *y, integer *incy, real *a, integer *lda); doublereal snrm2_(integer *n, real *x, integer *incx); /* Subroutine */ int srot_(integer *n, real *sx, integer *incx, real *sy, integer *incy, real *c__, real *s); /* Subroutine */ int srotg_(real *sa, real *sb, real *c__, real *s); /* Subroutine */ int srotm_(integer *n, real *sx, integer *incx, real *sy, integer *incy, real *sparam); /* Subroutine */ int srotmg_(real *sd1, real *sd2, real *sx1, real *sy1, real *sparam); /* Subroutine */ int ssbmv_(char *uplo, integer *n, integer *k, real *alpha, real *a, integer *lda, real *x, integer *incx, real *beta, real *y, integer *incy); /* Subroutine */ int sscal_(integer *n, real *sa, real *sx, integer *incx); /* Subroutine */ int sspmv_(char *uplo, integer *n, real *alpha, real *ap, real *x, integer *incx, real *beta, real *y, integer *incy); /* Subroutine */ int sspr_(char *uplo, integer *n, real *alpha, real *x, integer *incx, real *ap); /* Subroutine */ int sspr2_(char *uplo, integer *n, real *alpha, real *x, integer *incx, real *y, integer *incy, real *ap); /* Subroutine */ int sswap_(integer *n, real *sx, integer *incx, real *sy, integer *incy); /* Subroutine */ int ssymm_(char *side, char *uplo, integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, integer *ldb, real *beta, real *c__, integer *ldc); /* Subroutine */ int ssymv_(char *uplo, integer *n, real *alpha, real *a, integer *lda, real *x, integer *incx, real *beta, real *y, integer * incy); /* Subroutine */ int ssyr_(char *uplo, integer *n, real *alpha, real *x, integer *incx, real *a, integer *lda); /* Subroutine */ int ssyr2_(char *uplo, integer *n, real *alpha, real *x, integer *incx, real *y, integer *incy, real *a, integer *lda); /* Subroutine */ int ssyr2k_(char *uplo, char *trans, integer *n, integer *k, real *alpha, real *a, integer *lda, real *b, integer *ldb, real *beta, real *c__, integer *ldc); /* Subroutine */ int ssyrk_(char *uplo, char *trans, integer *n, integer *k, real *alpha, real *a, integer *lda, real *beta, real *c__, integer * ldc); /* Subroutine */ int stbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, real *a, integer *lda, real *x, integer *incx); /* Subroutine */ int stbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, real *a, integer *lda, real *x, integer *incx); /* Subroutine */ int stpmv_(char *uplo, char *trans, char *diag, integer *n, real *ap, real *x, integer *incx); /* Subroutine */ int stpsv_(char *uplo, char *trans, char *diag, integer *n, real *ap, real *x, integer *incx); /* Subroutine */ int strmm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, integer *ldb); /* Subroutine */ int strmv_(char *uplo, char *trans, char *diag, integer *n, real *a, integer *lda, real *x, integer *incx); /* Subroutine */ int strsm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, integer *ldb); /* Subroutine */ int strsv_(char *uplo, char *trans, char *diag, integer *n, real *a, integer *lda, real *x, integer *incx); /* Subroutine */ int xerbla_(char *srname, integer *info); /* Subroutine */ int xerbla_array__(char *srname_array__, integer * srname_len__, integer *info, ftnlen srname_array_len); /* Subroutine */ int zaxpy_(integer *n, doublecomplex *za, doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy); /* Subroutine */ int zcopy_(integer *n, doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy); /* Double Complex */ VOID zdotc_(doublecomplex * ret_val, integer *n, doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy); /* Double Complex */ VOID zdotu_(doublecomplex * ret_val, integer *n, doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy); /* Subroutine */ int zdrot_(integer *n, doublecomplex *cx, integer *incx, doublecomplex *cy, integer *incy, doublereal *c__, doublereal *s); /* Subroutine */ int zdscal_(integer *n, doublereal *da, doublecomplex *zx, integer *incx); /* Subroutine */ int zgbmv_(char *trans, integer *m, integer *n, integer *kl, integer *ku, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublecomplex *beta, doublecomplex * y, integer *incy); /* Subroutine */ int zgemm_(char *transa, char *transb, integer *m, integer * n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *beta, doublecomplex * c__, integer *ldc); /* Subroutine */ int zgemv_(char *trans, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * x, integer *incx, doublecomplex *beta, doublecomplex *y, integer * incy); /* Subroutine */ int zgerc_(integer *m, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublecomplex *a, integer *lda); /* Subroutine */ int zgeru_(integer *m, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublecomplex *a, integer *lda); /* Subroutine */ int zhbmv_(char *uplo, integer *n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer * incx, doublecomplex *beta, doublecomplex *y, integer *incy); /* Subroutine */ int zhemm_(char *side, char *uplo, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * b, integer *ldb, doublecomplex *beta, doublecomplex *c__, integer * ldc); /* Subroutine */ int zhemv_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublecomplex *beta, doublecomplex *y, integer *incy); /* Subroutine */ int zher_(char *uplo, integer *n, doublereal *alpha, doublecomplex *x, integer *incx, doublecomplex *a, integer *lda); /* Subroutine */ int zher2_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublecomplex *a, integer *lda); /* Subroutine */ int zher2k_(char *uplo, char *trans, integer *n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * b, integer *ldb, doublereal *beta, doublecomplex *c__, integer *ldc); /* Subroutine */ int zherk_(char *uplo, char *trans, integer *n, integer *k, doublereal *alpha, doublecomplex *a, integer *lda, doublereal *beta, doublecomplex *c__, integer *ldc); /* Subroutine */ int zhpmv_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *ap, doublecomplex *x, integer *incx, doublecomplex * beta, doublecomplex *y, integer *incy); /* Subroutine */ int zhpr_(char *uplo, integer *n, doublereal *alpha, doublecomplex *x, integer *incx, doublecomplex *ap); /* Subroutine */ int zhpr2_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublecomplex *ap); /* Subroutine */ int zrotg_(doublecomplex *ca, doublecomplex *cb, doublereal * c__, doublecomplex *s); /* Subroutine */ int zscal_(integer *n, doublecomplex *za, doublecomplex *zx, integer *incx); /* Subroutine */ int zswap_(integer *n, doublecomplex *zx, integer *incx, doublecomplex *zy, integer *incy); /* Subroutine */ int zsymm_(char *side, char *uplo, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * b, integer *ldb, doublecomplex *beta, doublecomplex *c__, integer * ldc); /* Subroutine */ int zsyr2k_(char *uplo, char *trans, integer *n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * b, integer *ldb, doublecomplex *beta, doublecomplex *c__, integer * ldc); /* Subroutine */ int zsyrk_(char *uplo, char *trans, integer *n, integer *k, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex * beta, doublecomplex *c__, integer *ldc); /* Subroutine */ int ztbmv_(char *uplo, char *trans, char *diag, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx); /* Subroutine */ int ztbsv_(char *uplo, char *trans, char *diag, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx); /* Subroutine */ int ztpmv_(char *uplo, char *trans, char *diag, integer *n, doublecomplex *ap, doublecomplex *x, integer *incx); /* Subroutine */ int ztpsv_(char *uplo, char *trans, char *diag, integer *n, doublecomplex *ap, doublecomplex *x, integer *incx); /* Subroutine */ int ztrmm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb); /* Subroutine */ int ztrmv_(char *uplo, char *trans, char *diag, integer *n, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx); /* Subroutine */ int ztrsm_(char *side, char *uplo, char *transa, char *diag, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb); /* Subroutine */ int ztrsv_(char *uplo, char *trans, char *diag, integer *n, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx); /* Subroutine */ int cbdsqr_(char *uplo, integer *n, integer *ncvt, integer * nru, integer *ncc, real *d__, real *e, complex *vt, integer *ldvt, complex *u, integer *ldu, complex *c__, integer *ldc, real *rwork, integer *info); /* Subroutine */ int cgbbrd_(char *vect, integer *m, integer *n, integer *ncc, integer *kl, integer *ku, complex *ab, integer *ldab, real *d__, real *e, complex *q, integer *ldq, complex *pt, integer *ldpt, complex *c__, integer *ldc, complex *work, real *rwork, integer *info); /* Subroutine */ int cgbcon_(char *norm, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, integer *ipiv, real *anorm, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int cgbequ_(integer *m, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int cgbequb_(integer *m, integer *n, integer *kl, integer * ku, complex *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int cgbrfs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, complex *ab, integer *ldab, complex *afb, integer * ldafb, integer *ipiv, complex *b, integer *ldb, complex *x, integer * ldx, real *ferr, real *berr, complex *work, real *rwork, integer * info); /* Subroutine */ int cgbrfsx_(char *trans, char *equed, integer *n, integer * kl, integer *ku, integer *nrhs, complex *ab, integer *ldab, complex * afb, integer *ldafb, integer *ipiv, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, complex *work, real *rwork, integer * info); /* Subroutine */ int cgbsv_(integer *n, integer *kl, integer *ku, integer * nrhs, complex *ab, integer *ldab, integer *ipiv, complex *b, integer * ldb, integer *info); /* Subroutine */ int cgbsvx_(char *fact, char *trans, integer *n, integer *kl, integer *ku, integer *nrhs, complex *ab, integer *ldab, complex *afb, integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cgbsvxx_(char *fact, char *trans, integer *n, integer * kl, integer *ku, integer *nrhs, complex *ab, integer *ldab, complex * afb, integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer *n_err_bnds__, real * err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real * params, complex *work, real *rwork, integer *info); /* Subroutine */ int cgbtf2_(integer *m, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int cgbtrf_(integer *m, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int cgbtrs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, complex *ab, integer *ldab, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int cgebak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, real *scale, integer *m, complex *v, integer *ldv, integer *info); /* Subroutine */ int cgebal_(char *job, integer *n, complex *a, integer *lda, integer *ilo, integer *ihi, real *scale, integer *info); /* Subroutine */ int cgebd2_(integer *m, integer *n, complex *a, integer *lda, real *d__, real *e, complex *tauq, complex *taup, complex *work, integer *info); /* Subroutine */ int cgebrd_(integer *m, integer *n, complex *a, integer *lda, real *d__, real *e, complex *tauq, complex *taup, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgecon_(char *norm, integer *n, complex *a, integer *lda, real *anorm, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int cgeequ_(integer *m, integer *n, complex *a, integer *lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int cgeequb_(integer *m, integer *n, complex *a, integer * lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int cgees_(char *jobvs, char *sort, L_fp select, integer *n, complex *a, integer *lda, integer *sdim, complex *w, complex *vs, integer *ldvs, complex *work, integer *lwork, real *rwork, logical * bwork, integer *info); /* Subroutine */ int cgeesx_(char *jobvs, char *sort, L_fp select, char * sense, integer *n, complex *a, integer *lda, integer *sdim, complex * w, complex *vs, integer *ldvs, real *rconde, real *rcondv, complex * work, integer *lwork, real *rwork, logical *bwork, integer *info); /* Subroutine */ int cgeev_(char *jobvl, char *jobvr, integer *n, complex *a, integer *lda, complex *w, complex *vl, integer *ldvl, complex *vr, integer *ldvr, complex *work, integer *lwork, real *rwork, integer * info); /* Subroutine */ int cgeevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, complex *a, integer *lda, complex *w, complex *vl, integer *ldvl, complex *vr, integer *ldvr, integer *ilo, integer *ihi, real *scale, real *abnrm, real *rconde, real *rcondv, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cgegs_(char *jobvsl, char *jobvsr, integer *n, complex * a, integer *lda, complex *b, integer *ldb, complex *alpha, complex * beta, complex *vsl, integer *ldvsl, complex *vsr, integer *ldvsr, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cgegv_(char *jobvl, char *jobvr, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, complex *vl, integer *ldvl, complex *vr, integer *ldvr, complex * work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cgehd2_(integer *n, integer *ilo, integer *ihi, complex * a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cgehrd_(integer *n, integer *ilo, integer *ihi, complex * a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgelq2_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cgelqf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgels_(char *trans, integer *m, integer *n, integer * nrhs, complex *a, integer *lda, complex *b, integer *ldb, complex * work, integer *lwork, integer *info); /* Subroutine */ int cgelsd_(integer *m, integer *n, integer *nrhs, complex * a, integer *lda, complex *b, integer *ldb, real *s, real *rcond, integer *rank, complex *work, integer *lwork, real *rwork, integer * iwork, integer *info); /* Subroutine */ int cgelss_(integer *m, integer *n, integer *nrhs, complex * a, integer *lda, complex *b, integer *ldb, real *s, real *rcond, integer *rank, complex *work, integer *lwork, real *rwork, integer * info); /* Subroutine */ int cgelsx_(integer *m, integer *n, integer *nrhs, complex * a, integer *lda, complex *b, integer *ldb, integer *jpvt, real *rcond, integer *rank, complex *work, real *rwork, integer *info); /* Subroutine */ int cgelsy_(integer *m, integer *n, integer *nrhs, complex * a, integer *lda, complex *b, integer *ldb, integer *jpvt, real *rcond, integer *rank, complex *work, integer *lwork, real *rwork, integer * info); /* Subroutine */ int cgeql2_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cgeqlf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgeqp3_(integer *m, integer *n, complex *a, integer *lda, integer *jpvt, complex *tau, complex *work, integer *lwork, real * rwork, integer *info); /* Subroutine */ int cgeqpf_(integer *m, integer *n, complex *a, integer *lda, integer *jpvt, complex *tau, complex *work, real *rwork, integer * info); /* Subroutine */ int cgeqr2_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cgeqrf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgerfs_(char *trans, integer *n, integer *nrhs, complex * a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cgerfsx_(char *trans, char *equed, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real * err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real * params, complex *work, real *rwork, integer *info); /* Subroutine */ int cgerq2_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cgerqf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgesc2_(integer *n, complex *a, integer *lda, complex * rhs, integer *ipiv, integer *jpiv, real *scale); /* Subroutine */ int cgesdd_(char *jobz, integer *m, integer *n, complex *a, integer *lda, real *s, complex *u, integer *ldu, complex *vt, integer *ldvt, complex *work, integer *lwork, real *rwork, integer *iwork, integer *info); /* Subroutine */ int cgesv_(integer *n, integer *nrhs, complex *a, integer * lda, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int cgesvd_(char *jobu, char *jobvt, integer *m, integer *n, complex *a, integer *lda, real *s, complex *u, integer *ldu, complex * vt, integer *ldvt, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cgesvx_(char *fact, char *trans, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, char *equed, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cgesvxx_(char *fact, char *trans, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, char *equed, real *r__, real *c__, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, complex *work, real *rwork, integer * info); /* Subroutine */ int cgetc2_(integer *n, complex *a, integer *lda, integer * ipiv, integer *jpiv, integer *info); /* Subroutine */ int cgetf2_(integer *m, integer *n, complex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int cgetrf_(integer *m, integer *n, complex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int cgetri_(integer *n, complex *a, integer *lda, integer * ipiv, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgetrs_(char *trans, integer *n, integer *nrhs, complex * a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * info); /* Subroutine */ int cggbak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, real *lscale, real *rscale, integer *m, complex *v, integer *ldv, integer *info); /* Subroutine */ int cggbal_(char *job, integer *n, complex *a, integer *lda, complex *b, integer *ldb, integer *ilo, integer *ihi, real *lscale, real *rscale, real *work, integer *info); /* Subroutine */ int cgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, integer *n, complex *a, integer *lda, complex *b, integer * ldb, integer *sdim, complex *alpha, complex *beta, complex *vsl, integer *ldvsl, complex *vsr, integer *ldvsr, complex *work, integer * lwork, real *rwork, logical *bwork, integer *info); /* Subroutine */ int cggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, char *sense, integer *n, complex *a, integer *lda, complex *b, integer *ldb, integer *sdim, complex *alpha, complex *beta, complex * vsl, integer *ldvsl, complex *vsr, integer *ldvsr, real *rconde, real *rcondv, complex *work, integer *lwork, real *rwork, integer *iwork, integer *liwork, logical *bwork, integer *info); /* Subroutine */ int cggev_(char *jobvl, char *jobvr, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, complex *vl, integer *ldvl, complex *vr, integer *ldvr, complex * work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cggevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, complex *vl, integer *ldvl, complex * vr, integer *ldvr, integer *ilo, integer *ihi, real *lscale, real * rscale, real *abnrm, real *bbnrm, real *rconde, real *rcondv, complex *work, integer *lwork, real *rwork, integer *iwork, logical *bwork, integer *info); /* Subroutine */ int cggglm_(integer *n, integer *m, integer *p, complex *a, integer *lda, complex *b, integer *ldb, complex *d__, complex *x, complex *y, complex *work, integer *lwork, integer *info); /* Subroutine */ int cgghrd_(char *compq, char *compz, integer *n, integer * ilo, integer *ihi, complex *a, integer *lda, complex *b, integer *ldb, complex *q, integer *ldq, complex *z__, integer *ldz, integer *info); /* Subroutine */ int cgglse_(integer *m, integer *n, integer *p, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, complex *d__, complex *x, complex *work, integer *lwork, integer *info); /* Subroutine */ int cggqrf_(integer *n, integer *m, integer *p, complex *a, integer *lda, complex *taua, complex *b, integer *ldb, complex *taub, complex *work, integer *lwork, integer *info); /* Subroutine */ int cggrqf_(integer *m, integer *p, integer *n, complex *a, integer *lda, complex *taua, complex *b, integer *ldb, complex *taub, complex *work, integer *lwork, integer *info); /* Subroutine */ int cggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, complex *a, integer * lda, complex *b, integer *ldb, real *alpha, real *beta, complex *u, integer *ldu, complex *v, integer *ldv, complex *q, integer *ldq, complex *work, real *rwork, integer *iwork, integer *info); /* Subroutine */ int cggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, complex *a, integer *lda, complex *b, integer *ldb, real *tola, real *tolb, integer *k, integer *l, complex *u, integer *ldu, complex *v, integer *ldv, complex *q, integer *ldq, integer *iwork, real *rwork, complex *tau, complex *work, integer * info); /* Subroutine */ int cgtcon_(char *norm, integer *n, complex *dl, complex * d__, complex *du, complex *du2, integer *ipiv, real *anorm, real * rcond, complex *work, integer *info); /* Subroutine */ int cgtrfs_(char *trans, integer *n, integer *nrhs, complex * dl, complex *d__, complex *du, complex *dlf, complex *df, complex * duf, complex *du2, integer *ipiv, complex *b, integer *ldb, complex * x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cgtsv_(integer *n, integer *nrhs, complex *dl, complex * d__, complex *du, complex *b, integer *ldb, integer *info); /* Subroutine */ int cgtsvx_(char *fact, char *trans, integer *n, integer * nrhs, complex *dl, complex *d__, complex *du, complex *dlf, complex * df, complex *duf, complex *du2, integer *ipiv, complex *b, integer * ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cgttrf_(integer *n, complex *dl, complex *d__, complex * du, complex *du2, integer *ipiv, integer *info); /* Subroutine */ int cgttrs_(char *trans, integer *n, integer *nrhs, complex * dl, complex *d__, complex *du, complex *du2, integer *ipiv, complex * b, integer *ldb, integer *info); /* Subroutine */ int cgtts2_(integer *itrans, integer *n, integer *nrhs, complex *dl, complex *d__, complex *du, complex *du2, integer *ipiv, complex *b, integer *ldb); /* Subroutine */ int chbev_(char *jobz, char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *info); /* Subroutine */ int chbevd_(char *jobz, char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *lrwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int chbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, complex *q, integer *ldq, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer * m, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int chbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, complex *x, integer *ldx, complex *work, real *rwork, integer *info); /* Subroutine */ int chbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *info); /* Subroutine */ int chbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int chbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, integer *kb, complex *ab, integer *ldab, complex *bb, integer *ldbb, complex *q, integer *ldq, real *vl, real *vu, integer * il, integer *iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *iwork, integer * ifail, integer *info); /* Subroutine */ int chbtrd_(char *vect, char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *d__, real *e, complex *q, integer * ldq, complex *work, integer *info); /* Subroutine */ int checon_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, real *anorm, real *rcond, complex *work, integer * info); /* Subroutine */ int cheequb_(char *uplo, integer *n, complex *a, integer * lda, real *s, real *scond, real *amax, complex *work, integer *info); /* Subroutine */ int cheev_(char *jobz, char *uplo, integer *n, complex *a, integer *lda, real *w, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int cheevd_(char *jobz, char *uplo, integer *n, complex *a, integer *lda, real *w, complex *work, integer *lwork, real *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int cheevr_(char *jobz, char *range, char *uplo, integer *n, complex *a, integer *lda, real *vl, real *vu, integer *il, integer * iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, integer *isuppz, complex *work, integer *lwork, real *rwork, integer * lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int cheevx_(char *jobz, char *range, char *uplo, integer *n, complex *a, integer *lda, real *vl, real *vu, integer *il, integer * iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *iwork, integer * ifail, integer *info); /* Subroutine */ int chegs2_(integer *itype, char *uplo, integer *n, complex * a, integer *lda, complex *b, integer *ldb, integer *info); /* Subroutine */ int chegst_(integer *itype, char *uplo, integer *n, complex * a, integer *lda, complex *b, integer *ldb, integer *info); /* Subroutine */ int chegv_(integer *itype, char *jobz, char *uplo, integer * n, complex *a, integer *lda, complex *b, integer *ldb, real *w, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int chegvd_(integer *itype, char *jobz, char *uplo, integer * n, complex *a, integer *lda, complex *b, integer *ldb, real *w, complex *work, integer *lwork, real *rwork, integer *lrwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int chegvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, complex *a, integer *lda, complex *b, integer *ldb, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer * m, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int cherfs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cherfsx_(char *uplo, char *equed, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, complex *work, real *rwork, integer *info); /* Subroutine */ int chesv_(char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, integer *ipiv, complex *b, integer *ldb, complex *work, integer *lwork, integer *info); /* Subroutine */ int chesvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int chesvxx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, char *equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer * n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer * nparams, real *params, complex *work, real *rwork, integer *info); /* Subroutine */ int chetd2_(char *uplo, integer *n, complex *a, integer *lda, real *d__, real *e, complex *tau, integer *info); /* Subroutine */ int chetf2_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int chetrd_(char *uplo, integer *n, complex *a, integer *lda, real *d__, real *e, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int chetrf_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, complex *work, integer *lwork, integer *info); /* Subroutine */ int chetri_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, complex *work, integer *info); /* Subroutine */ int chetrs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * info); /* Subroutine */ int chfrk_(char *transr, char *uplo, char *trans, integer *n, integer *k, real *alpha, complex *a, integer *lda, real *beta, complex *c__); /* Subroutine */ int chgeqz_(char *job, char *compq, char *compz, integer *n, integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *t, integer *ldt, complex *alpha, complex *beta, complex *q, integer *ldq, complex *z__, integer *ldz, complex *work, integer *lwork, real * rwork, integer *info); /* Character */ VOID chla_transtype__(char *ret_val, ftnlen ret_val_len, integer *trans); /* Subroutine */ int chpcon_(char *uplo, integer *n, complex *ap, integer * ipiv, real *anorm, real *rcond, complex *work, integer *info); /* Subroutine */ int chpev_(char *jobz, char *uplo, integer *n, complex *ap, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *info); /* Subroutine */ int chpevd_(char *jobz, char *uplo, integer *n, complex *ap, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int chpevx_(char *jobz, char *range, char *uplo, integer *n, complex *ap, real *vl, real *vu, integer *il, integer *iu, real * abstol, integer *m, real *w, complex *z__, integer *ldz, complex * work, real *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int chpgst_(integer *itype, char *uplo, integer *n, complex * ap, complex *bp, integer *info); /* Subroutine */ int chpgv_(integer *itype, char *jobz, char *uplo, integer * n, complex *ap, complex *bp, real *w, complex *z__, integer *ldz, complex *work, real *rwork, integer *info); /* Subroutine */ int chpgvd_(integer *itype, char *jobz, char *uplo, integer * n, complex *ap, complex *bp, real *w, complex *z__, integer *ldz, complex *work, integer *lwork, real *rwork, integer *lrwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int chpgvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, complex *ap, complex *bp, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, complex * z__, integer *ldz, complex *work, real *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int chprfs_(char *uplo, integer *n, integer *nrhs, complex * ap, complex *afp, integer *ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int chpsv_(char *uplo, integer *n, integer *nrhs, complex * ap, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int chpsvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *ap, complex *afp, integer *ipiv, complex *b, integer * ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int chptrd_(char *uplo, integer *n, complex *ap, real *d__, real *e, complex *tau, integer *info); /* Subroutine */ int chptrf_(char *uplo, integer *n, complex *ap, integer * ipiv, integer *info); /* Subroutine */ int chptri_(char *uplo, integer *n, complex *ap, integer * ipiv, complex *work, integer *info); /* Subroutine */ int chptrs_(char *uplo, integer *n, integer *nrhs, complex * ap, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int chsein_(char *side, char *eigsrc, char *initv, logical * select, integer *n, complex *h__, integer *ldh, complex *w, complex * vl, integer *ldvl, complex *vr, integer *ldvr, integer *mm, integer * m, complex *work, real *rwork, integer *ifaill, integer *ifailr, integer *info); /* Subroutine */ int chseqr_(char *job, char *compz, integer *n, integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, complex *z__, integer *ldz, complex *work, integer *lwork, integer *info); /* Subroutine */ int cla_gbamv__(integer *trans, integer *m, integer *n, integer *kl, integer *ku, real *alpha, complex *ab, integer *ldab, complex *x, integer *incx, real *beta, real *y, integer *incy); doublereal cla_gbrcond_c__(char *trans, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, complex *afb, integer *ldafb, integer * ipiv, real *c__, logical *capply, integer *info, complex *work, real * rwork, ftnlen trans_len); doublereal cla_gbrcond_x__(char *trans, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, complex *afb, integer *ldafb, integer * ipiv, complex *x, integer *info, complex *work, real *rwork, ftnlen trans_len); /* Subroutine */ int cla_gbrfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *kl, integer *ku, integer *nrhs, complex *ab, integer *ldab, complex *afb, integer *ldafb, integer * ipiv, logical *colequ, real *c__, complex *b, integer *ldb, complex * y, integer *ldy, real *berr_out__, integer *n_norms__, real *errs_n__, real *errs_c__, complex *res, real *ayb, complex *dy, complex * y_tail__, real *rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info); doublereal cla_gbrpvgrw__(integer *n, integer *kl, integer *ku, integer * ncols, complex *ab, integer *ldab, complex *afb, integer *ldafb); /* Subroutine */ int cla_geamv__(integer *trans, integer *m, integer *n, real *alpha, complex *a, integer *lda, complex *x, integer *incx, real * beta, real *y, integer *incy); doublereal cla_gercond_c__(char *trans, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, real *c__, logical *capply, integer *info, complex *work, real *rwork, ftnlen trans_len); doublereal cla_gercond_x__(char *trans, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex *x, integer *info, complex *work, real *rwork, ftnlen trans_len); /* Subroutine */ int cla_gerfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, logical *colequ, real *c__, complex *b, integer *ldb, complex *y, integer *ldy, real *berr_out__, integer *n_norms__, real *errs_n__, real *errs_c__, complex *res, real *ayb, complex *dy, complex *y_tail__, real *rcond, integer * ithresh, real *rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info); /* Subroutine */ int cla_heamv__(integer *uplo, integer *n, real *alpha, complex *a, integer *lda, complex *x, integer *incx, real *beta, real *y, integer *incy); doublereal cla_hercond_c__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, real *c__, logical *capply, integer *info, complex *work, real *rwork, ftnlen uplo_len); doublereal cla_hercond_x__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex *x, integer *info, complex *work, real *rwork, ftnlen uplo_len); /* Subroutine */ int cla_herfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, logical *colequ, real *c__, complex *b, integer *ldb, complex *y, integer *ldy, real *berr_out__, integer * n_norms__, real *errs_n__, real *errs_c__, complex *res, real *ayb, complex *dy, complex *y_tail__, real *rcond, integer *ithresh, real * rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal cla_herpvgrw__(char *uplo, integer *n, integer *info, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, real *work, ftnlen uplo_len); /* Subroutine */ int cla_lin_berr__(integer *n, integer *nz, integer *nrhs, complex *res, real *ayb, real *berr); doublereal cla_porcond_c__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, real *c__, logical *capply, integer *info, complex *work, real *rwork, ftnlen uplo_len); doublereal cla_porcond_x__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, complex *x, integer *info, complex *work, real *rwork, ftnlen uplo_len); /* Subroutine */ int cla_porfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, complex *af, integer *ldaf, logical *colequ, real *c__, complex *b, integer *ldb, complex *y, integer *ldy, real *berr_out__, integer *n_norms__, real * errs_n__, real *errs_c__, complex *res, real *ayb, complex *dy, complex *y_tail__, real *rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal cla_porpvgrw__(char *uplo, integer *ncols, complex *a, integer * lda, complex *af, integer *ldaf, real *work, ftnlen uplo_len); doublereal cla_rpvgrw__(integer *n, integer *ncols, complex *a, integer *lda, complex *af, integer *ldaf); /* Subroutine */ int cla_syamv__(integer *uplo, integer *n, real *alpha, complex *a, integer *lda, complex *x, integer *incx, real *beta, real *y, integer *incy); doublereal cla_syrcond_c__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, real *c__, logical *capply, integer *info, complex *work, real *rwork, ftnlen uplo_len); doublereal cla_syrcond_x__(char *uplo, integer *n, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex *x, integer *info, complex *work, real *rwork, ftnlen uplo_len); /* Subroutine */ int cla_syrfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, logical *colequ, real *c__, complex *b, integer *ldb, complex *y, integer *ldy, real *berr_out__, integer * n_norms__, real *errs_n__, real *errs_c__, complex *res, real *ayb, complex *dy, complex *y_tail__, real *rcond, integer *ithresh, real * rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal cla_syrpvgrw__(char *uplo, integer *n, integer *info, complex *a, integer *lda, complex *af, integer *ldaf, integer *ipiv, real *work, ftnlen uplo_len); /* Subroutine */ int cla_wwaddw__(integer *n, complex *x, complex *y, complex *w); /* Subroutine */ int clabrd_(integer *m, integer *n, integer *nb, complex *a, integer *lda, real *d__, real *e, complex *tauq, complex *taup, complex *x, integer *ldx, complex *y, integer *ldy); /* Subroutine */ int clacgv_(integer *n, complex *x, integer *incx); /* Subroutine */ int clacn2_(integer *n, complex *v, complex *x, real *est, integer *kase, integer *isave); /* Subroutine */ int clacon_(integer *n, complex *v, complex *x, real *est, integer *kase); /* Subroutine */ int clacp2_(char *uplo, integer *m, integer *n, real *a, integer *lda, complex *b, integer *ldb); /* Subroutine */ int clacpy_(char *uplo, integer *m, integer *n, complex *a, integer *lda, complex *b, integer *ldb); /* Subroutine */ int clacrm_(integer *m, integer *n, complex *a, integer *lda, real *b, integer *ldb, complex *c__, integer *ldc, real *rwork); /* Subroutine */ int clacrt_(integer *n, complex *cx, integer *incx, complex * cy, integer *incy, complex *c__, complex *s); /* Complex */ VOID cladiv_(complex * ret_val, complex *x, complex *y); /* Subroutine */ int claed0_(integer *qsiz, integer *n, real *d__, real *e, complex *q, integer *ldq, complex *qstore, integer *ldqs, real *rwork, integer *iwork, integer *info); /* Subroutine */ int claed7_(integer *n, integer *cutpnt, integer *qsiz, integer *tlvls, integer *curlvl, integer *curpbm, real *d__, complex * q, integer *ldq, real *rho, integer *indxq, real *qstore, integer * qptr, integer *prmptr, integer *perm, integer *givptr, integer * givcol, real *givnum, complex *work, real *rwork, integer *iwork, integer *info); /* Subroutine */ int claed8_(integer *k, integer *n, integer *qsiz, complex * q, integer *ldq, real *d__, real *rho, integer *cutpnt, real *z__, real *dlamda, complex *q2, integer *ldq2, real *w, integer *indxp, integer *indx, integer *indxq, integer *perm, integer *givptr, integer *givcol, real *givnum, integer *info); /* Subroutine */ int claein_(logical *rightv, logical *noinit, integer *n, complex *h__, integer *ldh, complex *w, complex *v, complex *b, integer *ldb, real *rwork, real *eps3, real *smlnum, integer *info); /* Subroutine */ int claesy_(complex *a, complex *b, complex *c__, complex * rt1, complex *rt2, complex *evscal, complex *cs1, complex *sn1); /* Subroutine */ int claev2_(complex *a, complex *b, complex *c__, real *rt1, real *rt2, real *cs1, complex *sn1); /* Subroutine */ int clag2z_(integer *m, integer *n, complex *sa, integer * ldsa, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int clags2_(logical *upper, real *a1, complex *a2, real *a3, real *b1, complex *b2, real *b3, real *csu, complex *snu, real *csv, complex *snv, real *csq, complex *snq); /* Subroutine */ int clagtm_(char *trans, integer *n, integer *nrhs, real * alpha, complex *dl, complex *d__, complex *du, complex *x, integer * ldx, real *beta, complex *b, integer *ldb); /* Subroutine */ int clahef_(char *uplo, integer *n, integer *nb, integer *kb, complex *a, integer *lda, integer *ipiv, complex *w, integer *ldw, integer *info); /* Subroutine */ int clahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * info); /* Subroutine */ int clahr2_(integer *n, integer *k, integer *nb, complex *a, integer *lda, complex *tau, complex *t, integer *ldt, complex *y, integer *ldy); /* Subroutine */ int clahrd_(integer *n, integer *k, integer *nb, complex *a, integer *lda, complex *tau, complex *t, integer *ldt, complex *y, integer *ldy); /* Subroutine */ int claic1_(integer *job, integer *j, complex *x, real *sest, complex *w, complex *gamma, real *sestpr, complex *s, complex *c__); /* Subroutine */ int clals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *nrhs, complex *b, integer *ldb, complex *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * difl, real *difr, real *z__, integer *k, real *c__, real *s, real * rwork, integer *info); /* Subroutine */ int clalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, complex *b, integer *ldb, complex *bx, integer *ldbx, real *u, integer *ldu, real *vt, integer *k, real *difl, real *difr, real *z__, real *poles, integer *givptr, integer *givcol, integer * ldgcol, integer *perm, real *givnum, real *c__, real *s, real *rwork, integer *iwork, integer *info); /* Subroutine */ int clalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, real *d__, real *e, complex *b, integer *ldb, real *rcond, integer *rank, complex *work, real *rwork, integer *iwork, integer * info); doublereal clangb_(char *norm, integer *n, integer *kl, integer *ku, complex * ab, integer *ldab, real *work); doublereal clange_(char *norm, integer *m, integer *n, complex *a, integer * lda, real *work); doublereal clangt_(char *norm, integer *n, complex *dl, complex *d__, complex *du); doublereal clanhb_(char *norm, char *uplo, integer *n, integer *k, complex * ab, integer *ldab, real *work); doublereal clanhe_(char *norm, char *uplo, integer *n, complex *a, integer * lda, real *work); doublereal clanhf_(char *norm, char *transr, char *uplo, integer *n, complex * a, real *work); doublereal clanhp_(char *norm, char *uplo, integer *n, complex *ap, real * work); doublereal clanhs_(char *norm, integer *n, complex *a, integer *lda, real * work); doublereal clanht_(char *norm, integer *n, real *d__, complex *e); doublereal clansb_(char *norm, char *uplo, integer *n, integer *k, complex * ab, integer *ldab, real *work); doublereal clansp_(char *norm, char *uplo, integer *n, complex *ap, real * work); doublereal clansy_(char *norm, char *uplo, integer *n, complex *a, integer * lda, real *work); doublereal clantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, complex *ab, integer *ldab, real *work); doublereal clantp_(char *norm, char *uplo, char *diag, integer *n, complex * ap, real *work); doublereal clantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, complex *a, integer *lda, real *work); /* Subroutine */ int clapll_(integer *n, complex *x, integer *incx, complex * y, integer *incy, real *ssmin); /* Subroutine */ int clapmt_(logical *forwrd, integer *m, integer *n, complex *x, integer *ldx, integer *k); /* Subroutine */ int claqgb_(integer *m, integer *n, integer *kl, integer *ku, complex *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, char *equed); /* Subroutine */ int claqge_(integer *m, integer *n, complex *a, integer *lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, char * equed); /* Subroutine */ int claqhb_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int claqhe_(char *uplo, integer *n, complex *a, integer *lda, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int claqhp_(char *uplo, integer *n, complex *ap, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int claqp2_(integer *m, integer *n, integer *offset, complex *a, integer *lda, integer *jpvt, complex *tau, real *vn1, real *vn2, complex *work); /* Subroutine */ int claqps_(integer *m, integer *n, integer *offset, integer *nb, integer *kb, complex *a, integer *lda, integer *jpvt, complex * tau, real *vn1, real *vn2, complex *auxv, complex *f, integer *ldf); /* Subroutine */ int claqr0_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, integer *iloz, integer *ihiz, complex *z__, integer *ldz, complex * work, integer *lwork, integer *info); /* Subroutine */ int claqr1_(integer *n, complex *h__, integer *ldh, complex * s1, complex *s2, complex *v); /* Subroutine */ int claqr2_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, complex *h__, integer *ldh, integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * ns, integer *nd, complex *sh, complex *v, integer *ldv, integer *nh, complex *t, integer *ldt, integer *nv, complex *wv, integer *ldwv, complex *work, integer *lwork); /* Subroutine */ int claqr3_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, complex *h__, integer *ldh, integer *iloz, integer *ihiz, complex *z__, integer *ldz, integer * ns, integer *nd, complex *sh, complex *v, integer *ldv, integer *nh, complex *t, integer *ldt, integer *nv, complex *wv, integer *ldwv, complex *work, integer *lwork); /* Subroutine */ int claqr4_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, complex *h__, integer *ldh, complex *w, integer *iloz, integer *ihiz, complex *z__, integer *ldz, complex * work, integer *lwork, integer *info); /* Subroutine */ int claqr5_(logical *wantt, logical *wantz, integer *kacc22, integer *n, integer *ktop, integer *kbot, integer *nshfts, complex *s, complex *h__, integer *ldh, integer *iloz, integer *ihiz, complex * z__, integer *ldz, complex *v, integer *ldv, complex *u, integer *ldu, integer *nv, complex *wv, integer *ldwv, integer *nh, complex *wh, integer *ldwh); /* Subroutine */ int claqsb_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int claqsp_(char *uplo, integer *n, complex *ap, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int claqsy_(char *uplo, integer *n, complex *a, integer *lda, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int clar1v_(integer *n, integer *b1, integer *bn, real * lambda, real *d__, real *l, real *ld, real *lld, real *pivmin, real * gaptol, complex *z__, logical *wantnc, integer *negcnt, real *ztz, real *mingma, integer *r__, integer *isuppz, real *nrminv, real * resid, real *rqcorr, real *work); /* Subroutine */ int clar2v_(integer *n, complex *x, complex *y, complex *z__, integer *incx, real *c__, complex *s, integer *incc); /* Subroutine */ int clarcm_(integer *m, integer *n, real *a, integer *lda, complex *b, integer *ldb, complex *c__, integer *ldc, real *rwork); /* Subroutine */ int clarf_(char *side, integer *m, integer *n, complex *v, integer *incv, complex *tau, complex *c__, integer *ldc, complex * work); /* Subroutine */ int clarfb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, complex *v, integer *ldv, complex *t, integer *ldt, complex *c__, integer *ldc, complex *work, integer *ldwork); /* Subroutine */ int clarfg_(integer *n, complex *alpha, complex *x, integer * incx, complex *tau); /* Subroutine */ int clarfp_(integer *n, complex *alpha, complex *x, integer * incx, complex *tau); /* Subroutine */ int clarft_(char *direct, char *storev, integer *n, integer * k, complex *v, integer *ldv, complex *tau, complex *t, integer *ldt); /* Subroutine */ int clarfx_(char *side, integer *m, integer *n, complex *v, complex *tau, complex *c__, integer *ldc, complex *work); /* Subroutine */ int clargv_(integer *n, complex *x, integer *incx, complex * y, integer *incy, real *c__, integer *incc); /* Subroutine */ int clarnv_(integer *idist, integer *iseed, integer *n, complex *x); /* Subroutine */ int clarrv_(integer *n, real *vl, real *vu, real *d__, real * l, real *pivmin, integer *isplit, integer *m, integer *dol, integer * dou, real *minrgp, real *rtol1, real *rtol2, real *w, real *werr, real *wgap, integer *iblock, integer *indexw, real *gers, complex * z__, integer *ldz, integer *isuppz, real *work, integer *iwork, integer *info); /* Subroutine */ int clarscl2_(integer *m, integer *n, real *d__, complex *x, integer *ldx); /* Subroutine */ int clartg_(complex *f, complex *g, real *cs, complex *sn, complex *r__); /* Subroutine */ int clartv_(integer *n, complex *x, integer *incx, complex * y, integer *incy, real *c__, complex *s, integer *incc); /* Subroutine */ int clarz_(char *side, integer *m, integer *n, integer *l, complex *v, integer *incv, complex *tau, complex *c__, integer *ldc, complex *work); /* Subroutine */ int clarzb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, integer *l, complex *v, integer *ldv, complex *t, integer *ldt, complex *c__, integer *ldc, complex *work, integer *ldwork); /* Subroutine */ int clarzt_(char *direct, char *storev, integer *n, integer * k, complex *v, integer *ldv, complex *tau, complex *t, integer *ldt); /* Subroutine */ int clascl_(char *type__, integer *kl, integer *ku, real * cfrom, real *cto, integer *m, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int clascl2_(integer *m, integer *n, real *d__, complex *x, integer *ldx); /* Subroutine */ int claset_(char *uplo, integer *m, integer *n, complex * alpha, complex *beta, complex *a, integer *lda); /* Subroutine */ int clasr_(char *side, char *pivot, char *direct, integer *m, integer *n, real *c__, real *s, complex *a, integer *lda); /* Subroutine */ int classq_(integer *n, complex *x, integer *incx, real * scale, real *sumsq); /* Subroutine */ int claswp_(integer *n, complex *a, integer *lda, integer * k1, integer *k2, integer *ipiv, integer *incx); /* Subroutine */ int clasyf_(char *uplo, integer *n, integer *nb, integer *kb, complex *a, integer *lda, integer *ipiv, complex *w, integer *ldw, integer *info); /* Subroutine */ int clatbs_(char *uplo, char *trans, char *diag, char * normin, integer *n, integer *kd, complex *ab, integer *ldab, complex * x, real *scale, real *cnorm, integer *info); /* Subroutine */ int clatdf_(integer *ijob, integer *n, complex *z__, integer *ldz, complex *rhs, real *rdsum, real *rdscal, integer *ipiv, integer *jpiv); /* Subroutine */ int clatps_(char *uplo, char *trans, char *diag, char * normin, integer *n, complex *ap, complex *x, real *scale, real *cnorm, integer *info); /* Subroutine */ int clatrd_(char *uplo, integer *n, integer *nb, complex *a, integer *lda, real *e, complex *tau, complex *w, integer *ldw); /* Subroutine */ int clatrs_(char *uplo, char *trans, char *diag, char * normin, integer *n, complex *a, integer *lda, complex *x, real *scale, real *cnorm, integer *info); /* Subroutine */ int clatrz_(integer *m, integer *n, integer *l, complex *a, integer *lda, complex *tau, complex *work); /* Subroutine */ int clatzm_(char *side, integer *m, integer *n, complex *v, integer *incv, complex *tau, complex *c1, complex *c2, integer *ldc, complex *work); /* Subroutine */ int clauu2_(char *uplo, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int clauum_(char *uplo, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int cpbcon_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *anorm, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int cpbequ_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int cpbrfs_(char *uplo, integer *n, integer *kd, integer * nrhs, complex *ab, integer *ldab, complex *afb, integer *ldafb, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real * berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cpbstf_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, integer *info); /* Subroutine */ int cpbsv_(char *uplo, integer *n, integer *kd, integer * nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, integer * info); /* Subroutine */ int cpbsvx_(char *fact, char *uplo, integer *n, integer *kd, integer *nrhs, complex *ab, integer *ldab, complex *afb, integer * ldafb, char *equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cpbtf2_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, integer *info); /* Subroutine */ int cpbtrf_(char *uplo, integer *n, integer *kd, complex *ab, integer *ldab, integer *info); /* Subroutine */ int cpbtrs_(char *uplo, integer *n, integer *kd, integer * nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, integer * info); /* Subroutine */ int cpftrf_(char *transr, char *uplo, integer *n, complex *a, integer *info); /* Subroutine */ int cpftri_(char *transr, char *uplo, integer *n, complex *a, integer *info); /* Subroutine */ int cpftrs_(char *transr, char *uplo, integer *n, integer * nrhs, complex *a, complex *b, integer *ldb, integer *info); /* Subroutine */ int cpocon_(char *uplo, integer *n, complex *a, integer *lda, real *anorm, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int cpoequ_(integer *n, complex *a, integer *lda, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int cpoequb_(integer *n, complex *a, integer *lda, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int cporfs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, complex *af, integer *ldaf, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cporfsx_(char *uplo, char *equed, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real * err_bnds_comp__, integer *nparams, real *params, complex *work, real * rwork, integer *info); /* Subroutine */ int cposv_(char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, complex *b, integer *ldb, integer *info); /* Subroutine */ int cposvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, char * equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cposvxx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, char * equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer *n_err_bnds__, real * err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real * params, complex *work, real *rwork, integer *info); /* Subroutine */ int cpotf2_(char *uplo, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int cpotrf_(char *uplo, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int cpotri_(char *uplo, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int cpotrs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, complex *b, integer *ldb, integer *info); /* Subroutine */ int cppcon_(char *uplo, integer *n, complex *ap, real *anorm, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int cppequ_(char *uplo, integer *n, complex *ap, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int cpprfs_(char *uplo, integer *n, integer *nrhs, complex * ap, complex *afp, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cppsv_(char *uplo, integer *n, integer *nrhs, complex * ap, complex *b, integer *ldb, integer *info); /* Subroutine */ int cppsvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *ap, complex *afp, char *equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cpptrf_(char *uplo, integer *n, complex *ap, integer * info); /* Subroutine */ int cpptri_(char *uplo, integer *n, complex *ap, integer * info); /* Subroutine */ int cpptrs_(char *uplo, integer *n, integer *nrhs, complex * ap, complex *b, integer *ldb, integer *info); /* Subroutine */ int cpstf2_(char *uplo, integer *n, complex *a, integer *lda, integer *piv, integer *rank, real *tol, real *work, integer *info); /* Subroutine */ int cpstrf_(char *uplo, integer *n, complex *a, integer *lda, integer *piv, integer *rank, real *tol, real *work, integer *info); /* Subroutine */ int cptcon_(integer *n, real *d__, complex *e, real *anorm, real *rcond, real *rwork, integer *info); /* Subroutine */ int cpteqr_(char *compz, integer *n, real *d__, real *e, complex *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int cptrfs_(char *uplo, integer *n, integer *nrhs, real *d__, complex *e, real *df, complex *ef, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cptsv_(integer *n, integer *nrhs, real *d__, complex *e, complex *b, integer *ldb, integer *info); /* Subroutine */ int cptsvx_(char *fact, integer *n, integer *nrhs, real *d__, complex *e, real *df, complex *ef, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cpttrf_(integer *n, real *d__, complex *e, integer *info); /* Subroutine */ int cpttrs_(char *uplo, integer *n, integer *nrhs, real *d__, complex *e, complex *b, integer *ldb, integer *info); /* Subroutine */ int cptts2_(integer *iuplo, integer *n, integer *nrhs, real * d__, complex *e, complex *b, integer *ldb); /* Subroutine */ int crot_(integer *n, complex *cx, integer *incx, complex * cy, integer *incy, real *c__, complex *s); /* Subroutine */ int cspcon_(char *uplo, integer *n, complex *ap, integer * ipiv, real *anorm, real *rcond, complex *work, integer *info); /* Subroutine */ int cspmv_(char *uplo, integer *n, complex *alpha, complex * ap, complex *x, integer *incx, complex *beta, complex *y, integer * incy); /* Subroutine */ int cspr_(char *uplo, integer *n, complex *alpha, complex *x, integer *incx, complex *ap); /* Subroutine */ int csprfs_(char *uplo, integer *n, integer *nrhs, complex * ap, complex *afp, integer *ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int cspsv_(char *uplo, integer *n, integer *nrhs, complex * ap, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int cspsvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *ap, complex *afp, integer *ipiv, complex *b, integer * ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int csptrf_(char *uplo, integer *n, complex *ap, integer * ipiv, integer *info); /* Subroutine */ int csptri_(char *uplo, integer *n, complex *ap, integer * ipiv, complex *work, integer *info); /* Subroutine */ int csptrs_(char *uplo, integer *n, integer *nrhs, complex * ap, integer *ipiv, complex *b, integer *ldb, integer *info); /* Subroutine */ int csrscl_(integer *n, real *sa, complex *sx, integer *incx); /* Subroutine */ int cstedc_(char *compz, integer *n, real *d__, real *e, complex *z__, integer *ldz, complex *work, integer *lwork, real * rwork, integer *lrwork, integer *iwork, integer *liwork, integer * info); /* Subroutine */ int cstegr_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, complex *z__, integer *ldz, integer *isuppz, real *work, integer *lwork, integer *iwork, integer *liwork, integer * info); /* Subroutine */ int cstein_(integer *n, real *d__, real *e, integer *m, real *w, integer *iblock, integer *isplit, complex *z__, integer *ldz, real *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int cstemr_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, integer *m, real *w, complex *z__, integer *ldz, integer *nzc, integer *isuppz, logical *tryrac, real *work, integer *lwork, integer *iwork, integer * liwork, integer *info); /* Subroutine */ int csteqr_(char *compz, integer *n, real *d__, real *e, complex *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int csycon_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, real *anorm, real *rcond, complex *work, integer * info); /* Subroutine */ int csyequb_(char *uplo, integer *n, complex *a, integer * lda, real *s, real *scond, real *amax, complex *work, integer *info); /* Subroutine */ int csymv_(char *uplo, integer *n, complex *alpha, complex * a, integer *lda, complex *x, integer *incx, complex *beta, complex *y, integer *incy); /* Subroutine */ int csyr_(char *uplo, integer *n, complex *alpha, complex *x, integer *incx, complex *a, integer *lda); /* Subroutine */ int csyrfs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, complex *af, integer *ldaf, integer *ipiv, complex * b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int csyrfsx_(char *uplo, char *equed, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, complex *work, real *rwork, integer *info); /* Subroutine */ int csysv_(char *uplo, integer *n, integer *nrhs, complex *a, integer *lda, integer *ipiv, complex *b, integer *ldb, complex *work, integer *lwork, integer *info); /* Subroutine */ int csysvx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *ferr, real *berr, complex *work, integer *lwork, real *rwork, integer *info); /* Subroutine */ int csysvxx_(char *fact, char *uplo, integer *n, integer * nrhs, complex *a, integer *lda, complex *af, integer *ldaf, integer * ipiv, char *equed, real *s, complex *b, integer *ldb, complex *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer * n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer * nparams, real *params, complex *work, real *rwork, integer *info); /* Subroutine */ int csytf2_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int csytrf_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, complex *work, integer *lwork, integer *info); /* Subroutine */ int csytri_(char *uplo, integer *n, complex *a, integer *lda, integer *ipiv, complex *work, integer *info); /* Subroutine */ int csytrs_(char *uplo, integer *n, integer *nrhs, complex * a, integer *lda, integer *ipiv, complex *b, integer *ldb, integer * info); /* Subroutine */ int ctbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, complex *ab, integer *ldab, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int ctbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int ctbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, complex *ab, integer *ldab, complex *b, integer *ldb, integer *info); /* Subroutine */ int ctfsm_(char *transr, char *side, char *uplo, char *trans, char *diag, integer *m, integer *n, complex *alpha, complex *a, complex *b, integer *ldb); /* Subroutine */ int ctftri_(char *transr, char *uplo, char *diag, integer *n, complex *a, integer *info); /* Subroutine */ int ctfttp_(char *transr, char *uplo, integer *n, complex * arf, complex *ap, integer *info); /* Subroutine */ int ctfttr_(char *transr, char *uplo, integer *n, complex * arf, complex *a, integer *lda, integer *info); /* Subroutine */ int ctgevc_(char *side, char *howmny, logical *select, integer *n, complex *s, integer *lds, complex *p, integer *ldp, complex *vl, integer *ldvl, complex *vr, integer *ldvr, integer *mm, integer *m, complex *work, real *rwork, integer *info); /* Subroutine */ int ctgex2_(logical *wantq, logical *wantz, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *q, integer *ldq, complex *z__, integer *ldz, integer *j1, integer *info); /* Subroutine */ int ctgexc_(logical *wantq, logical *wantz, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *q, integer *ldq, complex *z__, integer *ldz, integer *ifst, integer * ilst, integer *info); /* Subroutine */ int ctgsen_(integer *ijob, logical *wantq, logical *wantz, logical *select, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *alpha, complex *beta, complex *q, integer *ldq, complex *z__, integer *ldz, integer *m, real *pl, real *pr, real * dif, complex *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ctgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, integer *k, integer *l, complex *a, integer * lda, complex *b, integer *ldb, real *tola, real *tolb, real *alpha, real *beta, complex *u, integer *ldu, complex *v, integer *ldv, complex *q, integer *ldq, complex *work, integer *ncycle, integer * info); /* Subroutine */ int ctgsna_(char *job, char *howmny, logical *select, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *vl, integer *ldvl, complex *vr, integer *ldvr, real *s, real *dif, integer *mm, integer *m, complex *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int ctgsy2_(char *trans, integer *ijob, integer *m, integer * n, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, integer *ldc, complex *d__, integer *ldd, complex *e, integer *lde, complex *f, integer *ldf, real *scale, real *rdsum, real *rdscal, integer *info); /* Subroutine */ int ctgsyl_(char *trans, integer *ijob, integer *m, integer * n, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, integer *ldc, complex *d__, integer *ldd, complex *e, integer *lde, complex *f, integer *ldf, real *scale, real *dif, complex *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int ctpcon_(char *norm, char *uplo, char *diag, integer *n, complex *ap, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int ctprfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, complex *ap, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int ctptri_(char *uplo, char *diag, integer *n, complex *ap, integer *info); /* Subroutine */ int ctptrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, complex *ap, complex *b, integer *ldb, integer *info); /* Subroutine */ int ctpttf_(char *transr, char *uplo, integer *n, complex * ap, complex *arf, integer *info); /* Subroutine */ int ctpttr_(char *uplo, integer *n, complex *ap, complex *a, integer *lda, integer *info); /* Subroutine */ int ctrcon_(char *norm, char *uplo, char *diag, integer *n, complex *a, integer *lda, real *rcond, complex *work, real *rwork, integer *info); /* Subroutine */ int ctrevc_(char *side, char *howmny, logical *select, integer *n, complex *t, integer *ldt, complex *vl, integer *ldvl, complex *vr, integer *ldvr, integer *mm, integer *m, complex *work, real *rwork, integer *info); /* Subroutine */ int ctrexc_(char *compq, integer *n, complex *t, integer * ldt, complex *q, integer *ldq, integer *ifst, integer *ilst, integer * info); /* Subroutine */ int ctrrfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, complex *a, integer *lda, complex *b, integer *ldb, complex *x, integer *ldx, real *ferr, real *berr, complex *work, real *rwork, integer *info); /* Subroutine */ int ctrsen_(char *job, char *compq, logical *select, integer *n, complex *t, integer *ldt, complex *q, integer *ldq, complex *w, integer *m, real *s, real *sep, complex *work, integer *lwork, integer *info); /* Subroutine */ int ctrsna_(char *job, char *howmny, logical *select, integer *n, complex *t, integer *ldt, complex *vl, integer *ldvl, complex *vr, integer *ldvr, real *s, real *sep, integer *mm, integer * m, complex *work, integer *ldwork, real *rwork, integer *info); /* Subroutine */ int ctrsyl_(char *trana, char *tranb, integer *isgn, integer *m, integer *n, complex *a, integer *lda, complex *b, integer *ldb, complex *c__, integer *ldc, real *scale, integer *info); /* Subroutine */ int ctrti2_(char *uplo, char *diag, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int ctrtri_(char *uplo, char *diag, integer *n, complex *a, integer *lda, integer *info); /* Subroutine */ int ctrtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, complex *a, integer *lda, complex *b, integer *ldb, integer *info); /* Subroutine */ int ctrttf_(char *transr, char *uplo, integer *n, complex *a, integer *lda, complex *arf, integer *info); /* Subroutine */ int ctrttp_(char *uplo, integer *n, complex *a, integer *lda, complex *ap, integer *info); /* Subroutine */ int ctzrqf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, integer *info); /* Subroutine */ int ctzrzf_(integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cung2l_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cung2r_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cungbr_(char *vect, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunghr_(integer *n, integer *ilo, integer *ihi, complex * a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cungl2_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cunglq_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer * info); /* Subroutine */ int cungql_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer * info); /* Subroutine */ int cungqr_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer * info); /* Subroutine */ int cungr2_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *info); /* Subroutine */ int cungrq_(integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer * info); /* Subroutine */ int cungtr_(char *uplo, integer *n, complex *a, integer *lda, complex *tau, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunm2l_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int cunm2r_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int cunmbr_(char *vect, char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer * info); /* Subroutine */ int cunmhr_(char *side, char *trans, integer *m, integer *n, integer *ilo, integer *ihi, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer * info); /* Subroutine */ int cunml2_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int cunmlq_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunmql_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunmqr_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunmr2_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int cunmr3_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int cunmrq_(char *side, char *trans, integer *m, integer *n, integer *k, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer *info); /* Subroutine */ int cunmrz_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer * info); /* Subroutine */ int cunmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, complex *a, integer *lda, complex *tau, complex *c__, integer *ldc, complex *work, integer *lwork, integer *info); /* Subroutine */ int cupgtr_(char *uplo, integer *n, complex *ap, complex * tau, complex *q, integer *ldq, complex *work, integer *info); /* Subroutine */ int cupmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, complex *ap, complex *tau, complex *c__, integer *ldc, complex *work, integer *info); /* Subroutine */ int dbdsdc_(char *uplo, char *compq, integer *n, doublereal * d__, doublereal *e, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, doublereal *q, integer *iq, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dbdsqr_(char *uplo, integer *n, integer *ncvt, integer * nru, integer *ncc, doublereal *d__, doublereal *e, doublereal *vt, integer *ldvt, doublereal *u, integer *ldu, doublereal *c__, integer * ldc, doublereal *work, integer *info); /* Subroutine */ int ddisna_(char *job, integer *m, integer *n, doublereal * d__, doublereal *sep, integer *info); /* Subroutine */ int dgbbrd_(char *vect, integer *m, integer *n, integer *ncc, integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal * d__, doublereal *e, doublereal *q, integer *ldq, doublereal *pt, integer *ldpt, doublereal *c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dgbcon_(char *norm, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, integer *ipiv, doublereal *anorm, doublereal *rcond, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgbequ_(integer *m, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * info); /* Subroutine */ int dgbequb_(integer *m, integer *n, integer *kl, integer * ku, doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * info); /* Subroutine */ int dgbrfs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgbrfsx_(char *trans, char *equed, integer *n, integer * kl, integer *ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer * ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer * nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgbsv_(integer *n, integer *kl, integer *ku, integer * nrhs, doublereal *ab, integer *ldab, integer *ipiv, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dgbsvx_(char *fact, char *trans, integer *n, integer *kl, integer *ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgbsvxx_(char *fact, char *trans, integer *n, integer * kl, integer *ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgbtf2_(integer *m, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int dgbtrf_(integer *m, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int dgbtrs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, doublereal *ab, integer *ldab, integer *ipiv, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dgebak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, doublereal *scale, integer *m, doublereal *v, integer * ldv, integer *info); /* Subroutine */ int dgebal_(char *job, integer *n, doublereal *a, integer * lda, integer *ilo, integer *ihi, doublereal *scale, integer *info); /* Subroutine */ int dgebd2_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * taup, doublereal *work, integer *info); /* Subroutine */ int dgebrd_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal * taup, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgecon_(char *norm, integer *n, doublereal *a, integer * lda, doublereal *anorm, doublereal *rcond, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dgeequ_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer *info); /* Subroutine */ int dgeequb_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer *info); /* Subroutine */ int dgees_(char *jobvs, char *sort, L_fp select, integer *n, doublereal *a, integer *lda, integer *sdim, doublereal *wr, doublereal *wi, doublereal *vs, integer *ldvs, doublereal *work, integer *lwork, logical *bwork, integer *info); /* Subroutine */ int dgeesx_(char *jobvs, char *sort, L_fp select, char * sense, integer *n, doublereal *a, integer *lda, integer *sdim, doublereal *wr, doublereal *wi, doublereal *vs, integer *ldvs, doublereal *rconde, doublereal *rcondv, doublereal *work, integer * lwork, integer *iwork, integer *liwork, logical *bwork, integer *info); /* Subroutine */ int dgeev_(char *jobvl, char *jobvr, integer *n, doublereal * a, integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgeevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, doublereal *a, integer *lda, doublereal *wr, doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, integer *ilo, integer *ihi, doublereal *scale, doublereal *abnrm, doublereal *rconde, doublereal *rcondv, doublereal *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dgegs_(char *jobvsl, char *jobvsr, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * alphar, doublereal *alphai, doublereal *beta, doublereal *vsl, integer *ldvsl, doublereal *vsr, integer *ldvsr, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgegv_(char *jobvl, char *jobvr, integer *n, doublereal * a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal *beta, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgehd2_(integer *n, integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgehrd_(integer *n, integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgejsv_(char *joba, char *jobu, char *jobv, char *jobr, char *jobt, char *jobp, integer *m, integer *n, doublereal *a, integer *lda, doublereal *sva, doublereal *u, integer *ldu, doublereal *v, integer *ldv, doublereal *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dgelq2_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgelqf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgels_(char *trans, integer *m, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgelsd_(integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * s, doublereal *rcond, integer *rank, doublereal *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dgelss_(integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * s, doublereal *rcond, integer *rank, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgelsx_(integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * jpvt, doublereal *rcond, integer *rank, doublereal *work, integer * info); /* Subroutine */ int dgelsy_(integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * jpvt, doublereal *rcond, integer *rank, doublereal *work, integer * lwork, integer *info); /* Subroutine */ int dgeql2_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgeqlf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgeqp3_(integer *m, integer *n, doublereal *a, integer * lda, integer *jpvt, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgeqpf_(integer *m, integer *n, doublereal *a, integer * lda, integer *jpvt, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgeqr2_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgeqrf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgerfs_(char *trans, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer * ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgerfsx_(char *trans, char *equed, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgerq2_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgerqf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgesc2_(integer *n, doublereal *a, integer *lda, doublereal *rhs, integer *ipiv, integer *jpiv, doublereal *scale); /* Subroutine */ int dgesdd_(char *jobz, integer *m, integer *n, doublereal * a, integer *lda, doublereal *s, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dgesvd_(char *jobu, char *jobvt, integer *m, integer *n, doublereal *a, integer *lda, doublereal *s, doublereal *u, integer * ldu, doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgesvj_(char *joba, char *jobu, char *jobv, integer *m, integer *n, doublereal *a, integer *lda, doublereal *sva, integer *mv, doublereal *v, integer *ldv, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgesvx_(char *fact, char *trans, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dgesvxx_(char *fact, char *trans, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer * nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dgetc2_(integer *n, doublereal *a, integer *lda, integer *ipiv, integer *jpiv, integer *info); /* Subroutine */ int dgetf2_(integer *m, integer *n, doublereal *a, integer * lda, integer *ipiv, integer *info); /* Subroutine */ int dgetrf_(integer *m, integer *n, doublereal *a, integer * lda, integer *ipiv, integer *info); /* Subroutine */ int dgetri_(integer *n, doublereal *a, integer *lda, integer *ipiv, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgetrs_(char *trans, integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * ldb, integer *info); /* Subroutine */ int dggbak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, integer *m, doublereal *v, integer *ldv, integer *info); /* Subroutine */ int dggbal_(char *job, integer *n, doublereal *a, integer * lda, doublereal *b, integer *ldb, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, doublereal *work, integer * info); /* Subroutine */ int dgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer *sdim, doublereal *alphar, doublereal *alphai, doublereal *beta, doublereal *vsl, integer *ldvsl, doublereal *vsr, integer *ldvsr, doublereal *work, integer *lwork, logical *bwork, integer *info); /* Subroutine */ int dggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, char *sense, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer *sdim, doublereal *alphar, doublereal *alphai, doublereal *beta, doublereal *vsl, integer *ldvsl, doublereal *vsr, integer *ldvsr, doublereal *rconde, doublereal * rcondv, doublereal *work, integer *lwork, integer *iwork, integer * liwork, logical *bwork, integer *info); /* Subroutine */ int dggev_(char *jobvl, char *jobvr, integer *n, doublereal * a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal *beta, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dggevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * beta, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, doublereal *abnrm, doublereal *bbnrm, doublereal *rconde, doublereal * rcondv, doublereal *work, integer *lwork, integer *iwork, logical * bwork, integer *info); /* Subroutine */ int dggglm_(integer *n, integer *m, integer *p, doublereal * a, integer *lda, doublereal *b, integer *ldb, doublereal *d__, doublereal *x, doublereal *y, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgghrd_(char *compq, char *compz, integer *n, integer * ilo, integer *ihi, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *q, integer *ldq, doublereal *z__, integer * ldz, integer *info); /* Subroutine */ int dgglse_(integer *m, integer *n, integer *p, doublereal * a, integer *lda, doublereal *b, integer *ldb, doublereal *c__, doublereal *d__, doublereal *x, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dggqrf_(integer *n, integer *m, integer *p, doublereal * a, integer *lda, doublereal *taua, doublereal *b, integer *ldb, doublereal *taub, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dggrqf_(integer *m, integer *p, integer *n, doublereal * a, integer *lda, doublereal *taua, doublereal *b, integer *ldb, doublereal *taub, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *alpha, doublereal *beta, doublereal *u, integer *ldu, doublereal *v, integer *ldv, doublereal *q, integer *ldq, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *tola, doublereal *tolb, integer *k, integer *l, doublereal *u, integer *ldu, doublereal *v, integer *ldv, doublereal *q, integer *ldq, integer *iwork, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dgsvj0_(char *jobv, integer *m, integer *n, doublereal * a, integer *lda, doublereal *d__, doublereal *sva, integer *mv, doublereal *v, integer *ldv, doublereal *eps, doublereal *sfmin, doublereal *tol, integer *nsweep, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dgsvj1_(char *jobv, integer *m, integer *n, integer *n1, doublereal *a, integer *lda, doublereal *d__, doublereal *sva, integer *mv, doublereal *v, integer *ldv, doublereal *eps, doublereal *sfmin, doublereal *tol, integer *nsweep, doublereal *work, integer * lwork, integer *info); /* Subroutine */ int dgtcon_(char *norm, integer *n, doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, integer *ipiv, doublereal *anorm, doublereal *rcond, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dgtrfs_(char *trans, integer *n, integer *nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal *dlf, doublereal *df, doublereal *duf, doublereal *du2, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * ferr, doublereal *berr, doublereal *work, integer *iwork, integer * info); /* Subroutine */ int dgtsv_(integer *n, integer *nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dgtsvx_(char *fact, char *trans, integer *n, integer * nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal * dlf, doublereal *df, doublereal *duf, doublereal *du2, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dgttrf_(integer *n, doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, integer *ipiv, integer *info); /* Subroutine */ int dgttrs_(char *trans, integer *n, integer *nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, integer *ipiv, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dgtts2_(integer *itrans, integer *n, integer *nrhs, doublereal *dl, doublereal *d__, doublereal *du, doublereal *du2, integer *ipiv, doublereal *b, integer *ldb); /* Subroutine */ int dhgeqz_(char *job, char *compq, char *compz, integer *n, integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal *t, integer *ldt, doublereal *alphar, doublereal *alphai, doublereal * beta, doublereal *q, integer *ldq, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dhsein_(char *side, char *eigsrc, char *initv, logical * select, integer *n, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, doublereal *work, integer * ifaill, integer *ifailr, integer *info); /* Subroutine */ int dhseqr_(char *job, char *compz, integer *n, integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *info); logical disnan_(doublereal *din); /* Subroutine */ int dla_gbamv__(integer *trans, integer *m, integer *n, integer *kl, integer *ku, doublereal *alpha, doublereal *ab, integer * ldab, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal dla_gbrcond__(char *trans, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, integer *cmode, doublereal *c__, integer *info, doublereal *work, integer *iwork, ftnlen trans_len); /* Subroutine */ int dla_gbrfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *kl, integer *ku, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, integer *ipiv, logical *colequ, doublereal *c__, doublereal *b, integer *ldb, doublereal *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal *errs_c__, doublereal *res, doublereal *ayb, doublereal *dy, doublereal * y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical *ignore_cwise__, integer *info); doublereal dla_gbrpvgrw__(integer *n, integer *kl, integer *ku, integer * ncols, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb); /* Subroutine */ int dla_geamv__(integer *trans, integer *m, integer *n, doublereal *alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal dla_gercond__(char *trans, integer *n, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, integer *cmode, doublereal *c__, integer *info, doublereal *work, integer *iwork, ftnlen trans_len); /* Subroutine */ int dla_gerfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, logical *colequ, doublereal *c__, doublereal *b, integer *ldb, doublereal *y, integer * ldy, doublereal *berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal *errs_c__, doublereal *res, doublereal *ayb, doublereal * dy, doublereal *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical *ignore_cwise__, integer *info); /* Subroutine */ int dla_lin_berr__(integer *n, integer *nz, integer *nrhs, doublereal *res, doublereal *ayb, doublereal *berr); doublereal dla_porcond__(char *uplo, integer *n, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *cmode, doublereal *c__, integer *info, doublereal *work, integer *iwork, ftnlen uplo_len); /* Subroutine */ int dla_porfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal * af, integer *ldaf, logical *colequ, doublereal *c__, doublereal *b, integer *ldb, doublereal *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal *errs_c__, doublereal *res, doublereal *ayb, doublereal *dy, doublereal * y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal dla_porpvgrw__(char *uplo, integer *ncols, doublereal *a, integer * lda, doublereal *af, integer *ldaf, doublereal *work, ftnlen uplo_len); doublereal dla_rpvgrw__(integer *n, integer *ncols, doublereal *a, integer * lda, doublereal *af, integer *ldaf); /* Subroutine */ int dla_syamv__(integer *uplo, integer *n, doublereal *alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal dla_syrcond__(char *uplo, integer *n, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, integer *cmode, doublereal *c__, integer *info, doublereal *work, integer *iwork, ftnlen uplo_len); /* Subroutine */ int dla_syrfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal * af, integer *ldaf, integer *ipiv, logical *colequ, doublereal *c__, doublereal *b, integer *ldb, doublereal *y, integer *ldy, doublereal * berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal * errs_c__, doublereal *res, doublereal *ayb, doublereal *dy, doublereal *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal dla_syrpvgrw__(char *uplo, integer *n, integer *info, doublereal * a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, doublereal *work, ftnlen uplo_len); /* Subroutine */ int dla_wwaddw__(integer *n, doublereal *x, doublereal *y, doublereal *w); /* Subroutine */ int dlabad_(doublereal *small, doublereal *large); /* Subroutine */ int dlabrd_(integer *m, integer *n, integer *nb, doublereal * a, integer *lda, doublereal *d__, doublereal *e, doublereal *tauq, doublereal *taup, doublereal *x, integer *ldx, doublereal *y, integer *ldy); /* Subroutine */ int dlacn2_(integer *n, doublereal *v, doublereal *x, integer *isgn, doublereal *est, integer *kase, integer *isave); /* Subroutine */ int dlacon_(integer *n, doublereal *v, doublereal *x, integer *isgn, doublereal *est, integer *kase); /* Subroutine */ int dlacpy_(char *uplo, integer *m, integer *n, doublereal * a, integer *lda, doublereal *b, integer *ldb); /* Subroutine */ int dladiv_(doublereal *a, doublereal *b, doublereal *c__, doublereal *d__, doublereal *p, doublereal *q); /* Subroutine */ int dlae2_(doublereal *a, doublereal *b, doublereal *c__, doublereal *rt1, doublereal *rt2); /* Subroutine */ int dlaebz_(integer *ijob, integer *nitmax, integer *n, integer *mmax, integer *minp, integer *nbmin, doublereal *abstol, doublereal *reltol, doublereal *pivmin, doublereal *d__, doublereal * e, doublereal *e2, integer *nval, doublereal *ab, doublereal *c__, integer *mout, integer *nab, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlaed0_(integer *icompq, integer *qsiz, integer *n, doublereal *d__, doublereal *e, doublereal *q, integer *ldq, doublereal *qstore, integer *ldqs, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlaed1_(integer *n, doublereal *d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, integer *cutpnt, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlaed2_(integer *k, integer *n, integer *n1, doublereal * d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, doublereal *z__, doublereal *dlamda, doublereal *w, doublereal *q2, integer *indx, integer *indxc, integer *indxp, integer *coltyp, integer *info); /* Subroutine */ int dlaed3_(integer *k, integer *n, integer *n1, doublereal * d__, doublereal *q, integer *ldq, doublereal *rho, doublereal *dlamda, doublereal *q2, integer *indx, integer *ctot, doublereal *w, doublereal *s, integer *info); /* Subroutine */ int dlaed4_(integer *n, integer *i__, doublereal *d__, doublereal *z__, doublereal *delta, doublereal *rho, doublereal *dlam, integer *info); /* Subroutine */ int dlaed5_(integer *i__, doublereal *d__, doublereal *z__, doublereal *delta, doublereal *rho, doublereal *dlam); /* Subroutine */ int dlaed6_(integer *kniter, logical *orgati, doublereal * rho, doublereal *d__, doublereal *z__, doublereal *finit, doublereal * tau, integer *info); /* Subroutine */ int dlaed7_(integer *icompq, integer *n, integer *qsiz, integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, integer *cutpnt, doublereal *qstore, integer *qptr, integer *prmptr, integer * perm, integer *givptr, integer *givcol, doublereal *givnum, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlaed8_(integer *icompq, integer *k, integer *n, integer *qsiz, doublereal *d__, doublereal *q, integer *ldq, integer *indxq, doublereal *rho, integer *cutpnt, doublereal *z__, doublereal *dlamda, doublereal *q2, integer *ldq2, doublereal *w, integer *perm, integer *givptr, integer *givcol, doublereal *givnum, integer *indxp, integer *indx, integer *info); /* Subroutine */ int dlaed9_(integer *k, integer *kstart, integer *kstop, integer *n, doublereal *d__, doublereal *q, integer *ldq, doublereal * rho, doublereal *dlamda, doublereal *w, doublereal *s, integer *lds, integer *info); /* Subroutine */ int dlaeda_(integer *n, integer *tlvls, integer *curlvl, integer *curpbm, integer *prmptr, integer *perm, integer *givptr, integer *givcol, doublereal *givnum, doublereal *q, integer *qptr, doublereal *z__, doublereal *ztemp, integer *info); /* Subroutine */ int dlaein_(logical *rightv, logical *noinit, integer *n, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, doublereal *vr, doublereal *vi, doublereal *b, integer *ldb, doublereal *work, doublereal *eps3, doublereal *smlnum, doublereal * bignum, integer *info); /* Subroutine */ int dlaev2_(doublereal *a, doublereal *b, doublereal *c__, doublereal *rt1, doublereal *rt2, doublereal *cs1, doublereal *sn1); /* Subroutine */ int dlaexc_(logical *wantq, integer *n, doublereal *t, integer *ldt, doublereal *q, integer *ldq, integer *j1, integer *n1, integer *n2, doublereal *work, integer *info); /* Subroutine */ int dlag2_(doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *safmin, doublereal *scale1, doublereal * scale2, doublereal *wr1, doublereal *wr2, doublereal *wi); /* Subroutine */ int dlag2s_(integer *m, integer *n, doublereal *a, integer * lda, real *sa, integer *ldsa, integer *info); /* Subroutine */ int dlags2_(logical *upper, doublereal *a1, doublereal *a2, doublereal *a3, doublereal *b1, doublereal *b2, doublereal *b3, doublereal *csu, doublereal *snu, doublereal *csv, doublereal *snv, doublereal *csq, doublereal *snq); /* Subroutine */ int dlagtf_(integer *n, doublereal *a, doublereal *lambda, doublereal *b, doublereal *c__, doublereal *tol, doublereal *d__, integer *in, integer *info); /* Subroutine */ int dlagtm_(char *trans, integer *n, integer *nrhs, doublereal *alpha, doublereal *dl, doublereal *d__, doublereal *du, doublereal *x, integer *ldx, doublereal *beta, doublereal *b, integer *ldb); /* Subroutine */ int dlagts_(integer *job, integer *n, doublereal *a, doublereal *b, doublereal *c__, doublereal *d__, integer *in, doublereal *y, doublereal *tol, integer *info); /* Subroutine */ int dlagv2_(doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * beta, doublereal *csl, doublereal *snl, doublereal *csr, doublereal * snr); /* Subroutine */ int dlahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, integer *info); /* Subroutine */ int dlahr2_(integer *n, integer *k, integer *nb, doublereal * a, integer *lda, doublereal *tau, doublereal *t, integer *ldt, doublereal *y, integer *ldy); /* Subroutine */ int dlahrd_(integer *n, integer *k, integer *nb, doublereal * a, integer *lda, doublereal *tau, doublereal *t, integer *ldt, doublereal *y, integer *ldy); /* Subroutine */ int dlaic1_(integer *job, integer *j, doublereal *x, doublereal *sest, doublereal *w, doublereal *gamma, doublereal * sestpr, doublereal *s, doublereal *c__); logical dlaisnan_(doublereal *din1, doublereal *din2); /* Subroutine */ int dlaln2_(logical *ltrans, integer *na, integer *nw, doublereal *smin, doublereal *ca, doublereal *a, integer *lda, doublereal *d1, doublereal *d2, doublereal *b, integer *ldb, doublereal *wr, doublereal *wi, doublereal *x, integer *ldx, doublereal *scale, doublereal *xnorm, integer *info); /* Subroutine */ int dlals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *nrhs, doublereal *b, integer *ldb, doublereal *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal * poles, doublereal *difl, doublereal *difr, doublereal *z__, integer * k, doublereal *c__, doublereal *s, doublereal *work, integer *info); /* Subroutine */ int dlalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, doublereal *b, integer *ldb, doublereal *bx, integer * ldbx, doublereal *u, integer *ldu, doublereal *vt, integer *k, doublereal *difl, doublereal *difr, doublereal *z__, doublereal * poles, integer *givptr, integer *givcol, integer *ldgcol, integer * perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * work, integer *iwork, integer *info); /* Subroutine */ int dlalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb, doublereal *rcond, integer *rank, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlamrg_(integer *n1, integer *n2, doublereal *a, integer *dtrd1, integer *dtrd2, integer *index); integer dlaneg_(integer *n, doublereal *d__, doublereal *lld, doublereal * sigma, doublereal *pivmin, integer *r__); doublereal dlangb_(char *norm, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal *work); doublereal dlange_(char *norm, integer *m, integer *n, doublereal *a, integer *lda, doublereal *work); doublereal dlangt_(char *norm, integer *n, doublereal *dl, doublereal *d__, doublereal *du); doublereal dlanhs_(char *norm, integer *n, doublereal *a, integer *lda, doublereal *work); doublereal dlansb_(char *norm, char *uplo, integer *n, integer *k, doublereal *ab, integer *ldab, doublereal *work); doublereal dlansf_(char *norm, char *transr, char *uplo, integer *n, doublereal *a, doublereal *work); doublereal dlansp_(char *norm, char *uplo, integer *n, doublereal *ap, doublereal *work); doublereal dlanst_(char *norm, integer *n, doublereal *d__, doublereal *e); doublereal dlansy_(char *norm, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *work); doublereal dlantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, doublereal *ab, integer *ldab, doublereal *work); doublereal dlantp_(char *norm, char *uplo, char *diag, integer *n, doublereal *ap, doublereal *work); doublereal dlantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, doublereal *a, integer *lda, doublereal *work); /* Subroutine */ int dlanv2_(doublereal *a, doublereal *b, doublereal *c__, doublereal *d__, doublereal *rt1r, doublereal *rt1i, doublereal *rt2r, doublereal *rt2i, doublereal *cs, doublereal *sn); /* Subroutine */ int dlapll_(integer *n, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *ssmin); /* Subroutine */ int dlapmt_(logical *forwrd, integer *m, integer *n, doublereal *x, integer *ldx, integer *k); doublereal dlapy2_(doublereal *x, doublereal *y); doublereal dlapy3_(doublereal *x, doublereal *y, doublereal *z__); /* Subroutine */ int dlaqgb_(integer *m, integer *n, integer *kl, integer *ku, doublereal *ab, integer *ldab, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); /* Subroutine */ int dlaqge_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); /* Subroutine */ int dlaqp2_(integer *m, integer *n, integer *offset, doublereal *a, integer *lda, integer *jpvt, doublereal *tau, doublereal *vn1, doublereal *vn2, doublereal *work); /* Subroutine */ int dlaqps_(integer *m, integer *n, integer *offset, integer *nb, integer *kb, doublereal *a, integer *lda, integer *jpvt, doublereal *tau, doublereal *vn1, doublereal *vn2, doublereal *auxv, doublereal *f, integer *ldf); /* Subroutine */ int dlaqr0_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dlaqr1_(integer *n, doublereal *h__, integer *ldh, doublereal *sr1, doublereal *si1, doublereal *sr2, doublereal *si2, doublereal *v); /* Subroutine */ int dlaqr2_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer * ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal * v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer * nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork); /* Subroutine */ int dlaqr3_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, doublereal *h__, integer * ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, integer *ns, integer *nd, doublereal *sr, doublereal *si, doublereal * v, integer *ldv, integer *nh, doublereal *t, integer *ldt, integer * nv, doublereal *wv, integer *ldwv, doublereal *work, integer *lwork); /* Subroutine */ int dlaqr4_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublereal *h__, integer *ldh, doublereal *wr, doublereal *wi, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dlaqr5_(logical *wantt, logical *wantz, integer *kacc22, integer *n, integer *ktop, integer *kbot, integer *nshfts, doublereal *sr, doublereal *si, doublereal *h__, integer *ldh, integer *iloz, integer *ihiz, doublereal *z__, integer *ldz, doublereal *v, integer * ldv, doublereal *u, integer *ldu, integer *nv, doublereal *wv, integer *ldwv, integer *nh, doublereal *wh, integer *ldwh); /* Subroutine */ int dlaqsb_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int dlaqsp_(char *uplo, integer *n, doublereal *ap, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int dlaqsy_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int dlaqtr_(logical *ltran, logical *lreal, integer *n, doublereal *t, integer *ldt, doublereal *b, doublereal *w, doublereal *scale, doublereal *x, doublereal *work, integer *info); /* Subroutine */ int dlar1v_(integer *n, integer *b1, integer *bn, doublereal *lambda, doublereal *d__, doublereal *l, doublereal *ld, doublereal * lld, doublereal *pivmin, doublereal *gaptol, doublereal *z__, logical *wantnc, integer *negcnt, doublereal *ztz, doublereal *mingma, integer *r__, integer *isuppz, doublereal *nrminv, doublereal *resid, doublereal *rqcorr, doublereal *work); /* Subroutine */ int dlar2v_(integer *n, doublereal *x, doublereal *y, doublereal *z__, integer *incx, doublereal *c__, doublereal *s, integer *incc); /* Subroutine */ int dlarf_(char *side, integer *m, integer *n, doublereal *v, integer *incv, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work); /* Subroutine */ int dlarfb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, doublereal *v, integer * ldv, doublereal *t, integer *ldt, doublereal *c__, integer *ldc, doublereal *work, integer *ldwork); /* Subroutine */ int dlarfg_(integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *tau); /* Subroutine */ int dlarfp_(integer *n, doublereal *alpha, doublereal *x, integer *incx, doublereal *tau); /* Subroutine */ int dlarft_(char *direct, char *storev, integer *n, integer * k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, integer *ldt); /* Subroutine */ int dlarfx_(char *side, integer *m, integer *n, doublereal * v, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work); /* Subroutine */ int dlargv_(integer *n, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *c__, integer *incc); /* Subroutine */ int dlarnv_(integer *idist, integer *iseed, integer *n, doublereal *x); /* Subroutine */ int dlarra_(integer *n, doublereal *d__, doublereal *e, doublereal *e2, doublereal *spltol, doublereal *tnrm, integer *nsplit, integer *isplit, integer *info); /* Subroutine */ int dlarrb_(integer *n, doublereal *d__, doublereal *lld, integer *ifirst, integer *ilast, doublereal *rtol1, doublereal *rtol2, integer *offset, doublereal *w, doublereal *wgap, doublereal *werr, doublereal *work, integer *iwork, doublereal *pivmin, doublereal * spdiam, integer *twist, integer *info); /* Subroutine */ int dlarrc_(char *jobt, integer *n, doublereal *vl, doublereal *vu, doublereal *d__, doublereal *e, doublereal *pivmin, integer *eigcnt, integer *lcnt, integer *rcnt, integer *info); /* Subroutine */ int dlarrd_(char *range, char *order, integer *n, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *gers, doublereal *reltol, doublereal *d__, doublereal *e, doublereal *e2, doublereal *pivmin, integer *nsplit, integer *isplit, integer *m, doublereal *w, doublereal *werr, doublereal *wl, doublereal *wu, integer *iblock, integer *indexw, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlarre_(char *range, integer *n, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *d__, doublereal *e, doublereal *e2, doublereal *rtol1, doublereal *rtol2, doublereal * spltol, integer *nsplit, integer *isplit, integer *m, doublereal *w, doublereal *werr, doublereal *wgap, integer *iblock, integer *indexw, doublereal *gers, doublereal *pivmin, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dlarrf_(integer *n, doublereal *d__, doublereal *l, doublereal *ld, integer *clstrt, integer *clend, doublereal *w, doublereal *wgap, doublereal *werr, doublereal *spdiam, doublereal * clgapl, doublereal *clgapr, doublereal *pivmin, doublereal *sigma, doublereal *dplus, doublereal *lplus, doublereal *work, integer *info); /* Subroutine */ int dlarrj_(integer *n, doublereal *d__, doublereal *e2, integer *ifirst, integer *ilast, doublereal *rtol, integer *offset, doublereal *w, doublereal *werr, doublereal *work, integer *iwork, doublereal *pivmin, doublereal *spdiam, integer *info); /* Subroutine */ int dlarrk_(integer *n, integer *iw, doublereal *gl, doublereal *gu, doublereal *d__, doublereal *e2, doublereal *pivmin, doublereal *reltol, doublereal *w, doublereal *werr, integer *info); /* Subroutine */ int dlarrr_(integer *n, doublereal *d__, doublereal *e, integer *info); /* Subroutine */ int dlarrv_(integer *n, doublereal *vl, doublereal *vu, doublereal *d__, doublereal *l, doublereal *pivmin, integer *isplit, integer *m, integer *dol, integer *dou, doublereal *minrgp, doublereal *rtol1, doublereal *rtol2, doublereal *w, doublereal *werr, doublereal *wgap, integer *iblock, integer *indexw, doublereal *gers, doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlarscl2_(integer *m, integer *n, doublereal *d__, doublereal *x, integer *ldx); /* Subroutine */ int dlartg_(doublereal *f, doublereal *g, doublereal *cs, doublereal *sn, doublereal *r__); /* Subroutine */ int dlartv_(integer *n, doublereal *x, integer *incx, doublereal *y, integer *incy, doublereal *c__, doublereal *s, integer *incc); /* Subroutine */ int dlaruv_(integer *iseed, integer *n, doublereal *x); /* Subroutine */ int dlarz_(char *side, integer *m, integer *n, integer *l, doublereal *v, integer *incv, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work); /* Subroutine */ int dlarzb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, integer *l, doublereal *v, integer *ldv, doublereal *t, integer *ldt, doublereal *c__, integer * ldc, doublereal *work, integer *ldwork); /* Subroutine */ int dlarzt_(char *direct, char *storev, integer *n, integer * k, doublereal *v, integer *ldv, doublereal *tau, doublereal *t, integer *ldt); /* Subroutine */ int dlas2_(doublereal *f, doublereal *g, doublereal *h__, doublereal *ssmin, doublereal *ssmax); /* Subroutine */ int dlascl_(char *type__, integer *kl, integer *ku, doublereal *cfrom, doublereal *cto, integer *m, integer *n, doublereal *a, integer *lda, integer *info); /* Subroutine */ int dlascl2_(integer *m, integer *n, doublereal *d__, doublereal *x, integer *ldx); /* Subroutine */ int dlasd0_(integer *n, integer *sqre, doublereal *d__, doublereal *e, doublereal *u, integer *ldu, doublereal *vt, integer * ldvt, integer *smlsiz, integer *iwork, doublereal *work, integer * info); /* Subroutine */ int dlasd1_(integer *nl, integer *nr, integer *sqre, doublereal *d__, doublereal *alpha, doublereal *beta, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, integer *idxq, integer * iwork, doublereal *work, integer *info); /* Subroutine */ int dlasd2_(integer *nl, integer *nr, integer *sqre, integer *k, doublereal *d__, doublereal *z__, doublereal *alpha, doublereal * beta, doublereal *u, integer *ldu, doublereal *vt, integer *ldvt, doublereal *dsigma, doublereal *u2, integer *ldu2, doublereal *vt2, integer *ldvt2, integer *idxp, integer *idx, integer *idxc, integer * idxq, integer *coltyp, integer *info); /* Subroutine */ int dlasd3_(integer *nl, integer *nr, integer *sqre, integer *k, doublereal *d__, doublereal *q, integer *ldq, doublereal *dsigma, doublereal *u, integer *ldu, doublereal *u2, integer *ldu2, doublereal *vt, integer *ldvt, doublereal *vt2, integer *ldvt2, integer *idxc, integer *ctot, doublereal *z__, integer *info); /* Subroutine */ int dlasd4_(integer *n, integer *i__, doublereal *d__, doublereal *z__, doublereal *delta, doublereal *rho, doublereal * sigma, doublereal *work, integer *info); /* Subroutine */ int dlasd5_(integer *i__, doublereal *d__, doublereal *z__, doublereal *delta, doublereal *rho, doublereal *dsigma, doublereal * work); /* Subroutine */ int dlasd6_(integer *icompq, integer *nl, integer *nr, integer *sqre, doublereal *d__, doublereal *vf, doublereal *vl, doublereal *alpha, doublereal *beta, integer *idxq, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal *poles, doublereal *difl, doublereal * difr, doublereal *z__, integer *k, doublereal *c__, doublereal *s, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlasd7_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *k, doublereal *d__, doublereal *z__, doublereal *zw, doublereal *vf, doublereal *vfw, doublereal *vl, doublereal *vlw, doublereal *alpha, doublereal *beta, doublereal * dsigma, integer *idx, integer *idxp, integer *idxq, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal *c__, doublereal *s, integer *info); /* Subroutine */ int dlasd8_(integer *icompq, integer *k, doublereal *d__, doublereal *z__, doublereal *vf, doublereal *vl, doublereal *difl, doublereal *difr, integer *lddifr, doublereal *dsigma, doublereal * work, integer *info); /* Subroutine */ int dlasda_(integer *icompq, integer *smlsiz, integer *n, integer *sqre, doublereal *d__, doublereal *e, doublereal *u, integer *ldu, doublereal *vt, integer *k, doublereal *difl, doublereal *difr, doublereal *z__, doublereal *poles, integer *givptr, integer *givcol, integer *ldgcol, integer *perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dlasdq_(char *uplo, integer *sqre, integer *n, integer * ncvt, integer *nru, integer *ncc, doublereal *d__, doublereal *e, doublereal *vt, integer *ldvt, doublereal *u, integer *ldu, doublereal *c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dlasdt_(integer *n, integer *lvl, integer *nd, integer * inode, integer *ndiml, integer *ndimr, integer *msub); /* Subroutine */ int dlaset_(char *uplo, integer *m, integer *n, doublereal * alpha, doublereal *beta, doublereal *a, integer *lda); /* Subroutine */ int dlasq1_(integer *n, doublereal *d__, doublereal *e, doublereal *work, integer *info); /* Subroutine */ int dlasq2_(integer *n, doublereal *z__, integer *info); /* Subroutine */ int dlasq3_(integer *i0, integer *n0, doublereal *z__, integer *pp, doublereal *dmin__, doublereal *sigma, doublereal *desig, doublereal *qmax, integer *nfail, integer *iter, integer *ndiv, logical *ieee, integer *ttype, doublereal *dmin1, doublereal *dmin2, doublereal *dn, doublereal *dn1, doublereal *dn2, doublereal *g, doublereal *tau); /* Subroutine */ int dlasq4_(integer *i0, integer *n0, doublereal *z__, integer *pp, integer *n0in, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, doublereal *dn, doublereal *dn1, doublereal *dn2, doublereal *tau, integer *ttype, doublereal *g); /* Subroutine */ int dlasq5_(integer *i0, integer *n0, doublereal *z__, integer *pp, doublereal *tau, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, doublereal *dn, doublereal *dnm1, doublereal *dnm2, logical *ieee); /* Subroutine */ int dlasq6_(integer *i0, integer *n0, doublereal *z__, integer *pp, doublereal *dmin__, doublereal *dmin1, doublereal *dmin2, doublereal *dn, doublereal *dnm1, doublereal *dnm2); /* Subroutine */ int dlasr_(char *side, char *pivot, char *direct, integer *m, integer *n, doublereal *c__, doublereal *s, doublereal *a, integer * lda); /* Subroutine */ int dlasrt_(char *id, integer *n, doublereal *d__, integer * info); /* Subroutine */ int dlassq_(integer *n, doublereal *x, integer *incx, doublereal *scale, doublereal *sumsq); /* Subroutine */ int dlasv2_(doublereal *f, doublereal *g, doublereal *h__, doublereal *ssmin, doublereal *ssmax, doublereal *snr, doublereal * csr, doublereal *snl, doublereal *csl); /* Subroutine */ int dlaswp_(integer *n, doublereal *a, integer *lda, integer *k1, integer *k2, integer *ipiv, integer *incx); /* Subroutine */ int dlasy2_(logical *ltranl, logical *ltranr, integer *isgn, integer *n1, integer *n2, doublereal *tl, integer *ldtl, doublereal * tr, integer *ldtr, doublereal *b, integer *ldb, doublereal *scale, doublereal *x, integer *ldx, doublereal *xnorm, integer *info); /* Subroutine */ int dlasyf_(char *uplo, integer *n, integer *nb, integer *kb, doublereal *a, integer *lda, integer *ipiv, doublereal *w, integer * ldw, integer *info); /* Subroutine */ int dlat2s_(char *uplo, integer *n, doublereal *a, integer * lda, real *sa, integer *ldsa, integer *info); /* Subroutine */ int dlatbs_(char *uplo, char *trans, char *diag, char * normin, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *x, doublereal *scale, doublereal *cnorm, integer *info); /* Subroutine */ int dlatdf_(integer *ijob, integer *n, doublereal *z__, integer *ldz, doublereal *rhs, doublereal *rdsum, doublereal *rdscal, integer *ipiv, integer *jpiv); /* Subroutine */ int dlatps_(char *uplo, char *trans, char *diag, char * normin, integer *n, doublereal *ap, doublereal *x, doublereal *scale, doublereal *cnorm, integer *info); /* Subroutine */ int dlatrd_(char *uplo, integer *n, integer *nb, doublereal * a, integer *lda, doublereal *e, doublereal *tau, doublereal *w, integer *ldw); /* Subroutine */ int dlatrs_(char *uplo, char *trans, char *diag, char * normin, integer *n, doublereal *a, integer *lda, doublereal *x, doublereal *scale, doublereal *cnorm, integer *info); /* Subroutine */ int dlatrz_(integer *m, integer *n, integer *l, doublereal * a, integer *lda, doublereal *tau, doublereal *work); /* Subroutine */ int dlatzm_(char *side, integer *m, integer *n, doublereal * v, integer *incv, doublereal *tau, doublereal *c1, doublereal *c2, integer *ldc, doublereal *work); /* Subroutine */ int dlauu2_(char *uplo, integer *n, doublereal *a, integer * lda, integer *info); /* Subroutine */ int dlauum_(char *uplo, integer *n, doublereal *a, integer * lda, integer *info); /* Subroutine */ int dopgtr_(char *uplo, integer *n, doublereal *ap, doublereal *tau, doublereal *q, integer *ldq, doublereal *work, integer *info); /* Subroutine */ int dopmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, doublereal *ap, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dorg2l_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dorg2r_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dorgbr_(char *vect, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorghr_(integer *n, integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorgl2_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dorglq_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorgql_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorgqr_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorgr2_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *info); /* Subroutine */ int dorgrq_(integer *m, integer *n, integer *k, doublereal * a, integer *lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorgtr_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorm2l_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dorm2r_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dormbr_(char *vect, char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormhr_(char *side, char *trans, integer *m, integer *n, integer *ilo, integer *ihi, doublereal *a, integer *lda, doublereal * tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dorml2_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dormlq_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormql_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormr2_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dormr3_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, doublereal *a, integer *lda, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work, integer *info); /* Subroutine */ int dormrq_(char *side, char *trans, integer *m, integer *n, integer *k, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormrz_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, doublereal *a, integer *lda, doublereal *tau, doublereal *c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dormtr_(char *side, char *uplo, char *trans, integer *m, integer *n, doublereal *a, integer *lda, doublereal *tau, doublereal * c__, integer *ldc, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dpbcon_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, doublereal *anorm, doublereal *rcond, doublereal * work, integer *iwork, integer *info); /* Subroutine */ int dpbequ_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int dpbrfs_(char *uplo, integer *n, integer *kd, integer * nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * ferr, doublereal *berr, doublereal *work, integer *iwork, integer * info); /* Subroutine */ int dpbstf_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, integer *info); /* Subroutine */ int dpbsv_(char *uplo, integer *n, integer *kd, integer * nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dpbsvx_(char *fact, char *uplo, integer *n, integer *kd, integer *nrhs, doublereal *ab, integer *ldab, doublereal *afb, integer *ldafb, char *equed, doublereal *s, doublereal *b, integer * ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dpbtf2_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, integer *info); /* Subroutine */ int dpbtrf_(char *uplo, integer *n, integer *kd, doublereal * ab, integer *ldab, integer *info); /* Subroutine */ int dpbtrs_(char *uplo, integer *n, integer *kd, integer * nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dpftrf_(char *transr, char *uplo, integer *n, doublereal *a, integer *info); /* Subroutine */ int dpftri_(char *transr, char *uplo, integer *n, doublereal *a, integer *info); /* Subroutine */ int dpftrs_(char *transr, char *uplo, integer *n, integer * nrhs, doublereal *a, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dpocon_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *anorm, doublereal *rcond, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dpoequ_(integer *n, doublereal *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int dpoequb_(integer *n, doublereal *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int dporfs_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * ferr, doublereal *berr, doublereal *work, integer *iwork, integer * info); /* Subroutine */ int dporfsx_(char *uplo, char *equed, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, doublereal *s, doublereal *b, integer *ldb, doublereal *x, integer * ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer * nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dposv_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dposvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, char *equed, doublereal *s, doublereal *b, integer *ldb, doublereal * x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal * berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dposvxx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, char *equed, doublereal *s, doublereal *b, integer *ldb, doublereal * x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal * berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublereal * work, integer *iwork, integer *info); /* Subroutine */ int dpotf2_(char *uplo, integer *n, doublereal *a, integer * lda, integer *info); /* Subroutine */ int dpotrf_(char *uplo, integer *n, doublereal *a, integer * lda, integer *info); /* Subroutine */ int dpotri_(char *uplo, integer *n, doublereal *a, integer * lda, integer *info); /* Subroutine */ int dpotrs_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * info); /* Subroutine */ int dppcon_(char *uplo, integer *n, doublereal *ap, doublereal *anorm, doublereal *rcond, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dppequ_(char *uplo, integer *n, doublereal *ap, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int dpprfs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, doublereal *afp, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dppsv_(char *uplo, integer *n, integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dppsvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *ap, doublereal *afp, char *equed, doublereal *s, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * iwork, integer *info); /* Subroutine */ int dpptrf_(char *uplo, integer *n, doublereal *ap, integer * info); /* Subroutine */ int dpptri_(char *uplo, integer *n, doublereal *ap, integer * info); /* Subroutine */ int dpptrs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dpstf2_(char *uplo, integer *n, doublereal *a, integer * lda, integer *piv, integer *rank, doublereal *tol, doublereal *work, integer *info); /* Subroutine */ int dpstrf_(char *uplo, integer *n, doublereal *a, integer * lda, integer *piv, integer *rank, doublereal *tol, doublereal *work, integer *info); /* Subroutine */ int dptcon_(integer *n, doublereal *d__, doublereal *e, doublereal *anorm, doublereal *rcond, doublereal *work, integer *info); /* Subroutine */ int dpteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dptrfs_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *df, doublereal *ef, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *info); /* Subroutine */ int dptsv_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dptsvx_(char *fact, integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *df, doublereal *ef, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal * rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer * info); /* Subroutine */ int dpttrf_(integer *n, doublereal *d__, doublereal *e, integer *info); /* Subroutine */ int dpttrs_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dptts2_(integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublereal *b, integer *ldb); /* Subroutine */ int drscl_(integer *n, doublereal *sa, doublereal *sx, integer *incx); /* Subroutine */ int dsbev_(char *jobz, char *uplo, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dsbevd_(char *jobz, char *uplo, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *q, integer * ldq, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * ldbb, doublereal *x, integer *ldx, doublereal *work, integer *info); /* Subroutine */ int dsbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * ldbb, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dsbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, doublereal *ab, integer *ldab, doublereal *bb, integer * ldbb, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, integer *kb, doublereal *ab, integer *ldab, doublereal * bb, integer *ldbb, doublereal *q, integer *ldq, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsbtrd_(char *vect, char *uplo, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *d__, doublereal *e, doublereal *q, integer *ldq, doublereal *work, integer *info); /* Subroutine */ int dsfrk_(char *transr, char *uplo, char *trans, integer *n, integer *k, doublereal *alpha, doublereal *a, integer *lda, doublereal *beta, doublereal *c__); /* Subroutine */ int dsgesv_(integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, doublereal * x, integer *ldx, doublereal *work, real *swork, integer *iter, integer *info); /* Subroutine */ int dspcon_(char *uplo, integer *n, doublereal *ap, integer * ipiv, doublereal *anorm, doublereal *rcond, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dspev_(char *jobz, char *uplo, integer *n, doublereal * ap, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dspevd_(char *jobz, char *uplo, integer *n, doublereal * ap, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dspevx_(char *jobz, char *range, char *uplo, integer *n, doublereal *ap, doublereal *vl, doublereal *vu, integer *il, integer * iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dspgst_(integer *itype, char *uplo, integer *n, doublereal *ap, doublereal *bp, integer *info); /* Subroutine */ int dspgv_(integer *itype, char *jobz, char *uplo, integer * n, doublereal *ap, doublereal *bp, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dspgvd_(integer *itype, char *jobz, char *uplo, integer * n, doublereal *ap, doublereal *bp, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dspgvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, doublereal *ap, doublereal *bp, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsposv_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * x, integer *ldx, doublereal *work, real *swork, integer *iter, integer *info); /* Subroutine */ int dsprfs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, doublereal *afp, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dspsv_(char *uplo, integer *n, integer *nrhs, doublereal *ap, integer *ipiv, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dspsvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *ap, doublereal *afp, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dsptrd_(char *uplo, integer *n, doublereal *ap, doublereal *d__, doublereal *e, doublereal *tau, integer *info); /* Subroutine */ int dsptrf_(char *uplo, integer *n, doublereal *ap, integer * ipiv, integer *info); /* Subroutine */ int dsptri_(char *uplo, integer *n, doublereal *ap, integer * ipiv, doublereal *work, integer *info); /* Subroutine */ int dsptrs_(char *uplo, integer *n, integer *nrhs, doublereal *ap, integer *ipiv, doublereal *b, integer *ldb, integer * info); /* Subroutine */ int dstebz_(char *range, char *order, integer *n, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, doublereal *d__, doublereal *e, integer *m, integer *nsplit, doublereal *w, integer *iblock, integer *isplit, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dstedc_(char *compz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dstegr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dstein_(integer *n, doublereal *d__, doublereal *e, integer *m, doublereal *w, integer *iblock, integer *isplit, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dstemr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, integer *m, doublereal *w, doublereal *z__, integer *ldz, integer *nzc, integer *isuppz, logical *tryrac, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dsterf_(integer *n, doublereal *d__, doublereal *e, integer *info); /* Subroutine */ int dstev_(char *jobz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int dstevd_(char *jobz, integer *n, doublereal *d__, doublereal *e, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dstevr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dstevx_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsycon_(char *uplo, integer *n, doublereal *a, integer * lda, integer *ipiv, doublereal *anorm, doublereal *rcond, doublereal * work, integer *iwork, integer *info); /* Subroutine */ int dsyequb_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *s, doublereal *scond, doublereal *amax, doublereal * work, integer *info); /* Subroutine */ int dsyev_(char *jobz, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *w, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dsyevd_(char *jobz, char *uplo, integer *n, doublereal * a, integer *lda, doublereal *w, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsyevr_(char *jobz, char *range, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer * il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, integer *isuppz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsyevx_(char *jobz, char *range, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer * il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsygs2_(integer *itype, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * info); /* Subroutine */ int dsygst_(integer *itype, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, integer * info); /* Subroutine */ int dsygv_(integer *itype, char *jobz, char *uplo, integer * n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *w, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dsygvd_(integer *itype, char *jobz, char *uplo, integer * n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *w, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dsygvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *lwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int dsyrfs_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer * ipiv, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dsyrfsx_(char *uplo, char *equed, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, doublereal *s, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal *berr, integer * n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublereal * work, integer *iwork, integer *info); /* Subroutine */ int dsysv_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dsysvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, doublereal *b, integer *ldb, doublereal *x, integer * ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublereal *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dsysvxx_(char *fact, char *uplo, integer *n, integer * nrhs, doublereal *a, integer *lda, doublereal *af, integer *ldaf, integer *ipiv, char *equed, doublereal *s, doublereal *b, integer * ldb, doublereal *x, integer *ldx, doublereal *rcond, doublereal * rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal * err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dsytd2_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *d__, doublereal *e, doublereal *tau, integer *info); /* Subroutine */ int dsytf2_(char *uplo, integer *n, doublereal *a, integer * lda, integer *ipiv, integer *info); /* Subroutine */ int dsytrd_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *d__, doublereal *e, doublereal *tau, doublereal * work, integer *lwork, integer *info); /* Subroutine */ int dsytrf_(char *uplo, integer *n, doublereal *a, integer * lda, integer *ipiv, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dsytri_(char *uplo, integer *n, doublereal *a, integer * lda, integer *ipiv, doublereal *work, integer *info); /* Subroutine */ int dsytrs_(char *uplo, integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer * ldb, integer *info); /* Subroutine */ int dtbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, doublereal *ab, integer *ldab, doublereal *rcond, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, doublereal *ab, integer *ldab, doublereal *b, integer *ldb, integer *info); /* Subroutine */ int dtfsm_(char *transr, char *side, char *uplo, char *trans, char *diag, integer *m, integer *n, doublereal *alpha, doublereal *a, doublereal *b, integer *ldb); /* Subroutine */ int dtftri_(char *transr, char *uplo, char *diag, integer *n, doublereal *a, integer *info); /* Subroutine */ int dtfttp_(char *transr, char *uplo, integer *n, doublereal *arf, doublereal *ap, integer *info); /* Subroutine */ int dtfttr_(char *transr, char *uplo, integer *n, doublereal *arf, doublereal *a, integer *lda, integer *info); /* Subroutine */ int dtgevc_(char *side, char *howmny, logical *select, integer *n, doublereal *s, integer *lds, doublereal *p, integer *ldp, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, doublereal *work, integer *info); /* Subroutine */ int dtgex2_(logical *wantq, logical *wantz, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * q, integer *ldq, doublereal *z__, integer *ldz, integer *j1, integer * n1, integer *n2, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dtgexc_(logical *wantq, logical *wantz, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal * q, integer *ldq, doublereal *z__, integer *ldz, integer *ifst, integer *ilst, doublereal *work, integer *lwork, integer *info); /* Subroutine */ int dtgsen_(integer *ijob, logical *wantq, logical *wantz, logical *select, integer *n, doublereal *a, integer *lda, doublereal * b, integer *ldb, doublereal *alphar, doublereal *alphai, doublereal * beta, doublereal *q, integer *ldq, doublereal *z__, integer *ldz, integer *m, doublereal *pl, doublereal *pr, doublereal *dif, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int dtgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, integer *k, integer *l, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *tola, doublereal *tolb, doublereal *alpha, doublereal *beta, doublereal *u, integer *ldu, doublereal *v, integer *ldv, doublereal *q, integer * ldq, doublereal *work, integer *ncycle, integer *info); /* Subroutine */ int dtgsna_(char *job, char *howmny, logical *select, integer *n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr, doublereal *s, doublereal *dif, integer *mm, integer *m, doublereal * work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int dtgsy2_(char *trans, integer *ijob, integer *m, integer * n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, doublereal *e, integer *lde, doublereal *f, integer *ldf, doublereal * scale, doublereal *rdsum, doublereal *rdscal, integer *iwork, integer *pq, integer *info); /* Subroutine */ int dtgsyl_(char *trans, integer *ijob, integer *m, integer * n, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *c__, integer *ldc, doublereal *d__, integer *ldd, doublereal *e, integer *lde, doublereal *f, integer *ldf, doublereal * scale, doublereal *dif, doublereal *work, integer *lwork, integer * iwork, integer *info); /* Subroutine */ int dtpcon_(char *norm, char *uplo, char *diag, integer *n, doublereal *ap, doublereal *rcond, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtprfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtptri_(char *uplo, char *diag, integer *n, doublereal * ap, integer *info); /* Subroutine */ int dtptrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublereal *ap, doublereal *b, integer *ldb, integer * info); /* Subroutine */ int dtpttf_(char *transr, char *uplo, integer *n, doublereal *ap, doublereal *arf, integer *info); /* Subroutine */ int dtpttr_(char *uplo, integer *n, doublereal *ap, doublereal *a, integer *lda, integer *info); /* Subroutine */ int dtrcon_(char *norm, char *uplo, char *diag, integer *n, doublereal *a, integer *lda, doublereal *rcond, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtrevc_(char *side, char *howmny, logical *select, integer *n, doublereal *t, integer *ldt, doublereal *vl, integer * ldvl, doublereal *vr, integer *ldvr, integer *mm, integer *m, doublereal *work, integer *info); /* Subroutine */ int dtrexc_(char *compq, integer *n, doublereal *t, integer * ldt, doublereal *q, integer *ldq, integer *ifst, integer *ilst, doublereal *work, integer *info); /* Subroutine */ int dtrrfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer * ldb, doublereal *x, integer *ldx, doublereal *ferr, doublereal *berr, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int dtrsen_(char *job, char *compq, logical *select, integer *n, doublereal *t, integer *ldt, doublereal *q, integer *ldq, doublereal *wr, doublereal *wi, integer *m, doublereal *s, doublereal *sep, doublereal *work, integer *lwork, integer *iwork, integer * liwork, integer *info); /* Subroutine */ int dtrsna_(char *job, char *howmny, logical *select, integer *n, doublereal *t, integer *ldt, doublereal *vl, integer * ldvl, doublereal *vr, integer *ldvr, doublereal *s, doublereal *sep, integer *mm, integer *m, doublereal *work, integer *ldwork, integer * iwork, integer *info); /* Subroutine */ int dtrsyl_(char *trana, char *tranb, integer *isgn, integer *m, integer *n, doublereal *a, integer *lda, doublereal *b, integer * ldb, doublereal *c__, integer *ldc, doublereal *scale, integer *info); /* Subroutine */ int dtrti2_(char *uplo, char *diag, integer *n, doublereal * a, integer *lda, integer *info); /* Subroutine */ int dtrtri_(char *uplo, char *diag, integer *n, doublereal * a, integer *lda, integer *info); /* Subroutine */ int dtrtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer * ldb, integer *info); /* Subroutine */ int dtrttf_(char *transr, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *arf, integer *info); /* Subroutine */ int dtrttp_(char *uplo, integer *n, doublereal *a, integer * lda, doublereal *ap, integer *info); /* Subroutine */ int dtzrqf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, integer *info); /* Subroutine */ int dtzrzf_(integer *m, integer *n, doublereal *a, integer * lda, doublereal *tau, doublereal *work, integer *lwork, integer *info); doublereal dzsum1_(integer *n, doublecomplex *cx, integer *incx); integer icmax1_(integer *n, complex *cx, integer *incx); integer ieeeck_(integer *ispec, real *zero, real *one); integer ilaclc_(integer *m, integer *n, complex *a, integer *lda); integer ilaclr_(integer *m, integer *n, complex *a, integer *lda); integer iladiag_(char *diag); integer iladlc_(integer *m, integer *n, doublereal *a, integer *lda); integer iladlr_(integer *m, integer *n, doublereal *a, integer *lda); integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, integer *n2, integer *n3, integer *n4); integer ilaprec_(char *prec); integer ilaslc_(integer *m, integer *n, real *a, integer *lda); integer ilaslr_(integer *m, integer *n, real *a, integer *lda); integer ilatrans_(char *trans); integer ilauplo_(char *uplo); /* Subroutine */ int ilaver_(integer *vers_major__, integer *vers_minor__, integer *vers_patch__); integer ilazlc_(integer *m, integer *n, doublecomplex *a, integer *lda); integer ilazlr_(integer *m, integer *n, doublecomplex *a, integer *lda); integer iparmq_(integer *ispec, char *name__, char *opts, integer *n, integer *ilo, integer *ihi, integer *lwork); integer izmax1_(integer *n, doublecomplex *cx, integer *incx); logical lsamen_(integer *n, char *ca, char *cb); integer smaxloc_(real *a, integer *dimm); /* Subroutine */ int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, real *e, real *u, integer *ldu, real *vt, integer *ldvt, real *q, integer *iq, real *work, integer *iwork, integer *info); /* Subroutine */ int sbdsqr_(char *uplo, integer *n, integer *ncvt, integer * nru, integer *ncc, real *d__, real *e, real *vt, integer *ldvt, real * u, integer *ldu, real *c__, integer *ldc, real *work, integer *info); doublereal scsum1_(integer *n, complex *cx, integer *incx); /* Subroutine */ int sdisna_(char *job, integer *m, integer *n, real *d__, real *sep, integer *info); /* Subroutine */ int sgbbrd_(char *vect, integer *m, integer *n, integer *ncc, integer *kl, integer *ku, real *ab, integer *ldab, real *d__, real * e, real *q, integer *ldq, real *pt, integer *ldpt, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sgbcon_(char *norm, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, integer *ipiv, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int sgbequ_(integer *m, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real * colcnd, real *amax, integer *info); /* Subroutine */ int sgbequb_(integer *m, integer *n, integer *kl, integer * ku, real *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int sgbrfs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real * ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sgbrfsx_(char *trans, char *equed, integer *n, integer * kl, integer *ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *berr, integer * n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer * nparams, real *params, real *work, integer *iwork, integer *info); /* Subroutine */ int sgbsv_(integer *n, integer *kl, integer *ku, integer * nrhs, real *ab, integer *ldab, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sgbsvx_(char *fact, char *trans, integer *n, integer *kl, integer *ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sgbsvxx_(char *fact, char *trans, integer *n, integer * kl, integer *ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, char *equed, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real * rpvgrw, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, real *work, integer *iwork, integer *info); /* Subroutine */ int sgbtf2_(integer *m, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int sgbtrf_(integer *m, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int sgbtrs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, real *ab, integer *ldab, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sgebak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, real *scale, integer *m, real *v, integer *ldv, integer *info); /* Subroutine */ int sgebal_(char *job, integer *n, real *a, integer *lda, integer *ilo, integer *ihi, real *scale, integer *info); /* Subroutine */ int sgebd2_(integer *m, integer *n, real *a, integer *lda, real *d__, real *e, real *tauq, real *taup, real *work, integer *info); /* Subroutine */ int sgebrd_(integer *m, integer *n, real *a, integer *lda, real *d__, real *e, real *tauq, real *taup, real *work, integer * lwork, integer *info); /* Subroutine */ int sgecon_(char *norm, integer *n, real *a, integer *lda, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int sgeequ_(integer *m, integer *n, real *a, integer *lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int sgeequb_(integer *m, integer *n, real *a, integer *lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, integer *info); /* Subroutine */ int sgees_(char *jobvs, char *sort, L_fp select, integer *n, real *a, integer *lda, integer *sdim, real *wr, real *wi, real *vs, integer *ldvs, real *work, integer *lwork, logical *bwork, integer * info); /* Subroutine */ int sgeesx_(char *jobvs, char *sort, L_fp select, char * sense, integer *n, real *a, integer *lda, integer *sdim, real *wr, real *wi, real *vs, integer *ldvs, real *rconde, real *rcondv, real * work, integer *lwork, integer *iwork, integer *liwork, logical *bwork, integer *info); /* Subroutine */ int sgeev_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, real *wr, real *wi, real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, integer *lwork, integer *info); /* Subroutine */ int sgeevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, real *a, integer *lda, real *wr, real *wi, real * vl, integer *ldvl, real *vr, integer *ldvr, integer *ilo, integer * ihi, real *scale, real *abnrm, real *rconde, real *rcondv, real *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int sgegs_(char *jobvsl, char *jobvsr, integer *n, real *a, integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real *beta, real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, real * work, integer *lwork, integer *info); /* Subroutine */ int sgegv_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real *beta, real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, integer *lwork, integer *info); /* Subroutine */ int sgehd2_(integer *n, integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sgehrd_(integer *n, integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgejsv_(char *joba, char *jobu, char *jobv, char *jobr, char *jobt, char *jobp, integer *m, integer *n, real *a, integer *lda, real *sva, real *u, integer *ldu, real *v, integer *ldv, real *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int sgelq2_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sgelqf_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgels_(char *trans, integer *m, integer *n, integer * nrhs, real *a, integer *lda, real *b, integer *ldb, real *work, integer *lwork, integer *info); /* Subroutine */ int sgelsd_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, real *s, real *rcond, integer * rank, real *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int sgelss_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, real *s, real *rcond, integer * rank, real *work, integer *lwork, integer *info); /* Subroutine */ int sgelsx_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer *jpvt, real *rcond, integer *rank, real *work, integer *info); /* Subroutine */ int sgelsy_(integer *m, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer *jpvt, real *rcond, integer *rank, real *work, integer *lwork, integer *info); /* Subroutine */ int sgeql2_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sgeqlf_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgeqp3_(integer *m, integer *n, real *a, integer *lda, integer *jpvt, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgeqpf_(integer *m, integer *n, real *a, integer *lda, integer *jpvt, real *tau, real *work, integer *info); /* Subroutine */ int sgeqr2_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sgeqrf_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgerfs_(char *trans, integer *n, integer *nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * work, integer *iwork, integer *info); /* Subroutine */ int sgerfsx_(char *trans, char *equed, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, real *work, integer *iwork, integer *info); /* Subroutine */ int sgerq2_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sgerqf_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sgesc2_(integer *n, real *a, integer *lda, real *rhs, integer *ipiv, integer *jpiv, real *scale); /* Subroutine */ int sgesdd_(char *jobz, integer *m, integer *n, real *a, integer *lda, real *s, real *u, integer *ldu, real *vt, integer *ldvt, real *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int sgesv_(integer *n, integer *nrhs, real *a, integer *lda, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sgesvd_(char *jobu, char *jobvt, integer *m, integer *n, real *a, integer *lda, real *s, real *u, integer *ldu, real *vt, integer *ldvt, real *work, integer *lwork, integer *info); /* Subroutine */ int sgesvj_(char *joba, char *jobu, char *jobv, integer *m, integer *n, real *a, integer *lda, real *sva, integer *mv, real *v, integer *ldv, real *work, integer *lwork, integer *info); /* Subroutine */ int sgesvx_(char *fact, char *trans, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, char *equed, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sgesvxx_(char *fact, char *trans, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, char *equed, real *r__, real *c__, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer * n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer * nparams, real *params, real *work, integer *iwork, integer *info); /* Subroutine */ int sgetc2_(integer *n, real *a, integer *lda, integer *ipiv, integer *jpiv, integer *info); /* Subroutine */ int sgetf2_(integer *m, integer *n, real *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int sgetrf_(integer *m, integer *n, real *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int sgetri_(integer *n, real *a, integer *lda, integer *ipiv, real *work, integer *lwork, integer *info); /* Subroutine */ int sgetrs_(char *trans, integer *n, integer *nrhs, real *a, integer *lda, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sggbak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, real *lscale, real *rscale, integer *m, real *v, integer *ldv, integer *info); /* Subroutine */ int sggbal_(char *job, integer *n, real *a, integer *lda, real *b, integer *ldb, integer *ilo, integer *ihi, real *lscale, real *rscale, real *work, integer *info); /* Subroutine */ int sgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, integer *n, real *a, integer *lda, real *b, integer *ldb, integer *sdim, real *alphar, real *alphai, real *beta, real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, real *work, integer *lwork, logical *bwork, integer *info); /* Subroutine */ int sggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, char *sense, integer *n, real *a, integer *lda, real *b, integer *ldb, integer *sdim, real *alphar, real *alphai, real *beta, real *vsl, integer *ldvsl, real *vsr, integer *ldvsr, real *rconde, real *rcondv, real *work, integer *lwork, integer *iwork, integer * liwork, logical *bwork, integer *info); /* Subroutine */ int sggev_(char *jobvl, char *jobvr, integer *n, real *a, integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real *beta, real *vl, integer *ldvl, real *vr, integer *ldvr, real *work, integer *lwork, integer *info); /* Subroutine */ int sggevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, real *a, integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real *beta, real *vl, integer *ldvl, real *vr, integer *ldvr, integer *ilo, integer *ihi, real *lscale, real *rscale, real *abnrm, real *bbnrm, real *rconde, real *rcondv, real *work, integer *lwork, integer *iwork, logical *bwork, integer *info); /* Subroutine */ int sggglm_(integer *n, integer *m, integer *p, real *a, integer *lda, real *b, integer *ldb, real *d__, real *x, real *y, real *work, integer *lwork, integer *info); /* Subroutine */ int sgghrd_(char *compq, char *compz, integer *n, integer * ilo, integer *ihi, real *a, integer *lda, real *b, integer *ldb, real *q, integer *ldq, real *z__, integer *ldz, integer *info); /* Subroutine */ int sgglse_(integer *m, integer *n, integer *p, real *a, integer *lda, real *b, integer *ldb, real *c__, real *d__, real *x, real *work, integer *lwork, integer *info); /* Subroutine */ int sggqrf_(integer *n, integer *m, integer *p, real *a, integer *lda, real *taua, real *b, integer *ldb, real *taub, real * work, integer *lwork, integer *info); /* Subroutine */ int sggrqf_(integer *m, integer *p, integer *n, real *a, integer *lda, real *taua, real *b, integer *ldb, real *taub, real * work, integer *lwork, integer *info); /* Subroutine */ int sggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, real *a, integer *lda, real *b, integer *ldb, real *alpha, real *beta, real *u, integer * ldu, real *v, integer *ldv, real *q, integer *ldq, real *work, integer *iwork, integer *info); /* Subroutine */ int sggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, real *a, integer *lda, real *b, integer *ldb, real *tola, real *tolb, integer *k, integer *l, real *u, integer *ldu, real *v, integer *ldv, real *q, integer *ldq, integer *iwork, real * tau, real *work, integer *info); /* Subroutine */ int sgsvj0_(char *jobv, integer *m, integer *n, real *a, integer *lda, real *d__, real *sva, integer *mv, real *v, integer * ldv, real *eps, real *sfmin, real *tol, integer *nsweep, real *work, integer *lwork, integer *info); /* Subroutine */ int sgsvj1_(char *jobv, integer *m, integer *n, integer *n1, real *a, integer *lda, real *d__, real *sva, integer *mv, real *v, integer *ldv, real *eps, real *sfmin, real *tol, integer *nsweep, real *work, integer *lwork, integer *info); /* Subroutine */ int sgtcon_(char *norm, integer *n, real *dl, real *d__, real *du, real *du2, integer *ipiv, real *anorm, real *rcond, real * work, integer *iwork, integer *info); /* Subroutine */ int sgtrfs_(char *trans, integer *n, integer *nrhs, real *dl, real *d__, real *du, real *dlf, real *df, real *duf, real *du2, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real * ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sgtsv_(integer *n, integer *nrhs, real *dl, real *d__, real *du, real *b, integer *ldb, integer *info); /* Subroutine */ int sgtsvx_(char *fact, char *trans, integer *n, integer * nrhs, real *dl, real *d__, real *du, real *dlf, real *df, real *duf, real *du2, integer *ipiv, real *b, integer *ldb, real *x, integer * ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sgttrf_(integer *n, real *dl, real *d__, real *du, real * du2, integer *ipiv, integer *info); /* Subroutine */ int sgttrs_(char *trans, integer *n, integer *nrhs, real *dl, real *d__, real *du, real *du2, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sgtts2_(integer *itrans, integer *n, integer *nrhs, real *dl, real *d__, real *du, real *du2, integer *ipiv, real *b, integer * ldb); /* Subroutine */ int shgeqz_(char *job, char *compq, char *compz, integer *n, integer *ilo, integer *ihi, real *h__, integer *ldh, real *t, integer *ldt, real *alphar, real *alphai, real *beta, real *q, integer *ldq, real *z__, integer *ldz, real *work, integer *lwork, integer *info); /* Subroutine */ int shsein_(char *side, char *eigsrc, char *initv, logical * select, integer *n, real *h__, integer *ldh, real *wr, real *wi, real *vl, integer *ldvl, real *vr, integer *ldvr, integer *mm, integer *m, real *work, integer *ifaill, integer *ifailr, integer *info); /* Subroutine */ int shseqr_(char *job, char *compz, integer *n, integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real *wi, real *z__, integer *ldz, real *work, integer *lwork, integer *info); logical sisnan_(real *sin__); /* Subroutine */ int sla_gbamv__(integer *trans, integer *m, integer *n, integer *kl, integer *ku, real *alpha, real *ab, integer *ldab, real * x, integer *incx, real *beta, real *y, integer *incy); doublereal sla_gbrcond__(char *trans, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, integer *cmode, real *c__, integer *info, real *work, integer *iwork, ftnlen trans_len); /* Subroutine */ int sla_gbrfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *kl, integer *ku, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, integer *ipiv, logical *colequ, real *c__, real *b, integer *ldb, real *y, integer * ldy, real *berr_out__, integer *n_norms__, real *errs_n__, real * errs_c__, real *res, real *ayb, real *dy, real *y_tail__, real *rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical * ignore_cwise__, integer *info); doublereal sla_gbrpvgrw__(integer *n, integer *kl, integer *ku, integer * ncols, real *ab, integer *ldab, real *afb, integer *ldafb); /* Subroutine */ int sla_geamv__(integer *trans, integer *m, integer *n, real *alpha, real *a, integer *lda, real *x, integer *incx, real *beta, real *y, integer *incy); doublereal sla_gercond__(char *trans, integer *n, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, integer *cmode, real *c__, integer *info, real *work, integer *iwork, ftnlen trans_len); /* Subroutine */ int sla_gerfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *nrhs, real *a, integer *lda, real * af, integer *ldaf, integer *ipiv, logical *colequ, real *c__, real *b, integer *ldb, real *y, integer *ldy, real *berr_out__, integer * n_norms__, real *errs_n__, real *errs_c__, real *res, real *ayb, real *dy, real *y_tail__, real *rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info); /* Subroutine */ int sla_lin_berr__(integer *n, integer *nz, integer *nrhs, real *res, real *ayb, real *berr); doublereal sla_porcond__(char *uplo, integer *n, real *a, integer *lda, real * af, integer *ldaf, integer *cmode, real *c__, integer *info, real * work, integer *iwork, ftnlen uplo_len); /* Subroutine */ int sla_porfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *af, integer * ldaf, logical *colequ, real *c__, real *b, integer *ldb, real *y, integer *ldy, real *berr_out__, integer *n_norms__, real *errs_n__, real *errs_c__, real *res, real *ayb, real *dy, real *y_tail__, real * rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical * ignore_cwise__, integer *info, ftnlen uplo_len); doublereal sla_porpvgrw__(char *uplo, integer *ncols, real *a, integer *lda, real *af, integer *ldaf, real *work, ftnlen uplo_len); doublereal sla_rpvgrw__(integer *n, integer *ncols, real *a, integer *lda, real *af, integer *ldaf); /* Subroutine */ int sla_syamv__(integer *uplo, integer *n, real *alpha, real *a, integer *lda, real *x, integer *incx, real *beta, real *y, integer *incy); doublereal sla_syrcond__(char *uplo, integer *n, real *a, integer *lda, real * af, integer *ldaf, integer *ipiv, integer *cmode, real *c__, integer * info, real *work, integer *iwork, ftnlen uplo_len); /* Subroutine */ int sla_syrfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *af, integer * ldaf, integer *ipiv, logical *colequ, real *c__, real *b, integer * ldb, real *y, integer *ldy, real *berr_out__, integer *n_norms__, real *errs_n__, real *errs_c__, real *res, real *ayb, real *dy, real * y_tail__, real *rcond, integer *ithresh, real *rthresh, real *dz_ub__, logical *ignore_cwise__, integer *info, ftnlen uplo_len); doublereal sla_syrpvgrw__(char *uplo, integer *n, integer *info, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *work, ftnlen uplo_len); /* Subroutine */ int sla_wwaddw__(integer *n, real *x, real *y, real *w); /* Subroutine */ int slabad_(real *small, real *large); /* Subroutine */ int slabrd_(integer *m, integer *n, integer *nb, real *a, integer *lda, real *d__, real *e, real *tauq, real *taup, real *x, integer *ldx, real *y, integer *ldy); /* Subroutine */ int slacn2_(integer *n, real *v, real *x, integer *isgn, real *est, integer *kase, integer *isave); /* Subroutine */ int slacon_(integer *n, real *v, real *x, integer *isgn, real *est, integer *kase); /* Subroutine */ int slacpy_(char *uplo, integer *m, integer *n, real *a, integer *lda, real *b, integer *ldb); /* Subroutine */ int sladiv_(real *a, real *b, real *c__, real *d__, real *p, real *q); /* Subroutine */ int slae2_(real *a, real *b, real *c__, real *rt1, real *rt2); /* Subroutine */ int slaebz_(integer *ijob, integer *nitmax, integer *n, integer *mmax, integer *minp, integer *nbmin, real *abstol, real * reltol, real *pivmin, real *d__, real *e, real *e2, integer *nval, real *ab, real *c__, integer *mout, integer *nab, real *work, integer *iwork, integer *info); /* Subroutine */ int slaed0_(integer *icompq, integer *qsiz, integer *n, real *d__, real *e, real *q, integer *ldq, real *qstore, integer *ldqs, real *work, integer *iwork, integer *info); /* Subroutine */ int slaed1_(integer *n, real *d__, real *q, integer *ldq, integer *indxq, real *rho, integer *cutpnt, real *work, integer * iwork, integer *info); /* Subroutine */ int slaed2_(integer *k, integer *n, integer *n1, real *d__, real *q, integer *ldq, integer *indxq, real *rho, real *z__, real * dlamda, real *w, real *q2, integer *indx, integer *indxc, integer * indxp, integer *coltyp, integer *info); /* Subroutine */ int slaed3_(integer *k, integer *n, integer *n1, real *d__, real *q, integer *ldq, real *rho, real *dlamda, real *q2, integer * indx, integer *ctot, real *w, real *s, integer *info); /* Subroutine */ int slaed4_(integer *n, integer *i__, real *d__, real *z__, real *delta, real *rho, real *dlam, integer *info); /* Subroutine */ int slaed5_(integer *i__, real *d__, real *z__, real *delta, real *rho, real *dlam); /* Subroutine */ int slaed6_(integer *kniter, logical *orgati, real *rho, real *d__, real *z__, real *finit, real *tau, integer *info); /* Subroutine */ int slaed7_(integer *icompq, integer *n, integer *qsiz, integer *tlvls, integer *curlvl, integer *curpbm, real *d__, real *q, integer *ldq, integer *indxq, real *rho, integer *cutpnt, real * qstore, integer *qptr, integer *prmptr, integer *perm, integer * givptr, integer *givcol, real *givnum, real *work, integer *iwork, integer *info); /* Subroutine */ int slaed8_(integer *icompq, integer *k, integer *n, integer *qsiz, real *d__, real *q, integer *ldq, integer *indxq, real *rho, integer *cutpnt, real *z__, real *dlamda, real *q2, integer *ldq2, real *w, integer *perm, integer *givptr, integer *givcol, real * givnum, integer *indxp, integer *indx, integer *info); /* Subroutine */ int slaed9_(integer *k, integer *kstart, integer *kstop, integer *n, real *d__, real *q, integer *ldq, real *rho, real *dlamda, real *w, real *s, integer *lds, integer *info); /* Subroutine */ int slaeda_(integer *n, integer *tlvls, integer *curlvl, integer *curpbm, integer *prmptr, integer *perm, integer *givptr, integer *givcol, real *givnum, real *q, integer *qptr, real *z__, real *ztemp, integer *info); /* Subroutine */ int slaein_(logical *rightv, logical *noinit, integer *n, real *h__, integer *ldh, real *wr, real *wi, real *vr, real *vi, real *b, integer *ldb, real *work, real *eps3, real *smlnum, real *bignum, integer *info); /* Subroutine */ int slaev2_(real *a, real *b, real *c__, real *rt1, real * rt2, real *cs1, real *sn1); /* Subroutine */ int slaexc_(logical *wantq, integer *n, real *t, integer * ldt, real *q, integer *ldq, integer *j1, integer *n1, integer *n2, real *work, integer *info); /* Subroutine */ int slag2_(real *a, integer *lda, real *b, integer *ldb, real *safmin, real *scale1, real *scale2, real *wr1, real *wr2, real * wi); /* Subroutine */ int slag2d_(integer *m, integer *n, real *sa, integer *ldsa, doublereal *a, integer *lda, integer *info); /* Subroutine */ int slags2_(logical *upper, real *a1, real *a2, real *a3, real *b1, real *b2, real *b3, real *csu, real *snu, real *csv, real * snv, real *csq, real *snq); /* Subroutine */ int slagtf_(integer *n, real *a, real *lambda, real *b, real *c__, real *tol, real *d__, integer *in, integer *info); /* Subroutine */ int slagtm_(char *trans, integer *n, integer *nrhs, real * alpha, real *dl, real *d__, real *du, real *x, integer *ldx, real * beta, real *b, integer *ldb); /* Subroutine */ int slagts_(integer *job, integer *n, real *a, real *b, real *c__, real *d__, integer *in, real *y, real *tol, integer *info); /* Subroutine */ int slagv2_(real *a, integer *lda, real *b, integer *ldb, real *alphar, real *alphai, real *beta, real *csl, real *snl, real * csr, real *snr); /* Subroutine */ int slahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, integer * info); /* Subroutine */ int slahr2_(integer *n, integer *k, integer *nb, real *a, integer *lda, real *tau, real *t, integer *ldt, real *y, integer *ldy); /* Subroutine */ int slahrd_(integer *n, integer *k, integer *nb, real *a, integer *lda, real *tau, real *t, integer *ldt, real *y, integer *ldy); /* Subroutine */ int slaic1_(integer *job, integer *j, real *x, real *sest, real *w, real *gamma, real *sestpr, real *s, real *c__); logical slaisnan_(real *sin1, real *sin2); /* Subroutine */ int slaln2_(logical *ltrans, integer *na, integer *nw, real * smin, real *ca, real *a, integer *lda, real *d1, real *d2, real *b, integer *ldb, real *wr, real *wi, real *x, integer *ldx, real *scale, real *xnorm, integer *info); /* Subroutine */ int slals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *nrhs, real *b, integer *ldb, real *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * difl, real *difr, real *z__, integer *k, real *c__, real *s, real * work, integer *info); /* Subroutine */ int slalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, real *b, integer *ldb, real *bx, integer *ldbx, real * u, integer *ldu, real *vt, integer *k, real *difl, real *difr, real * z__, real *poles, integer *givptr, integer *givcol, integer *ldgcol, integer *perm, real *givnum, real *c__, real *s, real *work, integer * iwork, integer *info); /* Subroutine */ int slalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, real *d__, real *e, real *b, integer *ldb, real *rcond, integer *rank, real *work, integer *iwork, integer *info); /* Subroutine */ int slamrg_(integer *n1, integer *n2, real *a, integer * strd1, integer *strd2, integer *index); integer slaneg_(integer *n, real *d__, real *lld, real *sigma, real *pivmin, integer *r__); doublereal slangb_(char *norm, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, real *work); doublereal slange_(char *norm, integer *m, integer *n, real *a, integer *lda, real *work); doublereal slangt_(char *norm, integer *n, real *dl, real *d__, real *du); doublereal slanhs_(char *norm, integer *n, real *a, integer *lda, real *work); doublereal slansb_(char *norm, char *uplo, integer *n, integer *k, real *ab, integer *ldab, real *work); doublereal slansf_(char *norm, char *transr, char *uplo, integer *n, real *a, real *work); doublereal slansp_(char *norm, char *uplo, integer *n, real *ap, real *work); doublereal slanst_(char *norm, integer *n, real *d__, real *e); doublereal slansy_(char *norm, char *uplo, integer *n, real *a, integer *lda, real *work); doublereal slantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, real *ab, integer *ldab, real *work); doublereal slantp_(char *norm, char *uplo, char *diag, integer *n, real *ap, real *work); doublereal slantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, real *a, integer *lda, real *work); /* Subroutine */ int slanv2_(real *a, real *b, real *c__, real *d__, real * rt1r, real *rt1i, real *rt2r, real *rt2i, real *cs, real *sn); /* Subroutine */ int slapll_(integer *n, real *x, integer *incx, real *y, integer *incy, real *ssmin); /* Subroutine */ int slapmt_(logical *forwrd, integer *m, integer *n, real *x, integer *ldx, integer *k); doublereal slapy2_(real *x, real *y); doublereal slapy3_(real *x, real *y, real *z__); /* Subroutine */ int slaqgb_(integer *m, integer *n, integer *kl, integer *ku, real *ab, integer *ldab, real *r__, real *c__, real *rowcnd, real * colcnd, real *amax, char *equed); /* Subroutine */ int slaqge_(integer *m, integer *n, real *a, integer *lda, real *r__, real *c__, real *rowcnd, real *colcnd, real *amax, char * equed); /* Subroutine */ int slaqp2_(integer *m, integer *n, integer *offset, real *a, integer *lda, integer *jpvt, real *tau, real *vn1, real *vn2, real * work); /* Subroutine */ int slaqps_(integer *m, integer *n, integer *offset, integer *nb, integer *kb, real *a, integer *lda, integer *jpvt, real *tau, real *vn1, real *vn2, real *auxv, real *f, integer *ldf); /* Subroutine */ int slaqr0_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, real *work, integer *lwork, integer *info); /* Subroutine */ int slaqr1_(integer *n, real *h__, integer *ldh, real *sr1, real *si1, real *sr2, real *si2, real *v); /* Subroutine */ int slaqr2_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, real *h__, integer *ldh, integer *iloz, integer *ihiz, real *z__, integer *ldz, integer *ns, integer *nd, real *sr, real *si, real *v, integer *ldv, integer *nh, real *t, integer *ldt, integer *nv, real *wv, integer *ldwv, real * work, integer *lwork); /* Subroutine */ int slaqr3_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, real *h__, integer *ldh, integer *iloz, integer *ihiz, real *z__, integer *ldz, integer *ns, integer *nd, real *sr, real *si, real *v, integer *ldv, integer *nh, real *t, integer *ldt, integer *nv, real *wv, integer *ldwv, real * work, integer *lwork); /* Subroutine */ int slaqr4_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, real *h__, integer *ldh, real *wr, real * wi, integer *iloz, integer *ihiz, real *z__, integer *ldz, real *work, integer *lwork, integer *info); /* Subroutine */ int slaqr5_(logical *wantt, logical *wantz, integer *kacc22, integer *n, integer *ktop, integer *kbot, integer *nshfts, real *sr, real *si, real *h__, integer *ldh, integer *iloz, integer *ihiz, real *z__, integer *ldz, real *v, integer *ldv, real *u, integer *ldu, integer *nv, real *wv, integer *ldwv, integer *nh, real *wh, integer * ldwh); /* Subroutine */ int slaqsb_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int slaqsp_(char *uplo, integer *n, real *ap, real *s, real * scond, real *amax, char *equed); /* Subroutine */ int slaqsy_(char *uplo, integer *n, real *a, integer *lda, real *s, real *scond, real *amax, char *equed); /* Subroutine */ int slaqtr_(logical *ltran, logical *lreal, integer *n, real *t, integer *ldt, real *b, real *w, real *scale, real *x, real *work, integer *info); /* Subroutine */ int slar1v_(integer *n, integer *b1, integer *bn, real * lambda, real *d__, real *l, real *ld, real *lld, real *pivmin, real * gaptol, real *z__, logical *wantnc, integer *negcnt, real *ztz, real * mingma, integer *r__, integer *isuppz, real *nrminv, real *resid, real *rqcorr, real *work); /* Subroutine */ int slar2v_(integer *n, real *x, real *y, real *z__, integer *incx, real *c__, real *s, integer *incc); /* Subroutine */ int slarf_(char *side, integer *m, integer *n, real *v, integer *incv, real *tau, real *c__, integer *ldc, real *work); /* Subroutine */ int slarfb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, real *v, integer *ldv, real *t, integer *ldt, real *c__, integer *ldc, real *work, integer * ldwork); /* Subroutine */ int slarfg_(integer *n, real *alpha, real *x, integer *incx, real *tau); /* Subroutine */ int slarfp_(integer *n, real *alpha, real *x, integer *incx, real *tau); /* Subroutine */ int slarft_(char *direct, char *storev, integer *n, integer * k, real *v, integer *ldv, real *tau, real *t, integer *ldt); /* Subroutine */ int slarfx_(char *side, integer *m, integer *n, real *v, real *tau, real *c__, integer *ldc, real *work); /* Subroutine */ int slargv_(integer *n, real *x, integer *incx, real *y, integer *incy, real *c__, integer *incc); /* Subroutine */ int slarnv_(integer *idist, integer *iseed, integer *n, real *x); /* Subroutine */ int slarra_(integer *n, real *d__, real *e, real *e2, real * spltol, real *tnrm, integer *nsplit, integer *isplit, integer *info); /* Subroutine */ int slarrb_(integer *n, real *d__, real *lld, integer * ifirst, integer *ilast, real *rtol1, real *rtol2, integer *offset, real *w, real *wgap, real *werr, real *work, integer *iwork, real * pivmin, real *spdiam, integer *twist, integer *info); /* Subroutine */ int slarrc_(char *jobt, integer *n, real *vl, real *vu, real *d__, real *e, real *pivmin, integer *eigcnt, integer *lcnt, integer * rcnt, integer *info); /* Subroutine */ int slarrd_(char *range, char *order, integer *n, real *vl, real *vu, integer *il, integer *iu, real *gers, real *reltol, real * d__, real *e, real *e2, real *pivmin, integer *nsplit, integer * isplit, integer *m, real *w, real *werr, real *wl, real *wu, integer * iblock, integer *indexw, real *work, integer *iwork, integer *info); /* Subroutine */ int slarre_(char *range, integer *n, real *vl, real *vu, integer *il, integer *iu, real *d__, real *e, real *e2, real *rtol1, real *rtol2, real *spltol, integer *nsplit, integer *isplit, integer * m, real *w, real *werr, real *wgap, integer *iblock, integer *indexw, real *gers, real *pivmin, real *work, integer *iwork, integer *info); /* Subroutine */ int slarrf_(integer *n, real *d__, real *l, real *ld, integer *clstrt, integer *clend, real *w, real *wgap, real *werr, real *spdiam, real *clgapl, real *clgapr, real *pivmin, real *sigma, real *dplus, real *lplus, real *work, integer *info); /* Subroutine */ int slarrj_(integer *n, real *d__, real *e2, integer *ifirst, integer *ilast, real *rtol, integer *offset, real *w, real *werr, real *work, integer *iwork, real *pivmin, real *spdiam, integer *info); /* Subroutine */ int slarrk_(integer *n, integer *iw, real *gl, real *gu, real *d__, real *e2, real *pivmin, real *reltol, real *w, real *werr, integer *info); /* Subroutine */ int slarrr_(integer *n, real *d__, real *e, integer *info); /* Subroutine */ int slarrv_(integer *n, real *vl, real *vu, real *d__, real * l, real *pivmin, integer *isplit, integer *m, integer *dol, integer * dou, real *minrgp, real *rtol1, real *rtol2, real *w, real *werr, real *wgap, integer *iblock, integer *indexw, real *gers, real *z__, integer *ldz, integer *isuppz, real *work, integer *iwork, integer * info); /* Subroutine */ int slarscl2_(integer *m, integer *n, real *d__, real *x, integer *ldx); /* Subroutine */ int slartg_(real *f, real *g, real *cs, real *sn, real *r__); /* Subroutine */ int slartv_(integer *n, real *x, integer *incx, real *y, integer *incy, real *c__, real *s, integer *incc); /* Subroutine */ int slaruv_(integer *iseed, integer *n, real *x); /* Subroutine */ int slarz_(char *side, integer *m, integer *n, integer *l, real *v, integer *incv, real *tau, real *c__, integer *ldc, real * work); /* Subroutine */ int slarzb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, integer *l, real *v, integer *ldv, real *t, integer *ldt, real *c__, integer *ldc, real * work, integer *ldwork); /* Subroutine */ int slarzt_(char *direct, char *storev, integer *n, integer * k, real *v, integer *ldv, real *tau, real *t, integer *ldt); /* Subroutine */ int slas2_(real *f, real *g, real *h__, real *ssmin, real * ssmax); /* Subroutine */ int slascl_(char *type__, integer *kl, integer *ku, real * cfrom, real *cto, integer *m, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int slascl2_(integer *m, integer *n, real *d__, real *x, integer *ldx); /* Subroutine */ int slasd0_(integer *n, integer *sqre, real *d__, real *e, real *u, integer *ldu, real *vt, integer *ldvt, integer *smlsiz, integer *iwork, real *work, integer *info); /* Subroutine */ int slasd1_(integer *nl, integer *nr, integer *sqre, real * d__, real *alpha, real *beta, real *u, integer *ldu, real *vt, integer *ldvt, integer *idxq, integer *iwork, real *work, integer * info); /* Subroutine */ int slasd2_(integer *nl, integer *nr, integer *sqre, integer *k, real *d__, real *z__, real *alpha, real *beta, real *u, integer * ldu, real *vt, integer *ldvt, real *dsigma, real *u2, integer *ldu2, real *vt2, integer *ldvt2, integer *idxp, integer *idx, integer *idxc, integer *idxq, integer *coltyp, integer *info); /* Subroutine */ int slasd3_(integer *nl, integer *nr, integer *sqre, integer *k, real *d__, real *q, integer *ldq, real *dsigma, real *u, integer * ldu, real *u2, integer *ldu2, real *vt, integer *ldvt, real *vt2, integer *ldvt2, integer *idxc, integer *ctot, real *z__, integer * info); /* Subroutine */ int slasd4_(integer *n, integer *i__, real *d__, real *z__, real *delta, real *rho, real *sigma, real *work, integer *info); /* Subroutine */ int slasd5_(integer *i__, real *d__, real *z__, real *delta, real *rho, real *dsigma, real *work); /* Subroutine */ int slasd6_(integer *icompq, integer *nl, integer *nr, integer *sqre, real *d__, real *vf, real *vl, real *alpha, real *beta, integer *idxq, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, real *givnum, integer *ldgnum, real *poles, real * difl, real *difr, real *z__, integer *k, real *c__, real *s, real * work, integer *iwork, integer *info); /* Subroutine */ int slasd7_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *k, real *d__, real *z__, real *zw, real *vf, real *vfw, real *vl, real *vlw, real *alpha, real *beta, real *dsigma, integer *idx, integer *idxp, integer *idxq, integer *perm, integer * givptr, integer *givcol, integer *ldgcol, real *givnum, integer * ldgnum, real *c__, real *s, integer *info); /* Subroutine */ int slasd8_(integer *icompq, integer *k, real *d__, real * z__, real *vf, real *vl, real *difl, real *difr, integer *lddifr, real *dsigma, real *work, integer *info); /* Subroutine */ int slasda_(integer *icompq, integer *smlsiz, integer *n, integer *sqre, real *d__, real *e, real *u, integer *ldu, real *vt, integer *k, real *difl, real *difr, real *z__, real *poles, integer * givptr, integer *givcol, integer *ldgcol, integer *perm, real *givnum, real *c__, real *s, real *work, integer *iwork, integer *info); /* Subroutine */ int slasdq_(char *uplo, integer *sqre, integer *n, integer * ncvt, integer *nru, integer *ncc, real *d__, real *e, real *vt, integer *ldvt, real *u, integer *ldu, real *c__, integer *ldc, real * work, integer *info); /* Subroutine */ int slasdt_(integer *n, integer *lvl, integer *nd, integer * inode, integer *ndiml, integer *ndimr, integer *msub); /* Subroutine */ int slaset_(char *uplo, integer *m, integer *n, real *alpha, real *beta, real *a, integer *lda); /* Subroutine */ int slasq1_(integer *n, real *d__, real *e, real *work, integer *info); /* Subroutine */ int slasq2_(integer *n, real *z__, integer *info); /* Subroutine */ int slasq3_(integer *i0, integer *n0, real *z__, integer *pp, real *dmin__, real *sigma, real *desig, real *qmax, integer *nfail, integer *iter, integer *ndiv, logical *ieee, integer *ttype, real * dmin1, real *dmin2, real *dn, real *dn1, real *dn2, real *g, real * tau); /* Subroutine */ int slasq4_(integer *i0, integer *n0, real *z__, integer *pp, integer *n0in, real *dmin__, real *dmin1, real *dmin2, real *dn, real *dn1, real *dn2, real *tau, integer *ttype, real *g); /* Subroutine */ int slasq5_(integer *i0, integer *n0, real *z__, integer *pp, real *tau, real *dmin__, real *dmin1, real *dmin2, real *dn, real * dnm1, real *dnm2, logical *ieee); /* Subroutine */ int slasq6_(integer *i0, integer *n0, real *z__, integer *pp, real *dmin__, real *dmin1, real *dmin2, real *dn, real *dnm1, real * dnm2); /* Subroutine */ int slasr_(char *side, char *pivot, char *direct, integer *m, integer *n, real *c__, real *s, real *a, integer *lda); /* Subroutine */ int slasrt_(char *id, integer *n, real *d__, integer *info); /* Subroutine */ int slassq_(integer *n, real *x, integer *incx, real *scale, real *sumsq); /* Subroutine */ int slasv2_(real *f, real *g, real *h__, real *ssmin, real * ssmax, real *snr, real *csr, real *snl, real *csl); /* Subroutine */ int slaswp_(integer *n, real *a, integer *lda, integer *k1, integer *k2, integer *ipiv, integer *incx); /* Subroutine */ int slasy2_(logical *ltranl, logical *ltranr, integer *isgn, integer *n1, integer *n2, real *tl, integer *ldtl, real *tr, integer * ldtr, real *b, integer *ldb, real *scale, real *x, integer *ldx, real *xnorm, integer *info); /* Subroutine */ int slasyf_(char *uplo, integer *n, integer *nb, integer *kb, real *a, integer *lda, integer *ipiv, real *w, integer *ldw, integer *info); /* Subroutine */ int slatbs_(char *uplo, char *trans, char *diag, char * normin, integer *n, integer *kd, real *ab, integer *ldab, real *x, real *scale, real *cnorm, integer *info); /* Subroutine */ int slatdf_(integer *ijob, integer *n, real *z__, integer * ldz, real *rhs, real *rdsum, real *rdscal, integer *ipiv, integer * jpiv); /* Subroutine */ int slatps_(char *uplo, char *trans, char *diag, char * normin, integer *n, real *ap, real *x, real *scale, real *cnorm, integer *info); /* Subroutine */ int slatrd_(char *uplo, integer *n, integer *nb, real *a, integer *lda, real *e, real *tau, real *w, integer *ldw); /* Subroutine */ int slatrs_(char *uplo, char *trans, char *diag, char * normin, integer *n, real *a, integer *lda, real *x, real *scale, real *cnorm, integer *info); /* Subroutine */ int slatrz_(integer *m, integer *n, integer *l, real *a, integer *lda, real *tau, real *work); /* Subroutine */ int slatzm_(char *side, integer *m, integer *n, real *v, integer *incv, real *tau, real *c1, real *c2, integer *ldc, real * work); /* Subroutine */ int slauu2_(char *uplo, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int slauum_(char *uplo, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int sopgtr_(char *uplo, integer *n, real *ap, real *tau, real *q, integer *ldq, real *work, integer *info); /* Subroutine */ int sopmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, real *ap, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sorg2l_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sorg2r_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sorgbr_(char *vect, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorghr_(integer *n, integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorgl2_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sorglq_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorgql_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorgqr_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorgr2_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *info); /* Subroutine */ int sorgrq_(integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorgtr_(char *uplo, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int sorm2l_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sorm2r_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sormbr_(char *vect, char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormhr_(char *side, char *trans, integer *m, integer *n, integer *ilo, integer *ihi, real *a, integer *lda, real *tau, real * c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sorml2_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sormlq_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormql_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormqr_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormr2_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sormr3_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *info); /* Subroutine */ int sormrq_(char *side, char *trans, integer *m, integer *n, integer *k, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormrz_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int sormtr_(char *side, char *uplo, char *trans, integer *m, integer *n, real *a, integer *lda, real *tau, real *c__, integer *ldc, real *work, integer *lwork, integer *info); /* Subroutine */ int spbcon_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int spbequ_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int spbrfs_(char *uplo, integer *n, integer *kd, integer * nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * work, integer *iwork, integer *info); /* Subroutine */ int spbstf_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, integer *info); /* Subroutine */ int spbsv_(char *uplo, integer *n, integer *kd, integer * nrhs, real *ab, integer *ldab, real *b, integer *ldb, integer *info); /* Subroutine */ int spbsvx_(char *fact, char *uplo, integer *n, integer *kd, integer *nrhs, real *ab, integer *ldab, real *afb, integer *ldafb, char *equed, real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int spbtf2_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, integer *info); /* Subroutine */ int spbtrf_(char *uplo, integer *n, integer *kd, real *ab, integer *ldab, integer *info); /* Subroutine */ int spbtrs_(char *uplo, integer *n, integer *kd, integer * nrhs, real *ab, integer *ldab, real *b, integer *ldb, integer *info); /* Subroutine */ int spftrf_(char *transr, char *uplo, integer *n, real *a, integer *info); /* Subroutine */ int spftri_(char *transr, char *uplo, integer *n, real *a, integer *info); /* Subroutine */ int spftrs_(char *transr, char *uplo, integer *n, integer * nrhs, real *a, real *b, integer *ldb, integer *info); /* Subroutine */ int spocon_(char *uplo, integer *n, real *a, integer *lda, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int spoequ_(integer *n, real *a, integer *lda, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int spoequb_(integer *n, real *a, integer *lda, real *s, real *scond, real *amax, integer *info); /* Subroutine */ int sporfs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *af, integer *ldaf, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sporfsx_(char *uplo, char *equed, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, real *s, real * b, integer *ldb, real *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real *params, real *work, integer *iwork, integer * info); /* Subroutine */ int sposv_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer *info); /* Subroutine */ int sposvx_(char *fact, char *uplo, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, char *equed, real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sposvxx_(char *fact, char *uplo, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, char *equed, real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer *n_err_bnds__, real * err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real * params, real *work, integer *iwork, integer *info); /* Subroutine */ int spotf2_(char *uplo, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int spotrf_(char *uplo, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int spotri_(char *uplo, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int spotrs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer *info); /* Subroutine */ int sppcon_(char *uplo, integer *n, real *ap, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int sppequ_(char *uplo, integer *n, real *ap, real *s, real * scond, real *amax, integer *info); /* Subroutine */ int spprfs_(char *uplo, integer *n, integer *nrhs, real *ap, real *afp, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int sppsv_(char *uplo, integer *n, integer *nrhs, real *ap, real *b, integer *ldb, integer *info); /* Subroutine */ int sppsvx_(char *fact, char *uplo, integer *n, integer * nrhs, real *ap, real *afp, char *equed, real *s, real *b, integer * ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int spptrf_(char *uplo, integer *n, real *ap, integer *info); /* Subroutine */ int spptri_(char *uplo, integer *n, real *ap, integer *info); /* Subroutine */ int spptrs_(char *uplo, integer *n, integer *nrhs, real *ap, real *b, integer *ldb, integer *info); /* Subroutine */ int spstf2_(char *uplo, integer *n, real *a, integer *lda, integer *piv, integer *rank, real *tol, real *work, integer *info); /* Subroutine */ int spstrf_(char *uplo, integer *n, real *a, integer *lda, integer *piv, integer *rank, real *tol, real *work, integer *info); /* Subroutine */ int sptcon_(integer *n, real *d__, real *e, real *anorm, real *rcond, real *work, integer *info); /* Subroutine */ int spteqr_(char *compz, integer *n, real *d__, real *e, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int sptrfs_(integer *n, integer *nrhs, real *d__, real *e, real *df, real *ef, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *info); /* Subroutine */ int sptsv_(integer *n, integer *nrhs, real *d__, real *e, real *b, integer *ldb, integer *info); /* Subroutine */ int sptsvx_(char *fact, integer *n, integer *nrhs, real *d__, real *e, real *df, real *ef, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *info); /* Subroutine */ int spttrf_(integer *n, real *d__, real *e, integer *info); /* Subroutine */ int spttrs_(integer *n, integer *nrhs, real *d__, real *e, real *b, integer *ldb, integer *info); /* Subroutine */ int sptts2_(integer *n, integer *nrhs, real *d__, real *e, real *b, integer *ldb); /* Subroutine */ int srscl_(integer *n, real *sa, real *sx, integer *incx); /* Subroutine */ int ssbev_(char *jobz, char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *w, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int ssbevd_(char *jobz, char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *w, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ssbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *q, integer *ldq, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real * w, real *z__, integer *ldz, real *work, integer *iwork, integer * ifail, integer *info); /* Subroutine */ int ssbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * x, integer *ldx, real *work, integer *info); /* Subroutine */ int ssbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * w, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int ssbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, real *ab, integer *ldab, real *bb, integer *ldbb, real * w, real *z__, integer *ldz, real *work, integer *lwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int ssbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, integer *kb, real *ab, integer *ldab, real *bb, integer * ldbb, real *q, integer *ldq, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int ssbtrd_(char *vect, char *uplo, integer *n, integer *kd, real *ab, integer *ldab, real *d__, real *e, real *q, integer *ldq, real *work, integer *info); /* Subroutine */ int ssfrk_(char *transr, char *uplo, char *trans, integer *n, integer *k, real *alpha, real *a, integer *lda, real *beta, real * c__); /* Subroutine */ int sspcon_(char *uplo, integer *n, real *ap, integer *ipiv, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int sspev_(char *jobz, char *uplo, integer *n, real *ap, real *w, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int sspevd_(char *jobz, char *uplo, integer *n, real *ap, real *w, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sspevx_(char *jobz, char *range, char *uplo, integer *n, real *ap, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real *work, integer * iwork, integer *ifail, integer *info); /* Subroutine */ int sspgst_(integer *itype, char *uplo, integer *n, real *ap, real *bp, integer *info); /* Subroutine */ int sspgv_(integer *itype, char *jobz, char *uplo, integer * n, real *ap, real *bp, real *w, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int sspgvd_(integer *itype, char *jobz, char *uplo, integer * n, real *ap, real *bp, real *w, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sspgvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, real *ap, real *bp, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer * ldz, real *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int ssprfs_(char *uplo, integer *n, integer *nrhs, real *ap, real *afp, integer *ipiv, real *b, integer *ldb, real *x, integer * ldx, real *ferr, real *berr, real *work, integer *iwork, integer * info); /* Subroutine */ int sspsv_(char *uplo, integer *n, integer *nrhs, real *ap, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sspsvx_(char *fact, char *uplo, integer *n, integer * nrhs, real *ap, real *afp, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int ssptrd_(char *uplo, integer *n, real *ap, real *d__, real *e, real *tau, integer *info); /* Subroutine */ int ssptrf_(char *uplo, integer *n, real *ap, integer *ipiv, integer *info); /* Subroutine */ int ssptri_(char *uplo, integer *n, real *ap, integer *ipiv, real *work, integer *info); /* Subroutine */ int ssptrs_(char *uplo, integer *n, integer *nrhs, real *ap, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int sstebz_(char *range, char *order, integer *n, real *vl, real *vu, integer *il, integer *iu, real *abstol, real *d__, real *e, integer *m, integer *nsplit, real *w, integer *iblock, integer * isplit, real *work, integer *iwork, integer *info); /* Subroutine */ int sstedc_(char *compz, integer *n, real *d__, real *e, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sstegr_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, integer *isuppz, real * work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sstein_(integer *n, real *d__, real *e, integer *m, real *w, integer *iblock, integer *isplit, real *z__, integer *ldz, real * work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int sstemr_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, integer *m, real *w, real *z__, integer *ldz, integer *nzc, integer *isuppz, logical *tryrac, real *work, integer *lwork, integer *iwork, integer * liwork, integer *info); /* Subroutine */ int ssteqr_(char *compz, integer *n, real *d__, real *e, real *z__, integer *ldz, real *work, integer *info); /* Subroutine */ int ssterf_(integer *n, real *d__, real *e, integer *info); /* Subroutine */ int sstev_(char *jobz, integer *n, real *d__, real *e, real * z__, integer *ldz, real *work, integer *info); /* Subroutine */ int sstevd_(char *jobz, integer *n, real *d__, real *e, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sstevr_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, integer *isuppz, real * work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int sstevx_(char *jobz, char *range, integer *n, real *d__, real *e, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real *work, integer * iwork, integer *ifail, integer *info); /* Subroutine */ int ssycon_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, real *anorm, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int ssyequb_(char *uplo, integer *n, real *a, integer *lda, real *s, real *scond, real *amax, real *work, integer *info); /* Subroutine */ int ssyev_(char *jobz, char *uplo, integer *n, real *a, integer *lda, real *w, real *work, integer *lwork, integer *info); /* Subroutine */ int ssyevd_(char *jobz, char *uplo, integer *n, real *a, integer *lda, real *w, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ssyevr_(char *jobz, char *range, char *uplo, integer *n, real *a, integer *lda, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, integer * isuppz, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ssyevx_(char *jobz, char *range, char *uplo, integer *n, real *a, integer *lda, real *vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real * work, integer *lwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int ssygs2_(integer *itype, char *uplo, integer *n, real *a, integer *lda, real *b, integer *ldb, integer *info); /* Subroutine */ int ssygst_(integer *itype, char *uplo, integer *n, real *a, integer *lda, real *b, integer *ldb, integer *info); /* Subroutine */ int ssygv_(integer *itype, char *jobz, char *uplo, integer * n, real *a, integer *lda, real *b, integer *ldb, real *w, real *work, integer *lwork, integer *info); /* Subroutine */ int ssygvd_(integer *itype, char *jobz, char *uplo, integer * n, real *a, integer *lda, real *b, integer *ldb, real *w, real *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ssygvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, real *a, integer *lda, real *b, integer *ldb, real * vl, real *vu, integer *il, integer *iu, real *abstol, integer *m, real *w, real *z__, integer *ldz, real *work, integer *lwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int ssyrfs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real * work, integer *iwork, integer *info); /* Subroutine */ int ssyrfsx_(char *uplo, char *equed, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *berr, integer *n_err_bnds__, real *err_bnds_norm__, real * err_bnds_comp__, integer *nparams, real *params, real *work, integer * iwork, integer *info); /* Subroutine */ int ssysv_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, integer *ipiv, real *b, integer *ldb, real *work, integer *lwork, integer *info); /* Subroutine */ int ssysvx_(char *fact, char *uplo, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *ferr, real *berr, real *work, integer *lwork, integer *iwork, integer * info); /* Subroutine */ int ssysvxx_(char *fact, char *uplo, integer *n, integer * nrhs, real *a, integer *lda, real *af, integer *ldaf, integer *ipiv, char *equed, real *s, real *b, integer *ldb, real *x, integer *ldx, real *rcond, real *rpvgrw, real *berr, integer *n_err_bnds__, real * err_bnds_norm__, real *err_bnds_comp__, integer *nparams, real * params, real *work, integer *iwork, integer *info); /* Subroutine */ int ssytd2_(char *uplo, integer *n, real *a, integer *lda, real *d__, real *e, real *tau, integer *info); /* Subroutine */ int ssytf2_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int ssytrd_(char *uplo, integer *n, real *a, integer *lda, real *d__, real *e, real *tau, real *work, integer *lwork, integer * info); /* Subroutine */ int ssytrf_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, real *work, integer *lwork, integer *info); /* Subroutine */ int ssytri_(char *uplo, integer *n, real *a, integer *lda, integer *ipiv, real *work, integer *info); /* Subroutine */ int ssytrs_(char *uplo, integer *n, integer *nrhs, real *a, integer *lda, integer *ipiv, real *b, integer *ldb, integer *info); /* Subroutine */ int stbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, real *ab, integer *ldab, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int stbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, real *ab, integer *ldab, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int stbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, real *ab, integer *ldab, real *b, integer *ldb, integer *info); /* Subroutine */ int stfsm_(char *transr, char *side, char *uplo, char *trans, char *diag, integer *m, integer *n, real *alpha, real *a, real *b, integer *ldb); /* Subroutine */ int stftri_(char *transr, char *uplo, char *diag, integer *n, real *a, integer *info); /* Subroutine */ int stfttp_(char *transr, char *uplo, integer *n, real *arf, real *ap, integer *info); /* Subroutine */ int stfttr_(char *transr, char *uplo, integer *n, real *arf, real *a, integer *lda, integer *info); /* Subroutine */ int stgevc_(char *side, char *howmny, logical *select, integer *n, real *s, integer *lds, real *p, integer *ldp, real *vl, integer *ldvl, real *vr, integer *ldvr, integer *mm, integer *m, real *work, integer *info); /* Subroutine */ int stgex2_(logical *wantq, logical *wantz, integer *n, real *a, integer *lda, real *b, integer *ldb, real *q, integer *ldq, real * z__, integer *ldz, integer *j1, integer *n1, integer *n2, real *work, integer *lwork, integer *info); /* Subroutine */ int stgexc_(logical *wantq, logical *wantz, integer *n, real *a, integer *lda, real *b, integer *ldb, real *q, integer *ldq, real * z__, integer *ldz, integer *ifst, integer *ilst, real *work, integer * lwork, integer *info); /* Subroutine */ int stgsen_(integer *ijob, logical *wantq, logical *wantz, logical *select, integer *n, real *a, integer *lda, real *b, integer * ldb, real *alphar, real *alphai, real *beta, real *q, integer *ldq, real *z__, integer *ldz, integer *m, real *pl, real *pr, real *dif, real *work, integer *lwork, integer *iwork, integer *liwork, integer * info); /* Subroutine */ int stgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, integer *k, integer *l, real *a, integer *lda, real *b, integer *ldb, real *tola, real *tolb, real *alpha, real * beta, real *u, integer *ldu, real *v, integer *ldv, real *q, integer * ldq, real *work, integer *ncycle, integer *info); /* Subroutine */ int stgsna_(char *job, char *howmny, logical *select, integer *n, real *a, integer *lda, real *b, integer *ldb, real *vl, integer *ldvl, real *vr, integer *ldvr, real *s, real *dif, integer * mm, integer *m, real *work, integer *lwork, integer *iwork, integer * info); /* Subroutine */ int stgsy2_(char *trans, integer *ijob, integer *m, integer * n, real *a, integer *lda, real *b, integer *ldb, real *c__, integer * ldc, real *d__, integer *ldd, real *e, integer *lde, real *f, integer *ldf, real *scale, real *rdsum, real *rdscal, integer *iwork, integer *pq, integer *info); /* Subroutine */ int stgsyl_(char *trans, integer *ijob, integer *m, integer * n, real *a, integer *lda, real *b, integer *ldb, real *c__, integer * ldc, real *d__, integer *ldd, real *e, integer *lde, real *f, integer *ldf, real *scale, real *dif, real *work, integer *lwork, integer * iwork, integer *info); /* Subroutine */ int stpcon_(char *norm, char *uplo, char *diag, integer *n, real *ap, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int stprfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, real *ap, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int stptri_(char *uplo, char *diag, integer *n, real *ap, integer *info); /* Subroutine */ int stptrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, real *ap, real *b, integer *ldb, integer *info); /* Subroutine */ int stpttf_(char *transr, char *uplo, integer *n, real *ap, real *arf, integer *info); /* Subroutine */ int stpttr_(char *uplo, integer *n, real *ap, real *a, integer *lda, integer *info); /* Subroutine */ int strcon_(char *norm, char *uplo, char *diag, integer *n, real *a, integer *lda, real *rcond, real *work, integer *iwork, integer *info); /* Subroutine */ int strevc_(char *side, char *howmny, logical *select, integer *n, real *t, integer *ldt, real *vl, integer *ldvl, real *vr, integer *ldvr, integer *mm, integer *m, real *work, integer *info); /* Subroutine */ int strexc_(char *compq, integer *n, real *t, integer *ldt, real *q, integer *ldq, integer *ifst, integer *ilst, real *work, integer *info); /* Subroutine */ int strrfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, real *x, integer *ldx, real *ferr, real *berr, real *work, integer *iwork, integer *info); /* Subroutine */ int strsen_(char *job, char *compq, logical *select, integer *n, real *t, integer *ldt, real *q, integer *ldq, real *wr, real *wi, integer *m, real *s, real *sep, real *work, integer *lwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int strsna_(char *job, char *howmny, logical *select, integer *n, real *t, integer *ldt, real *vl, integer *ldvl, real *vr, integer *ldvr, real *s, real *sep, integer *mm, integer *m, real * work, integer *ldwork, integer *iwork, integer *info); /* Subroutine */ int strsyl_(char *trana, char *tranb, integer *isgn, integer *m, integer *n, real *a, integer *lda, real *b, integer *ldb, real * c__, integer *ldc, real *scale, integer *info); /* Subroutine */ int strti2_(char *uplo, char *diag, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int strtri_(char *uplo, char *diag, integer *n, real *a, integer *lda, integer *info); /* Subroutine */ int strtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, real *a, integer *lda, real *b, integer *ldb, integer * info); /* Subroutine */ int strttf_(char *transr, char *uplo, integer *n, real *a, integer *lda, real *arf, integer *info); /* Subroutine */ int strttp_(char *uplo, integer *n, real *a, integer *lda, real *ap, integer *info); /* Subroutine */ int stzrqf_(integer *m, integer *n, real *a, integer *lda, real *tau, integer *info); /* Subroutine */ int stzrzf_(integer *m, integer *n, real *a, integer *lda, real *tau, real *work, integer *lwork, integer *info); /* Subroutine */ int xerbla_(char *srname, integer *info); /* Subroutine */ int xerbla_array__(char *srname_array__, integer * srname_len__, integer *info, ftnlen srname_array_len); /* Subroutine */ int zbdsqr_(char *uplo, integer *n, integer *ncvt, integer * nru, integer *ncc, doublereal *d__, doublereal *e, doublecomplex *vt, integer *ldvt, doublecomplex *u, integer *ldu, doublecomplex *c__, integer *ldc, doublereal *rwork, integer *info); /* Subroutine */ int zcgesv_(integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublecomplex *work, complex *swork, doublereal *rwork, integer *iter, integer *info); /* Subroutine */ int zcposv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublecomplex *work, complex *swork, doublereal *rwork, integer *iter, integer *info); /* Subroutine */ int zdrscl_(integer *n, doublereal *sa, doublecomplex *sx, integer *incx); /* Subroutine */ int zgbbrd_(char *vect, integer *m, integer *n, integer *ncc, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublereal *d__, doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *pt, integer *ldpt, doublecomplex *c__, integer *ldc, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgbcon_(char *norm, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zgbequ_(integer *m, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer * info); /* Subroutine */ int zgbequb_(integer *m, integer *n, integer *kl, integer * ku, doublecomplex *ab, integer *ldab, doublereal *r__, doublereal * c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer *info); /* Subroutine */ int zgbrfs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex * afb, integer *ldafb, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgbrfsx_(char *trans, char *equed, integer *n, integer * kl, integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *berr, integer * n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zgbsv_(integer *n, integer *kl, integer *ku, integer * nrhs, doublecomplex *ab, integer *ldab, integer *ipiv, doublecomplex * b, integer *ldb, integer *info); /* Subroutine */ int zgbsvx_(char *fact, char *trans, integer *n, integer *kl, integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zgbsvxx_(char *fact, char *trans, integer *n, integer * kl, integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgbtf2_(integer *m, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int zgbtrf_(integer *m, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, integer *ipiv, integer *info); /* Subroutine */ int zgbtrs_(char *trans, integer *n, integer *kl, integer * ku, integer *nrhs, doublecomplex *ab, integer *ldab, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zgebak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, doublereal *scale, integer *m, doublecomplex *v, integer *ldv, integer *info); /* Subroutine */ int zgebal_(char *job, integer *n, doublecomplex *a, integer *lda, integer *ilo, integer *ihi, doublereal *scale, integer *info); /* Subroutine */ int zgebd2_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, doublecomplex *taup, doublecomplex *work, integer *info); /* Subroutine */ int zgebrd_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, doublecomplex *taup, doublecomplex *work, integer *lwork, integer * info); /* Subroutine */ int zgecon_(char *norm, integer *n, doublecomplex *a, integer *lda, doublereal *anorm, doublereal *rcond, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zgeequ_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer *info); /* Subroutine */ int zgeequb_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, integer *info); /* Subroutine */ int zgees_(char *jobvs, char *sort, L_fp select, integer *n, doublecomplex *a, integer *lda, integer *sdim, doublecomplex *w, doublecomplex *vs, integer *ldvs, doublecomplex *work, integer *lwork, doublereal *rwork, logical *bwork, integer *info); /* Subroutine */ int zgeesx_(char *jobvs, char *sort, L_fp select, char * sense, integer *n, doublecomplex *a, integer *lda, integer *sdim, doublecomplex *w, doublecomplex *vs, integer *ldvs, doublereal * rconde, doublereal *rcondv, doublecomplex *work, integer *lwork, doublereal *rwork, logical *bwork, integer *info); /* Subroutine */ int zgeev_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, integer *lda, doublecomplex *w, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgeevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, doublecomplex *a, integer *lda, doublecomplex *w, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, integer *ilo, integer *ihi, doublereal *scale, doublereal *abnrm, doublereal *rconde, doublereal *rcondv, doublecomplex *work, integer * lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgegs_(char *jobvsl, char *jobvsr, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex *beta, doublecomplex *vsl, integer *ldvsl, doublecomplex *vsr, integer *ldvsr, doublecomplex * work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgegv_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgehd2_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *info); /* Subroutine */ int zgehrd_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zgelq2_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); /* Subroutine */ int zgelqf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgels_(char *trans, integer *m, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgelsd_(integer *m, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *s, doublereal *rcond, integer *rank, doublecomplex *work, integer *lwork, doublereal *rwork, integer *iwork, integer *info); /* Subroutine */ int zgelss_(integer *m, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *s, doublereal *rcond, integer *rank, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgelsx_(integer *m, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *jpvt, doublereal *rcond, integer *rank, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgelsy_(integer *m, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *jpvt, doublereal *rcond, integer *rank, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgeql2_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); /* Subroutine */ int zgeqlf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgeqp3_(integer *m, integer *n, doublecomplex *a, integer *lda, integer *jpvt, doublecomplex *tau, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgeqpf_(integer *m, integer *n, doublecomplex *a, integer *lda, integer *jpvt, doublecomplex *tau, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgeqr2_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); /* Subroutine */ int zgeqrf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgerfs_(char *trans, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgerfsx_(char *trans, char *equed, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, doublereal *r__, doublereal *c__, doublecomplex * b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgerq2_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *info); /* Subroutine */ int zgerqf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgesc2_(integer *n, doublecomplex *a, integer *lda, doublecomplex *rhs, integer *ipiv, integer *jpiv, doublereal *scale); /* Subroutine */ int zgesdd_(char *jobz, integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublecomplex *u, integer *ldu, doublecomplex *vt, integer *ldvt, doublecomplex *work, integer *lwork, doublereal *rwork, integer *iwork, integer *info); /* Subroutine */ int zgesv_(integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer * info); /* Subroutine */ int zgesvd_(char *jobu, char *jobvt, integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublecomplex *u, integer *ldu, doublecomplex *vt, integer *ldvt, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zgesvx_(char *fact, char *trans, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zgesvxx_(char *fact, char *trans, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, char *equed, doublereal *r__, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer * n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zgetc2_(integer *n, doublecomplex *a, integer *lda, integer *ipiv, integer *jpiv, integer *info); /* Subroutine */ int zgetf2_(integer *m, integer *n, doublecomplex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int zgetrf_(integer *m, integer *n, doublecomplex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int zgetri_(integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgetrs_(char *trans, integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zggbak_(char *job, char *side, integer *n, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, integer *m, doublecomplex *v, integer *ldv, integer *info); /* Subroutine */ int zggbal_(char *job, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, doublereal *work, integer * info); /* Subroutine */ int zgges_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *sdim, doublecomplex *alpha, doublecomplex * beta, doublecomplex *vsl, integer *ldvsl, doublecomplex *vsr, integer *ldvsr, doublecomplex *work, integer *lwork, doublereal *rwork, logical *bwork, integer *info); /* Subroutine */ int zggesx_(char *jobvsl, char *jobvsr, char *sort, L_fp selctg, char *sense, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *sdim, doublecomplex *alpha, doublecomplex *beta, doublecomplex *vsl, integer *ldvsl, doublecomplex *vsr, integer *ldvsr, doublereal *rconde, doublereal * rcondv, doublecomplex *work, integer *lwork, doublereal *rwork, integer *iwork, integer *liwork, logical *bwork, integer *info); /* Subroutine */ int zggev_(char *jobvl, char *jobvr, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zggevx_(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex *beta, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, integer *ilo, integer *ihi, doublereal *lscale, doublereal *rscale, doublereal *abnrm, doublereal *bbnrm, doublereal *rconde, doublereal * rcondv, doublecomplex *work, integer *lwork, doublereal *rwork, integer *iwork, logical *bwork, integer *info); /* Subroutine */ int zggglm_(integer *n, integer *m, integer *p, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *d__, doublecomplex *x, doublecomplex *y, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zgghrd_(char *compq, char *compz, integer *n, integer * ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *q, integer *ldq, doublecomplex *z__, integer *ldz, integer *info); /* Subroutine */ int zgglse_(integer *m, integer *n, integer *p, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *c__, doublecomplex *d__, doublecomplex *x, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zggqrf_(integer *n, integer *m, integer *p, doublecomplex *a, integer *lda, doublecomplex *taua, doublecomplex *b, integer *ldb, doublecomplex *taub, doublecomplex *work, integer * lwork, integer *info); /* Subroutine */ int zggrqf_(integer *m, integer *p, integer *n, doublecomplex *a, integer *lda, doublecomplex *taua, doublecomplex *b, integer *ldb, doublecomplex *taub, doublecomplex *work, integer * lwork, integer *info); /* Subroutine */ int zggsvd_(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *alpha, doublereal *beta, doublecomplex *u, integer *ldu, doublecomplex *v, integer *ldv, doublecomplex *q, integer *ldq, doublecomplex *work, doublereal *rwork, integer *iwork, integer *info); /* Subroutine */ int zggsvp_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *tola, doublereal *tolb, integer *k, integer *l, doublecomplex *u, integer *ldu, doublecomplex *v, integer *ldv, doublecomplex *q, integer *ldq, integer *iwork, doublereal * rwork, doublecomplex *tau, doublecomplex *work, integer *info); /* Subroutine */ int zgtcon_(char *norm, integer *n, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *du2, integer * ipiv, doublereal *anorm, doublereal *rcond, doublecomplex *work, integer *info); /* Subroutine */ int zgtrfs_(char *trans, integer *n, integer *nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *dlf, doublecomplex *df, doublecomplex *duf, doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zgtsv_(integer *n, integer *nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zgtsvx_(char *fact, char *trans, integer *n, integer * nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *dlf, doublecomplex *df, doublecomplex *duf, doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zgttrf_(integer *n, doublecomplex *dl, doublecomplex * d__, doublecomplex *du, doublecomplex *du2, integer *ipiv, integer * info); /* Subroutine */ int zgttrs_(char *trans, integer *n, integer *nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zgtts2_(integer *itrans, integer *n, integer *nrhs, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *du2, integer *ipiv, doublecomplex *b, integer *ldb); /* Subroutine */ int zhbev_(char *jobz, char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zhbevd_(char *jobz, char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zhbevx_(char *jobz, char *range, char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublecomplex *q, integer *ldq, doublereal *vl, doublereal *vu, integer *il, integer * iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int zhbgst_(char *vect, char *uplo, integer *n, integer *ka, integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, integer *ldbb, doublecomplex *x, integer *ldx, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zhbgv_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, integer *ldbb, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zhbgvd_(char *jobz, char *uplo, integer *n, integer *ka, integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, integer *ldbb, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer * lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zhbgvx_(char *jobz, char *range, char *uplo, integer *n, integer *ka, integer *kb, doublecomplex *ab, integer *ldab, doublecomplex *bb, integer *ldbb, doublecomplex *q, integer *ldq, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal * abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer *iwork, integer * ifail, integer *info); /* Subroutine */ int zhbtrd_(char *vect, char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *d__, doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *work, integer *info); /* Subroutine */ int zhecon_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex *work, integer *info); /* Subroutine */ int zheequb_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, doublecomplex *work, integer *info); /* Subroutine */ int zheev_(char *jobz, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zheevd_(char *jobz, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zheevr_(char *jobz, char *range, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal * w, doublecomplex *z__, integer *ldz, integer *isuppz, doublecomplex * work, integer *lwork, doublereal *rwork, integer *lrwork, integer * iwork, integer *liwork, integer *info); /* Subroutine */ int zheevx_(char *jobz, char *range, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal * w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer * lwork, doublereal *rwork, integer *iwork, integer *ifail, integer * info); /* Subroutine */ int zhegs2_(integer *itype, char *uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zhegst_(integer *itype, char *uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zhegv_(integer *itype, char *jobz, char *uplo, integer * n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zhegvd_(integer *itype, char *jobz, char *uplo, integer * n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *w, doublecomplex *work, integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zhegvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *vl, doublereal *vu, integer *il, integer * iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int zherfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zherfsx_(char *uplo, char *equed, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zhesv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zhesvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zhesvxx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, char *equed, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer * nparams, doublereal *params, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zhetd2_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, doublecomplex *tau, integer *info); /* Subroutine */ int zhetf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int zhetrd_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zhetrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zhetri_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *work, integer *info); /* Subroutine */ int zhetrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zhfrk_(char *transr, char *uplo, char *trans, integer *n, integer *k, doublereal *alpha, doublecomplex *a, integer *lda, doublereal *beta, doublecomplex *c__); /* Subroutine */ int zhgeqz_(char *job, char *compq, char *compz, integer *n, integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *t, integer *ldt, doublecomplex *alpha, doublecomplex * beta, doublecomplex *q, integer *ldq, doublecomplex *z__, integer * ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer * info); /* Subroutine */ int zhpcon_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex * work, integer *info); /* Subroutine */ int zhpev_(char *jobz, char *uplo, integer *n, doublecomplex *ap, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zhpevd_(char *jobz, char *uplo, integer *n, doublecomplex *ap, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer * lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zhpevx_(char *jobz, char *range, char *uplo, integer *n, doublecomplex *ap, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal * rwork, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int zhpgst_(integer *itype, char *uplo, integer *n, doublecomplex *ap, doublecomplex *bp, integer *info); /* Subroutine */ int zhpgv_(integer *itype, char *jobz, char *uplo, integer * n, doublecomplex *ap, doublecomplex *bp, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zhpgvd_(integer *itype, char *jobz, char *uplo, integer * n, doublecomplex *ap, doublecomplex *bp, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal * rwork, integer *lrwork, integer *iwork, integer *liwork, integer * info); /* Subroutine */ int zhpgvx_(integer *itype, char *jobz, char *range, char * uplo, integer *n, doublecomplex *ap, doublecomplex *bp, doublereal * vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, doublecomplex *work, doublereal *rwork, integer *iwork, integer * ifail, integer *info); /* Subroutine */ int zhprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex * b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zhpsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zhpsvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zhptrd_(char *uplo, integer *n, doublecomplex *ap, doublereal *d__, doublereal *e, doublecomplex *tau, integer *info); /* Subroutine */ int zhptrf_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, integer *info); /* Subroutine */ int zhptri_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, doublecomplex *work, integer *info); /* Subroutine */ int zhptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zhsein_(char *side, char *eigsrc, char *initv, logical * select, integer *n, doublecomplex *h__, integer *ldh, doublecomplex * w, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, integer *mm, integer *m, doublecomplex *work, doublereal *rwork, integer *ifaill, integer *ifailr, integer *info); /* Subroutine */ int zhseqr_(char *job, char *compz, integer *n, integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zla_gbamv__(integer *trans, integer *m, integer *n, integer *kl, integer *ku, doublereal *alpha, doublecomplex *ab, integer *ldab, doublecomplex *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal zla_gbrcond_c__(char *trans, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, doublereal *c__, logical *capply, integer *info, doublecomplex *work, doublereal *rwork, ftnlen trans_len); doublereal zla_gbrcond_x__(char *trans, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, doublecomplex *x, integer *info, doublecomplex *work, doublereal *rwork, ftnlen trans_len); /* Subroutine */ int zla_gbrfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *kl, integer *ku, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, integer *ipiv, logical *colequ, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal *errs_c__, doublecomplex *res, doublereal *ayb, doublecomplex *dy, doublecomplex *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical *ignore_cwise__, integer *info); doublereal zla_gbrpvgrw__(integer *n, integer *kl, integer *ku, integer * ncols, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer * ldafb); /* Subroutine */ int zla_geamv__(integer *trans, integer *m, integer *n, doublereal *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal zla_gercond_c__(char *trans, integer *n, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublereal * c__, logical *capply, integer *info, doublecomplex *work, doublereal * rwork, ftnlen trans_len); doublereal zla_gercond_x__(char *trans, integer *n, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex * x, integer *info, doublecomplex *work, doublereal *rwork, ftnlen trans_len); /* Subroutine */ int zla_gerfsx_extended__(integer *prec_type__, integer * trans_type__, integer *n, integer *nrhs, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, integer *ipiv, logical *colequ, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal * errs_n__, doublereal *errs_c__, doublecomplex *res, doublereal *ayb, doublecomplex *dy, doublecomplex *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical * ignore_cwise__, integer *info); /* Subroutine */ int zla_heamv__(integer *uplo, integer *n, doublereal *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal zla_hercond_c__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublereal *c__, logical *capply, integer *info, doublecomplex *work, doublereal * rwork, ftnlen uplo_len); doublereal zla_hercond_x__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex * x, integer *info, doublecomplex *work, doublereal *rwork, ftnlen uplo_len); /* Subroutine */ int zla_herfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, logical *colequ, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal * errs_n__, doublereal *errs_c__, doublecomplex *res, doublereal *ayb, doublecomplex *dy, doublecomplex *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical * ignore_cwise__, integer *info, ftnlen uplo_len); doublereal zla_herpvgrw__(char *uplo, integer *n, integer *info, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublereal *work, ftnlen uplo_len); /* Subroutine */ int zla_lin_berr__(integer *n, integer *nz, integer *nrhs, doublecomplex *res, doublereal *ayb, doublereal *berr); doublereal zla_porcond_c__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, doublereal *c__, logical * capply, integer *info, doublecomplex *work, doublereal *rwork, ftnlen uplo_len); doublereal zla_porcond_x__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, doublecomplex *x, integer * info, doublecomplex *work, doublereal *rwork, ftnlen uplo_len); /* Subroutine */ int zla_porfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, logical *colequ, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal *errs_n__, doublereal *errs_c__, doublecomplex *res, doublereal *ayb, doublecomplex *dy, doublecomplex *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical * ignore_cwise__, integer *info, ftnlen uplo_len); doublereal zla_porpvgrw__(char *uplo, integer *ncols, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, doublereal *work, ftnlen uplo_len); doublereal zla_rpvgrw__(integer *n, integer *ncols, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf); /* Subroutine */ int zla_syamv__(integer *uplo, integer *n, doublereal *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublereal *beta, doublereal *y, integer *incy); doublereal zla_syrcond_c__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublereal *c__, logical *capply, integer *info, doublecomplex *work, doublereal * rwork, ftnlen uplo_len); doublereal zla_syrcond_x__(char *uplo, integer *n, doublecomplex *a, integer * lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex * x, integer *info, doublecomplex *work, doublereal *rwork, ftnlen uplo_len); /* Subroutine */ int zla_syrfsx_extended__(integer *prec_type__, char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, logical *colequ, doublereal *c__, doublecomplex *b, integer *ldb, doublecomplex *y, integer *ldy, doublereal *berr_out__, integer *n_norms__, doublereal * errs_n__, doublereal *errs_c__, doublecomplex *res, doublereal *ayb, doublecomplex *dy, doublecomplex *y_tail__, doublereal *rcond, integer *ithresh, doublereal *rthresh, doublereal *dz_ub__, logical * ignore_cwise__, integer *info, ftnlen uplo_len); doublereal zla_syrpvgrw__(char *uplo, integer *n, integer *info, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublereal *work, ftnlen uplo_len); /* Subroutine */ int zla_wwaddw__(integer *n, doublecomplex *x, doublecomplex *y, doublecomplex *w); /* Subroutine */ int zlabrd_(integer *m, integer *n, integer *nb, doublecomplex *a, integer *lda, doublereal *d__, doublereal *e, doublecomplex *tauq, doublecomplex *taup, doublecomplex *x, integer * ldx, doublecomplex *y, integer *ldy); /* Subroutine */ int zlacgv_(integer *n, doublecomplex *x, integer *incx); /* Subroutine */ int zlacn2_(integer *n, doublecomplex *v, doublecomplex *x, doublereal *est, integer *kase, integer *isave); /* Subroutine */ int zlacon_(integer *n, doublecomplex *v, doublecomplex *x, doublereal *est, integer *kase); /* Subroutine */ int zlacp2_(char *uplo, integer *m, integer *n, doublereal * a, integer *lda, doublecomplex *b, integer *ldb); /* Subroutine */ int zlacpy_(char *uplo, integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb); /* Subroutine */ int zlacrm_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *b, integer *ldb, doublecomplex *c__, integer *ldc, doublereal *rwork); /* Subroutine */ int zlacrt_(integer *n, doublecomplex *cx, integer *incx, doublecomplex *cy, integer *incy, doublecomplex *c__, doublecomplex * s); /* Double Complex */ VOID zladiv_(doublecomplex * ret_val, doublecomplex *x, doublecomplex *y); /* Subroutine */ int zlaed0_(integer *qsiz, integer *n, doublereal *d__, doublereal *e, doublecomplex *q, integer *ldq, doublecomplex *qstore, integer *ldqs, doublereal *rwork, integer *iwork, integer *info); /* Subroutine */ int zlaed7_(integer *n, integer *cutpnt, integer *qsiz, integer *tlvls, integer *curlvl, integer *curpbm, doublereal *d__, doublecomplex *q, integer *ldq, doublereal *rho, integer *indxq, doublereal *qstore, integer *qptr, integer *prmptr, integer *perm, integer *givptr, integer *givcol, doublereal *givnum, doublecomplex * work, doublereal *rwork, integer *iwork, integer *info); /* Subroutine */ int zlaed8_(integer *k, integer *n, integer *qsiz, doublecomplex *q, integer *ldq, doublereal *d__, doublereal *rho, integer *cutpnt, doublereal *z__, doublereal *dlamda, doublecomplex * q2, integer *ldq2, doublereal *w, integer *indxp, integer *indx, integer *indxq, integer *perm, integer *givptr, integer *givcol, doublereal *givnum, integer *info); /* Subroutine */ int zlaein_(logical *rightv, logical *noinit, integer *n, doublecomplex *h__, integer *ldh, doublecomplex *w, doublecomplex *v, doublecomplex *b, integer *ldb, doublereal *rwork, doublereal *eps3, doublereal *smlnum, integer *info); /* Subroutine */ int zlaesy_(doublecomplex *a, doublecomplex *b, doublecomplex *c__, doublecomplex *rt1, doublecomplex *rt2, doublecomplex *evscal, doublecomplex *cs1, doublecomplex *sn1); /* Subroutine */ int zlaev2_(doublecomplex *a, doublecomplex *b, doublecomplex *c__, doublereal *rt1, doublereal *rt2, doublereal *cs1, doublecomplex *sn1); /* Subroutine */ int zlag2c_(integer *m, integer *n, doublecomplex *a, integer *lda, complex *sa, integer *ldsa, integer *info); /* Subroutine */ int zlags2_(logical *upper, doublereal *a1, doublecomplex * a2, doublereal *a3, doublereal *b1, doublecomplex *b2, doublereal *b3, doublereal *csu, doublecomplex *snu, doublereal *csv, doublecomplex * snv, doublereal *csq, doublecomplex *snq); /* Subroutine */ int zlagtm_(char *trans, integer *n, integer *nrhs, doublereal *alpha, doublecomplex *dl, doublecomplex *d__, doublecomplex *du, doublecomplex *x, integer *ldx, doublereal *beta, doublecomplex *b, integer *ldb); /* Subroutine */ int zlahef_(char *uplo, integer *n, integer *nb, integer *kb, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *w, integer *ldw, integer *info); /* Subroutine */ int zlahqr_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, integer *info); /* Subroutine */ int zlahr2_(integer *n, integer *k, integer *nb, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *t, integer *ldt, doublecomplex *y, integer *ldy); /* Subroutine */ int zlahrd_(integer *n, integer *k, integer *nb, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *t, integer *ldt, doublecomplex *y, integer *ldy); /* Subroutine */ int zlaic1_(integer *job, integer *j, doublecomplex *x, doublereal *sest, doublecomplex *w, doublecomplex *gamma, doublereal * sestpr, doublecomplex *s, doublecomplex *c__); /* Subroutine */ int zlals0_(integer *icompq, integer *nl, integer *nr, integer *sqre, integer *nrhs, doublecomplex *b, integer *ldb, doublecomplex *bx, integer *ldbx, integer *perm, integer *givptr, integer *givcol, integer *ldgcol, doublereal *givnum, integer *ldgnum, doublereal *poles, doublereal *difl, doublereal *difr, doublereal * z__, integer *k, doublereal *c__, doublereal *s, doublereal *rwork, integer *info); /* Subroutine */ int zlalsa_(integer *icompq, integer *smlsiz, integer *n, integer *nrhs, doublecomplex *b, integer *ldb, doublecomplex *bx, integer *ldbx, doublereal *u, integer *ldu, doublereal *vt, integer * k, doublereal *difl, doublereal *difr, doublereal *z__, doublereal * poles, integer *givptr, integer *givcol, integer *ldgcol, integer * perm, doublereal *givnum, doublereal *c__, doublereal *s, doublereal * rwork, integer *iwork, integer *info); /* Subroutine */ int zlalsd_(char *uplo, integer *smlsiz, integer *n, integer *nrhs, doublereal *d__, doublereal *e, doublecomplex *b, integer *ldb, doublereal *rcond, integer *rank, doublecomplex *work, doublereal * rwork, integer *iwork, integer *info); doublereal zlangb_(char *norm, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublereal *work); doublereal zlange_(char *norm, integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *work); doublereal zlangt_(char *norm, integer *n, doublecomplex *dl, doublecomplex * d__, doublecomplex *du); doublereal zlanhb_(char *norm, char *uplo, integer *n, integer *k, doublecomplex *ab, integer *ldab, doublereal *work); doublereal zlanhe_(char *norm, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *work); doublereal zlanhf_(char *norm, char *transr, char *uplo, integer *n, doublecomplex *a, doublereal *work); doublereal zlanhp_(char *norm, char *uplo, integer *n, doublecomplex *ap, doublereal *work); doublereal zlanhs_(char *norm, integer *n, doublecomplex *a, integer *lda, doublereal *work); doublereal zlanht_(char *norm, integer *n, doublereal *d__, doublecomplex *e); doublereal zlansb_(char *norm, char *uplo, integer *n, integer *k, doublecomplex *ab, integer *ldab, doublereal *work); doublereal zlansp_(char *norm, char *uplo, integer *n, doublecomplex *ap, doublereal *work); doublereal zlansy_(char *norm, char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *work); doublereal zlantb_(char *norm, char *uplo, char *diag, integer *n, integer *k, doublecomplex *ab, integer *ldab, doublereal *work); doublereal zlantp_(char *norm, char *uplo, char *diag, integer *n, doublecomplex *ap, doublereal *work); doublereal zlantr_(char *norm, char *uplo, char *diag, integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *work); /* Subroutine */ int zlapll_(integer *n, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublereal *ssmin); /* Subroutine */ int zlapmt_(logical *forwrd, integer *m, integer *n, doublecomplex *x, integer *ldx, integer *k); /* Subroutine */ int zlaqgb_(integer *m, integer *n, integer *kl, integer *ku, doublecomplex *ab, integer *ldab, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); /* Subroutine */ int zlaqge_(integer *m, integer *n, doublecomplex *a, integer *lda, doublereal *r__, doublereal *c__, doublereal *rowcnd, doublereal *colcnd, doublereal *amax, char *equed); /* Subroutine */ int zlaqhb_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlaqhe_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlaqhp_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlaqp2_(integer *m, integer *n, integer *offset, doublecomplex *a, integer *lda, integer *jpvt, doublecomplex *tau, doublereal *vn1, doublereal *vn2, doublecomplex *work); /* Subroutine */ int zlaqps_(integer *m, integer *n, integer *offset, integer *nb, integer *kb, doublecomplex *a, integer *lda, integer *jpvt, doublecomplex *tau, doublereal *vn1, doublereal *vn2, doublecomplex * auxv, doublecomplex *f, integer *ldf); /* Subroutine */ int zlaqr0_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zlaqr1_(integer *n, doublecomplex *h__, integer *ldh, doublecomplex *s1, doublecomplex *s2, doublecomplex *v); /* Subroutine */ int zlaqr2_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, doublecomplex *h__, integer *ldh, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, integer *ns, integer *nd, doublecomplex *sh, doublecomplex *v, integer *ldv, integer *nh, doublecomplex *t, integer *ldt, integer *nv, doublecomplex *wv, integer *ldwv, doublecomplex *work, integer *lwork); /* Subroutine */ int zlaqr3_(logical *wantt, logical *wantz, integer *n, integer *ktop, integer *kbot, integer *nw, doublecomplex *h__, integer *ldh, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, integer *ns, integer *nd, doublecomplex *sh, doublecomplex *v, integer *ldv, integer *nh, doublecomplex *t, integer *ldt, integer *nv, doublecomplex *wv, integer *ldwv, doublecomplex *work, integer *lwork); /* Subroutine */ int zlaqr4_(logical *wantt, logical *wantz, integer *n, integer *ilo, integer *ihi, doublecomplex *h__, integer *ldh, doublecomplex *w, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zlaqr5_(logical *wantt, logical *wantz, integer *kacc22, integer *n, integer *ktop, integer *kbot, integer *nshfts, doublecomplex *s, doublecomplex *h__, integer *ldh, integer *iloz, integer *ihiz, doublecomplex *z__, integer *ldz, doublecomplex *v, integer *ldv, doublecomplex *u, integer *ldu, integer *nv, doublecomplex *wv, integer *ldwv, integer *nh, doublecomplex *wh, integer *ldwh); /* Subroutine */ int zlaqsb_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlaqsp_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlaqsy_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, char *equed); /* Subroutine */ int zlar1v_(integer *n, integer *b1, integer *bn, doublereal *lambda, doublereal *d__, doublereal *l, doublereal *ld, doublereal * lld, doublereal *pivmin, doublereal *gaptol, doublecomplex *z__, logical *wantnc, integer *negcnt, doublereal *ztz, doublereal *mingma, integer *r__, integer *isuppz, doublereal *nrminv, doublereal *resid, doublereal *rqcorr, doublereal *work); /* Subroutine */ int zlar2v_(integer *n, doublecomplex *x, doublecomplex *y, doublecomplex *z__, integer *incx, doublereal *c__, doublecomplex *s, integer *incc); /* Subroutine */ int zlarcm_(integer *m, integer *n, doublereal *a, integer * lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, doublereal *rwork); /* Subroutine */ int zlarf_(char *side, integer *m, integer *n, doublecomplex *v, integer *incv, doublecomplex *tau, doublecomplex *c__, integer * ldc, doublecomplex *work); /* Subroutine */ int zlarfb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, doublecomplex *v, integer *ldv, doublecomplex *t, integer *ldt, doublecomplex *c__, integer * ldc, doublecomplex *work, integer *ldwork); /* Subroutine */ int zlarfg_(integer *n, doublecomplex *alpha, doublecomplex * x, integer *incx, doublecomplex *tau); /* Subroutine */ int zlarfp_(integer *n, doublecomplex *alpha, doublecomplex * x, integer *incx, doublecomplex *tau); /* Subroutine */ int zlarft_(char *direct, char *storev, integer *n, integer * k, doublecomplex *v, integer *ldv, doublecomplex *tau, doublecomplex * t, integer *ldt); /* Subroutine */ int zlarfx_(char *side, integer *m, integer *n, doublecomplex *v, doublecomplex *tau, doublecomplex *c__, integer * ldc, doublecomplex *work); /* Subroutine */ int zlargv_(integer *n, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublereal *c__, integer *incc); /* Subroutine */ int zlarnv_(integer *idist, integer *iseed, integer *n, doublecomplex *x); /* Subroutine */ int zlarrv_(integer *n, doublereal *vl, doublereal *vu, doublereal *d__, doublereal *l, doublereal *pivmin, integer *isplit, integer *m, integer *dol, integer *dou, doublereal *minrgp, doublereal *rtol1, doublereal *rtol2, doublereal *w, doublereal *werr, doublereal *wgap, integer *iblock, integer *indexw, doublereal *gers, doublecomplex *z__, integer *ldz, integer *isuppz, doublereal *work, integer *iwork, integer *info); /* Subroutine */ int zlarscl2_(integer *m, integer *n, doublereal *d__, doublecomplex *x, integer *ldx); /* Subroutine */ int zlartg_(doublecomplex *f, doublecomplex *g, doublereal * cs, doublecomplex *sn, doublecomplex *r__); /* Subroutine */ int zlartv_(integer *n, doublecomplex *x, integer *incx, doublecomplex *y, integer *incy, doublereal *c__, doublecomplex *s, integer *incc); /* Subroutine */ int zlarz_(char *side, integer *m, integer *n, integer *l, doublecomplex *v, integer *incv, doublecomplex *tau, doublecomplex * c__, integer *ldc, doublecomplex *work); /* Subroutine */ int zlarzb_(char *side, char *trans, char *direct, char * storev, integer *m, integer *n, integer *k, integer *l, doublecomplex *v, integer *ldv, doublecomplex *t, integer *ldt, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *ldwork); /* Subroutine */ int zlarzt_(char *direct, char *storev, integer *n, integer * k, doublecomplex *v, integer *ldv, doublecomplex *tau, doublecomplex * t, integer *ldt); /* Subroutine */ int zlascl_(char *type__, integer *kl, integer *ku, doublereal *cfrom, doublereal *cto, integer *m, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zlascl2_(integer *m, integer *n, doublereal *d__, doublecomplex *x, integer *ldx); /* Subroutine */ int zlaset_(char *uplo, integer *m, integer *n, doublecomplex *alpha, doublecomplex *beta, doublecomplex *a, integer * lda); /* Subroutine */ int zlasr_(char *side, char *pivot, char *direct, integer *m, integer *n, doublereal *c__, doublereal *s, doublecomplex *a, integer *lda); /* Subroutine */ int zlassq_(integer *n, doublecomplex *x, integer *incx, doublereal *scale, doublereal *sumsq); /* Subroutine */ int zlaswp_(integer *n, doublecomplex *a, integer *lda, integer *k1, integer *k2, integer *ipiv, integer *incx); /* Subroutine */ int zlasyf_(char *uplo, integer *n, integer *nb, integer *kb, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *w, integer *ldw, integer *info); /* Subroutine */ int zlat2c_(char *uplo, integer *n, doublecomplex *a, integer *lda, complex *sa, integer *ldsa, integer *info); /* Subroutine */ int zlatbs_(char *uplo, char *trans, char *diag, char * normin, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublecomplex *x, doublereal *scale, doublereal *cnorm, integer *info); /* Subroutine */ int zlatdf_(integer *ijob, integer *n, doublecomplex *z__, integer *ldz, doublecomplex *rhs, doublereal *rdsum, doublereal * rdscal, integer *ipiv, integer *jpiv); /* Subroutine */ int zlatps_(char *uplo, char *trans, char *diag, char * normin, integer *n, doublecomplex *ap, doublecomplex *x, doublereal * scale, doublereal *cnorm, integer *info); /* Subroutine */ int zlatrd_(char *uplo, integer *n, integer *nb, doublecomplex *a, integer *lda, doublereal *e, doublecomplex *tau, doublecomplex *w, integer *ldw); /* Subroutine */ int zlatrs_(char *uplo, char *trans, char *diag, char * normin, integer *n, doublecomplex *a, integer *lda, doublecomplex *x, doublereal *scale, doublereal *cnorm, integer *info); /* Subroutine */ int zlatrz_(integer *m, integer *n, integer *l, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work); /* Subroutine */ int zlatzm_(char *side, integer *m, integer *n, doublecomplex *v, integer *incv, doublecomplex *tau, doublecomplex * c1, doublecomplex *c2, integer *ldc, doublecomplex *work); /* Subroutine */ int zlauu2_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zlauum_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zpbcon_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *anorm, doublereal * rcond, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zpbequ_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int zpbrfs_(char *uplo, integer *n, integer *kd, integer * nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer * ldafb, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * rwork, integer *info); /* Subroutine */ int zpbstf_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, integer *info); /* Subroutine */ int zpbsv_(char *uplo, integer *n, integer *kd, integer * nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer * ldb, integer *info); /* Subroutine */ int zpbsvx_(char *fact, char *uplo, integer *n, integer *kd, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *afb, integer *ldafb, char *equed, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal * ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zpbtf2_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, integer *info); /* Subroutine */ int zpbtrf_(char *uplo, integer *n, integer *kd, doublecomplex *ab, integer *ldab, integer *info); /* Subroutine */ int zpbtrs_(char *uplo, integer *n, integer *kd, integer * nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer * ldb, integer *info); /* Subroutine */ int zpftrf_(char *transr, char *uplo, integer *n, doublecomplex *a, integer *info); /* Subroutine */ int zpftri_(char *transr, char *uplo, integer *n, doublecomplex *a, integer *info); /* Subroutine */ int zpftrs_(char *transr, char *uplo, integer *n, integer * nrhs, doublecomplex *a, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zpocon_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *anorm, doublereal *rcond, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zpoequ_(integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int zpoequb_(integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int zporfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * rwork, integer *info); /* Subroutine */ int zporfsx_(char *uplo, char *equed, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *berr, integer * n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zposv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zposvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, char *equed, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zposvxx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, char *equed, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zpotf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zpotrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zpotri_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int zpotrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zppcon_(char *uplo, integer *n, doublecomplex *ap, doublereal *anorm, doublereal *rcond, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zppequ_(char *uplo, integer *n, doublecomplex *ap, doublereal *s, doublereal *scond, doublereal *amax, integer *info); /* Subroutine */ int zpprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *afp, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zppsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zppsvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *ap, doublecomplex *afp, char *equed, doublereal * s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zpptrf_(char *uplo, integer *n, doublecomplex *ap, integer *info); /* Subroutine */ int zpptri_(char *uplo, integer *n, doublecomplex *ap, integer *info); /* Subroutine */ int zpptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zpstf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *piv, integer *rank, doublereal *tol, doublereal *work, integer *info); /* Subroutine */ int zpstrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *piv, integer *rank, doublereal *tol, doublereal *work, integer *info); /* Subroutine */ int zptcon_(integer *n, doublereal *d__, doublecomplex *e, doublereal *anorm, doublereal *rcond, doublereal *rwork, integer * info); /* Subroutine */ int zpteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int zptrfs_(char *uplo, integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, doublereal *df, doublecomplex *ef, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * rwork, integer *info); /* Subroutine */ int zptsv_(integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zptsvx_(char *fact, integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, doublereal *df, doublecomplex *ef, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zpttrf_(integer *n, doublereal *d__, doublecomplex *e, integer *info); /* Subroutine */ int zpttrs_(char *uplo, integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zptts2_(integer *iuplo, integer *n, integer *nrhs, doublereal *d__, doublecomplex *e, doublecomplex *b, integer *ldb); /* Subroutine */ int zrot_(integer *n, doublecomplex *cx, integer *incx, doublecomplex *cy, integer *incy, doublereal *c__, doublecomplex *s); /* Subroutine */ int zspcon_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex * work, integer *info); /* Subroutine */ int zspmv_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *ap, doublecomplex *x, integer *incx, doublecomplex * beta, doublecomplex *y, integer *incy); /* Subroutine */ int zspr_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *ap); /* Subroutine */ int zsprfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex * b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int zspsv_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zspsvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *ap, doublecomplex *afp, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zsptrf_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, integer *info); /* Subroutine */ int zsptri_(char *uplo, integer *n, doublecomplex *ap, integer *ipiv, doublecomplex *work, integer *info); /* Subroutine */ int zsptrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *ap, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int zstedc_(char *compz, integer *n, doublereal *d__, doublereal *e, doublecomplex *z__, integer *ldz, doublecomplex *work, integer *lwork, doublereal *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zstegr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublecomplex *z__, integer *ldz, integer *isuppz, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zstein_(integer *n, doublereal *d__, doublereal *e, integer *m, doublereal *w, integer *iblock, integer *isplit, doublecomplex *z__, integer *ldz, doublereal *work, integer *iwork, integer *ifail, integer *info); /* Subroutine */ int zstemr_(char *jobz, char *range, integer *n, doublereal * d__, doublereal *e, doublereal *vl, doublereal *vu, integer *il, integer *iu, integer *m, doublereal *w, doublecomplex *z__, integer * ldz, integer *nzc, integer *isuppz, logical *tryrac, doublereal *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int zsteqr_(char *compz, integer *n, doublereal *d__, doublereal *e, doublecomplex *z__, integer *ldz, doublereal *work, integer *info); /* Subroutine */ int zsycon_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublereal *anorm, doublereal *rcond, doublecomplex *work, integer *info); /* Subroutine */ int zsyequb_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublereal *s, doublereal *scond, doublereal *amax, doublecomplex *work, integer *info); /* Subroutine */ int zsymv_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer *incx, doublecomplex *beta, doublecomplex *y, integer *incy); /* Subroutine */ int zsyr_(char *uplo, integer *n, doublecomplex *alpha, doublecomplex *x, integer *incx, doublecomplex *a, integer *lda); /* Subroutine */ int zsyrfs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer *ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zsyrfsx_(char *uplo, char *equed, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal * err_bnds_comp__, integer *nparams, doublereal *params, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int zsysv_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zsysvx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *ferr, doublereal *berr, doublecomplex *work, integer *lwork, doublereal *rwork, integer *info); /* Subroutine */ int zsysvxx_(char *fact, char *uplo, integer *n, integer * nrhs, doublecomplex *a, integer *lda, doublecomplex *af, integer * ldaf, integer *ipiv, char *equed, doublereal *s, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *rcond, doublereal *rpvgrw, doublereal *berr, integer *n_err_bnds__, doublereal *err_bnds_norm__, doublereal *err_bnds_comp__, integer * nparams, doublereal *params, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int zsytf2_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, integer *info); /* Subroutine */ int zsytrf_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zsytri_(char *uplo, integer *n, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *work, integer *info); /* Subroutine */ int zsytrs_(char *uplo, integer *n, integer *nrhs, doublecomplex *a, integer *lda, integer *ipiv, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int ztbcon_(char *norm, char *uplo, char *diag, integer *n, integer *kd, doublecomplex *ab, integer *ldab, doublereal *rcond, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int ztbrfs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal * rwork, integer *info); /* Subroutine */ int ztbtrs_(char *uplo, char *trans, char *diag, integer *n, integer *kd, integer *nrhs, doublecomplex *ab, integer *ldab, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int ztfsm_(char *transr, char *side, char *uplo, char *trans, char *diag, integer *m, integer *n, doublecomplex *alpha, doublecomplex *a, doublecomplex *b, integer *ldb); /* Subroutine */ int ztftri_(char *transr, char *uplo, char *diag, integer *n, doublecomplex *a, integer *info); /* Subroutine */ int ztfttp_(char *transr, char *uplo, integer *n, doublecomplex *arf, doublecomplex *ap, integer *info); /* Subroutine */ int ztfttr_(char *transr, char *uplo, integer *n, doublecomplex *arf, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int ztgevc_(char *side, char *howmny, logical *select, integer *n, doublecomplex *s, integer *lds, doublecomplex *p, integer *ldp, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer * ldvr, integer *mm, integer *m, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int ztgex2_(logical *wantq, logical *wantz, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *q, integer *ldq, doublecomplex *z__, integer *ldz, integer *j1, integer *info); /* Subroutine */ int ztgexc_(logical *wantq, logical *wantz, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *q, integer *ldq, doublecomplex *z__, integer *ldz, integer *ifst, integer *ilst, integer *info); /* Subroutine */ int ztgsen_(integer *ijob, logical *wantq, logical *wantz, logical *select, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *alpha, doublecomplex * beta, doublecomplex *q, integer *ldq, doublecomplex *z__, integer * ldz, integer *m, doublereal *pl, doublereal *pr, doublereal *dif, doublecomplex *work, integer *lwork, integer *iwork, integer *liwork, integer *info); /* Subroutine */ int ztgsja_(char *jobu, char *jobv, char *jobq, integer *m, integer *p, integer *n, integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublereal *tola, doublereal *tolb, doublereal *alpha, doublereal *beta, doublecomplex * u, integer *ldu, doublecomplex *v, integer *ldv, doublecomplex *q, integer *ldq, doublecomplex *work, integer *ncycle, integer *info); /* Subroutine */ int ztgsna_(char *job, char *howmny, logical *select, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer * ldvr, doublereal *s, doublereal *dif, integer *mm, integer *m, doublecomplex *work, integer *lwork, integer *iwork, integer *info); /* Subroutine */ int ztgsy2_(char *trans, integer *ijob, integer *m, integer * n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, doublecomplex *d__, integer *ldd, doublecomplex *e, integer *lde, doublecomplex *f, integer *ldf, doublereal *scale, doublereal *rdsum, doublereal *rdscal, integer * info); /* Subroutine */ int ztgsyl_(char *trans, integer *ijob, integer *m, integer * n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, doublecomplex *d__, integer *ldd, doublecomplex *e, integer *lde, doublecomplex *f, integer *ldf, doublereal *scale, doublereal *dif, doublecomplex *work, integer * lwork, integer *iwork, integer *info); /* Subroutine */ int ztpcon_(char *norm, char *uplo, char *diag, integer *n, doublecomplex *ap, doublereal *rcond, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int ztprfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int ztptri_(char *uplo, char *diag, integer *n, doublecomplex *ap, integer *info); /* Subroutine */ int ztptrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublecomplex *ap, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int ztpttf_(char *transr, char *uplo, integer *n, doublecomplex *ap, doublecomplex *arf, integer *info); /* Subroutine */ int ztpttr_(char *uplo, integer *n, doublecomplex *ap, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int ztrcon_(char *norm, char *uplo, char *diag, integer *n, doublecomplex *a, integer *lda, doublereal *rcond, doublecomplex * work, doublereal *rwork, integer *info); /* Subroutine */ int ztrevc_(char *side, char *howmny, logical *select, integer *n, doublecomplex *t, integer *ldt, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, integer *mm, integer *m, doublecomplex *work, doublereal *rwork, integer *info); /* Subroutine */ int ztrexc_(char *compq, integer *n, doublecomplex *t, integer *ldt, doublecomplex *q, integer *ldq, integer *ifst, integer * ilst, integer *info); /* Subroutine */ int ztrrfs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *x, integer *ldx, doublereal *ferr, doublereal *berr, doublecomplex *work, doublereal *rwork, integer * info); /* Subroutine */ int ztrsen_(char *job, char *compq, logical *select, integer *n, doublecomplex *t, integer *ldt, doublecomplex *q, integer *ldq, doublecomplex *w, integer *m, doublereal *s, doublereal *sep, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int ztrsna_(char *job, char *howmny, logical *select, integer *n, doublecomplex *t, integer *ldt, doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr, doublereal *s, doublereal *sep, integer *mm, integer *m, doublecomplex *work, integer *ldwork, doublereal *rwork, integer *info); /* Subroutine */ int ztrsyl_(char *trana, char *tranb, integer *isgn, integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, doublecomplex *c__, integer *ldc, doublereal *scale, integer *info); /* Subroutine */ int ztrti2_(char *uplo, char *diag, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int ztrtri_(char *uplo, char *diag, integer *n, doublecomplex *a, integer *lda, integer *info); /* Subroutine */ int ztrtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb, integer *info); /* Subroutine */ int ztrttf_(char *transr, char *uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *arf, integer *info); /* Subroutine */ int ztrttp_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *ap, integer *info); /* Subroutine */ int ztzrqf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, integer *info); /* Subroutine */ int ztzrzf_(integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zung2l_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *info); /* Subroutine */ int zung2r_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *info); /* Subroutine */ int zungbr_(char *vect, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zunghr_(integer *n, integer *ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zungl2_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *info); /* Subroutine */ int zunglq_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zungql_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zungqr_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zungr2_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *info); /* Subroutine */ int zungrq_(integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zungtr_(char *uplo, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zunm2l_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); /* Subroutine */ int zunm2r_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); /* Subroutine */ int zunmbr_(char *vect, char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * lwork, integer *info); /* Subroutine */ int zunmhr_(char *side, char *trans, integer *m, integer *n, integer *ilo, integer *ihi, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex * work, integer *lwork, integer *info); /* Subroutine */ int zunml2_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); /* Subroutine */ int zunmlq_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zunmql_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zunmqr_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zunmr2_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); /* Subroutine */ int zunmr3_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * info); /* Subroutine */ int zunmrq_(char *side, char *trans, integer *m, integer *n, integer *k, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zunmrz_(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer * lwork, integer *info); /* Subroutine */ int zunmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, doublecomplex *a, integer *lda, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *lwork, integer *info); /* Subroutine */ int zupgtr_(char *uplo, integer *n, doublecomplex *ap, doublecomplex *tau, doublecomplex *q, integer *ldq, doublecomplex * work, integer *info); /* Subroutine */ int zupmtr_(char *side, char *uplo, char *trans, integer *m, integer *n, doublecomplex *ap, doublecomplex *tau, doublecomplex *c__, integer *ldc, doublecomplex *work, integer *info); /* Subroutine */ int dlamc1_(integer *beta, integer *t, logical *rnd, logical *ieee1); doublereal dsecnd_(); /* Subroutine */ int ilaver_(integer *vers_major__, integer *vers_minor__, integer *vers_patch__); logical lsame_(char *ca, char *cb); doublereal second_(); doublereal slamch_(char *cmach); /* Subroutine */ int slamc1_(integer *beta, integer *t, logical *rnd, logical *ieee1); /* Subroutine */ int slamc2_(integer *beta, integer *t, logical *rnd, real * eps, integer *emin, real *rmin, integer *emax, real *rmax); doublereal slamc3_(real *a, real *b); /* Subroutine */ int slamc4_(integer *emin, real *start, integer *base); /* Subroutine */ int slamc5_(integer *beta, integer *p, integer *emin, logical *ieee, integer *emax, real *rmax); doublereal dlamch_(char *cmach); /* Subroutine */ int dlamc1_(integer *beta, integer *t, logical *rnd, logical *ieee1); /* Subroutine */ int dlamc2_(integer *beta, integer *t, logical *rnd, doublereal *eps, integer *emin, doublereal *rmin, integer *emax, doublereal *rmax); doublereal dlamc3_(doublereal *a, doublereal *b); /* Subroutine */ int dlamc4_(integer *emin, doublereal *start, integer *base); /* Subroutine */ int dlamc5_(integer *beta, integer *p, integer *emin, logical *ieee, integer *emax, doublereal *rmax); integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, integer *n2, integer *n3, integer *n4); #ifdef __cplusplus } #endif #endif /* __CLAPACK_H */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack/detail/f2c.h000066400000000000000000000111201231531733200256110ustar00rootroot00000000000000/* f2c.h -- Standard Fortran to C header file */ /** barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed." - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */ #ifndef F2C_INCLUDE #define F2C_INCLUDE typedef long int integer; typedef unsigned long int uinteger; typedef char *address; typedef short int shortint; typedef float real; typedef double doublereal; typedef struct { real r, i; } complex; typedef struct { doublereal r, i; } doublecomplex; typedef long int logical; typedef short int shortlogical; typedef char logical1; typedef char integer1; #ifdef INTEGER_STAR_8 /* Adjust for integer*8. */ typedef long long longint; /* system-dependent */ typedef unsigned long long ulongint; /* system-dependent */ #define qbit_clear(a,b) ((a) & ~((ulongint)1 << (b))) #define qbit_set(a,b) ((a) | ((ulongint)1 << (b))) #endif #define TRUE_ (1) #define FALSE_ (0) /* Extern is for use with -E */ #ifndef Extern #define Extern extern #endif /* I/O stuff */ #ifdef f2c_i2 /* for -i2 */ typedef short flag; typedef short ftnlen; typedef short ftnint; #else typedef long int flag; typedef long int ftnlen; typedef long int ftnint; #endif /*external read, write*/ typedef struct { flag cierr; ftnint ciunit; flag ciend; char *cifmt; ftnint cirec; } cilist; /*internal read, write*/ typedef struct { flag icierr; char *iciunit; flag iciend; char *icifmt; ftnint icirlen; ftnint icirnum; } icilist; /*open*/ typedef struct { flag oerr; ftnint ounit; char *ofnm; ftnlen ofnmlen; char *osta; char *oacc; char *ofm; ftnint orl; char *oblnk; } olist; /*close*/ typedef struct { flag cerr; ftnint cunit; char *csta; } cllist; /*rewind, backspace, endfile*/ typedef struct { flag aerr; ftnint aunit; } alist; /* inquire */ typedef struct { flag inerr; ftnint inunit; char *infile; ftnlen infilen; ftnint *inex; /*parameters in standard's order*/ ftnint *inopen; ftnint *innum; ftnint *innamed; char *inname; ftnlen innamlen; char *inacc; ftnlen inacclen; char *inseq; ftnlen inseqlen; char *indir; ftnlen indirlen; char *infmt; ftnlen infmtlen; char *inform; ftnint informlen; char *inunf; ftnlen inunflen; ftnint *inrecl; ftnint *innrec; char *inblank; ftnlen inblanklen; } inlist; #define VOID void union Multitype { /* for multiple entry points */ integer1 g; shortint h; integer i; /* longint j; */ real r; doublereal d; complex c; doublecomplex z; }; typedef union Multitype Multitype; /*typedef long int Long;*/ /* No longer used; formerly in Namelist */ struct Vardesc { /* for Namelist */ char *name; char *addr; ftnlen *dims; int type; }; typedef struct Vardesc Vardesc; struct Namelist { char *name; Vardesc **vars; int nvars; }; typedef struct Namelist Namelist; #define abs(x) ((x) >= 0 ? (x) : -(x)) #define dabs(x) (doublereal)abs(x) #define min(a,b) ((a) <= (b) ? (a) : (b)) #define max(a,b) ((a) >= (b) ? (a) : (b)) #define dmin(a,b) (doublereal)min(a,b) #define dmax(a,b) (doublereal)max(a,b) #define bit_test(a,b) ((a) >> (b) & 1) #define bit_clear(a,b) ((a) & ~((uinteger)1 << (b))) #define bit_set(a,b) ((a) | ((uinteger)1 << (b))) /* procedure parameter types for -A and -C++ */ #define F2C_proc_par_types 1 #ifdef __cplusplus typedef int /* Unknown procedure type */ (*U_fp)(...); typedef shortint (*J_fp)(...); typedef integer (*I_fp)(...); typedef real (*R_fp)(...); typedef doublereal (*D_fp)(...), (*E_fp)(...); typedef /* Complex */ VOID (*C_fp)(...); typedef /* Double Complex */ VOID (*Z_fp)(...); typedef logical (*L_fp)(...); typedef shortlogical (*K_fp)(...); typedef /* Character */ VOID (*H_fp)(...); typedef /* Subroutine */ int (*S_fp)(...); #else typedef int /* Unknown procedure type */ (*U_fp)(); typedef shortint (*J_fp)(); typedef integer (*I_fp)(); typedef real (*R_fp)(); typedef doublereal (*D_fp)(), (*E_fp)(); typedef /* Complex */ VOID (*C_fp)(); typedef /* Double Complex */ VOID (*Z_fp)(); typedef logical (*L_fp)(); typedef shortlogical (*K_fp)(); typedef /* Character */ VOID (*H_fp)(); typedef /* Subroutine */ int (*S_fp)(); #endif /* E_fp is for real functions when -R is not specified */ typedef VOID C_f; /* complex function */ typedef VOID H_f; /* character function */ typedef VOID Z_f; /* double complex function */ typedef doublereal E_f; /* real function with -R not specified */ /* undef any lower-case symbols that your C compiler predefines, e.g.: */ #ifndef Skip_f2c_Undefs #undef cray #undef gcos #undef mc68010 #undef mc68020 #undef mips #undef pdp11 #undef sgi #undef sparc #undef sun #undef sun2 #undef sun3 #undef sun4 #undef u370 #undef u3b #undef u3b2 #undef u3b5 #undef unix #undef vax #endif #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_gaussian_elimination.hpp000066400000000000000000000101211231531733200305170ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_LAPACK_GAUSSIAN_ELIMINATION__HPP__ #define __VMML__VMMLIB_LAPACK_GAUSSIAN_ELIMINATION__HPP__ #include #include #include #include #include #include /** * * this is a wrapper for the following lapack routines: * * xGESV * * */ namespace vmml { // XYYZZZ // X = data type: S - float, D - double // YY = matrix type, GE - general, TR - triangular // ZZZ = function name namespace lapack { // // // // SGESV/DGESV // // template< typename float_t > struct xgesv_params { lapack_int n; // order of matrix A = M * N lapack_int nrhs; // number of columns of B float_t* a; // input A, output P*L*U lapack_int lda; // leading dimension of A (for us: number of rows) lapack_int* ipiv; // pivot indices, integer array of size N float_t* b; // input b, output X lapack_int ldb; // leading dimension of b lapack_int info; friend std::ostream& operator << ( std::ostream& os, const xgesv_params< float_t >& p ) { os << "n " << p.n << " nrhs " << p.nrhs << " lda " << p.lda << " ldb " << p.ldb << " info " << p.info << std::endl; return os; } }; #if 0 /* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info); #endif template< typename float_t > inline void xgesv_call( xgesv_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void xgesv_call( xgesv_params< float >& p ) { sgesv_( &p.n, &p.nrhs, p.a, &p.lda, p.ipiv, p.b, &p.ldb, &p.info ); } template<> inline void xgesv_call( xgesv_params< double >& p ) { dgesv_( &p.n, &p.nrhs, p.a, &p.lda, p.ipiv, p.b, &p.ldb, &p.info ); } template< size_t M, size_t N, typename float_t > struct gaussian_elimination { // computes x ( Ax = b ). x replaces b on output. void compute( matrix< N, N, float_t >& A, matrix< N, M, float_t >& b ); void compute( matrix< N, N, float_t >& A, vector< N, float_t >& b ); gaussian_elimination(); ~gaussian_elimination(); const lapack::xgesv_params< float_t >& get_params() { return p; } lapack::xgesv_params< float_t > p; }; // struct lapack_linear_least_squares template< size_t M, size_t N, typename float_t > void gaussian_elimination< M, N, float_t >:: compute( matrix< N, N, float_t >& A, matrix< N, M, float_t >& b ) { p.a = A.array; p.b = b.array; lapack::xgesv_call( p ); if ( p.info != 0 ) { if ( p.info < 0 ) VMMLIB_ERROR( "invalid value in input matrix", VMMLIB_HERE ); else VMMLIB_ERROR( "factor U is exactly singular, solution could not be computed.", VMMLIB_HERE ); } } template< size_t M, size_t N, typename float_t > void gaussian_elimination< M, N, float_t >:: compute( matrix< N, N, float_t >& A, vector< N, float_t >& b ) { p.a = A.array; p.b = b.array; lapack::xgesv_call( p ); if ( p.info != 0 ) { if ( p.info < 0 ) VMMLIB_ERROR( "invalid value in input matrix", VMMLIB_HERE ); else VMMLIB_ERROR( "factor U is exactly singular, solution could not be computed.", VMMLIB_HERE ); } } template< size_t M, size_t N, typename float_t > gaussian_elimination< M, N, float_t >:: gaussian_elimination() { p.n = N; p.nrhs = M; p.lda = N; p.ldb = N; p.ipiv = new lapack_int[ N ]; } template< size_t M, size_t N, typename float_t > gaussian_elimination< M, N, float_t >:: ~gaussian_elimination() { delete[] p.ipiv; } } // namespace lapack } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_includes.hpp000066400000000000000000000004411231531733200261270ustar00rootroot00000000000000#ifndef __VMML__LAPACK_INCLUDES__HPP__ #define __VMML__LAPACK_INCLUDES__HPP__ #ifdef __APPLE__ #include #else extern "C" { #include #include } #endif #endif /* __VMML__LAPACK_INCLUDES__HPP__ */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_linear_least_squares.hpp000066400000000000000000000170421231531733200305330ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_LAPACK_LINEAR_LEAST_SQUARES__HPP__ #define __VMML__VMMLIB_LAPACK_LINEAR_LEAST_SQUARES__HPP__ #include #include #include #include #include #include /** * * this is a wrapper for the following lapack routines: * * xGELS * * */ namespace vmml { // XYYZZZ // X = data type: S - float, D - double // YY = matrix type, GE - general, TR - triangular // ZZZ = function name namespace lapack { // // // SGELS/DGELS // // // parameter struct template< typename float_t > struct llsq_params_xgels { char trans; // 'N'->A, 'T'->Atransposed lapack_int m; // number of rows, M >= 0 lapack_int n; // number of columns, N >= 0 lapack_int nrhs; // number of columns of B/X float_t* a; // input A lapack_int lda; // leading dimension of A (number of rows) float_t* b; // input B, output X lapack_int ldb; // leading dimension of b float_t* work; // workspace lapack_int lwork; // workspace size lapack_int info; // 'return' value friend std::ostream& operator << ( std::ostream& os, const llsq_params_xgels< float_t >& p ) { os << " m " << p.m << " n " << p.n << " nrhs " << p.nrhs << " lda " << p.lda << " ldb " << p.ldb << " lwork " << p.lwork << " info " << p.info << std::endl; return os; } }; // call wrappers #if 0 void dgels_(const char *trans, const int *M, const int *N, const int *nrhs, double *A, const int *lda, double *b, const int *ldb, double *work, const int * lwork, int *info); #endif template< typename float_t > inline void llsq_call_xgels( llsq_params_xgels< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void llsq_call_xgels( llsq_params_xgels< float >& p ) { sgels_( &p.trans, &p.m, &p.n, &p.nrhs, p.a, &p.lda, p.b, &p.ldb, p.work, &p.lwork, &p.info ); } template<> inline void llsq_call_xgels( llsq_params_xgels< double >& p ) { dgels_( &p.trans, &p.m, &p.n, &p.nrhs, p.a, &p.lda, p.b, &p.ldb, p.work, &p.lwork, &p.info ); } template< size_t M, size_t N, typename float_t > struct linear_least_squares_xgels { bool compute( const matrix< M, N, float_t >& A, const vector< M, float_t >& B, vector< N, float_t >& x ); linear_least_squares_xgels(); ~linear_least_squares_xgels(); const lapack::llsq_params_xgels< float_t >& get_params(){ return p; }; matrix< M, N, float_t >& get_factorized_A() { return _A; } protected: matrix< M, N, float_t > _A; vector< M, float_t > _b; llsq_params_xgels< float_t > p; }; template< size_t M, size_t N, typename float_t > bool linear_least_squares_xgels< M, N, float_t >::compute( const matrix< M, N, float_t >& A, const vector< M, float_t >& B, vector< N, float_t >& x ) { _A = A; _b = B; llsq_call_xgels( p ); // success if ( p.info == 0 ) { for( size_t index = 0; index < N; ++index ) { x( index ) = _b( index ); } return true; } if ( p.info < 0 ) { VMMLIB_ERROR( "xGELS - invalid argument.", VMMLIB_HERE ); } else { std::cout << "A\n" << A << std::endl; std::cout << "B\n" << B << std::endl; VMMLIB_ERROR( "least squares solution could not be computed.", VMMLIB_HERE ); } return false; } template< size_t M, size_t N, typename float_t > linear_least_squares_xgels< M, N, float_t >:: linear_least_squares_xgels() { p.trans = 'N'; p.m = M; p.n = N; p.nrhs = 1; p.a = _A.array; p.lda = M; p.b = _b.array; p.ldb = M; p.work = new float_t(); p.lwork = -1; // workspace query llsq_call_xgels( p ); p.lwork = static_cast< lapack_int > ( p.work[0] ); delete p.work; p.work = new float_t[ p.lwork ]; } template< size_t M, size_t N, typename float_t > linear_least_squares_xgels< M, N, float_t >:: ~linear_least_squares_xgels() { delete[] p.work; } // // // SGESV/DGESV // // template< typename float_t > struct llsq_params_xgesv { lapack_int n; // order of matrix A = M * N lapack_int nrhs; // number of columns of B float_t* a; // input A, output P*L*U lapack_int lda; // leading dimension of A (for us: number of rows) lapack_int* ipiv; // pivot indices, integer array of size N float_t* b; // input b, output X lapack_int ldb; // leading dimension of b lapack_int info; friend std::ostream& operator << ( std::ostream& os, const llsq_params_xgesv< float_t >& p ) { os << "n " << p.n << " nrhs " << p.nrhs << " lda " << p.lda << " ldb " << p.ldvt << " info " << p.info << std::endl; return os; } }; #if 0 /* Subroutine */ int dgesv_(integer *n, integer *nrhs, doublereal *a, integer *lda, integer *ipiv, doublereal *b, integer *ldb, integer *info); #endif template< typename float_t > inline void llsq_call_xgesv( llsq_params_xgesv< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void llsq_call_xgesv( llsq_params_xgesv< float >& p ) { sgesv_( &p.n, &p.nrhs, p.a, &p.lda, p.ipiv, p.b, &p.ldb, &p.info ); } template<> inline void llsq_call_xgesv( llsq_params_xgesv< double >& p ) { dgesv_( &p.n, &p.nrhs, p.a, &p.lda, p.ipiv, p.b, &p.ldb, &p.info ); } template< size_t M, size_t N, typename float_t > struct linear_least_squares_xgesv { // computes x ( Ax = b ). x replaces b on output. void compute( matrix< N, N, float_t >& A, matrix< N, M, float_t >& b ); linear_least_squares_xgesv(); ~linear_least_squares_xgesv(); const lapack::llsq_params_xgesv< float_t >& get_params() { return p; } lapack::llsq_params_xgesv< float_t > p; }; // struct lapack_linear_least_squares template< size_t M, size_t N, typename float_t > void linear_least_squares_xgesv< M, N, float_t >:: compute( matrix< N, N, float_t >& A, matrix< N, M, float_t >& b ) { p.a = A.array; p.b = b.array; lapack::llsq_call_xgesv( p ); if ( p.info != 0 ) { if ( p.info < 0 ) VMMLIB_ERROR( "invalid value in input matrix", VMMLIB_HERE ); else VMMLIB_ERROR( "factor U is exactly singular, solution could not be computed.", VMMLIB_HERE ); } } template< size_t M, size_t N, typename float_t > linear_least_squares_xgesv< M, N, float_t >:: linear_least_squares_xgesv() { p.n = N; p.nrhs = M; p.lda = N; p.ldb = N; p.ipiv = new lapack_int[ N ]; } template< size_t M, size_t N, typename float_t > linear_least_squares_xgesv< M, N, float_t >:: ~linear_least_squares_xgesv() { delete[] p.ipiv; } } // namespace lapack } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_svd.hpp000066400000000000000000000162511231531733200251230ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_LAPACK_SVD__HPP__ #define __VMML__VMMLIB_LAPACK_SVD__HPP__ #include #include #include #include #include #include /** * * a wrapper for lapack's DGESVD routine. * * returns a boolean to indicate success of the operation. * if the return value is false, you can get the parameters using * get_params(). * error states: * * INFO (output) INTEGER * = 0: successful exit. * < 0: if INFO = -i, the i-th argument had an illegal value. * > 0: if DBDSQR did not converge, INFO specifies how many * superdiagonals of an intermediate bidiagonal form B * did not converge to zero. See the description of WORK * above for details. * * more information in: http://www.netlib.org/lapack/double/dgesvd.f ** */ namespace vmml { namespace lapack { // XYYZZZ // X = data type: S - float, D - double // YY = matrix type, GE - general, TR - triangular // ZZZ = function name template< typename float_t > struct svd_params { char jobu; char jobvt; lapack_int m; lapack_int n; float_t* a; lapack_int lda; float_t* s; float_t* u; lapack_int ldu; float_t* vt; lapack_int ldvt; float_t* work; lapack_int lwork; lapack_int info; friend std::ostream& operator << ( std::ostream& os, const svd_params< float_t >& p ) { os << "jobu " << p.jobu << " jobvt " << p.jobvt << " m " << p.m << " n " << p.n << " lda " << p.lda << " ldu " << p.ldu << " ldvt " << p.ldvt << " lwork " << p.lwork << " info " << p.info << std::endl; return os; } }; #if 0 /* Subroutine */ int dgesvd_(char *jobu, char *jobvt, integer *m, integer *n, doublereal *a, integer *lda, doublereal *s, doublereal *u, integer * ldu, doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, integer *info); #endif template< typename float_t > inline void svd_call( svd_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void svd_call( svd_params< float >& p ) { //std::cout << "calling lapack svd (single precision) " << std::endl; sgesvd_( &p.jobu, &p.jobvt, &p.m, &p.n, p.a, &p.lda, p.s, p.u, &p.ldu, p.vt, &p.ldvt, p.work, &p.lwork, &p.info ); } template<> inline void svd_call( svd_params< double >& p ) { //std::cout << "calling lapack svd (double precision) " << std::endl; dgesvd_( &p.jobu, &p.jobvt, &p.m, &p.n, p.a, &p.lda, p.s, p.u, &p.ldu, p.vt, &p.ldvt, p.work, &p.lwork, &p.info ); } } // namespace lapack template< size_t M, size_t N, typename float_t > struct lapack_svd { lapack_svd(); ~lapack_svd(); // slow version, full SVD, use if all values of U(MXM) and Vt(NXN) are needed bool compute_full( const matrix< M, N, float_t >& A, matrix< M, M, float_t >& U, vector< N, float_t >& sigma, matrix< N, N, float_t >& Vt ); // version of reduced SVD, computes only most significant left and right singular vectors, // i.e., use if U(MXN) and Vt(NXN) are needed bool compute( const matrix< M, N, float_t >& A, matrix< M, N, float_t >& U, vector< N, float_t >& sigma, matrix< N, N, float_t >& Vt ); // overwrites A with the result U, bool compute_and_overwrite_input( matrix< M, N, float_t >& A_U, vector< N, float_t >& sigma ); // fast version, use if only sigma is needed. bool compute( const matrix< M, N, float_t >& A, vector< N, float_t >& sigma ); inline bool test_success( lapack::lapack_int info ); lapack::svd_params< float_t > p; const lapack::svd_params< float_t >& get_params(){ return p; }; }; // struct lapack_svd template< size_t M, size_t N, typename float_t > lapack_svd< M, N, float_t >::lapack_svd() { p.jobu = 'N'; p.jobvt = 'N'; p.m = M; p.n = N; p.a = 0; p.lda = M; p.s = 0; p.u = 0; p.ldu = M; p.vt = 0; p.ldvt = 1; p.work = new float_t; p.lwork = -1; // workspace query lapack::svd_call( p ); p.lwork = static_cast< lapack::lapack_int >( p.work[0] ); delete p.work; p.work = new float_t[ p.lwork ]; } template< size_t M, size_t N, typename float_t > lapack_svd< M, N, float_t >::~lapack_svd() { delete[] p.work; } template< size_t M, size_t N, typename float_t > bool lapack_svd< M, N, float_t >::compute_full( const matrix< M, N, float_t >& A, matrix< M, M, float_t >& U, vector< N, float_t >& S, matrix< N, N, float_t >& Vt ) { // lapack destroys the contents of the input matrix typedef matrix< M, N, float_t > m_type; m_type* AA = new m_type( A ); p.jobu = 'A'; p.jobvt = 'A'; p.a = AA->array; p.u = U.array; p.s = S.array; p.vt = Vt.array; p.ldvt = N; lapack::svd_call< float_t >( p ); delete AA; return p.info == 0; } template< size_t M, size_t N, typename float_t > bool lapack_svd< M, N, float_t >::compute( const matrix< M, N, float_t >& A, matrix< M, N, float_t >& U, vector< N, float_t >& S, matrix< N, N, float_t >& Vt ) { // lapack destroys the contents of the input matrix typedef matrix< M, N, float_t > m_type; m_type* AA = new m_type( A ); p.jobu = 'S'; p.jobvt = 'S'; p.a = AA->array; p.u = U.array; p.s = S.array; p.vt = Vt.array; p.ldvt = N; lapack::svd_call< float_t >( p ); delete AA; return p.info == 0; } template< size_t M, size_t N, typename float_t > bool lapack_svd< M, N, float_t >::compute_and_overwrite_input( matrix< M, N, float_t >& A_U, vector< N, float_t >& S ) { p.jobu = 'O'; p.jobvt = 'N'; p.a = A_U.array; p.s = S.array; p.ldvt = N; lapack::svd_call< float_t >( p ); return p.info == 0; } template< size_t M, size_t N, typename float_t > bool lapack_svd< M, N, float_t >::compute( const matrix< M, N, float_t >& A, vector< N, float_t >& S ) { // lapack destroys the contents of the input matrix typedef matrix< M, N, float_t > m_type; m_type* AA = new m_type( A ); p.jobu = 'N'; p.jobvt = 'N'; p.a = AA->array; p.u = 0; p.s = S.array; p.vt = 0; lapack::svd_call< float_t >( p ); delete AA; return p.info == 0; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_sym_eigs.hpp000066400000000000000000000273351231531733200261530ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_LAPACK_SYM_EIGS__HPP__ #define __VMML__VMMLIB_LAPACK_SYM_EIGS__HPP__ #include #include #include #include #include #include #include /** * * a wrapper for lapack's DSYEVX routine. * DSYEVX computes selected eigenvalues and, optionally, eigenvectors * of a real symmetric matrix A. Eigenvalues and eigenvectors can be * selected by specifying either a range of values or a range of indices * for the desired eigenvalues. * * returns a boolean to indicate success of the operation. * if the return value is false, you can get the parameters using * get_params(). * error states: * * INFO (output) INTEGER * = 0: successful exit. * < 0: if INFO = -i, the i-th argument had an illegal value. * > 0: if DBDSQR did not converge, INFO specifies how many * superdiagonals of an intermediate bidiagonal form B * did not converge to zero. See the description of WORK * above for details. * * more information in: http://www.netlib.org/lapack/double/dsyevx.f (see also: * http://www.netlib.org/lapack/double/dsyev.f , but needs more space) ** */ namespace vmml { namespace lapack { // XYYZZZ // X = data type: S - float, D - double // YY = matrix type, GE - general, TR - triangular // ZZZ = function name template< typename float_t > struct eigs_params { char jobz; char range; char uplo; lapack_int n; float_t* a; lapack_int lda; //leading dimension of input array float_t* vl; float_t* vu; lapack_int il; lapack_int iu; float_t abstol; lapack_int m; //number of found eigenvalues float_t* w; //first m eigenvalues float_t* z; //first m eigenvectors lapack_int ldz; //leading dimension of z float_t* work; lapack_int lwork; lapack_int* iwork; lapack_int* ifail; lapack_int info; friend std::ostream& operator << ( std::ostream& os, const eigs_params< float_t >& p ) { os << " (1)\tjobz " << p.jobz << std::endl << " (2)\trange " << p.range << std::endl << " (3)\tuplo " << p.uplo << std::endl << " (4)\tn " << p.n << std::endl << " (5)\ta " << *p.a << std::endl << " (6)\tlda " << p.lda << std::endl << " (7)\tvl " << p.vl << std::endl << " (8)\tvu " << p.vu << std::endl << " (9)\til " << p.il << std::endl << " (10)\tiu " << p.iu << std::endl << " (11)\tabstol " << p.abstol << std::endl << " (12)\tm " << p.m << std::endl << " (13)\tw " << p.w << std::endl << " (14)\tz " << p.z << std::endl << " (15)\tldz " << p.ldz << std::endl << " (16)\twork " << *p.work << std::endl << " (17)\tlwork " << p.lwork << std::endl << " (18)\tiwork " << *p.iwork << std::endl << " (19)\tifail " << *p.ifail << std::endl << " (20)\tinfo " << p.info << std::endl; return os; } }; #if 0 /* Subroutine */ int dsyevx_( char *jobz, char *range, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *vl, doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z, integer *ldz, doublereal *work, integer* lwork, integer* iwork, integer* ifail, integer* info ); #endif template< typename float_t > inline void sym_eigs_call( eigs_params< float_t >& p ) { VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE ); } template<> inline void sym_eigs_call( eigs_params< float >& p ) { //std::cout << "calling lapack sym x eigs (single precision) " << std::endl; ssyevx_( &p.jobz, &p.range, &p.uplo, &p.n, p.a, &p.lda, p.vl, p.vu, &p.il, &p.iu, &p.abstol, &p.m, p.w, p.z, &p.ldz, p.work, &p.lwork, p.iwork, p.ifail, &p.info ); } template<> inline void sym_eigs_call( eigs_params< double >& p ) { //std::cout << "calling lapack sym x eigs (double precision) " << std::endl; dsyevx_( &p.jobz, &p.range, &p.uplo, &p.n, p.a, &p.lda, p.vl, p.vu, &p.il, &p.iu, &p.abstol, &p.m, p.w, p.z, &p.ldz, p.work, &p.lwork, p.iwork, p.ifail, &p.info ); } } // namespace lapack template< size_t N, typename float_t > struct lapack_sym_eigs { typedef matrix< N, N, float_t > m_input_type; typedef matrix< N, N, float_t > evectors_type; typedef vector< N, float_t > evalues_type; typedef vector< N, float_t > evector_type; typedef typename evalues_type::iterator evalue_iterator; typedef typename evalues_type::const_iterator evalue_const_iterator; typedef std::pair< float_t, size_t > eigv_pair_type; lapack_sym_eigs(); ~lapack_sym_eigs(); // version of reduced sym. eigenvalue decomposition, // computes only the x largest magn. eigenvalues and their corresponding eigenvectors template< size_t X> bool compute_x( const m_input_type& A, matrix< N, X, float_t >& eigvectors_, vector< X, float_t >& eigvalues_ ); // partial sym. eigenvalue decomposition // returns only the largest magn. eigenvalue and the corresponding eigenvector bool compute_1st( const m_input_type& A, evector_type& eigvector_, float_t& eigvalue_ ); //computes all eigenvalues and eigenvectors for matrix A bool compute_all( const m_input_type& A, evectors_type& eigvectors_, evalues_type& eigvalues_ ); inline bool test_success( lapack::lapack_int info ); lapack::eigs_params< float_t > p; const lapack::eigs_params< float_t >& get_params(){ return p; }; // comparison functor struct eigenvalue_compare { inline bool operator()( const eigv_pair_type& a, const eigv_pair_type& b ) { return fabs( a.first ) > fabs( b.first ); } }; }; // struct lapack_sym_eigs template< size_t N, typename float_t > lapack_sym_eigs< N, float_t >::lapack_sym_eigs() { p.jobz = 'V'; // Compute eigenvalues and eigenvectors. p.range = 'A'; // all eigenvalues will be found. p.uplo = 'U'; // Upper triangle of A is stored; or Lower triangle of A is stored. p.n = N; p.a = 0; //If UPLO = 'U', the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. p.lda = N; p.vl = 0; //Not referenced if RANGE = 'A' or 'I'. p.vu = 0; //Not referenced if RANGE = 'A' or 'I'. p.il = 0; //Not referenced if RANGE = 'A' or 'V'. p.iu = 0; //Not referenced if RANGE = 'A' or 'V'. p.abstol = 0.0001; //lie in an interval [a,b] of width less than or equal to ABSTOL + EPS * max( |a|,|b| ) p.m = N; //The total number of eigenvalues found. 0 <= M <= N. p.w = 0; //first m eigenvalues p.z = 0; //first m eigenvectors p.ldz = N; // The leading dimension of the array Z. LDZ >= 1, and if JOBZ = 'V', LDZ >= max(1,N). p.work = new float_t; //FIXME: check if correct datatype p.iwork = new lapack::lapack_int[5*N]; //[5*N]; // INTEGER array, dimension (5*N) p.ifail = new lapack::lapack_int[N]; //[N]; p.lwork = -1; //8N // workspace query lapack::sym_eigs_call( p ); p.lwork = static_cast< lapack::lapack_int >( p.work[0] ); delete p.work; p.work = new float_t[ p.lwork ]; } template< size_t N, typename float_t > lapack_sym_eigs< N, float_t >::~lapack_sym_eigs() { delete[] p.work; delete[] p.iwork; delete[] p.ifail; } template< size_t N, typename float_t > bool lapack_sym_eigs< N, float_t >::compute_all( const m_input_type& A, evectors_type& eigvectors_, evalues_type& eigvalues_ ) { // lapack destroys the contents of the input matrix m_input_type* AA = new m_input_type( A ); p.range = 'A'; // all eigenvalues will be found. p.a = AA->array; p.ldz = N; p.w = eigvalues_.array; p.z = eigvectors_.array; //debug std::cout << p << std::endl; lapack::sym_eigs_call< float_t >( p ); delete AA; return p.info == 0; } template< size_t N, typename float_t > template< size_t X > bool lapack_sym_eigs< N, float_t >::compute_x( const m_input_type& A, matrix< N, X, float_t >& eigvectors_, vector< X, float_t >& eigvalues_ ) { //(1) get all eigenvalues and eigenvectors evectors_type* all_eigvectors = new evectors_type; evalues_type* all_eigvalues = new evalues_type; compute_all( A, *all_eigvectors, *all_eigvalues ); //(2) sort the eigenvalues //std::pair< data, original_index >; std::vector< eigv_pair_type >* eig_permutations = new std::vector< eigv_pair_type >; evalue_const_iterator it = all_eigvalues->begin(), it_end = all_eigvalues->end(); size_t counter = 0; for( ; it != it_end; ++it, ++counter ) { eig_permutations->push_back( eigv_pair_type( *it, counter ) ); } std::sort( eig_permutations->begin(), eig_permutations->end(), eigenvalue_compare() ); delete all_eigvalues; //sort the eigenvectors according to eigenvalue permutations evectors_type* sorted_eigvectors = new evectors_type; evalues_type* sorted_eigvalues = new evalues_type; typename std::vector< eigv_pair_type >::const_iterator it2 = eig_permutations->begin(), it2_end = eig_permutations->end(); evalue_iterator evalues_it = sorted_eigvalues->begin(); for( counter = 0; it2 != it2_end; ++it2, ++evalues_it, ++counter ) { *evalues_it = it2->first; sorted_eigvectors->set_column( counter, all_eigvectors->get_column( it2->second )); } delete all_eigvectors; delete eig_permutations; //(3) select the largest magnitude eigenvalues and the corresponding eigenvectors typename vector< X, float_t >::iterator it3 = eigvalues_.begin(), it3_end = eigvalues_.end(); evalues_it = sorted_eigvalues->begin(); for( ; it3 != it3_end; ++it3, ++evalues_it ) { *it3 = *evalues_it; } sorted_eigvectors->get_sub_matrix( eigvectors_ ); delete sorted_eigvectors; delete sorted_eigvalues; return p.info == 0; } template< size_t N, typename float_t > bool lapack_sym_eigs< N, float_t >::compute_1st( const m_input_type& A, evector_type& eigvector_, float_t& eigvalue_ ) { //(1) get all eigenvalues and eigenvectors evectors_type* all_eigvectors = new evectors_type; evalues_type* all_eigvalues = new evalues_type; compute_all( A, *all_eigvectors, *all_eigvalues ); //(2) sort the eigenvalues //std::pair< data, original_index >; std::vector< eigv_pair_type >* eig_permutations = new std::vector< eigv_pair_type >; evalue_const_iterator it = all_eigvalues->begin(), it_end = all_eigvalues->end(); size_t counter = 0; for( ; it != it_end; ++it, ++counter ) { eig_permutations->push_back( eigv_pair_type( *it, counter ) ); } std::sort( eig_permutations->begin(), eig_permutations->end(), eigenvalue_compare() ); //(2) select the largest magnitude eigenvalue and the corresponding eigenvector typename std::vector< eigv_pair_type >::const_iterator it2 = eig_permutations->begin(); eigvalue_ = it2->first; all_eigvectors->get_column( it2->second, eigvector_ ); delete eig_permutations; delete all_eigvalues; delete all_eigvectors; return p.info == 0; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lapack_types.hpp000066400000000000000000000004611231531733200254670ustar00rootroot00000000000000#ifndef __VMML__LAPACK_TYPES__HPP__ #define __VMML__LAPACK_TYPES__HPP__ #include "lapack_includes.hpp" namespace vmml { namespace lapack { #ifdef __APPLE__ typedef __CLPK_integer lapack_int; #else typedef integer lapack_int; #endif } // namespace lapack } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/linear_least_squares.hpp000066400000000000000000000053131231531733200272160ustar00rootroot00000000000000#ifndef __VMML__LINEAR_LEAST_SQUARES__HPP__ #define __VMML__LINEAR_LEAST_SQUARES__HPP__ #include #include "matrix_mxn.hpp" namespace vmml { // beta_hat = ( Xt * X )^-1 * Xt * y; // beta_hat -> best-fit 'solutions' to a,b = [ a,b ]transposed. // TODO FIXME what about the constant??? struct linear_least_squares { template< size_t number_of_data_points, size_t number_of_unknowns, typename float_t > vmml::matrix_mxn< number_of_unknowns, 1, float_t > solve( std::vector< Vector3< float_t > >& data_points, float_t tolerance = 1e-9 ) { assert( data_points.size() >= number_of_data_points ); matrix_mxn< number_of_data_points, number_of_unknowns, float_t > X; matrix_mxn< number_of_data_points, 1, float_t > y; for( size_t nb_index = 0; nb_index < number_of_data_points; ++nb_index ) { float_t x = data_points[ nb_index ].x; for( size_t index = 0; index < number_of_unknowns; ++index ) { X[ nb_index ][ index ] = x; x *= x; } y[ nb_index ][ 0 ] = data_points[ nb_index ].y; } std::cout << X << std::endl; vmml::matrix_mxn< number_of_unknowns, number_of_data_points > Xt; X.transposeTo( Xt ); std::cout << Xt << std::endl; vmml::matrix_mxm< number_of_unknowns > XtX; XtX.mul( Xt, X ); vmml::matrix_mxm< number_of_unknowns > XtX_inverse; XtX.computeInverse( XtX_inverse, tolerance ); vmml::matrix_mxn< number_of_unknowns, number_of_data_points > XtX_inv_mul_Xt; XtX_inv_mul_Xt.mul( XtX_inverse, Xt ); vmml::matrix_mxn< number_of_unknowns, 1 > beta_hat; beta_hat.mul( XtX_inv_mul_Xt, y ); std::cout << beta_hat << std::endl; return beta_hat; } template< size_t number_of_data_points, size_t number_of_unknowns, typename float_t > vmml::matrix_mxn< number_of_unknowns, 1, float_t > solve_using_qr_decomposition( std::vector< Vector3< float_t > >& data_points, float_t tolerance = 1e-9 ) { assert( data_points.size() >= number_of_data_points ); matrix_mxn< number_of_data_points, number_of_unknowns, float_t > X; matrix_mxn< number_of_data_points, 1, float_t > y; // r = y - X * Beta // X = Q*R // Qt * r = Qt * y - ( Qt * Q ) R * Beta = // // | ( Qt * y )_n - R_n * Beta | | U | // | ( Qt * y )_m-n | = | L | // // S = rt * Q * Qt * r = rt * r // // S = Ut * U + Lt * L // // => R_n * BetaHat = ( Qt * y )_n // vmml::matrix_mxn< number_of_unknowns, 1 > beta_hat; return beta_hat; } template< size_t number_of_data_points, size_t number_of_unknowns, typename float_t > vmml::matrix_mxn< number_of_unknowns, 1, float_t > solve_using_svd( std::vector< Vector3< float_t > >& data_points, float_t tolerance = 1e-9 ) { } }; } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/lowpass_filter.hpp000066400000000000000000000036471231531733200260560ustar00rootroot00000000000000/* * VMMLib - Filter classes * * @author Jafet Villafranca * * Implements low pass filtering on a templated data type, which needs to * implement multiplication by a scalar float for smoothing. * */ #ifndef __VMML__LOWPASS_FILTER__HPP__ #define __VMML__LOWPASS_FILTER__HPP__ #include namespace vmml { template< size_t M, typename T > class lowpass_filter { public: /** Constructor @param[in] F Smooth factor to use during the filter process */ lowpass_filter( const float F ) : _smooth_factor(F) {} ~lowpass_filter() {} /** Filter the content of the data structure @return The filtered output value */ const T& get() const { return _value; } /** Access the filtered value. */ const T* operator->() const { return &_value; } /** Access the filtered value. */ const T& operator*() const { return _value; } /** Add a value to the data set and return the filtered output @param[in] value Value to add @return The filtered output value */ T add( const T& value ); /** Sets the smooth factor @param[in] f Smooth factor to use during the filter process */ void set_smooth_factor( const float& f ); private: std::deque< T > _data; float _smooth_factor; T _value; }; template< size_t M, typename T > T lowpass_filter< M, T >::add( const T& value ) { _data.push_front( value ); while( _data.size() > M ) _data.pop_back(); // update typename std::deque< T >::const_iterator i = _data.begin(); _value = *i; double weight = _smooth_factor; for( ++i ; i != _data.end(); ++i ) { _value = _value * (1 - weight) + (*i) * weight; weight *= _smooth_factor; } return _value; } template< size_t M, typename T > void lowpass_filter< M, T>::set_smooth_factor( const float& f ) { _smooth_factor = f; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/math.hpp000066400000000000000000000017361231531733200237470ustar00rootroot00000000000000#ifndef __VMML__MATH__HPP__ #define __VMML__MATH__HPP__ #include namespace vmml { namespace math { // helpers for certain cmath functions template< class T > inline T squared( const T a ) { return ( a == 0.0 ) ? 0.0 : a * a; } /* * Computes (a2 + b2)1/2 without destructive underflow or overflow. */ template< class T > inline T pythag( T a, T b ) { a = fabs(a); b = fabs(b); if ( a > b ) return a * sqrt( 1.0 + squared( b / a ) ); else return ( b == 0.0 ) ? 0.0 : b * sqrt( 1.0 + squared( a / b ) ); } template< class T > inline T sign( T a, T b ) { return ( b >= 0.0 ) ? fabs( a ) : -fabs( a ); } template< typename T > struct abs_less { T operator()( const T& a, const T& b ) { return fabs(a) < fabs( b ); } }; template< typename T > struct abs_greater { T operator()( const T& a, const T& b ) { return fabs(a) > fabs( b ); } }; } // namespace math } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/matrix.hpp000066400000000000000000002246261231531733200243270ustar00rootroot00000000000000#ifndef __VMML__MATRIX__HPP__ #define __VMML__MATRIX__HPP__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // file I/O namespace vmml { // matrix of type T with m rows and n columns template< size_t M, size_t N, typename T = float > class matrix { public: typedef T value_type; typedef T* pointer; typedef T& reference; typedef T* iterator; typedef const T* const_iterator; typedef std::reverse_iterator< iterator > reverse_iterator; typedef std::reverse_iterator< const_iterator > const_reverse_iterator; static const size_t ROWS = M; static const size_t COLS = N; // accessors inline T& operator()( size_t row_index, size_t col_index ); inline const T& operator()( size_t row_index, size_t col_index ) const; inline T& at( size_t row_index, size_t col_index ); inline const T& at( size_t row_index, size_t col_index ) const; // element iterators - NOTE: column-major order iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; reverse_iterator rbegin(); reverse_iterator rend(); const_reverse_iterator rbegin() const; const_reverse_iterator rend() const; // ctors // note: this ctor does not initialize anything because of performance reasons. matrix(); template< size_t P, size_t Q, typename U > matrix( const matrix< P, Q, U >& source_ ); #ifndef VMMLIB_NO_CONVERSION_OPERATORS // auto conversion operator operator T*(); operator const T*() const; #endif bool operator==( const matrix& other ) const; bool operator!=( const matrix& other ) const; // due to limited precision, two 'identical' matrices might seem different. // this function allows to specify a tolerance when comparing matrices. bool equals( const matrix& other, T tolerance ) const; // this version takes a comparison functor to compare the components of // the two matrices template< typename compare_t > bool equals( const matrix& other, compare_t& cmp ) const; void multiply_piecewise( const matrix& other ); // (this) matrix = left matrix_mxp * right matrix_pxn template< size_t P > void multiply( const matrix< M, P, T >& left, const matrix< P, N, T >& right ); // convolution operation (extending borders) of (this) matrix and the given kernel template< size_t U, size_t V > void convolve(const matrix< U, V, T >& kernel); // returned matrix_mxp = (this) matrix * other matrix_nxp; // note: using multiply(...) it avoids a copy of the resulting matrix template< size_t P > matrix< M, P, T > operator*( const matrix< N, P, T >& other ) const; // operator *= is only enabled for square matrices template< size_t O, size_t P, typename TT > typename enable_if< M == N && O == P && M == O, TT >::type* operator*=( const matrix< O, P, TT >& right ); inline matrix operator+( const matrix& other ) const; inline matrix operator-( const matrix& other ) const; void operator+=( const matrix& other ); void operator-=( const matrix& other ); void operator+=( T scalar ); void operator-=( T scalar ); template< size_t O, size_t P, size_t Q, size_t R > typename enable_if< M == O + Q && N == P + R >::type* direct_sum( const matrix< O, P, T >& m0, const matrix< Q, R, T >& m1 ); // // matrix-scalar operations / scaling // matrix operator*( T scalar ); void operator*=( T scalar ); matrix operator/( T scalar ); void operator/=( T scalar ); // // matrix-vector operations // // transform column vector by matrix ( vec = matrix * vec ) vector< M, T > operator*( const vector< N, T >& other ) const; // transform column vector by matrix ( vec = matrix * vec ) // assume homogenous coords, e.g. vec3 = mat4x4 * vec3, with w = 1.0 template< size_t O > vector< O, T > operator*( const vector< O, T >& vector_ ) const; inline matrix< M, N, T > operator-() const; matrix< M, N, T > negate() const; // compute tensor product: (this) = vector (X) vector void tensor( const vector< M, T >& u, const vector< N, T >& v ); // tensor, for api compatibility with old vmmlib version. // WARNING: for M = N = 4 only. template< size_t uM, size_t vM > typename enable_if< uM == 3 && vM == 3 && M == N && M == 4 >::type* tensor( const vector< uM, T >& u, const vector< vM, T >& v ); // row_offset and col_offset define the starting indices for the sub_matrix // the sub_matrix is extracted according to the size of the target matrix, i.e. ( OXP ) template< size_t O, size_t P > matrix< O, P, T > get_sub_matrix( size_t row_offset, size_t col_offset, typename enable_if< O <= M && P <= N >::type* = 0 ) const; template< size_t O, size_t P > typename enable_if< O <= M && P <= N >::type* get_sub_matrix( matrix< O, P, T >& result, size_t row_offset = 0, size_t col_offset = 0 ) const; template< size_t O, size_t P > typename enable_if< O <= M && P <= N >::type* set_sub_matrix( const matrix< O, P, T >& sub_matrix, size_t row_offset = 0, size_t col_offset = 0 ); // copies a transposed version of *this into transposedMatrix void transpose_to( matrix< N, M, T >& transpose_ ) const; //symmetric covariance matrix of a right matrix multiplication: MxN x NxM = MxM void symmetric_covariance( matrix< M, M, T >& cov_m_ ) const; const matrix& operator=( const matrix< M, N, T >& source_ ); // these assignment operators return nothing to avoid silent loss of // precision template< size_t P, size_t Q, typename U > void operator=( const matrix< P, Q, U >& source_ ); void operator=( const T old_fashioned_matrix[ M ][ N ] ); // WARNING: data_array[] must be at least of size M * N - otherwise CRASH! // WARNING: assumes row_by_row layout - if this is not the case, // use matrix::set( data_array, false ) void operator=( const T* data_array ); void operator=( const std::vector< T >& data ); // sets all elements to fill_value void operator=( T fill_value ); void fill( T fill_value ); // note: this function copies elements until either the matrix is full or // the iterator equals end_. template< typename input_iterator_t > void set( input_iterator_t begin_, input_iterator_t end_, bool row_major_layout = true ); //sets all matrix values with random values //remember to set srand( seed ); //if seed is set to -1, srand( seed ) was set outside set_random //otherwise srand( seed ) will be called with the given seed void set_random( int seed = -1 ); //sets all matrix values with discrete cosine transform coefficients (receive orthonormal coefficients) void set_dct(); void zero(); void identity(); double frobenius_norm() const; double p_norm( double p ) const; template< typename TT > void cast_from( const matrix< M, N, TT >& other ); void read_csv_file( const std::string& dir_, const std::string& filename_ ); void write_csv_file( const std::string& dir_, const std::string& filename_ ) const; void write_to_raw( const std::string& dir_, const std::string& filename_ ) const; void read_from_raw( const std::string& dir_, const std::string& filename_ ) ; template< typename TT > void quantize_to( matrix< M, N, TT >& quantized_, const T& min_value, const T& max_value ) const; template< typename TT > void quantize( matrix< M, N, TT >& quantized_, T& min_value, T& max_value ) const; template< typename TT > void dequantize( matrix< M, N, TT >& quantized_, const TT& min_value, const TT& max_value ) const; void columnwise_sum( vector< N, T>& summed_columns_ ) const; double sum_elements() const; void sum_rows( matrix< M/2, N, T>& other ) const; void sum_columns( matrix< M, N/2, T>& other ) const; template< size_t R > typename enable_if< R == M && R == N >::type* diag( const vector< R, T >& diag_values_ ); //Khatri-Rao Product: columns must be of same size template< size_t O > void khatri_rao_product( const matrix< O, N, T >& right_, matrix< M*O, N, T >& prod_ ) const; //Kronecker Product: MxN x_kronecker OxP = M*OxN*P template< size_t O, size_t P > void kronecker_product( const matrix< O, P, T >& right_, matrix< M*O, N*P, T >& result_) const; T get_min() const; T get_max() const; T get_abs_min() const; T get_abs_max() const; //returns number of non-zeros size_t nnz() const; size_t nnz( const T& threshold_ ) const; void threshold( const T& threshold_value_ ); vector< M, T > get_column( size_t column_index ) const; void get_column( size_t column_index, vector< M, T>& column ) const; void set_column( size_t index, const vector< M, T >& column ); void get_column( size_t index, matrix< M, 1, T >& column ) const; void set_column( size_t index, const matrix< M, 1, T >& column ); vector< N, T > get_row( size_t index ) const; void get_row( size_t index, vector< N, T >& row ) const; void set_row( size_t index, const vector< N, T >& row ); void get_row( size_t index, matrix< 1, N, T >& row ) const; void set_row( size_t index, const matrix< 1, N, T >& row ); size_t size() const; // return M * N; size_t get_number_of_rows() const; size_t get_number_of_columns() const; T det() const; // the return value indicates if the matrix is invertible. // we need a tolerance term since the computation of the determinant is // subject to precision errors. template< size_t O, size_t P, typename TT > bool inverse( matrix< O, P, TT >& inverse_, T tolerance = std::numeric_limits::epsilon(), typename enable_if< M == N && O == P && O == M && M >= 2 && M <= 4, TT >::type* = 0 ) const; template< size_t O, size_t P > typename enable_if< O == P && M == N && O == M && M >= 2 >::type* get_adjugate( matrix< O, P, T >& adjugate ) const; template< size_t O, size_t P > typename enable_if< O == P && M == N && O == M && M >= 2 >::type* get_cofactors( matrix< O, P, T >& cofactors ) const; // returns the determinant of a square matrix M-1, N-1 template< size_t O, size_t P > T get_minor( matrix< O, P, T >& minor_, size_t row_to_cut, size_t col_to_cut, typename enable_if< O == M-1 && P == N-1 && M == N && M >= 2 >::type* = 0 ) const; // // 4*4 matrices only // /** create rotation matrix from parameters. * @param angle - angle in radians * @param rotation axis - must be normalized! */ template< typename TT > matrix< M, N, T >& rotate( const TT angle, const vector< M-1, T >& axis, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& rotate_x( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& rotate_y( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& rotate_z( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& pre_rotate_x( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& pre_rotate_y( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& pre_rotate_z( const TT angle, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& scale( const TT scale[3], typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& scale( const TT x_, const T y, const T z, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& scale( const vector< 3, TT >& scale_, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& scale_translation( const TT scale_[3], typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& scale_translation( const vector< 3, TT >& scale_, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& set_translation( const TT x_, const TT y_, const TT z_, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& set_translation( const TT trans[3], typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > matrix< M, N, T >& set_translation( const vector< 3, TT >& t, typename enable_if< M == N && M == 4, TT >::type* = 0 ); template< typename TT > void get_translation( vector< 3, TT >& translation_, typename enable_if< M == N && M == 4, TT >::type* = 0 ) const; // hack for static-member-init template< typename init_functor_t > static const matrix get_initialized_matrix(); inline T& x(); inline T& y(); inline T& z(); // tests every component for isnan && isinf // inline bool is_valid() const; -> moved to class validator // legacy/compatibility accessor struct row_accessor { row_accessor( T* array_ ) : array( array_ ) {} T& operator[]( size_t col_index ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( col_index >= N ) VMMLIB_ERROR( "column index out of bounds", VMMLIB_HERE ); #endif return array[ col_index * M ]; } const T& operator[]( size_t col_index ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( col_index >= N ) VMMLIB_ERROR( "column index out of bounds", VMMLIB_HERE ); #endif return array[ col_index * M ]; } T* array; private: row_accessor() {} // disallow std ctor }; // this is a hack to allow array-style access to matrix elements // usage: matrix< 2, 2, float > m; m[ 1 ][ 0 ] = 37.0f; inline row_accessor operator[]( size_t row_index ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index > M ) VMMLIB_ERROR( "row index out of bounds", VMMLIB_HERE ); #endif return row_accessor( array + row_index ); } // this is a hack to remove a warning about implicit conversions inline row_accessor operator[]( int row_index ) { return ( *this )[ size_t ( row_index ) ]; } friend std::ostream& operator << ( std::ostream& os, const matrix< M, N, T >& matrix ) { #ifdef EQFABRIC_API_H const std::ios::fmtflags flags = os.flags(); const int prec = os.precision(); os.setf( std::ios::right, std::ios::adjustfield ); os.precision( 5 ); for( size_t row_index = 0; row_index < M; ++row_index ) { os << "|"; for( size_t col_index = 0; col_index < N; ++col_index ) { os << std::setw(10) << matrix.at( row_index, col_index ) << " "; } os << "|" << std::endl; } os.precision( prec ); os.setf( flags ); #else for( size_t row_index = 0; row_index < M; ++row_index ) { os << "("; for( size_t col_index = 0; col_index < N; ++col_index ) { if( sizeof(T) ==sizeof(unsigned char)) { os << int(matrix.at( row_index, col_index )); } else { os << matrix.at( row_index, col_index ); } if (col_index + 1 < N ) os << ", "; } os << ")" << std::endl; } #endif return os; }; // protected: // column_by_column VMMLIB_ALIGN( T array[ M * N ] ); // static members static const matrix< M, N, T > IDENTITY; static const matrix< M, N, T > ZERO; }; // class matrix #ifndef VMMLIB_NO_TYPEDEFS typedef matrix< 3, 3, float > mat3f; typedef matrix< 3, 3, double > mat3d; typedef matrix< 4, 4, float > mat4f; typedef matrix< 4, 4, double > mat4d; #endif /* * free functions */ template< size_t M, size_t N, typename T > bool equals( const matrix< M, N, T >& m0, const matrix< M, N, T >& m1, const T tolerance = std::numeric_limits< T >::epsilon()) { return m0.equals( m1, tolerance ); } template< size_t M, size_t N, typename T > inline void multiply( const matrix< M, N, T >& left, const matrix< M, N, T >& right, matrix< M, N, T >& result ) { result.multiply( left, right ); } template< size_t M, size_t N, typename T > template< size_t U, size_t V > void matrix< M, N, T>::convolve(const matrix< U, V, T >& kernel) { matrix< M, N, T> temp; // do not override original values instantly as old values are needed for calculation for(size_t y_ = 0; y_ < N; ++y_) { for(size_t x_ = 0; x_ < M; ++x_) { double sum = 0.0; for(size_t j = 0; j < V; ++j) { int srcy = y_ - V/2 + j; // Extending border values if(srcy < 0) srcy = 0; if(srcy >= int(N)) srcy = N-1; for(size_t i = 0; i < U; ++i) { int srcx = x_ - U/2 + i; // Extending border values if(srcx < 0) srcx = 0; if(srcx >= int(M)) srcx = M-1; sum += kernel.at(j,i) * at(srcy,srcx); } } temp.at(y_,x_) = sum; } } *this = temp; } template< size_t M, size_t N, size_t P, typename T > inline void multiply( const matrix< M, P, T >& left, const matrix< P, N, T >& right, matrix< M, N, T >& result ) { result.multiply( left, right ); } template< size_t M, size_t N, typename T > inline typename enable_if< M == N >::type* identity( matrix< M, N, T >& matrix_ ) { matrix_ = static_cast< T >( 0.0 ); for( size_t index = 0; index < M; ++index ) { matrix_( index, index ) = static_cast< T >( 1.0 ); } return 0; // for sfinae } template< typename T > inline T compute_determinant( const matrix< 1, 1, T >& matrix_ ) { return matrix_.array[ 0 ]; } template< typename T > inline T compute_determinant( const matrix< 2, 2, T >& matrix_ ) { const T& a = matrix_( 0, 0 ); const T& b = matrix_( 0, 1 ); const T& c = matrix_( 1, 0 ); const T& d = matrix_( 1, 1 ); return a * d - b * c; } template< typename T > inline T compute_determinant( const matrix< 3, 3, T >& m_ ) { return m_( 0,0 ) * ( m_( 1,1 ) * m_( 2,2 ) - m_( 1,2 ) * m_( 2,1 ) ) + m_( 0,1 ) * ( m_( 1,2 ) * m_( 2,0 ) - m_( 1,0 ) * m_( 2,2 ) ) + m_( 0,2 ) * ( m_( 1,0 ) * m_( 2,1 ) - m_( 1,1 ) * m_( 2,0 ) ); } template< typename T > inline T compute_determinant( const matrix< 4, 4, T >& m ) { T m00 = m( 0, 0 ); T m10 = m( 1, 0 ); T m20 = m( 2, 0 ); T m30 = m( 3, 0 ); T m01 = m( 0, 1 ); T m11 = m( 1, 1 ); T m21 = m( 2, 1 ); T m31 = m( 3, 1 ); T m02 = m( 0, 2 ); T m12 = m( 1, 2 ); T m22 = m( 2, 2 ); T m32 = m( 3, 2 ); T m03 = m( 0, 3 ); T m13 = m( 1, 3 ); T m23 = m( 2, 3 ); T m33 = m( 3, 3 ); return m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 + m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 + m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 + m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 + m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 + m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33; } template< typename T > bool compute_inverse( const matrix< 2, 2, T >& m_, matrix< 2, 2, T >& inverse_, T tolerance_ = std::numeric_limits::epsilon()) { const T det_ = compute_determinant( m_ ); if( fabs( det_ ) < tolerance_ ) return false; const T detinv = static_cast< T >( 1.0 ) / det_; m_.get_adjugate( inverse_ ); // set inverse_ to the adjugate of M inverse_ *= detinv; return true; } template< typename T > bool compute_inverse( const matrix< 3, 3, T >& m_, matrix< 3, 3, T >& inverse_, T tolerance_ = std::numeric_limits::epsilon() ) { // Invert a 3x3 using cofactors. This is about 8 times faster than // the Numerical Recipes code which uses Gaussian elimination. inverse_.at( 0, 0 ) = m_.at( 1, 1 ) * m_.at( 2, 2 ) - m_.at( 1, 2 ) * m_.at( 2, 1 ); inverse_.at( 0, 1 ) = m_.at( 0, 2 ) * m_.at( 2, 1 ) - m_.at( 0, 1 ) * m_.at( 2, 2 ); inverse_.at( 0, 2 ) = m_.at( 0, 1 ) * m_.at( 1, 2 ) - m_.at( 0, 2 ) * m_.at( 1, 1 ); inverse_.at( 1, 0 ) = m_.at( 1, 2 ) * m_.at( 2, 0 ) - m_.at( 1, 0 ) * m_.at( 2, 2 ); inverse_.at( 1, 1 ) = m_.at( 0, 0 ) * m_.at( 2, 2 ) - m_.at( 0, 2 ) * m_.at( 2, 0 ); inverse_.at( 1, 2 ) = m_.at( 0, 2 ) * m_.at( 1, 0 ) - m_.at( 0, 0 ) * m_.at( 1, 2 ); inverse_.at( 2, 0 ) = m_.at( 1, 0 ) * m_.at( 2, 1 ) - m_.at( 1, 1 ) * m_.at( 2, 0 ); inverse_.at( 2, 1 ) = m_.at( 0, 1 ) * m_.at( 2, 0 ) - m_.at( 0, 0 ) * m_.at( 2, 1 ); inverse_.at( 2, 2 ) = m_.at( 0, 0 ) * m_.at( 1, 1 ) - m_.at( 0, 1 ) * m_.at( 1, 0 ); const T determinant = m_.at( 0, 0 ) * inverse_.at( 0, 0 ) + m_.at( 0, 1 ) * inverse_.at( 1, 0 ) + m_.at( 0, 2 ) * inverse_.at( 2, 0 ); if ( fabs( determinant ) <= tolerance_ ) return false; // matrix is not invertible const T detinv = static_cast< T >( 1.0 ) / determinant; inverse_.at( 0, 0 ) *= detinv; inverse_.at( 0, 1 ) *= detinv; inverse_.at( 0, 2 ) *= detinv; inverse_.at( 1, 0 ) *= detinv; inverse_.at( 1, 1 ) *= detinv; inverse_.at( 1, 2 ) *= detinv; inverse_.at( 2, 0 ) *= detinv; inverse_.at( 2, 1 ) *= detinv; inverse_.at( 2, 2 ) *= detinv; return true; } template< typename T > bool compute_inverse( const matrix< 4, 4, T >& m_, matrix< 4, 4, T >& inv_, T tolerance_ = std::numeric_limits::epsilon() ) { const T* array = m_.array; // tuned version from Claude Knaus /* first set of 2x2 determinants: 12 multiplications, 6 additions */ const T t1[6] = { array[ 2] * array[ 7] - array[ 6] * array[ 3], array[ 2] * array[11] - array[10] * array[ 3], array[ 2] * array[15] - array[14] * array[ 3], array[ 6] * array[11] - array[10] * array[ 7], array[ 6] * array[15] - array[14] * array[ 7], array[10] * array[15] - array[14] * array[11] }; /* first half of comatrix: 24 multiplications, 16 additions */ inv_.array[0] = array[ 5] * t1[5] - array[ 9] * t1[4] + array[13] * t1[3]; inv_.array[1] = array[ 9] * t1[2] - array[13] * t1[1] - array[ 1] * t1[5]; inv_.array[2] = array[13] * t1[0] - array[ 5] * t1[2] + array[ 1] * t1[4]; inv_.array[3] = array[ 5] * t1[1] - array[ 1] * t1[3] - array[ 9] * t1[0]; inv_.array[4] = array[ 8] * t1[4] - array[ 4] * t1[5] - array[12] * t1[3]; inv_.array[5] = array[ 0] * t1[5] - array[ 8] * t1[2] + array[12] * t1[1]; inv_.array[6] = array[ 4] * t1[2] - array[12] * t1[0] - array[ 0] * t1[4]; inv_.array[7] = array[ 0] * t1[3] - array[ 4] * t1[1] + array[ 8] * t1[0]; /* second set of 2x2 determinants: 12 multiplications, 6 additions */ const T t2[6] = { array[ 0] * array[ 5] - array[ 4] * array[ 1], array[ 0] * array[ 9] - array[ 8] * array[ 1], array[ 0] * array[13] - array[12] * array[ 1], array[ 4] * array[ 9] - array[ 8] * array[ 5], array[ 4] * array[13] - array[12] * array[ 5], array[ 8] * array[13] - array[12] * array[ 9] }; /* second half of comatrix: 24 multiplications, 16 additions */ inv_.array[8] = array[ 7] * t2[5] - array[11] * t2[4] + array[15] * t2[3]; inv_.array[9] = array[11] * t2[2] - array[15] * t2[1] - array[ 3] * t2[5]; inv_.array[10] = array[15] * t2[0] - array[ 7] * t2[2] + array[ 3] * t2[4]; inv_.array[11] = array[ 7] * t2[1] - array[ 3] * t2[3] - array[11] * t2[0]; inv_.array[12] = array[10] * t2[4] - array[ 6] * t2[5] - array[14] * t2[3]; inv_.array[13] = array[ 2] * t2[5] - array[10] * t2[2] + array[14] * t2[1]; inv_.array[14] = array[ 6] * t2[2] - array[14] * t2[0] - array[ 2] * t2[4]; inv_.array[15] = array[ 2] * t2[3] - array[ 6] * t2[1] + array[10] * t2[0]; /* determinant: 4 multiplications, 3 additions */ const T determinant = array[0] * inv_.array[0] + array[4] * inv_.array[1] + array[8] * inv_.array[2] + array[12] * inv_.array[3]; if( fabs( determinant ) <= tolerance_ ) return false; // matrix is not invertible /* division: 16 multiplications, 1 division */ const T detinv = static_cast< T >( 1.0 ) / determinant; for( size_t i = 0; i != 16; ++i ) inv_.array[i] *= detinv; return true; } // this function returns the transpose of a matrix // however, using matrix::transpose_to( .. ) avoids the copy. template< size_t M, size_t N, typename T > inline matrix< N, M, T > transpose( const matrix< M, N, T >& matrix_ ) { matrix< N, M, T > transpose_; matrix_.transpose_to( transpose_ ); return transpose_; } template< size_t M, size_t N, typename T > bool is_positive_definite( const matrix< M, N, T >& matrix_, const T limit = -1e12, typename enable_if< M == N && M <= 3 >::type* = 0 ) { if ( matrix_.at( 0, 0 ) < limit ) return false; // sylvester criterion if ( M > 1 ) { matrix< 2, 2, T > m; matrix_.get_sub_matrix( m, 0, 0 ); if ( compute_determinant( m ) < limit ) return false; } if ( M > 2 ) { matrix< 3, 3, T > m; matrix_.get_sub_matrix( m, 0, 0 ); if ( compute_determinant( m ) < limit ) return false; } return true; } template< size_t M, size_t N, typename T > matrix< M, N, T >::matrix() { // no initialization for performance reasons. } template< size_t M, size_t N, typename T > template< size_t P, size_t Q, typename U > matrix< M, N, T >::matrix( const matrix< P, Q, U >& source_ ) { (*this) = source_; } template< size_t M, size_t N, typename T > inline T& matrix< M, N, T >::at( size_t row_index, size_t col_index ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M || col_index >= N ) VMMLIB_ERROR( "at( row, col ) - index out of bounds", VMMLIB_HERE ); #endif return array[ col_index * M + row_index ]; } template< size_t M, size_t N, typename T > const inline T& matrix< M, N, T >::at( size_t row_index, size_t col_index ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M || col_index >= N ) VMMLIB_ERROR( "at( row, col ) - index out of bounds", VMMLIB_HERE ); #endif return array[ col_index * M + row_index ]; } template< size_t M, size_t N, typename T > inline T& matrix< M, N, T >::operator()( size_t row_index, size_t col_index ) { return at( row_index, col_index ); } template< size_t M, size_t N, typename T > const inline T& matrix< M, N, T >::operator()( size_t row_index, size_t col_index ) const { return at( row_index, col_index ); } #ifndef VMMLIB_NO_CONVERSION_OPERATORS template< size_t M, size_t N, typename T > matrix< M, N, T >:: operator T*() { return array; } template< size_t M, size_t N, typename T > matrix< M, N, T >:: operator const T*() const { return array; } #endif template< size_t M, size_t N, typename T > bool matrix< M, N, T >:: operator==( const matrix< M, N, T >& other ) const { bool is_ok = true; for( size_t i = 0; is_ok && i < M * N; ++i ) { is_ok = array[ i ] == other.array[ i ]; } return is_ok; } template< size_t M, size_t N, typename T > bool matrix< M, N, T >:: operator!=( const matrix< M, N, T >& other ) const { return ! operator==( other ); } template< size_t M, size_t N, typename T > bool matrix< M, N, T >:: equals( const matrix< M, N, T >& other, T tolerance ) const { bool is_ok = true; for( size_t row_index = 0; is_ok && row_index < M; row_index++) { for( size_t col_index = 0; is_ok && col_index < N; col_index++) { is_ok = fabs( at( row_index, col_index ) - other( row_index, col_index ) ) < tolerance; } } return is_ok; } template< size_t M, size_t N, typename T > template< typename compare_t > bool matrix< M, N, T >::equals( const matrix< M, N, T >& other_matrix, compare_t& cmp ) const { bool is_ok = true; for( size_t row = 0; is_ok && row < M; ++row ) { for( size_t col = 0; is_ok && col < N; ++col) { is_ok = cmp( at( row, col ), other_matrix.at( row, col ) ); } } return is_ok; } #if (( __GNUC__ > 4 ) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) ) # pragma GCC diagnostic ignored "-Warray-bounds" // gcc 4.4.7 bug WAR #endif template< size_t M, size_t N, typename T > const matrix< M, N, T >& matrix< M, N, T >::operator=( const matrix< M, N, T >& source_ ) { memcpy( array, source_.array, M * N * sizeof( T )); return *this; } #if (( __GNUC__ > 4 ) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) ) # pragma GCC diagnostic warning "-Warray-bounds" #endif template< size_t M, size_t N, typename T > template< size_t P, size_t Q, typename U > void matrix< M, N, T >::operator=( const matrix< P, Q, U >& source_ ) { const size_t minL = P < M ? P : M; const size_t minC = Q < N ? Q : N; if( minL < M || minC < N ) zero(); for ( size_t i = 0 ; i < minL ; i++ ) for ( size_t j = 0 ; j < minC ; j++ ) at( i,j ) = static_cast< T >( source_( i, j )); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator=( const T old_fashioned_matrix[ M ][ N ] ) { for( size_t row = 0; row < M; row++) { for( size_t col = 0; col < N; col++) { at( row, col ) = old_fashioned_matrix[ row ][ col ]; } } } // WARNING: data_array[] must be at least of size M * N - otherwise CRASH! // WARNING: assumes row_by_row layout - if this is not the case, // use matrix::set( data_array, false ) template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator=( const T* data_array ) { set( data_array, data_array + M * N, true ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator=( const std::vector< T >& data ) { if ( data.size() < M * N ) VMMLIB_ERROR( "index out of bounds.", VMMLIB_HERE ); set( data.begin(), data.end(), true ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::multiply_piecewise( const matrix& other ) { for( size_t row_index = 0; row_index < M; row_index++) { for( size_t col_index = 0; col_index < N; col_index++ ) { T& value = at( row_index, col_index ); value *= other.at( row_index, col_index ); } } } template< size_t M, size_t N, typename T > template< size_t P > void matrix< M, N, T >::multiply( const matrix< M, P, T >& left, const matrix< P, N, T >& right ) { for( size_t row_index = 0; row_index < M; row_index++) { for( size_t col_index = 0; col_index < N; col_index++) { T& component = at( row_index, col_index ); component = static_cast< T >( 0.0 ); for( size_t p = 0; p < P; p++) { component += left.at( row_index, p ) * right.at( p, col_index ); } } } } template< size_t M, size_t N, typename T > template< size_t P > matrix< M, P, T > matrix< M, N, T >::operator*( const matrix< N, P, T >& other ) const { matrix< M, P, T > result; result.multiply( *this, other ); return result; } template< size_t M, size_t N, typename T > template< size_t O, size_t P, typename TT > typename enable_if< M == N && O == P && M == O, TT >::type* matrix< M, N, T >::operator*=( const matrix< O, P, TT >& right ) { matrix< M, N, T > copy( *this ); multiply( copy, right ); return 0; } template< size_t M, size_t N, typename T > matrix< M, N, T > matrix< M, N, T >::operator/( T scalar ) { matrix< M, N, T > result; for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { result.at( row_index, col_index ) = at( row_index, col_index ) / scalar; } } return result; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator/=( T scalar ) { for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { at( row_index, col_index ) /= scalar; } } } template< size_t M, size_t N, typename T > matrix< M, N, T > matrix< M, N, T >::operator*( T scalar ) { matrix< M, N, T > result; for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { result.at( row_index, col_index ) = at( row_index, col_index ) * scalar; } } return result; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator*=( T scalar ) { for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { at( row_index, col_index ) *= scalar; } } } template< size_t M, size_t N, typename T > vector< M, T > matrix< M, N, T >::operator*( const vector< N, T >& vec ) const { vector< M, T > result; // this < M, 1 > = < M, P > * < P, 1 > for( size_t i = 0; i < M; ++i ) { T tmp( 0 ); for( size_t j = 0; j < N; ++j ) tmp += at( i, j ) * vec.at( j ); result.at( i ) = tmp; } return result; } // transform vector by matrix ( vec = matrix * vec ) // assume homogenous coords( for vec3 = mat4 * vec3 ), e.g. vec[3] = 1.0 template< size_t M, size_t N, typename T > template< size_t O > vector< O, T > matrix< M, N, T >::operator*( const vector< O, T >& vector_ ) const { vector< O, T > result; T tmp; for( size_t row_index = 0; row_index < M; ++row_index ) { tmp = 0.0; for( size_t col_index = 0; col_index < N-1; ++col_index ) { tmp += vector_( col_index ) * at( row_index, col_index ); } if ( row_index < N - 1 ) result( row_index ) = tmp + at( row_index, N-1 ); // * 1.0 -> homogeneous vec4 else { tmp += at( row_index, N - 1 ); for( size_t col_index = 0; col_index < N - 1; ++col_index ) { result( col_index ) /= tmp; } } } return result; } template< size_t M, size_t N, typename T > inline matrix< M, N, T > matrix< M, N, T >::operator-() const { return negate(); } template< size_t M, size_t N, typename T > matrix< M, N, T > matrix< M, N, T >::negate() const { matrix< M, N, T > result; result *= -1.0; return result; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::tensor( const vector< M, T >& u, const vector< N, T >& v ) { for ( size_t col_index = 0; col_index < N; ++col_index ) for ( size_t row_index = 0; row_index < M; ++row_index ) at( row_index, col_index ) = u.array[ col_index ] * v.array[ row_index ]; } template< size_t M, size_t N, typename T > template< size_t uM, size_t vM > typename enable_if< uM == 3 && vM == 3 && M == N && M == 4 >::type* matrix< M, N, T >::tensor( const vector< uM, T >& u, const vector< vM, T >& v ) { for ( size_t col_index = 0; col_index < 3; ++col_index ) { for ( size_t row_index = 0; row_index < 3; ++row_index ) at( row_index, col_index ) = u.array[ col_index ] * v.array[ row_index ]; at( 3, col_index ) = u.array[ col_index ]; } for ( size_t row_index = 0; row_index < 3; ++row_index ) at( row_index, 3 ) = v.array[ row_index ]; at( 3, 3 ) = 1.0; return 0; } template< size_t M, size_t N, typename T > void matrix< M, N, T >:: transpose_to( matrix< N, M, T >& tM ) const { for( size_t row = 0; row < M; ++row ) { for( size_t col = 0; col < N; ++col ) { tM.at( col, row ) = at( row, col ); } } } template< size_t M, size_t N, typename T > void matrix< M, N, T >:: symmetric_covariance( matrix< M, M, T >& cov_m_ ) const { T tmp = 0; for( size_t row = 0; row < M; ++row ) { for( size_t col = row; col < M; ++col ) { for ( size_t k = 0; k < N; ++k ) { tmp += (at( row, k ) * at( col, k )); } cov_m_.at( row, col ) = tmp; cov_m_.at( col, row ) = tmp; tmp = 0; } } } template< size_t M, size_t N, typename T > vector< M, T > matrix< M, N, T >::get_column( size_t index ) const { vector< M, T > column; get_column( index, column ); return column; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::get_column( size_t index, vector< M, T >& column ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= N ) VMMLIB_ERROR( "get_column() - index out of bounds.", VMMLIB_HERE ); #endif memcpy( &column.array[0], &array[ M * index ], M * sizeof( T ) ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_column( size_t index, const vector< M, T >& column ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= N ) VMMLIB_ERROR( "set_column() - index out of bounds.", VMMLIB_HERE ); #endif memcpy( array + M * index, column.array, M * sizeof( T ) ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::get_column( size_t index, matrix< M, 1, T >& column ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= N ) VMMLIB_ERROR( "get_column() - index out of bounds.", VMMLIB_HERE ); #endif memcpy( column.array, array + M * index, M * sizeof( T ) ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_column( size_t index, const matrix< M, 1, T >& column ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= N ) VMMLIB_ERROR( "set_column() - index out of bounds.", VMMLIB_HERE ); #endif memcpy( &array[ M * index ], column.array, M * sizeof( T ) ); } template< size_t M, size_t N, typename T > vector< N, T > matrix< M, N, T >::get_row( size_t index ) const { vector< N, T > row; get_row( index, row ); return row; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::get_row( size_t row_index, vector< N, T >& row ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M ) VMMLIB_ERROR( "get_row() - index out of bounds.", VMMLIB_HERE ); #endif for( size_t col_index = 0; col_index < N; ++col_index ) { row.at( col_index ) = at( row_index, col_index ); } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_row( size_t row_index, const vector< N, T >& row ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M ) VMMLIB_ERROR( "set_row() - index out of bounds.", VMMLIB_HERE ); #endif for( size_t col_index = 0; col_index < N; ++col_index ) { at( row_index, col_index ) = row.at( col_index ); } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::get_row( size_t row_index, matrix< 1, N, T >& row ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M ) VMMLIB_ERROR( "get_row() - index out of bounds.", VMMLIB_HERE ); #endif for( size_t col_index = 0; col_index < N; ++col_index ) { row.at( 0, col_index ) = at( row_index, col_index ); } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_row( size_t row_index, const matrix< 1, N, T >& row ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( row_index >= M ) VMMLIB_ERROR( "set_row() - index out of bounds.", VMMLIB_HERE ); #endif for( size_t col_index = 0; col_index < N; ++col_index ) { at( row_index, col_index ) = row.at( 0, col_index ); } } template< size_t M, size_t N, typename T > size_t matrix< M, N, T >:: get_number_of_rows() const { return M; } template< size_t M, size_t N, typename T > size_t matrix< M, N, T >:: get_number_of_columns() const { return N; } template< size_t M, size_t N, typename T > void matrix< M, N, T >:: fill( T fillValue ) { for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { at( row_index, col_index ) = fillValue; } } } template< size_t M, size_t N, typename T > inline T& matrix< M, N, T >::x() { return array[ 12 ]; } template< size_t M, size_t N, typename T > inline T& matrix< M, N, T >::y() { return array[ 13 ]; } template< size_t M, size_t N, typename T > inline T& matrix< M, N, T >::z() { return array[ 14 ]; } template< size_t M, size_t N, typename T > template< typename input_iterator_t > void matrix< M, N, T >::set( input_iterator_t begin_, input_iterator_t end_, bool row_major_layout ) { input_iterator_t it( begin_ ); if( row_major_layout ) { for( size_t row = 0; row < M; ++row ) { for( size_t col = 0; col < N; ++col, ++it ) { if ( it == end_ ) return; at( row, col ) = static_cast< T >( *it ); } } } else { std::copy( it, it + ( M * N ), begin() ); } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::zero() { fill( static_cast< T >( 0.0 ) ); } template< size_t M, size_t N, typename T > void matrix< M, N, T >:: operator=( T value_ ) { std::fill( begin(), end(), value_ ); } template< size_t M, size_t N, typename T > inline matrix< M, N, T > matrix< M, N, T >::operator+( const matrix< M, N, T >& other ) const { matrix< M, N, T > result( *this ); result += other; return result; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator+=( const matrix< M, N, T >& other ) { iterator it = begin(), it_end = end(); const_iterator other_it = other.begin(); for( ; it != it_end; ++it, ++other_it ) { *it += *other_it; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator+=( T scalar ) { iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { *it += scalar; } } template< size_t M, size_t N, typename T > inline matrix< M, N, T > matrix< M, N, T >:: operator-( const matrix< M, N, T >& other ) const { matrix< M, N, T > result( *this ); result -= other; return result; } template< size_t M, size_t N, typename T > void matrix< M, N, T >:: operator-=( const matrix< M, N, T >& other ) { iterator it = begin(), it_end = end(); const_iterator other_it = other.begin(); for( ; it != it_end; ++it, ++other_it ) { *it -= *other_it; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::operator-=( T scalar ) { iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { *it -= scalar; } } template< size_t M, size_t N, typename T > template< size_t O, size_t P, size_t Q, size_t R > typename enable_if< M == O + Q && N == P + R >::type* matrix< M, N, T >:: direct_sum( const matrix< O, P, T >& upper_left, const matrix< Q, R, T >& lower_right ) { (*this) = static_cast< T >( 0.0 ); for( size_t row = 0; row < O; ++row ) { for( size_t col = 0; col < P; ++col ) { at( row, col ) = upper_left( row, col ); } } for( size_t row = 0; row < Q; ++row ) { for( size_t col = 0; col < R; ++col ) { at( O + row, P + col ) = lower_right( row, col ); } } return 0; } template< size_t M, size_t N, typename T > template< size_t O, size_t P > matrix< O, P, T > matrix< M, N, T >:: get_sub_matrix( size_t row_offset, size_t col_offset, typename enable_if< O <= M && P <= N >::type* ) const { matrix< O, P, T > result; get_sub_matrix( result, row_offset, col_offset ); return result; } template< size_t M, size_t N, typename T > template< size_t O, size_t P > typename enable_if< O <= M && P <= N >::type* matrix< M, N, T >:: get_sub_matrix( matrix< O, P, T >& result, size_t row_offset, size_t col_offset ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( O + row_offset > M || P + col_offset > N ) VMMLIB_ERROR( "index out of bounds.", VMMLIB_HERE ); #endif for( size_t row = 0; row < O; ++row ) { for( size_t col = 0; col < P; ++col ) { result.at( row, col ) = at( row_offset + row, col_offset + col ); } } return 0; } template< size_t M, size_t N, typename T > template< size_t O, size_t P > typename enable_if< O <= M && P <= N >::type* matrix< M, N, T >:: set_sub_matrix( const matrix< O, P, T >& sub_matrix, size_t row_offset, size_t col_offset ) { for( size_t row = 0; row < O; ++row ) { for( size_t col = 0; col < P; ++col ) { at( row_offset + row, col_offset + col ) = sub_matrix.at( row, col ); } } return 0; // for sfinae } template< size_t M, size_t N, typename T > inline T matrix< M, N, T >::det() const { return compute_determinant( *this ); } template< size_t M, size_t N, typename T > template< size_t O, size_t P, typename TT > inline bool matrix< M, N, T >::inverse( matrix< O, P, TT >& inverse_, T tolerance, typename enable_if< M == N && O == P && O == M && M >= 2 && M <= 4, TT >::type* ) const { return compute_inverse( *this, inverse_, tolerance ); } template< size_t M, size_t N, typename T > template< size_t O, size_t P > typename enable_if< O == P && M == N && O == M && M >= 2 >::type* matrix< M, N, T >:: get_adjugate( matrix< O, P, T >& adjugate ) const { get_cofactors( adjugate ); adjugate = transpose( adjugate ); return 0; } template< size_t M, size_t N, typename T > template< size_t O, size_t P > typename enable_if< O == P && M == N && O == M && M >= 2 >::type* matrix< M, N, T >:: get_cofactors( matrix< O, P, T >& cofactors ) const { matrix< M-1, N-1, T > minor_; const size_t _negate = 1u; for( size_t row_index = 0; row_index < M; ++row_index ) { for( size_t col_index = 0; col_index < N; ++col_index ) { if ( ( row_index + col_index ) & _negate ) cofactors( row_index, col_index ) = -get_minor( minor_, row_index, col_index ); else cofactors( row_index, col_index ) = get_minor( minor_, row_index, col_index ); } } return 0; } template< size_t M, size_t N, typename T > template< size_t O, size_t P > T matrix< M, N, T >:: get_minor( matrix< O, P, T >& minor_, size_t row_to_cut, size_t col_to_cut, typename enable_if< O == M-1 && P == N-1 && M == N && M >= 2 >::type* ) const { size_t row_offset = 0; size_t col_offset = 0; for( size_t row_index = 0; row_index < M; ++row_index ) { if ( row_index == row_to_cut ) row_offset = -1; else { for( size_t col_index = 0; col_index < M; ++col_index ) { if ( col_index == col_to_cut ) col_offset = -1; else minor_.at( row_index + row_offset, col_index + col_offset ) = at( row_index, col_index ); } col_offset = 0; } } return compute_determinant( minor_ ); } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::rotate( const TT angle_, const vector< M-1, T >& axis, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); // this is necessary since Visual Studio cannot resolve the // std::pow()-call correctly if we just use 2.0 directly. // this way, the '2.0' is converted to the same format // as the axis components const T _zero = 0.0; const T one = 1.0; const T two = 2.0; array[0] = cosine + ( one - cosine ) * std::pow( axis.array[0], two ); array[1] = ( one - cosine ) * axis.array[0] * axis.array[1] + sine * axis.array[2]; array[2] = ( one - cosine ) * axis.array[0] * axis.array[2] - sine * axis.array[1]; array[3] = _zero; array[4] = ( one - cosine ) * axis.array[0] * axis.array[1] - sine * axis.array[2]; array[5] = cosine + ( one - cosine ) * std::pow( axis.array[1], two ); array[6] = ( one - cosine ) * axis.array[1] * axis.array[2] + sine * axis.array[0]; array[7] = _zero; array[8] = ( one - cosine ) * axis.array[0] * axis.array[2] + sine * axis.array[1]; array[9] = ( one - cosine ) * axis.array[1] * axis.array[2] - sine * axis.array[0]; array[10] = cosine + ( one - cosine ) * std::pow( axis.array[2], two ); array[11] = _zero; array[12] = _zero; array[13] = _zero; array[14] = _zero; array[15] = one; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::rotate_x( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 4 ] * cosine + array[ 8 ] * sine; array[ 8 ] = - array[ 4 ] * sine + array[ 8 ] * cosine; array[ 4 ] = tmp; tmp = array[ 5 ] * cosine + array[ 9 ] * sine; array[ 9 ] = - array[ 5 ] * sine + array[ 9 ] * cosine; array[ 5 ] = tmp; tmp = array[ 6 ] * cosine + array[ 10 ] * sine; array[ 10 ] = - array[ 6 ] * sine + array[ 10 ] * cosine; array[ 6 ] = tmp; tmp = array[ 7 ] * cosine + array[ 11 ] * sine; array[ 11 ] = - array[ 7 ] * sine + array[ 11 ] * cosine; array[ 7 ] = tmp; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::rotate_y( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 0 ] * cosine - array[ 8 ] * sine; array[ 8 ] = array[ 0 ] * sine + array[ 8 ] * cosine; array[ 0 ] = tmp; tmp = array[ 1 ] * cosine - array[ 9 ] * sine; array[ 9 ] = array[ 1 ] * sine + array[ 9 ] * cosine; array[ 1 ] = tmp; tmp = array[ 2 ] * cosine - array[ 10 ] * sine; array[ 10 ] = array[ 2 ] * sine + array[ 10 ] * cosine; array[ 2 ] = tmp; tmp = array[ 3 ] * cosine - array[ 11 ] * sine; array[ 11 ] = array[ 3 ] * sine + array[ 11 ] * cosine; array[ 3 ] = tmp; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::rotate_z( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 0 ] * cosine + array[ 4 ] * sine; array[ 4 ] = - array[ 0 ] * sine + array[ 4 ] * cosine; array[ 0 ] = tmp; tmp = array[ 1 ] * cosine + array[ 5 ] * sine; array[ 5 ] = - array[ 1 ] * sine + array[ 5 ] * cosine; array[ 1 ] = tmp; tmp = array[ 2 ] * cosine + array[ 6 ] * sine; array[ 6 ] = - array[ 2 ] * sine + array[ 6 ] * cosine; array[ 2 ] = tmp; tmp = array[ 3 ] * cosine + array[ 7 ] * sine; array[ 7 ] = - array[ 3 ] * sine + array[ 7 ] * cosine; array[ 3 ] = tmp; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::pre_rotate_x( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 1 ]; array[ 1 ] = array[ 1 ] * cosine + array[ 2 ] * sine; array[ 2 ] = tmp * -sine + array[ 2 ] * cosine; tmp = array[ 5 ]; array[ 5 ] = array[ 5 ] * cosine + array[ 6 ] * sine; array[ 6 ] = tmp * -sine + array[ 6 ] * cosine; tmp = array[ 9 ]; array[ 9 ] = array[ 9 ] * cosine + array[ 10 ] * sine; array[ 10 ] = tmp * -sine + array[ 10 ] * cosine; tmp = array[ 13 ]; array[ 13 ] = array[ 13 ] * cosine + array[ 14 ] * sine; array[ 14 ] = tmp * -sine + array[ 14 ] * cosine; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::pre_rotate_y( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 0 ]; array[ 0 ] = array[ 0 ] * cosine - array[ 2 ] * sine; array[ 2 ] = tmp * sine + array[ 2 ] * cosine; tmp = array[ 4 ]; array[ 4 ] = array[ 4 ] * cosine - array[ 6 ] * sine; array[ 6 ] = tmp * sine + array[ 6 ] * cosine; tmp = array[ 8 ]; array[ 8 ] = array[ 8 ] * cosine - array[ 10 ] * sine; array[ 10 ] = tmp * sine + array[ 10 ] * cosine; tmp = array[ 12 ]; array[ 12 ] = array[ 12 ] * cosine - array[ 14 ] * sine; array[ 14 ] = tmp * sine + array[ 14 ] * cosine; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::pre_rotate_z( const TT angle_, typename enable_if< M == N && M == 4, TT >::type* ) { const T angle = static_cast< T >( angle_ ); const T sine = std::sin( angle ); const T cosine = std::cos( angle ); T tmp; tmp = array[ 0 ]; array[ 0 ] = array[ 0 ] * cosine + array[ 1 ] * sine; array[ 1 ] = tmp * -sine + array[ 1 ] * cosine; tmp = array[ 4 ]; array[ 4 ] = array[ 4 ] * cosine + array[ 5 ] * sine; array[ 5 ] = tmp * -sine + array[ 5 ] * cosine; tmp = array[ 8 ]; array[ 8 ] = array[ 8 ] * cosine + array[ 9 ] * sine; array[ 9 ] = tmp * -sine + array[ 9 ] * cosine; tmp = array[ 12 ]; array[ 12 ] = array[ 12 ] * cosine + array[ 13 ] * sine; array[ 13 ] = tmp * -sine + array[ 13 ] * cosine; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::scale( const TT _scale[3], typename enable_if< M == N && M == 4, TT >::type* ) { const T scale0 = static_cast< T >( _scale[ 0 ] ); const T scale1 = static_cast< T >( _scale[ 1 ] ); const T scale2 = static_cast< T >( _scale[ 2 ] ); array[0] *= scale0; array[1] *= scale0; array[2] *= scale0; array[3] *= scale0; array[4] *= scale1; array[5] *= scale1; array[6] *= scale1; array[7] *= scale1; array[8] *= scale2; array[9] *= scale2; array[10] *= scale2; array[11] *= scale2; return *this; } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::scale( const TT x_, const T y_, const T z_, typename enable_if< M == N && M == 4, TT >::type* ) { const T _x = static_cast< T >( x_ ); array[0] *= _x; array[1] *= _x; array[2] *= _x; array[3] *= _x; array[4] *= y_; array[5] *= y_; array[6] *= y_; array[7] *= y_; array[8] *= z_; array[9] *= z_; array[10] *= z_; array[11] *= z_; return *this; } template< size_t M, size_t N, typename T > template< typename TT > inline matrix< M, N, T >& matrix< M, N, T >::scale( const vector< 3, TT >& scale_, typename enable_if< M == N && M == 4, TT >::type* ) { return scale( scale_.array ); } template< size_t M, size_t N, typename T > template< typename TT > matrix< M, N, T >& matrix< M, N, T >::scale_translation( const TT scale_[3], typename enable_if< M == N && M == 4, TT >::type* ) { array[12] *= static_cast< T >( scale_[0] ); array[13] *= static_cast< T >( scale_[1] ); array[14] *= static_cast< T >( scale_[2] ); return *this; } template< size_t M, size_t N, typename T > template< typename TT > inline matrix< M, N, T >& matrix< M, N, T >::scale_translation( const vector< 3, TT >& scale_, typename enable_if< M == N && M == 4, TT >::type* ) { return scale_translation( scale_.array ); } template< size_t M, size_t N, typename T > template< typename TT > inline matrix< M, N, T >& matrix< M, N, T >::set_translation( const TT x_, const TT y_, const TT z_, typename enable_if< M == N && M == 4, TT >::type* ) { array[12] = static_cast< T >( x_ ); array[13] = static_cast< T >( y_ ); array[14] = static_cast< T >( z_ ); return *this; } template< size_t M, size_t N, typename T > template< typename TT > inline matrix< M, N, T >& matrix< M, N, T >::set_translation( const TT trans[3], typename enable_if< M == N && M == 4, TT >::type* ) { array[12] = static_cast< T >( trans[ 0 ] ); array[13] = static_cast< T >( trans[ 1 ] ); array[14] = static_cast< T >( trans[ 2 ] ); return *this; } template< size_t M, size_t N, typename T > template< typename TT > inline matrix< M, N, T >& matrix< M, N, T >::set_translation( const vector< 3, TT >& translation_, typename enable_if< M == N && M == 4, TT >::type* ) { return set_translation( translation_.array ); } template< size_t M, size_t N, typename T > template< typename TT > inline void matrix< M, N, T >:: get_translation( vector< 3, TT >& translation_, typename enable_if< M == N && M == 4, TT >::type* ) const { translation_.array[ 0 ] = array[ 12 ]; translation_.array[ 1 ] = array[ 13 ]; translation_.array[ 2 ] = array[ 14 ]; } template< size_t M, size_t N, typename T > size_t matrix< M, N, T >:: size() const { return M * N; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::iterator matrix< M, N, T >:: begin() { return array; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::iterator matrix< M, N, T >:: end() { return array + size(); } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::const_iterator matrix< M, N, T >:: begin() const { return array; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::const_iterator matrix< M, N, T >:: end() const { return array + size(); } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::reverse_iterator matrix< M, N, T >:: rbegin() { return array + size() - 1; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::reverse_iterator matrix< M, N, T >:: rend() { return array - 1; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::const_reverse_iterator matrix< M, N, T >:: rbegin() const { return array + size() - 1; } template< size_t M, size_t N, typename T > typename matrix< M, N, T >::const_reverse_iterator matrix< M, N, T >:: rend() const { return array - 1; } template< size_t M, size_t N, typename T > template< typename init_functor_t > const matrix< M, N, T > matrix< M, N, T >::get_initialized_matrix() { matrix< M, N, T > matrix_; init_functor_t()( matrix_ ); return matrix_; } // it's ugly, but it allows having properly initialized static members // without having to worry about static initialization order. template< size_t M, size_t N, typename T > const matrix< M, N, T > matrix< M, N, T >::IDENTITY( matrix< M, N, T >:: get_initialized_matrix< set_to_identity_functor< matrix< M, N, T > > >() ); template< size_t M, size_t N, typename T > const matrix< M, N, T > matrix< M, N, T >::ZERO( matrix< M, N, T >:: get_initialized_matrix< set_to_zero_functor< matrix< M, N, T > > >() ); template< size_t M, size_t N, typename T > double matrix< M, N, T >::frobenius_norm( ) const { double norm = 0.0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { norm += *it * *it; } return sqrt(norm); } template< size_t M, size_t N, typename T > double matrix< M, N, T >::p_norm( double p ) const { double norm = 0.0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { norm += std::pow(*it, p); } return std::pow(norm,1./p); } template< size_t M, size_t N, typename T > template< size_t O > void matrix< M, N, T >::khatri_rao_product( const matrix< O, N, T >& right_, matrix< M*O, N, T >& prod_ ) const { //build product for every column for (size_t col = 0; col < N; ++col ) { for ( size_t m = 0; m < M; ++m ) { for (size_t o = 0; o < O; ++o ) { prod_.at(O*m + o, col) = at( m, col ) * right_.at( o, col ); } } } } template< size_t M, size_t N, typename T > template< size_t O, size_t P > void matrix< M, N, T >::kronecker_product( const matrix< O, P, T >& right_, matrix< M*O, N*P, T >& result_ ) const { //build product for every column for (size_t m = 0; m < M; ++m ) { for ( size_t n = 0; n < N; ++n ) { for (size_t o = 0; o < O; ++o ) { for (size_t p = 0; p < P; ++p ) { result_.at(O*m + o, P*n + p) = at( m, n ) * right_.at( o, p ); } } } } } template< size_t M, size_t N, typename T > template< typename TT > void matrix< M, N, T >::cast_from( const matrix< M, N, TT >& other ) { typedef vmml::matrix< M, N, TT > matrix_tt_type ; typedef typename matrix_tt_type::const_iterator tt_const_iterator; iterator it = begin(), it_end = end(); tt_const_iterator other_it = other.begin(); for( ; it != it_end; ++it, ++other_it ) { *it = static_cast< T >( *other_it ); } } template< size_t M, size_t N, typename T > T matrix< M, N, T >::get_min() const { T min_value = static_cast(std::numeric_limits::max()); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( *it < min_value ) { min_value = *it; } } return min_value; } template< size_t M, size_t N, typename T > T matrix< M, N, T >::get_max() const { T max_value = static_cast(0); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( *it > max_value ) { max_value = *it; } } return max_value; } template< size_t M, size_t N, typename T > T matrix< M, N, T >::get_abs_min() const { T min_value = static_cast(std::numeric_limits::max()); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( fabs(*it) < fabs(min_value) ) { min_value = fabs(*it); } } return min_value; } template< size_t M, size_t N, typename T > T matrix< M, N, T >::get_abs_max() const { T max_value = static_cast(0); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( fabs(*it) > fabs(max_value) ) { max_value = fabs(*it); } } return max_value; } template< size_t M, size_t N, typename T > size_t matrix< M, N, T >::nnz() const { size_t counter = 0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( *it != 0 ) { ++counter; } } return counter; } template< size_t M, size_t N, typename T > size_t matrix< M, N, T >::nnz( const T& threshold_ ) const { size_t counter = 0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( fabs(*it) > threshold_ ) { ++counter; } } return counter; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::threshold( const T& threshold_value_ ) { iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( fabs(*it) <= threshold_value_ ) { *it = static_cast (0); } } } template< size_t M, size_t N, typename T > template< typename TT > void matrix< M, N, T >::quantize_to( matrix< M, N, TT >& quantized_, const T& min_value, const T& max_value ) const { long max_tt_range = long(std::numeric_limits< TT >::max()); long min_tt_range = long(std::numeric_limits< TT >::min()); long tt_range = (max_tt_range - min_tt_range); T t_range = max_value - min_value; typedef matrix< M, N, TT > m_tt_type ; typedef typename m_tt_type::iterator tt_iterator; tt_iterator it_quant = quantized_.begin(); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it, ++it_quant ) { if (std::numeric_limits::is_signed ) { *it_quant = TT( std::min( std::max( min_tt_range, long(( *it * tt_range / t_range ) + 0.5)), max_tt_range )); } else { *it_quant = TT( std::min( std::max( min_tt_range, long(((*it - min_value) * tt_range / t_range) + 0.5)), max_tt_range )); } } } template< size_t M, size_t N, typename T > template< typename TT > void matrix< M, N, T >::quantize( matrix< M, N, TT >& quantized_, T& min_value, T& max_value ) const { min_value = get_min(); max_value = get_max(); quantize_to( quantized_, min_value, max_value ); } template< size_t M, size_t N, typename T > template< typename TT > void matrix< M, N, T >::dequantize( matrix< M, N, TT >& dequantized_, const TT& min_value, const TT& max_value ) const { long max_t_range = long(std::numeric_limits< T >::max()); long min_t_range = long(std::numeric_limits< T >::min()); long t_range = (max_t_range - min_t_range); TT tt_range = max_value - min_value; typedef matrix< M, N, TT > m_tt_type ; typedef typename m_tt_type::iterator tt_iterator; tt_iterator it_dequant = dequantized_.begin(); const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it, ++it_dequant ) { if (std::numeric_limits::is_signed ) { *it_dequant = std::min( std::max( min_value, TT((TT(*it) / t_range) * tt_range)), max_value ); } else { *it_dequant = std::min( std::max( min_value, TT((((TT(*it) / t_range)) * tt_range ) + min_value)), max_value ); } } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::columnwise_sum( vector< N, T>& summed_columns_ ) const { for ( size_t n = 0; n < N; ++n ) { T value = 0; for ( size_t m = 0; m < M; ++m ) { value += at( m, n ); } summed_columns_.at( n ) = value; } } template< size_t M, size_t N, typename T > double matrix< M, N, T >::sum_elements( ) const { double sum = 0.0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { sum += *it; } return sum; } template< size_t M, size_t N, typename T > template< size_t R> typename enable_if< R == M && R == N>::type* matrix< M, N, T >::diag( const vector< R, T >& diag_values_ ) { zero(); for( size_t r = 0; r < R; ++r ) { at(r, r) = static_cast< T >( diag_values_.at(r) ); } return 0; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_dct() { double weight = 0.0f; double num_rows = M; double fill_value = 0.0f; for( size_t row = 0; row < M; ++row ) { weight = ( row == 0.0 ) ? sqrt(1/num_rows) : sqrt(2/num_rows); //to reiceive orthonormality for( size_t col = 0; col < N; ++col ) { fill_value = (2 * col + 1) * row * M_PI / (2*M); fill_value = std::cos( fill_value ); fill_value *= weight; at( row, col ) = static_cast< T >( fill_value ) ; } } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::set_random( int seed ) { if ( seed >= 0 ) srand( seed ); double fillValue = 0.0f; for( size_t row = 0; row < M; ++row ) { for( size_t col = 0; col < N; ++col ) { fillValue = rand(); fillValue /= RAND_MAX; at( row, col ) = -1.0 + 2.0 * static_cast< double >( fillValue ) ; } } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::write_to_raw( const std::string& dir_, const std::string& filename_ ) const { int dir_length = dir_.size() -1; int last_separator = dir_.find_last_of( "/"); std::string path = dir_; if (last_separator < dir_length ) { path.append( "/" ); } path.append( filename_ ); //check for format if( filename_.find( "raw", filename_.size() -3) == std::string::npos ) { path.append( "."); path.append( "raw" ); } std::string path_raw = path; std::ofstream outfile; outfile.open( path_raw.c_str() ); if( outfile.is_open() ) { size_t len_slice = sizeof(T) * M*N; outfile.write( (char*)&(*this), len_slice ); outfile.close(); } else { std::cout << "no file open" << std::endl; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::read_from_raw( const std::string& dir_, const std::string& filename_ ) { int dir_length = dir_.size() -1; int last_separator = dir_.find_last_of( "/"); std::string path = dir_; if (last_separator < dir_length ) { path.append( "/" ); } path.append( filename_ ); size_t max_file_len = 2147483648u - sizeof(T) ; size_t len_data = sizeof(T) * size(); size_t len_read = 0; char* data = new char[ len_data ]; std::ifstream infile; infile.open( path.c_str(), std::ios::in); if( infile.is_open()) { iterator it = begin(), it_end = end(); while ( len_data > 0 ) { len_read = (len_data % max_file_len ) > 0 ? len_data % max_file_len : len_data; len_data -= len_read; infile.read( data, len_read ); T* T_ptr = (T*)&(data[0]); for( ; (it != it_end) && (len_read > 0); ++it, len_read -= sizeof(T) ) { *it = *T_ptr; ++T_ptr; } } delete[] data; infile.close(); } else { std::cout << "no file open" << std::endl; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::write_csv_file( const std::string& dir_, const std::string& filename_ ) const { int dir_length = dir_.size() -1; int last_separator = dir_.find_last_of( "/"); std::string path = dir_; if (last_separator < dir_length ) { path.append( "/" ); } path.append( filename_ ); //check for format int suffix_pos = filename_.find( "csv", filename_.size() -3); if( suffix_pos == (-1)) { path.append( "."); path.append( "csv" ); } std::ofstream outfile; outfile.open( path.c_str() ); if( outfile.is_open() ) { outfile << *this << std::endl; outfile.close(); } else { std::cout << "no file open" << std::endl; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::read_csv_file( const std::string& dir_, const std::string& filename_ ) { int dir_length = dir_.size() -1; int last_separator = dir_.find_last_of( "/"); std::string path = dir_; if (last_separator < dir_length ) { path.append( "/" ); } path.append( filename_ ); //check for format int suffix_pos = filename_.find( "csv", filename_.size() -3); if( suffix_pos == (-1)) { path.append( "."); path.append( "csv" ); } std::ifstream infile; infile.open( path.c_str(), std::ios::in); if( infile.is_open() ) { //TODO: not yet implemented //infile >> *this >> std::endl; infile.close(); } else { std::cout << "no file open" << std::endl; } } template< size_t M, size_t N, typename T > void matrix< M, N, T >::sum_rows( matrix< M/2, N, T>& other ) const { typedef vector< N, T > row_type; row_type* row0 = new row_type; row_type* row1 = new row_type; other.zero(); for ( size_t row = 0; row < M; ++row ) { get_row( row++, *row0 ); if ( row < M ) { get_row( row, *row1 ); *row0 += *row1; other.set_row( row/2 , *row0 ); } } delete row0; delete row1; } template< size_t M, size_t N, typename T > void matrix< M, N, T >::sum_columns( matrix< M, N/2, T>& other ) const { typedef vector< M, T > col_type; col_type* col0 = new col_type; col_type* col1 = new col_type; other.zero(); for ( size_t col = 0; col< N; ++col ) { get_column( col++, *col0 ); if ( col < N ) { get_column( col, *col1 ); *col0 += *col1; other.set_column( col/2, *col0 ); } } delete col0; delete col1; } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/matrix_functors.hpp000066400000000000000000000065131231531733200262430ustar00rootroot00000000000000#ifndef __VMML__MATRIX_FUNCTORS__HPP__ #define __VMML__MATRIX_FUNCTORS__HPP__ #include #include #include namespace vmml { template< typename T > struct set_to_zero_functor { inline void operator()( T& matrix_ ) const { matrix_ = static_cast< typename T::value_type >( 0.0 ); } }; // struct set_to_zero template< typename T > struct set_to_identity_functor { inline typename enable_if< T::ROWS == T::COLS >::type* operator()( T& matrix_ ) { set_to_zero_functor< T >()( matrix_ ); for( size_t index = 0; index < T::ROWS; ++index ) { matrix_( index, index ) = static_cast< typename T::value_type >( 1.0 ); } return 0; // for sfinae } }; // struct set_to_identity // this functor compares to matrices, and also returns true/equal if // the matrices have the same values but some rows/columns are inverted template< typename T > struct matrix_equals_allow_inverted_rows : std::binary_function< const T&, const T&, bool > { bool operator()( const T& matrix0, const T& matrix1 ) { const size_t r = matrix0.get_number_of_rows(); bool ok = true; for( size_t index = 0; ok && index < r; ++index ) { if ( matrix0.get_row( index ) != matrix1.get_row( index ) && matrix0.get_row( index ) != - matrix1.get_row( index ) ) { ok = false; } } return ok; } bool operator()( const T& matrix0, const T& matrix1, typename T::value_type tolerance ) { const size_t r = matrix0.get_number_of_rows(); bool ok = true; for( size_t index = 0; ok && index < r; ++index ) { if ( ! matrix0.get_row( index ).equals( matrix1.get_row( index ), tolerance ) && ! matrix0.get_row( index ).equals( - matrix1.get_row( index ), tolerance ) ) { ok = false; } } return ok; } }; // struct matrix_equals_allow_inverted_rows template< typename T > struct matrix_equals_allow_inverted_columns : std::binary_function< const T&, const T&, bool > { bool operator()( const T& matrix0, const T& matrix1 ) { const size_t r = matrix0.get_number_of_columns(); bool ok = true; for( size_t index = 0; ok && index < r; ++index ) { if ( matrix0.get_column( index ) != matrix1.get_column( index ) && matrix0.get_column( index ) != - matrix1.get_column( index ) ) { ok = false; } } return ok; } bool operator()( const T& matrix0, const T& matrix1, typename T::value_type tolerance ) { const size_t r = matrix0.get_number_of_columns(); bool ok = true; for( size_t index = 0; ok && index < r; ++index ) { if ( ! matrix0.get_column( index ).equals( matrix1.get_column( index ), tolerance ) && ! matrix0.get_column( index ).equals( - matrix1.get_column( index ), tolerance ) ) { ok = false; } } return ok; } }; // struct matrix_equals_allow_inverted_columns } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/matrix_pseudoinverse.hpp000066400000000000000000000173641231531733200273010ustar00rootroot00000000000000#ifndef __VMML__MATRIX_PSEUDOINVERSE__HPP__ #define __VMML__MATRIX_PSEUDOINVERSE__HPP__ #include #include #include #include #include #include /* *** computes the pseudo inverse of a non-square matrix *** - the pseudo inverse is computed by the help of SVD - the tolerance for the significant singular values is optionally set - implementation works only for matrices with more rows than columns or quadratic matrices. use a transposed input matrix for matrices with more columns than rows */ namespace vmml { // T - vmml::matrix<...> or compatible // Tinternal - float or double template< typename T, typename Tinternal = double > class compute_pseudoinverse { public: typedef typename T::value_type Texternal; typedef matrix< T::ROWS, T::COLS, Tinternal > matrix_mn_type; typedef matrix< T::COLS, T::ROWS, Tinternal > matrix_nm_type; typedef matrix< T::COLS, T::COLS, Tinternal > matrix_nn_type; typedef matrix< T::ROWS, T::ROWS, Tinternal > matrix_mm_type; typedef matrix< T::COLS, T::ROWS, Texternal > pinv_type; typedef vector< T::COLS, Tinternal > vec_n_type; typedef vector< T::ROWS, Tinternal > vec_m_type; typedef lapack_svd< T::ROWS, T::COLS, Tinternal > svd_type; typedef blas_dgemm< T::COLS, 1, T::ROWS, Tinternal > blas_type; typedef lapack_svd< T::COLS, T::ROWS, Tinternal > svd_type_inv; typedef blas_dgemm< T::ROWS, 1, T::COLS, Tinternal > blas_type_inv; struct tmp_matrices { matrix_mn_type U; vec_n_type sigmas; matrix_nn_type Vt; matrix_mn_type input; matrix_nm_type result; pinv_type pseudoinverse; matrix_nm_type tmp; }; struct tmp_matrices_inv { matrix_nm_type U; vec_m_type sigmas; matrix_mm_type Vt; matrix_nm_type input; matrix_mn_type result; matrix_mn_type tmp; }; void operator()(const T& input, T& pseudoinverse_transposed) { if (T::ROWS < T::COLS) { //cols > rows compute_inv(input, pseudoinverse_transposed); } else { //rows >= cols compute(input, pseudoinverse_transposed); } } void compute_inv(const T& input, T& pseudoinverse_transposed, typename T::value_type tolerance = std::numeric_limits< typename T::value_type >::epsilon()) { if (_work_inv == 0) { _work_inv = new tmp_matrices_inv(); } // perform an SVD on the matrix to get the singular values svd_type_inv svd; matrix_nm_type& U = _work_inv->U; vec_m_type& sigmas = _work_inv->sigmas; matrix_mm_type& Vt = _work_inv->Vt; matrix_nm_type& in_data = _work_inv->input; in_data.cast_from(transpose(input)); bool svd_ok = svd.compute(in_data, U, sigmas, Vt); // FIXME it always gives bad error code if (!svd_ok) { VMMLIB_ERROR("matrix compute_pseudoinverse - problem with lapack svd.", VMMLIB_HERE); } /*std::cout << "U: " << std::endl << U << std::endl << " sigmas: " << std::endl << sigmas << std::endl << " Vt: " << std::endl << Vt << std::endl;*/ // get the number of significant singular, i.e., values which are above the tolerance value typename vector< T::ROWS, Tinternal >::const_iterator it = sigmas.begin(), it_end = sigmas.end(); size_t num_sigmas = 0; for (; it != it_end; ++it) { if (*it >= tolerance) ++num_sigmas; else return; } //compute inverse with all the significant inverse singular values matrix_mn_type& result = _work_inv->result; result.zero(); matrix_mn_type& tmp = _work_inv->tmp; sigmas.reciprocal_safe(); vec_m_type vt_i; vec_n_type u_i; blas_type_inv blas_dgemm1; if (num_sigmas >= 1) { it = sigmas.begin(); for (size_t i = 0; i < num_sigmas && it != it_end; ++it, ++i) { Vt.get_row(i, vt_i); U.get_column(i, u_i); blas_dgemm1.compute_vv_outer(vt_i, u_i, tmp); tmp *= *it; result += tmp; } pseudoinverse_transposed.cast_from(result); } else { pseudoinverse_transposed.zero(); //return matrix with zeros } } void compute(const T& input, T& pseudoinverse_transposed, typename T::value_type tolerance = std::numeric_limits< typename T::value_type >::epsilon()) { if (_work == 0) { _work = new tmp_matrices(); } // perform an SVD on the matrix to get the singular values svd_type svd; matrix_mn_type& U = _work->U; vec_n_type& sigmas = _work->sigmas; matrix_nn_type& Vt = _work->Vt; matrix_mn_type& in_data = _work->input; in_data.cast_from(input); bool svd_ok = svd.compute(in_data, U, sigmas, Vt); // FIXME it always gives bad error code if (!svd_ok) { VMMLIB_ERROR("matrix compute_pseudoinverse - problem with lapack svd.", VMMLIB_HERE); } /*std::cout << "U: " << std::endl << U << std::endl << " sigmas: " << std::endl << sigmas << std::endl << " Vt: " << std::endl << Vt << std::endl;*/ // get the number of significant singular, i.e., values which are above the tolerance value typename vector< T::COLS, Tinternal >::const_iterator it = sigmas.begin(), it_end = sigmas.end(); size_t num_sigmas = 0; for (; it != it_end; ++it) { if (*it >= tolerance) ++num_sigmas; else return; } //compute inverse with all the significant inverse singular values matrix_nm_type& result = _work->result; result.zero(); pinv_type& pseudoinverse = _work->pseudoinverse; matrix_nm_type& tmp = _work->tmp; sigmas.reciprocal_safe(); //double sigma_inv = 0; vec_n_type vt_i; vec_m_type u_i; blas_type blas_dgemm1; if (num_sigmas >= 1) { it = sigmas.begin(); for (size_t i = 0; i < num_sigmas && it != it_end; ++it, ++i) { Vt.get_row(i, vt_i); U.get_column(i, u_i); blas_dgemm1.compute_vv_outer(vt_i, u_i, tmp); tmp *= *it; result += tmp; } pseudoinverse.cast_from(result); pseudoinverse.transpose_to(pseudoinverse_transposed); } else { pseudoinverse_transposed.zero(); //return matrix with zeros } } compute_pseudoinverse() : _work(0), _work_inv(0) { } compute_pseudoinverse(const compute_pseudoinverse& cp) : _work(0), _work_inv(0) { } ~compute_pseudoinverse() { delete _work; delete _work_inv; } protected: tmp_matrices* _work; tmp_matrices_inv* _work_inv; }; //end compute_pseudoinverse class }// end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/matrix_traits.hpp000066400000000000000000000025451231531733200257070ustar00rootroot00000000000000//Copyright (c) 2010 Daniel Pfeifer #ifndef __VMML_MATRIX_TRAITS_HPP__ #define __VMML_MATRIX_TRAITS_HPP__ #include #include namespace boost { namespace la { template struct matrix_traits > { typedef vmml::matrix matrix_type; static const int rows = M; static const int cols = N; typedef T scalar_type; template static scalar_type r(const matrix_type& m) { BOOST_STATIC_ASSERT(Row >= 0); BOOST_STATIC_ASSERT(Row < rows); BOOST_STATIC_ASSERT(Col >= 0); BOOST_STATIC_ASSERT(Col < cols); return m.at(Col, Row); } template static scalar_type& w(matrix_type& m) { BOOST_STATIC_ASSERT(Row >= 0); BOOST_STATIC_ASSERT(Row < rows); BOOST_STATIC_ASSERT(Col >= 0); BOOST_STATIC_ASSERT(Col < cols); return m.at(Col, Row); } static scalar_type ir(int row, int col, const matrix_type& m) { BOOST_ASSERT(row >= 0); BOOST_ASSERT(row < rows); BOOST_ASSERT(col >= 0); BOOST_ASSERT(col < cols); return m.at(col, row); } static scalar_type& iw(int row, int col, matrix_type& m) { BOOST_ASSERT(row >= 0); BOOST_ASSERT(row < rows); BOOST_ASSERT(col >= 0); BOOST_ASSERT(col < cols); return m.at(col, row); } }; } // namespace la } // namespace boost #endif /* VMML_MATRIX_TRAITS_HPP */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/qr_decomposition.hpp000066400000000000000000000034631231531733200263730ustar00rootroot00000000000000#ifndef __VMML__QR_DECOMPOSITION__HPP__ #define __VMML__QR_DECOMPOSITION__HPP__ #include #include #include #include #include /* * QR decomposition using stabilized gram-schmidt * A -> matrix to be factorized * Q -> orthonormal * Rn -> upper triangular */ namespace vmml { template< size_t M, size_t N, typename T > void qr_decompose_gram_schmidt( const matrix< M, N, T >& A_, matrix< M, M, T >& Q, matrix< N, N, T >& R ) { Q = 0.0; R = 0.0; // create a copy of A_ since we will change it in the algorithm matrix< M, N, T > A( A_ ); vector< M, T > a_column, q_column; #if 0 // for each column for( size_t k = 0; k < N; ++k ) { // compute norm of A's column k A.get_column( k, a_column ); const T a_norm = a_column.length(); R.at( k, k ) = a_norm; if ( a_norm == static_cast< T >( 0.0 ) ) break; Q.set_column( k, a_column / a_norm ); for( size_t j = k+1; j < N; ++j ) { Q.get_column( k, q_column ); A.get_column( j, a_column ); R.at( k, j ) = a_column.dot( q_column ); for( size_t i = 0; i < M; ++i ) { A( i, j ) = A( i, j ) - R( k, j ) * Q( i, k ); } } } #else vector< M, T > v; for( unsigned j = 0; j < N; ++j ) { A.get_column( j, v ); for( unsigned i = 0; i < j; ++i ) { Q.get_column( i, q_column ); A.get_column( j, a_column ); R( i, j ) = dot( q_column, a_column ); v -= q_column * R(i,j); } R(j,j) = v.length(); Q.set_column( j, v / R(j,j) ); } #endif } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/qtucker3_tensor.hpp000066400000000000000000000424401231531733200261460ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * Quantized version of Tucker3 tensor * - 16bit linear factor matrices quantization * - 8bit logarithmic core tensor quantization * * reference: * - Suter, Iglesias, Marton, Agus, Elsener, Zollikofer, Gopi, Gobbetti, and Pajarola: * "Interactive Multiscale Tensor Reconstruction for Multiresolution Volume Visualization", * IEEE Transactions on Visualization and Computer Graphics. 2011. * */ #ifndef __VMML__QTUCKER3_TENSOR__HPP__ #define __VMML__QTUCKER3_TENSOR__HPP__ #define CORE_RANGE 127 #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value = float, typename T_coeff = double > class qtucker3_tensor { public: typedef float T_internal; typedef qtucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > tucker3_type; typedef tensor3< I1, I2, I3, T_value > t3_type; typedef tensor3< I1, I2, I3, T_coeff > t3_coeff_type; typedef tensor3< R1, R2, R3, T_coeff > t3_core_type; typedef matrix< I1, R1, T_coeff > u1_type; typedef matrix< I2, R2, T_coeff > u2_type; typedef matrix< I3, R3, T_coeff > u3_type; typedef tensor3< I1, I2, I3, T_internal > t3_comp_type; typedef tensor3< R1, R2, R3, T_internal > t3_core_comp_type; typedef matrix< I1, R1, T_internal > u1_comp_type; typedef matrix< I2, R2, T_internal > u2_comp_type; typedef matrix< I3, R3, T_internal > u3_comp_type; typedef tensor3< R1, R2, R3, char > t3_core_signs_type; static const size_t SIZE = R1*R2*R3 + I1*R1 + I2*R2 + I3*R3; qtucker3_tensor(); qtucker3_tensor( t3_core_type& core ); qtucker3_tensor( t3_core_type& core, u1_type& U1, u2_type& U2, u3_type& U3 ); qtucker3_tensor( const t3_type& data_, u1_type& U1, u2_type& U2, u3_type& U3 ); qtucker3_tensor( const tucker3_type& other ); ~qtucker3_tensor(); void enable_quantify_hot() { _is_quantify_hot = true; _is_quantify_log = false; _is_quantify_linear = false;}; void disable_quantify_hot() { _is_quantify_hot = false; } ; void enable_quantify_linear() { _is_quantify_linear = true; _is_quantify_hot = false;}; void disable_quantify_linear() { _is_quantify_linear = false; } ; void enable_quantify_log() { _is_quantify_log = true; _is_quantify_hot = false;}; void disable_quantify_log() { _is_quantify_log = false; } ; void get_core_signs( t3_core_signs_type& signs_ ) { signs_ = _signs; }; void set_core_signs( const t3_core_signs_type signs_ ) { _signs = signs_; } ; T_internal get_hottest_value() { return _hottest_core_value; }; void set_hottest_value( const T_internal value_ ) { _hottest_core_value = value_; } ; void set_core( t3_core_type& core ) { _core = t3_core_type( core ); _core_comp.cast_from( core ); } ; void set_u1( u1_type& U1 ) { *_u1 = U1; _u1_comp->cast_from( U1 ); } ; void set_u2( u2_type& U2 ) { *_u2 = U2; _u2_comp->cast_from( U2 ); } ; void set_u3( u3_type& U3 ) { *_u3 = U3; _u3_comp->cast_from( U3 ); } ; void get_core( t3_core_type& data_ ) const { data_ = _core; } ; void get_u1( u1_type& U1 ) const { U1 = *_u1; } ; void get_u2( u2_type& U2 ) const { U2 = *_u2; } ; void get_u3( u3_type& U3 ) const { U3 = *_u3; } ; void set_core_comp( t3_core_comp_type& core ) { _core_comp = t3_core_comp_type( core ); _core.cast_from( _core_comp ); } ; void set_u1_comp( u1_comp_type& U1 ) { *_u1_comp = U1; _u1->cast_from( U1 ); } ; void set_u2_comp( u2_comp_type& U2 ) { *_u2_comp = U2; _u2->cast_from( U2 ); } ; void set_u3_comp( u3_comp_type& U3 ) { *_u3_comp = U3; _u3->cast_from( U3 ); } ; void get_core_comp( t3_core_comp_type& data_ ) const { data_ = _core_comp; } ; void get_u1_comp( u1_comp_type& U1 ) const { U1 = *_u1_comp; } ; void get_u2_comp( u2_comp_type& U2 ) const { U2 = *_u2_comp; } ; void get_u3_comp( u3_comp_type& U3 ) const { U3 = *_u3_comp; } ; //get number of nonzeros for tensor decomposition size_t nnz() const; size_t nnz( const T_value& threshold ) const; size_t nnz_core() const; size_t size_core() const; size_t size() const { return SIZE; } ; void threshold_core( const size_t& nnz_core_, size_t& nnz_core_is_ ); void threshold_core( const T_coeff& threshold_value_, size_t& nnz_core_ ); void reconstruct( t3_type& data_, const T_internal& u_min_, const T_internal& u_max_, const T_internal& core_min_, const T_internal& core_max_ ); void reconstruct( t3_type& data_, const T_internal& u1_min_, const T_internal& u1_max_, const T_internal& u2_min_, const T_internal& u2_max_, const T_internal& u3_min_, const T_internal& u3_max_, const T_internal& core_min_, const T_internal& core_max_ ); template< typename T_init> void decompose( const t3_type& data_, T_internal& u1_min_, T_internal& u1_max_, T_internal& u2_min_, T_internal& u2_max_, T_internal& u3_min_, T_internal& u3_max_, T_internal& core_min_, T_internal& core_max_, T_init init ); template< typename T_init> void decompose( const t3_type& data_, T_internal& u_min_, T_internal& u_max_, T_internal& core_min_, T_internal& core_max_, T_init init ); template< typename T_init> void tucker_als( const t3_type& data_, T_init init ); friend std::ostream& operator << ( std::ostream& os, const tucker3_type& t3 ) { t3_core_type core; t3.get_core( core ); u1_type* u1 = new u1_type; t3.get_u1( *u1 ); u2_type* u2 = new u2_type; t3.get_u2( *u2 ); u3_type* u3 = new u3_type; t3.get_u3( *u3 ); os << "U1: " << std::endl << *u1 << std::endl << "U2: " << std::endl << *u2 << std::endl << "U3: " << std::endl << *u3 << std::endl << "core: " << std::endl << core << std::endl; delete u1; delete u2; delete u3; return os; } void cast_members(); void cast_comp_members(); void quantize_basis_matrices( T_internal& u_min_, T_internal& u_max_ ); void quantize_basis_matrices( T_internal& u1_min_, T_internal& u1_max_, T_internal& u2_min_, T_internal& u2_max_, T_internal& u3_min_, T_internal& u3_max_ ); void quantize_core( T_internal& core_min_, T_internal& core_max_ ); void dequantize_basis_matrices( const T_internal& u1_min_, const T_internal& u1_max_, const T_internal& u2_min_, const T_internal& u2_max_, const T_internal& u3_min_, const T_internal& u3_max_ ); void dequantize_core( const T_internal& core_min_, const T_internal& core_max_ ); protected: tucker3_type operator=( const tucker3_type& other ) { return (*this); }; template< typename T_init> void decompose( const t3_type& data_, T_init init ); void reconstruct( t3_type& data_ ); private: //t3_core_type* _core ; u1_type* _u1 ; u2_type* _u2 ; u3_type* _u3 ; t3_core_type _core ; //used only internally for computations to have a higher precision t3_core_comp_type _core_comp ; u1_comp_type* _u1_comp ; u2_comp_type* _u2_comp ; u3_comp_type* _u3_comp ; T_internal _hottest_core_value; t3_core_signs_type _signs; bool _is_quantify_hot; bool _is_quantify_log; bool _is_quantify_linear; }; // class qtucker3_tensor #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME qtucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::qtucker3_tensor( ) : _hottest_core_value( 0 ) , _is_quantify_hot( false ) , _is_quantify_log( false ) , _is_quantify_linear( false ) { _core.zero(); _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _core_comp.zero(); _u1_comp = new u1_comp_type(); _u1_comp->zero(); _u2_comp = new u2_comp_type(); _u2_comp->zero(); _u3_comp = new u3_comp_type(); _u3_comp->zero(); _signs.zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::qtucker3_tensor( t3_core_type& core ) : _hottest_core_value( 0 ) , _is_quantify_hot( false ) , _is_quantify_log( false ) , _is_quantify_linear( false ) { _core = core; _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _u1_comp = new u1_comp_type(); _u1_comp->zero(); _u2_comp = new u2_comp_type(); _u2_comp->zero(); _u3_comp = new u3_comp_type(); _u3_comp->zero(); _core_comp.cast_from( core ); _signs.zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::qtucker3_tensor( t3_core_type& core, u1_type& U1, u2_type& U2, u3_type& U3 ) : _hottest_core_value( 0 ) , _is_quantify_hot( false ) , _is_quantify_log( false ) , _is_quantify_linear( false ) { _core = core; _u1 = new u1_type( U1 ); _u2 = new u2_type( U2 ); _u3 = new u3_type( U3 ); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); cast_comp_members(); _signs.zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::qtucker3_tensor( const t3_type& data_, u1_type& U1, u2_type& U2, u3_type& U3 ) : _hottest_core_value( 0 ) , _is_quantify_hot( false ) , _is_quantify_log( false ) , _is_quantify_linear( false ) { _u1 = new u1_type( U1 ); _u2 = new u2_type( U2 ); _u3 = new u3_type( U3 ); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); t3_hooi< R1, R2, R3, I1, I2, I3, T_coeff >::derive_core( data_, *_u1, *_u2, *_u3, _core ); cast_comp_members(); _signs.zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::qtucker3_tensor( const tucker3_type& other ) : _hottest_core_value( 0 ) , _is_quantify_hot( false ) , _is_quantify_log( false ) , _is_quantify_linear( false ) { _u1 = new u1_type(); _u2 = new u2_type(); _u3 = new u3_type(); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); other.get_core( _core ); other.get_u1( *_u1 ); other.get_u2( *_u2 ); other.get_u3( *_u3 ); cast_comp_members(); _signs.zero(); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_members() { _u1->cast_from( *_u1_comp ); _u2->cast_from( *_u2_comp ); _u3->cast_from( *_u3_comp ); _core.cast_from( _core_comp); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_comp_members() { _u1_comp->cast_from( *_u1 ); _u2_comp->cast_from( *_u2 ); _u3_comp->cast_from( *_u3 ); _core_comp.cast_from( _core); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz_core() const { return _core_comp.nnz(); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::size_core() const { return _core_comp.size(); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::quantize_basis_matrices(T_internal& u1_min_, T_internal& u1_max_, T_internal& u2_min_, T_internal& u2_max_, T_internal& u3_min_, T_internal& u3_max_ ) { _u1_comp->quantize( *_u1, u1_min_, u1_max_ ); _u2_comp->quantize( *_u2, u2_min_, u2_max_ ); _u3_comp->quantize( *_u3, u3_min_, u3_max_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::quantize_basis_matrices(T_internal& u_min_, T_internal& u_max_) { u_min_ = _u1_comp->get_min(); T_internal u2_min = _u2_comp->get_min(); T_internal u3_min = _u3_comp->get_min(); if ( u2_min < u_min_) { u_min_ = u2_min; } if ( u3_min < u_min_) { u_min_ = u3_min; } u_max_ = _u1_comp->get_max(); T_internal u2_max = _u2_comp->get_max(); T_internal u3_max = _u3_comp->get_max(); if ( u2_max > u_max_ ) { u_max_ = u2_max; } if ( u3_max > u_max_ ) { u_max_ = u3_max; } _u1_comp->quantize_to( *_u1, u_min_, u_max_ ); _u2_comp->quantize_to( *_u2, u_min_, u_max_ ); _u3_comp->quantize_to( *_u3, u_min_, u_max_ ); #if 0 std::cout << "quantized (1u): " << std::endl << "u1-u3: " << std::endl << *_u1 << std::endl << *_u1_comp << std::endl << *_u2 << std::endl << *_u2_comp << std::endl << *_u3 << std::endl << *_u3_comp << std::endl << " core " << std::endl << _core << std::endl << " core_comp " << std::endl << _core_comp << std::endl; #endif } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::quantize_core( T_internal& core_min_, T_internal& core_max_ ) { if ( _is_quantify_hot ) { _hottest_core_value = _core_comp.at(0,0,0); _core_comp.at( 0, 0, 0 ) = 0; _core_comp.quantize_log( _core, _signs, core_min_, core_max_, T_coeff(CORE_RANGE) ); } else if ( _is_quantify_linear ) { _core_comp.quantize( _core, core_min_, core_max_ ); } else if ( _is_quantify_log ) { _core_comp.quantize_log( _core, _signs, core_min_, core_max_, T_coeff(CORE_RANGE) ); } else { _core_comp.quantize( _core, core_min_, core_max_ ); std::cout << "quant.method not specified" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::dequantize_basis_matrices( const T_internal& u1_min_, const T_internal& u1_max_, const T_internal& u2_min_, const T_internal& u2_max_, const T_internal& u3_min_, const T_internal& u3_max_ ) { _u1->dequantize( *_u1_comp, u1_min_, u1_max_ ); _u2->dequantize( *_u2_comp, u2_min_, u2_max_ ); _u3->dequantize( *_u3_comp, u3_min_, u3_max_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::dequantize_core( const T_internal& core_min_, const T_internal& core_max_ ) { if ( _is_quantify_hot ) { _core.dequantize_log( _core_comp, _signs, core_min_, core_max_ ); _core.at(0,0,0) = _hottest_core_value; _core_comp.at(0,0,0) = _hottest_core_value; } else if ( _is_quantify_linear ) { _core.dequantize( _core_comp, core_min_, core_max_ ); } else if ( _is_quantify_log ) { _core.dequantize_log( _core_comp, _signs, core_min_, core_max_ ); } else { _core.dequantize( _core_comp, core_min_, core_max_ ); } } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~qtucker3_tensor( ) { delete _u1; delete _u2; delete _u3; delete _u1_comp; delete _u2_comp; delete _u3_comp; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct( t3_type& data_, const T_internal& u_min_, const T_internal& u_max_, const T_internal& core_min_, const T_internal& core_max_ ) { dequantize_basis_matrices( u_min_, u_max_, u_min_, u_max_, u_min_, u_max_ ); dequantize_core( core_min_, core_max_ ); #if 0 std::cout << "dequantized (1u): " << std::endl << "u1-u3: " << std::endl << *_u1 << std::endl << *_u1_comp << std::endl << *_u2 << std::endl << *_u2_comp << std::endl << *_u3 << std::endl << *_u3_comp << std::endl << " core " << std::endl << _core << std::endl << " core_comp " << std::endl << _core_comp << std::endl; #endif reconstruct( data_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct( t3_type& data_, const T_internal& u1_min_, const T_internal& u1_max_, const T_internal& u2_min_, const T_internal& u2_max_, const T_internal& u3_min_, const T_internal& u3_max_, const T_internal& core_min_, const T_internal& core_max_ ) { dequantize_basis_matrices( u1_min_, u1_max_, u2_min_, u2_max_, u3_min_, u3_max_ ); dequantize_core( core_min_, core_max_ ); reconstruct( data_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct( t3_type& data_ ) { t3_comp_type data; data.cast_from( data_ ); t3_ttm::full_tensor3_matrix_multiplication( _core_comp, *_u1_comp, *_u2_comp, *_u3_comp, data ); //convert reconstructed data, which is in type T_internal (double, float) to T_value (uint8 or uint16) if( (sizeof(T_value) == 1) || (sizeof(T_value) == 2) ){ data_.float_t_to_uint_t( data ); } else { data_.cast_from( data ); } } VMML_TEMPLATE_STRING template< typename T_init> void VMML_TEMPLATE_CLASSNAME::decompose( const t3_type& data_, T_init init ) { tucker_als( data_, init ); } VMML_TEMPLATE_STRING template< typename T_init> void VMML_TEMPLATE_CLASSNAME::decompose( const t3_type& data_, T_internal& u1_min_, T_internal& u1_max_, T_internal& u2_min_, T_internal& u2_max_, T_internal& u3_min_, T_internal& u3_max_, T_internal& core_min_, T_internal& core_max_, T_init init ) { decompose( data_, init ); quantize_basis_matrices( u1_min_, u1_max_, u2_min_, u2_max_, u3_min_, u3_max_ ); quantize_core(core_min_, core_max_ ); } VMML_TEMPLATE_STRING template< typename T_init> void VMML_TEMPLATE_CLASSNAME::decompose( const t3_type& data_, T_internal& u_min_, T_internal& u_max_, T_internal& core_min_, T_internal& core_max_, T_init init ) { decompose( data_, init ); quantize_basis_matrices( u_min_, u_max_ ); quantize_core(core_min_, core_max_ ); } VMML_TEMPLATE_STRING template< typename T_init > void VMML_TEMPLATE_CLASSNAME::tucker_als( const t3_type& data_, T_init init ) { t3_comp_type data; data.cast_from( data_ ); typedef t3_hooi< R1, R2, R3, I1, I2, I3, T_internal > hooi_type; hooi_type::als( data, *_u1_comp, *_u2_comp, *_u3_comp, _core_comp, init ); cast_members(); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz() const { size_t counter = 0; counter += _u1_comp->nnz(); counter += _u2_comp->nnz(); counter += _u3_comp->nnz(); counter += _core_comp.nnz(); return counter; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz( const T_value& threshold ) const { size_t counter = 0; counter += _u1_comp->nnz( threshold ); counter += _u2_comp->nnz( threshold ); counter += _u3_comp->nnz( threshold ); counter += _core_comp.nnz( threshold ); return counter; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/quaternion.hpp000066400000000000000000000517111231531733200252010ustar00rootroot00000000000000/* * VMMLib - Vector & Matrix Math Lib * * @author Philip Schlegel * @author Jonas Boesch * @author Julius Natrup * */ #ifndef __VMML__QUATERNION__HPP__ #define __VMML__QUATERNION__HPP__ #include #include #include #include #include #include #include #include #include #include #include #include #include // - declaration - // #define QUATERNION_TRACE_EPSILON 1e-5 namespace vmml { template < typename T > class quaternion : private vector< 4, T > { public: typedef vector< 4, T > super; using super::operator(); //using super::operator=; using super::at; using super::x; using super::y; using super::z; using super::w; using super::array; using super::find_min; using super::find_max; using super::find_min_index; using super::find_max_index; using super::iter_set; //constructors quaternion(); // warning: components NOT initialised (for performance) quaternion( T x, T y, T z, T w ); quaternion( const vector< 3, T >& xyz , T w ); // initializes the quaternion with xyz, sets w to zero quaternion( const vector< 3, T >& xyz ); // uses the top-left 3x3 part of the supplied matrix as rotation matrix template< size_t M > quaternion( const matrix< M, M, T >& rotation_matrix_, typename enable_if< M >= 3 >::type* = 0 ); void zero(); void identity(); template< size_t D > void set( const matrix< D, D, T >& rotation_matrix_ ); void set( T ww, T xx, T yy, T zz); void set( vector< 3, T >& xyz, T w ); template< typename input_iterator_t > void set( input_iterator_t begin_, input_iterator_t end_ ); bool operator==( const T& a ) const; bool operator!=( const T& a ) const; bool operator==( const quaternion& a ) const; bool operator!=( const quaternion& a ) const; bool operator==( const vector< 4, T >& a ) const; bool operator!=( const vector< 4, T >& a ) const; bool is_akin( const quaternion& a, const T& delta = std::numeric_limits< T >::epsilon() ); void conjugate(); quaternion get_conjugate() const; T abs() const; T squared_abs() const; T normalize(); quaternion get_normalized() const; quaternion negate() const; quaternion operator-() const; const quaternion& operator=(const quaternion& other); const vector< 4, T >& operator=( const vector< 4, T >& other ); // // quaternion/quaternion operations // quaternion operator+( const quaternion< T >& a ) const; quaternion operator-( const quaternion< T >& a ) const; // caution: a * q != q * a in general quaternion operator*( const quaternion< T >& a ) const; void operator+=( const quaternion< T >& a ); void operator-=( const quaternion< T >& a ); // caution: a *= q != q *= a in general void operator*=( const quaternion< T >& a ); // // quaternion/scalar operations // quaternion operator*( T a ) const; quaternion operator/( T a ) const; void operator*=( T a ); void operator/=( T a ); // //quaternion/vector operations // quaternion operator+( const vector< 3, T >& a ) const; quaternion operator-( const vector< 3, T >& a ) const; quaternion operator*( const vector< 3, T >& a ) const; void operator+=( const vector< 3, T >& a ); void operator-=( const vector< 3, T >& a ); void operator*=( const vector< 3, T >& a ); // vec3 = this x b vector< 3, T > cross( const quaternion< T >& b ) const; T dot( const quaternion< T >& a ) const; static T dot( const quaternion< T >& a, const quaternion< T >& b ); // returns multiplicative inverse quaternion inverse(); void normal( const quaternion& aa, const quaternion& bb, const quaternion& cc, const quaternion& dd ); quaternion normal( const quaternion& aa, const quaternion& bb, const quaternion& cc ); // to combine two rotations, multiply the respective quaternions before using rotate // instead of rotating twice for increased performance, but be aware of non-commutativity! void rotate( T theta, const vector< 3, T >& a ); quaternion rotate( T theta, vector< 3, T >& axis, const vector< 3, T >& a ); quaternion rotate_x( T theta, const vector< 3, T >& a ); quaternion rotate_y( T theta, const vector< 3, T >& a ); quaternion rotate_z( T theta, const vector< 3, T >& a ); static quaternion slerp( T a, const quaternion& p, const quaternion& q, const T epsilon = 1e-13 ); matrix< 3, 3, T > get_rotation_matrix() const; template< size_t D > void get_rotation_matrix( matrix< D, D, T >& result ) const; friend std::ostream& operator<< ( std::ostream& os, const quaternion& q ) { os << "("; size_t index = 0; for( ; index < 3; ++index ) { os << q.at( index ) << ", "; } os << q.at( index ) << ") "; return os; }; static const quaternion ZERO; static const quaternion IDENTITY; static const quaternion QUATERI; static const quaternion QUATERJ; static const quaternion QUATERK; }; // class quaternion #ifndef VMMLIB_NO_TYPEDEFS typedef quaternion< float > quaternionf; typedef quaternion< double > quaterniond; #endif // - implementation - // template < typename T > const quaternion< T > quaternion< T >::ZERO( 0, 0, 0, 0 ); template < typename T > const quaternion< T > quaternion< T >::IDENTITY( 0, 0, 0, 1 ); template < typename T > const quaternion< T > quaternion< T >::QUATERI( 1, 0, 0, 0 ); template < typename T > const quaternion< T > quaternion< T >::QUATERJ( 0, 1, 0, 0 ); template < typename T > const quaternion< T > quaternion< T >::QUATERK( 0, 0, 1, 0 ); template < typename T > quaternion< T >::quaternion() { // intentionally left empty } template < typename T > quaternion< T >::quaternion( T x_, T y_, T z_, T w_ ) { x() = x_; y() = y_; z() = z_; w() = w_; } template < typename T > quaternion< T >::quaternion( const vector< 3, T >& xyz, T w_ ) { super::set( xyz, w_ ); } template < typename T > quaternion< T >::quaternion( const vector< 3, T >& xyz ) { super::set( xyz, static_cast< T >( 0.0 ) ); } template< typename T > template< size_t M > quaternion< T >::quaternion( const matrix< M, M, T >& rotation_matrix_, typename enable_if< M >= 3 >::type* ) { this->template set< M >( rotation_matrix_ ); } // top-left 3x3 is interpreted as rot matrix. template < typename T > template< size_t D > void quaternion< T >::set( const matrix< D, D, T >& M ) { T trace = M( 0, 0 ) + M( 1, 1 ) + M( 2,2 ) + 1.0; // very small traces may introduce a big numerical error if( trace > QUATERNION_TRACE_EPSILON ) { T s = 0.5 / sqrt( trace ); x() = M( 2, 1 ) - M( 1, 2 ); x() *= s; y() = M( 0, 2 ) - M( 2, 0 ); y() *= s; z() = M( 1, 0 ) - M( 0, 1 ); z() *= s; w() = 0.25 / s; } else { vector< 3, T > diag( M( 0, 0 ), M( 1, 1 ), M( 2, 2 ) ); size_t largest = diag.find_max_index(); // 0, 0 is largest if ( largest == 0 ) { T s = 0.5 / sqrt( 1.0 + M( 0, 0 ) - M( 1, 1 ) - M( 2, 2 ) ); x() = 0.25 / s; y() = M( 0,1 ) + M( 1,0 ); y() *= s; z() = M( 0,2 ) + M( 2,0 ); z() *= s; w() = M( 1,2 ) - M( 2,1 ); w() *= s; } else if ( largest == 1 ) { T s = 0.5 / sqrt( 1.0 + M( 1,1 ) - M( 0,0 ) - M( 2,2 ) ); x() = M( 0,1 ) + M( 1,0 ); x() *= s; y() = 0.25 / s; z() = M( 1,2 ) + M( 2,1 ); z() *= s; w() = M( 0,2 ) - M( 2,0 ); w() *= s; } // 2, 2 is largest else if ( largest == 2 ) { T s = 0.5 / sqrt( 1.0 + M( 2,2 ) - M( 0,0 ) - M( 1,1 ) ); x() = M( 0,2 ) + M( 2,0 ); x() *= s; y() = M( 1,2 ) + M( 2,1 ); y() *= s; z() = 0.25 / s; w() = M( 0,1 ) - M( 1,0 ); w() *= s; } else { *this = ZERO; assert( 0 ); } } } template < typename T > void quaternion< T >::zero() { (*this) = ZERO; } template < typename T > void quaternion< T >::identity() { (*this) = IDENTITY; } template < typename T > void quaternion< T >::set( T xx, T yy, T zz, T ww ) { x() = xx; y() = yy; z() = zz; w() = ww; } template< typename T > void quaternion< T >::set( vector< 3, T >& xyz, T _w ) { x() = xyz.x(); y() = xyz.y(); z() = xyz.z(); w() = _w; } template < typename T > template< typename input_iterator_t > void quaternion< T >::set( input_iterator_t begin_, input_iterator_t end_ ) { super::template set< input_iterator_t >( begin_, end_ ); } template < typename T > bool quaternion< T >::operator==( const T& a ) const { return ( w() == a && x() == 0 && y() == 0 && z() == 0 ); } template < typename T > bool quaternion< T >::operator!=( const T& a ) const { return ( w() != a || x() != 0 || y() != 0 || z() != 0 ); } template < typename T > bool quaternion< T >::operator==( const vector< 4, T >& a ) const { return this->operator==( reinterpret_cast< const quaternion< T >& >( a ) ); } template < typename T > bool quaternion< T >::operator!=( const vector< 4, T >& a ) const { return ! this->operator==( a ); } template < typename T > bool quaternion< T >::operator==( const quaternion& a ) const { return ( w() == a.w() && x() == a.x() && y() == a.y() && z() == a.z() ); } template < typename T > bool quaternion< T >::operator!=( const quaternion& a ) const { return ! this->operator==( a ); } template < typename T > bool quaternion< T >::is_akin( const quaternion& a, const T& delta ) { if( fabsf( w() - a.w() ) > delta || fabsf( x() - a.x() ) > delta || fabsf( y() - a.y() ) > delta || fabsf( z() - a.z() ) > delta ) return false; return true; } template < typename T > void quaternion< T >::conjugate() { x() = -x(); y() = -y(); z() = -z(); } template < typename T > quaternion< T > quaternion< T >::get_conjugate() const { return quaternion< T > ( -x(), -y(), -z(), w() ); } template < typename T > T quaternion< T >::abs() const { return sqrt( squared_abs() ); } template < typename T > T quaternion< T >::squared_abs() const { return x() * x() + y() * y() + z() * z() + w() * w(); } template < typename T > quaternion< T > quaternion< T >::inverse() { quaternion< T > q( *this ); q.conjugate(); T tmp = squared_abs(); tmp = static_cast< T >( 1.0 ) / tmp; return q * tmp; } template < typename T > T quaternion< T >::normalize() { T len = abs(); if( len == 0.0 ) return 0.0; len = 1.0f / len; this->operator*=( len ); return len; } template < typename T > quaternion< T > quaternion< T >::get_normalized() const { quaternion< T > q( *this ); q.normalize(); return q; } // // quaternion/quaternion operations // template < typename T > quaternion< T > quaternion< T >::operator+( const quaternion< T >& a ) const { return quaternion( x() + a.x(), y() + a.y(), z() + a.z(), w() + a.w() ); } template < typename T > quaternion< T > quaternion< T >::operator-( const quaternion< T >& a ) const { return quaternion( x() - a.x(), y() - a.y(), z() - a.z(), w() - a.w() ); } // returns Grasssmann product template < typename T > quaternion< T > quaternion< T >::operator*( const quaternion< T >& a ) const { quaternion< T > ret( *this ); ret *= a; return ret; } // Grassmann product template < typename T > void quaternion< T >::operator*=( const quaternion< T >& q ) { #if 0 quaternion< T > orig( *this ); x() = orig.w() * a.x() + orig.x() * a.w() + orig.y() * a.z() - orig.z() * a.y(); y() = orig.w() * a.y() + orig.y() * a.w() + orig.z() * a.x() - orig.x() * a.z(); z() = orig.w() * a.z() + orig.z() * a.w() + orig.x() * a.y() - orig.y() * a.x(); w() = orig.w() * a.w() - orig.x() * a.x() - orig.y() * a.y() - orig.z() * a.z(); #else // optimized version, 7 less mul, but 15 more add/subs // after Henrik Engstrom, from a gamedev.net article. T* _array = super::array; const T& a = _array[ 3 ]; const T& b = _array[ 0 ]; const T& c = _array[ 1 ]; const T& d = _array[ 2 ]; const T& _x = q.array[ 3 ]; const T& _y = q.array[ 0 ]; const T& _z = q.array[ 1 ]; const T& _w = q.array[ 2 ]; const T tmp_00 = (d - c) * (_z - _w); const T tmp_01 = (a + b) * (_x + _y); const T tmp_02 = (a - b) * (_z + _w); const T tmp_03 = (c + d) * (_x - _y); const T tmp_04 = (d - b) * (_y - _z); const T tmp_05 = (d + b) * (_y + _z); const T tmp_06 = (a + c) * (_x - _w); const T tmp_07 = (a - c) * (_x + _w); const T tmp_08 = tmp_05 + tmp_06 + tmp_07; const T tmp_09 = 0.5 * (tmp_04 + tmp_08); _array[ 3 ] = tmp_00 + tmp_09 - tmp_05; _array[ 0 ] = tmp_01 + tmp_09 - tmp_08; _array[ 1 ] = tmp_02 + tmp_09 - tmp_07; _array[ 2 ] = tmp_03 + tmp_09 - tmp_06; #endif } template < typename T > quaternion< T > quaternion< T >::operator-() const { return quaternion( -x(), -y(), -z(), -w() ); } template < typename T > void quaternion< T >::operator+=( const quaternion< T >& q ) { array[ 0 ] += q.array[ 0 ]; array[ 1 ] += q.array[ 1 ]; array[ 2 ] += q.array[ 2 ]; array[ 3 ] += q.array[ 3 ]; } template < typename T > void quaternion< T >::operator-=( const quaternion< T >& q ) { array[ 0 ] -= q.array[ 0 ]; array[ 1 ] -= q.array[ 1 ]; array[ 2 ] -= q.array[ 2 ]; array[ 3 ] -= q.array[ 3 ]; } // // quaternion/scalar operations // template < typename T > quaternion< T > quaternion< T >::operator*( const T a ) const { return quaternion( x() * a, y() * a, z() * a, w() * a ); } template < typename T > quaternion< T > quaternion< T >::operator/( T a ) const { if ( a == 0.0 ) { VMMLIB_ERROR( "Division by zero.", VMMLIB_HERE ); } a = 1.0 / a; return quaternion( x() * a, y() * a, z() * a, w() * a ); } template < typename T > void quaternion< T >::operator*=( T q ) { array[ 0 ] *= q; array[ 1 ] *= q; array[ 2 ] *= q; array[ 3 ] *= q; } template < typename T > void quaternion< T >::operator/=( T q ) { if ( q == 0.0 ) { VMMLIB_ERROR( "Division by zero", VMMLIB_HERE ); } q = 1.0f / q; this->operator*=( q ); } //quaternion/vector operations template < typename T > quaternion< T > quaternion< T >::operator+( const vector< 3, T >& a ) const { return quaternion( x() + a.x(), y() + a.y(), z() + a.z(), w() ); } template < typename T > quaternion< T > quaternion< T >::operator-( const vector< 3, T >& a ) const { return quaternion( w(), x() - a.x(), y() - a.y(), z() - a.z() ); } template < typename T > quaternion< T > quaternion< T >::operator*( const vector< 3, T >& a ) const { return quaternion( -x() * a.x() - y() * a.y() - z() * a.z(), w() * a.x() + y() * a.z() - z() * a.y(), w() * a.y() + z() * a.x() - x() * a.z(), w() * a.z() + x() * a.y() - y() * a.x() ); } template < typename T > void quaternion< T >::operator+=( const vector< 3, T >& xyz ) { x() += xyz.x(); y() += xyz.y(); y() += xyz.z(); } template < typename T > void quaternion< T >::operator-=( const vector< 3, T >& xyz ) { x() -= xyz.x(); y() -= xyz.y(); z() -= xyz.z(); return; } template < typename T > void quaternion< T >::operator*=(const vector< 3, T >& a ) { T _x = x(); T _y = y(); T _z = z(); T _w = w(); x() = _w * a.x() + _y * a.z() - _z * a.y(); y() = _w * a.y() + _z * a.x() - _x * a.z(); z() = _w * a.z() + _x * a.y() - _y * a.x(); w() = -_x * a.x() - _y * a.y() - _z * a.z(); } template < typename T > vector< 3, T > quaternion< T >::cross( const quaternion< T >& bb ) const { vector< 3, T > result; result.array[ 0 ] = y() * bb.z() - z() * bb.y(); result.array[ 1 ] = z() * bb.x() - x() * bb.z(); result.array[ 2 ] = x() * bb.y() - y() * bb.x(); return result; } template < typename T > T quaternion< T >::dot( const quaternion< T >& q ) const { return w() * q.w() + x() * q.x() + y() * q.y() + z() * q.z(); } template < typename T > T quaternion< T >:: dot( const quaternion< T >& p, const quaternion< T >& q ) { return p.w() * q.w() + p.x() * q.x() + p.y() * q.y() + p.z() * q.z(); } template < typename T > void quaternion< T >::normal( const quaternion< T >& aa, const quaternion< T >& bb, const quaternion< T >& cc, const quaternion< T >& dd ) { //right hand system, CCW triangle const quaternion< T > quat_t = bb - aa; const quaternion< T > quat_u = cc - aa; const quaternion< T > quat_v = dd - aa; cross( quat_t ); cross( quat_u ); cross( quat_v ); normalize(); } template < typename T > quaternion< T > quaternion< T >::normal( const quaternion< T >& aa, const quaternion< T >& bb, const quaternion< T >& cc ) { quaternion< T > tmp; tmp.normal( *this, aa, bb, cc ); return tmp; } // to combine two rotations, multiply the respective quaternions before using rotate // instead of rotating twice for increased performance, but be aware of non-commutativity! // (the first rotation quaternion has to be the first factor) template< typename T > quaternion< T > quaternion< T >::rotate( T theta, vector< 3, T >& axis, const vector< 3, T >& a ) { quaternion< T > p = a; T alpha = theta / 2; quaternion< T > q = std::cos( alpha ) + ( std::sin( alpha ) * axis.normalize() ); return q * p * q.invert(); } template< typename T > quaternion< T > quaternion< T >::rotate_x( T theta, const vector< 3, T >& a ) { quaternion< T > p = a; T alpha = theta / 2; quaternion< T > q = std::cos( alpha ) + ( std::sin( alpha ) * QUATERI ); return q * p * q.invert(); } template< typename T > quaternion< T > quaternion< T >::rotate_y( T theta, const vector< 3, T >& a ) { quaternion< T > p = a; T alpha = theta / 2; quaternion< T > q = std::cos( alpha ) + ( std::sin( alpha ) * QUATERJ ); return q * p * q.invert(); } template< typename T > quaternion< T > quaternion< T >::rotate_z( T theta, const vector< 3, T >& a ) { quaternion< T > p = a; T alpha = theta / 2; quaternion< T > q = std::cos( alpha ) + ( std::sin( alpha ) * QUATERK ); return q * p * q.invert(); } template < typename T > matrix< 3, 3, T > quaternion< T >::get_rotation_matrix() const { matrix< 3, 3, T > result; get_rotation_matrix< 3 >( result ); return result; } template < typename T > template< size_t D > void quaternion< T >::get_rotation_matrix( matrix< D, D, T >& M ) const { T w2 = w() * w(); T x2 = x() * x(); T y2 = y() * y(); T z2 = z() * z(); T wx = w() * x(); T wy = w() * y(); T wz = w() * z(); T xy = x() * y(); T xz = x() * z(); T yz = y() * z(); M( 0, 0 ) = w2 + x2 - y2 - z2; M( 0, 1 ) = 2. * (xy - wz); M( 0, 2 ) = 2. * (xz + wy); M( 1, 0 ) = 2. * (xy + wz); M( 1, 1 ) = w2 - x2 + y2 - z2; M( 1, 2 ) = 2. * (yz - wx); M( 2, 0 ) = 2. * (xz - wy); M( 2, 1 ) = 2. * (yz + wx); M( 2, 2 ) = w2 - x2 - y2 + z2; } template< typename T > quaternion< T > quaternion< T >:: slerp( T a, const quaternion< T >& p, const quaternion< T >& q, const T epsilon ) { quaternion< T > px = p.get_normalized(); quaternion< T > qx = q.get_normalized(); T cosine = px.dot( qx ); // check if inverted rotation is needed if ( cosine < 0.0 ) { cosine = -cosine; qx = -qx; } const T abs_cos = static_cast< T >( fabs(cosine) ); const T one_x = static_cast< T >( 1. - epsilon ); if( abs_cos < one_x ) { // standard slerp T sine = sqrt( 1. - ( cosine * cosine ) ); T angle = atan2( sine, cosine ); T coeff1 = std::sin( ( 1.0 - a ) * angle) / sine; T coeff2 = std::sin( a * angle ) / sine; qx *= coeff2; px *= coeff1; px += qx; } else { // linear interpolation for very small angles px *= 1. - a; qx *= a; px += qx; px.normalize(); } return px; } template < typename T > const quaternion< T >& quaternion< T >::operator=(const quaternion& other) { memcpy( array, other.array, 4 * sizeof( T ) ); return *this; } template < typename T > const vector< 4, T >& quaternion< T >::operator=( const vector< 4, T >& other ) { memcpy( array, other.array, 4 * sizeof( T ) ); return other; } } #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/svd.hpp000066400000000000000000000212121231531733200236010ustar00rootroot00000000000000#ifndef __VMML__SINGULAR_VALUE_DECOMPOSITION__HPP__ #define __VMML__SINGULAR_VALUE_DECOMPOSITION__HPP__ #include #include #include namespace vmml { /* * Given a matrix a[1..m][1..n], this routine computes its singular value * decomposition, A = U·W·V T. The matrix U replaces a on output. The diagonal * matrix of singular values W is output as a vector w[1..n]. The transpose V T * (not the matrix V ! ) is output as v[1..n][1..n]. */ //static double rv1[16]; template < size_t M, size_t N, typename T > void svdecompose( matrix< M, N, T >& a, vector< N, T >& w, matrix< N, N, T >& v ) { int m = M; int n = N; int flag, i, its, j, jj, k, l, nm = 0; T anorm, c, f, g, h, s, scale, x, y, z; //T* rv1 = (T*)calloc( n, sizeof(T)); // vector(1,n); vector< N, T > rv1; g = scale = anorm = 0.0; // Householder reduction to bidiagonal form. for ( i = 0; i < n; ++i ) { l = i + 1; rv1[i] = scale * g; g = s = scale = 0.0; if ( i < m ) { for ( k = i; k < m; ++k ) scale += fabs(a[k][i]); if ( scale ) { for ( k = i; k < m; ++k ) { a[k][i] /= scale; s += a[k][i] * a[k][i]; } f = a[i][i]; g = -math::sign( static_cast< T >(sqrt(s)), f); h = f * g - s; a[i][i] = f - g; for ( j = l; j < n; ++j ) { for ( s = 0.0, k = i; k < m; ++k ) s += a[k][i] * a[k][j]; f = s / h; for ( k = i; k < m; ++k ) a[k][j] += f * a[k][i]; } for ( k = i; k < m; ++k ) a[k][i] *= scale; } } w[i] = scale * g; g = s = scale = 0.0; if ( i < m && i != n-1 ) { for ( k = l; k < n; ++k ) scale += fabs(a[i][k]); if ( scale ) { for ( k = l; k < n; ++k ) { a[i][k] /= scale; s += a[i][k] * a[i][k]; } f = a[i][l]; g = -math::sign( static_cast< T >( sqrt(s)), f); h = f * g - s; a[i][l] = f - g; for ( k = l; k < n; ++k ) rv1[k] = a[i][k] / h; for ( j = l; j < m; ++j ) { for ( s = 0.0, k = l; k < n; ++k ) s += a[j][k] * a[i][k]; for ( k = l; k < n; ++k ) a[j][k] += s * rv1[k]; } for ( k = l; k < n; ++k ) a[i][k] *= scale; } } anorm = (std::max)( anorm, static_cast< T >( ( fabs( w[i] ) + fabs( rv1[i] ) ) ) ); } for ( i = n-1; i >= 0; --i ) { // Accumulation of right-hand transformations. if ( i < n ) { if ( g ) { for ( j = l; j < n; ++j ) // Double division to avoid possible underflow. v[j][i] = (a[i][j] / a[i][l]) / g; for ( j = l; j < n; ++j ) { for ( s = 0.0, k = l; k < n; ++k ) s += a[i][k] * v[k][j]; for ( k = l; k < n; ++k ) v[k][j] += s * v[k][i]; } } for ( j = l; j < n; ++j ) v[i][j] = v[j][i] = 0.0; } v[i][i] = 1.0; g = rv1[i]; l = i; } i = ( m < n ) ? m - 1 : n - 1; for ( ; i >= 0; --i ) // IMIN { // Accumulation of left-hand transformations. l = i + 1; g = w[i]; for ( j = l; j < n; ++j ) a[i][j] = 0.0; if ( g ) { g = 1.0 / g; for ( j = l; j < n; ++j ) { for ( s = 0.0, k = l; k < m; ++k ) s += a[k][i] * a[k][j]; f = (s / a[i][i]) * g; for ( k = i; k < m; ++k ) a[k][j] += f * a[k][i]; } for ( j = i; j < m; ++j ) a[j][i] *= g; } else for ( j = i; j < m; ++j ) a[j][i] = 0.0; ++a[i][i]; } for ( k = n-1; k >= 0; --k ) { // Diagonalization of the bidiagonal form: Loop over singular values, // and over allowed iterations. for ( its = 0; its < 30; ++its ) { flag = 1; for ( l = k; l >= 0; --l ) { // Test for splitting. nm = l - 1; // Note that rv1[1] is always zero. if ( ( fabs( rv1[l] ) + anorm ) == anorm ) { flag = 0; break; } if ( ( fabs( w[ nm ] ) + anorm ) == anorm ) break; } if ( flag ) { c = 0.0; // Cancellation of rv1[l], if l > 1. s = 1.0; for ( i = l; i <= k; ++i ) { f = s * rv1[i]; rv1[i] = c * rv1[i]; if ( ( fabs(f) + anorm ) == anorm ) break; g = w[i]; h = math::pythag(f, g); w[i] = h; h = 1.0 / h; c = g * h; s = -f * h; for ( j = 0; j < m; ++j ) { y = a[j][nm]; z = a[j][i]; a[j][nm] = y * c + z * s; a[j][i] = z * c - y * s; } } } z = w[k]; if ( l == k ) { // Convergence. if ( z < 0.0 ) { // Singular value is made nonnegative. w[k] = -z; for ( j = 0; j < n; ++j ) v[j][k] = -v[j][k]; } break; } if ( its == 30 ) { //fprintf(stderr, "Warning: no convergence in 30 svdcmp iterations\n"); std::cerr << "SingularValueDecomposition - Warning: no convergence in 30 iterations." << std::endl; } x = w[l]; // Shift from bottom 2-by-2 minor. nm = k - 1; y = w[nm]; g = rv1[nm]; h = rv1[k]; f = ( (y-z) * (y+z) + (g-h) * (g+h) ) / (2.0 * h * y ); g = math::pythag( f, static_cast< T >( 1.0 ) ); f = ( ( x - z ) * ( x + z ) + h * ( ( y / ( f + math::sign( g, f ) ) ) - h ) ) / x; c = s = 1.0; // Next QR transformation: for ( j = l; j <= nm; ++j ) { i = j + 1; g = rv1[i]; y = w[i]; h = s * g; g = c * g; z = math::pythag( f, h ); rv1[j] = z; c = f / z; s = h / z; f = x * c + g * s; g = g * c - x * s; h = y * s; y *= c; for ( jj = 0; jj < n; ++jj ) { x = v[jj][j]; z = v[jj][i]; v[jj][j] = x * c + z * s; v[jj][i] = z * c - x * s; } z = math::pythag( f, h ); w[j] = z; // Rotation can be arbitrary if z = 0. if ( z ) { z = 1.0 / z; c = f * z; s = h * z; } f = c * g + s * y; x = c * y - s * g; for ( jj = 0; jj < m; ++jj ) { y = a[jj][j]; z = a[jj][i]; a[jj][j] = y * c + z * s; a[jj][i] = z * c - y * s; } } rv1[l] = 0.0; rv1[k] = f; w[k] = x; } } //free(rv1); for ( i = 0; i < 3; ++i ) for ( j = 0; j < 3; ++j ) if ( i < j && w[i] < w[j] ) { double t = w[i]; double u = w[j]; w[i] = u; w[j] = t; for ( k = 0; k < 3; ++k ) { t = v[i][k]; u = v[j][k]; v[i][k] = u * std::pow( -1., i ); v[j][k] = t * std::pow( -1., j ); t = a[k][i]; u = a[k][j]; a[k][i] = u * std::pow( -1., i ); a[k][j] = t * std::pow( -1., j ); } } } } #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_converter.hpp000066400000000000000000000451141231531733200254310ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * class to read/write and convert tensor3 files (from raw, to csv...) * */ #ifndef __VMML__T3_CONVERTER__HPP__ #define __VMML__T3_CONVERTER__HPP__ #include namespace vmml { template< size_t I1, size_t I2, size_t I3, typename T = float > class t3_converter { public: typedef tensor3< I1, I2, I3, T > t3_t; typedef typename vmml::tensor3_iterator< tensor3< I1, I2, I3, T > > iterator; typedef typename vmml::tensor3_const_iterator< tensor3< I1, I2, I3, T > > const_iterator; template< typename T_convert > static void convert_raw(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_); //header size as bytes static void remove_uct_cylinder(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_, const double& sigma_, const size_t header_size_, const size_t radius_offset_, int seed_ = 0); static void export_to(const t3_t& input_, std::vector< T >& output_); static void import_from(const std::vector< T >& input_, t3_t& output_); static void write_to_raw(const t3_t& data_, const std::string& dir_, const std::string& filename_); // OK static void read_from_raw(t3_t& data_, const std::string& dir_, const std::string& filename_); // OK static void write_datfile(const std::string& dir_, const std::string& filename_); static void write_to_csv(const t3_t& data_, const std::string& dir_, const std::string& filename_); static void remove_normals_from_raw(const t3_t& data_, const std::string& dir_, const std::string& filename_); static double rmse_from_files(const std::string& dir_, const std::string& filename_a_, const std::string& filename_b_ ); template< typename TT > static void quantize_to(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_, const T& min_value_, const T& max_value_); protected: static void concat_path(const std::string& dir_, const std::string& filename_, std::string& path_); }; //end t3_converter #define VMML_TEMPLATE_STRING template< size_t I1, size_t I2, size_t I3, typename T > #define VMML_TEMPLATE_CLASSNAME t3_converter< I1, I2, I3, T > VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize_to(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_, const T& min_value_, const T& max_value_) { std::string path_in_raw = ""; std::string path_out_raw = ""; concat_path(dir_, in_filename_, path_in_raw); concat_path(dir_, out_filename_, path_out_raw); std::ofstream outfile; outfile.open(path_out_raw.c_str()); std::ifstream infile; infile.open(path_in_raw.c_str(), std::ios::in); if (infile.is_open() && outfile.is_open()) { double max_tt_range = double((std::numeric_limits< TT >::max)()); double min_tt_range = double((std::numeric_limits< TT >::min)()); double tt_range = max_tt_range - min_tt_range; double t_range = max_value_ - min_value_; //std::cout << "tt min= " << min_tt_range << ", tt max= " << max_tt_range << ", t min= " << min_value_ << ", t max= " << max_value_ << std::endl; //std::cout << "tt range=" << tt_range << ", t range= " << t_range << std::endl; T* in_value; TT out_value; size_t len_in = sizeof (T); size_t len_out = sizeof (TT); char* data = new char[ len_in ]; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { //read value infile.read(data, len_in); in_value = (T*)&(data[0]); //Quantize value if (std::numeric_limits::is_signed) { out_value = TT((std::min)((std::max)(min_tt_range, double((*in_value * tt_range / t_range) + 0.5)), max_tt_range)); } else { out_value = TT((std::min)((std::max)(min_tt_range, double(((*in_value - min_value_) * tt_range / t_range) + 0.5)), max_tt_range)); } //write_value outfile.write((char*) &(out_value), len_out); } } } infile.close(); outfile.close(); } else { infile.close(); outfile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::concat_path(const std::string& dir_, const std::string& filename_, std::string& path_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); path_ = dir_; if (last_separator < dir_length) { path_.append("/"); } path_.append(filename_); //check for format if( filename_.find("raw", filename_.size() - 3) == std::string::npos ) { path_.append("."); path_.append("raw"); } } VMML_TEMPLATE_STRING template< typename T_convert > void VMML_TEMPLATE_CLASSNAME::convert_raw(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_) { std::string path_in_raw = ""; std::string path_out_raw = ""; concat_path(dir_, in_filename_, path_in_raw); concat_path(dir_, out_filename_, path_out_raw); std::ofstream outfile; outfile.open(path_out_raw.c_str()); std::ifstream infile; infile.open(path_in_raw.c_str(), std::ios::in); if (infile.is_open() && outfile.is_open()) { T* in_value; T_convert out_value; size_t len_in = sizeof (T); size_t len_out = sizeof (T_convert); char* data = new char[ len_in ]; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { infile.read(data, len_in); in_value = (T*)&(data[0]); out_value = static_cast (*in_value); outfile.write((char*) &(out_value), len_out); } } } infile.close(); outfile.close(); } else { infile.close(); outfile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::remove_uct_cylinder(const std::string& dir_, const std::string& in_filename_, const std::string& out_filename_, const double& sigma_, const size_t header_size_, const size_t radius_offset_, int seed_) { std::string path_in_raw = ""; std::string path_out_raw = ""; concat_path(dir_, in_filename_, path_in_raw); concat_path(dir_, out_filename_, path_out_raw); std::ofstream outfile; outfile.open(path_out_raw.c_str()); std::ifstream infile; infile.open(path_in_raw.c_str(), std::ios::in); //for noise adding in outer area if (seed_ >= 0) srand(seed_); double length = 0; double radius = (I1 - 1.0) / 2.0 - radius_offset_; radius *= radius; double k1 = 0; double k2 = 0; double fill_value = 0; if (infile.is_open() && outfile.is_open()) { T* in_value; T out_value; size_t len_val = sizeof (T); char* data = new char[ len_val ]; //skip header infile.read(data, header_size_); //Read/write data for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { k1 = i1 - (I1 - 1.0) / 2.0; for (size_t i2 = 0; i2 < I2; ++i2) { infile.read(data, len_val); in_value = (T*)&(data[0]); fill_value = static_cast (*in_value); //check if value is outside cylinder k2 = i2 - (I2 - 1.0) / 2.0; length = k1 * k1 + k2*k2; if (length >= radius) { fill_value = rand(); fill_value /= RAND_MAX; fill_value *= sigma_; } out_value = static_cast (fill_value); outfile.write((char*) &(out_value), len_val); } } } infile.close(); outfile.close(); } else { infile.close(); outfile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::export_to(const t3_t& input_, std::vector< T >& output_) { output_.clear(); const_iterator it = input_.begin(), it_end = input_.end(); for (; it != it_end; ++it) { output_.push_back(*it); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::import_from(const std::vector< T >& input_, t3_t& output_) { size_t i = 0; //iterator over data_ size_t input_size = input_.size(); iterator it = output_.begin(), it_end = output_.end(); for (; it != it_end; ++it, ++i) { if (i >= input_size) *it = static_cast (0); else *it = input_.at(i); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::remove_normals_from_raw(const t3_t& data_, const std::string& dir_, const std::string& filename_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } path.append(filename_); size_t max_file_len = 2147483648u - sizeof (T); size_t len_data = sizeof (T) * data_.SIZE; size_t len_value = sizeof (T) * 4; //three normals per scalar value size_t len_read = 0; char* data = new char[ len_data ]; std::ifstream infile; infile.open(path.c_str(), std::ios::in); if (infile.is_open()) { tensor3_iterator it = data_.begin(), it_end = data_.end(); size_t counter = 0; while (len_data > 0) { len_read = (len_data % max_file_len) > 0 ? len_data % max_file_len : len_data; len_data -= len_read; infile.read(data, len_read); T* T_ptr = (T*)&(data[0]); for (; (it != it_end) && (len_read > 0); ++it, len_read -= len_value) { ++T_ptr; ++T_ptr; ++T_ptr; *it = *T_ptr; ++T_ptr; ++counter; } } delete[] data; infile.close(); } else { std::cout << "no file open" << std::endl; } std::cout << "converted normals" << std::endl; std::string filename = ""; filename = filename_.substr(0, filename_.size() - 6); write_datfile(".", filename); write_to_raw(".", filename); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::read_from_raw(t3_t& data_, const std::string& dir_, const std::string& filename_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } path.append(filename_); size_t max_file_len = 2147483648u - sizeof (T); size_t len_data = sizeof (T) * data_.SIZE; size_t len_read = 0; char* data = new char[ len_data ]; std::ifstream infile; infile.open(path.c_str(), std::ios::in); if (infile.is_open()) { tensor3_iterator it = data_.begin(), it_end = data_.end(); while (len_data > 0) { len_read = (len_data % max_file_len) > 0 ? len_data % max_file_len : len_data; len_data -= len_read; infile.read(data, len_read); T* T_ptr = (T*)&(data[0]); for (; (it != it_end) && (len_read > 0); ++it, len_read -= sizeof (T)) { *it = *T_ptr; ++T_ptr; } } delete[] data; infile.close(); } else { std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::write_to_raw(const t3_t& data_, const std::string& dir_, const std::string& filename_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } path.append(filename_); //check for format if (filename_.find("raw", filename_.size() - 3) == std::string::npos) { path.append("."); path.append("raw"); } std::string path_raw = path; std::ofstream outfile; outfile.open(path_raw.c_str()); if (outfile.is_open()) { size_t len_slice = sizeof (T) * I1 * I2; for (size_t index = 0; index < I3; ++index) { outfile.write((char*) &(data_.get_frontal_slice_fwd(index)), len_slice); } outfile.close(); } else { outfile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::write_datfile(const std::string& dir_, const std::string& filename_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } std::string filename = filename_; const size_t pos = filename_.size(); if ((filename_.find(".raw", pos) + 4 == pos) || (filename_.find(".dat", pos) + 4 == pos)) { filename = filename_.substr(0, filename_.size() - 4); } path.append(filename); //check for format if (filename_.find("dat", filename_.size() - 3) == std::string::npos) { path.append("."); path.append("dat"); } std::string path_dat = path; const char* format = (sizeof (T) == 2) ? "USHORT" : "UCHAR"; FILE* datfile = fopen(path_dat.c_str(), "w"); fprintf(datfile, "ObjectFileName:\t%s.raw\n", filename.c_str()); fprintf(datfile, "TaggedFileName:\t---\nResolution:\t%i %i %i\n", int(I1), int(I2), int(I3)); fprintf(datfile, "SliceThickness:\t1.0 1.0 1.0\n"); fprintf(datfile, "Format:\t%s\nNbrTags:\t0\n", format); fprintf(datfile, "ObjectType:\tTEXTURE_VOLUME_OBJECT\nObjectModel:\tI\nGridType:\tEQUIDISTANT\n"); fprintf(datfile, "Modality:\tunknown\nTimeStep:\t0\n"); fclose(datfile); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::write_to_csv(const t3_t& data_, const std::string& dir_, const std::string& filename_) { int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } path.append(filename_); //check for format if (filename_.find("csv", filename_.size() - 3) == std::string::npos) { path.append("."); path.append("csv"); } std::ofstream outfile; outfile.open(path.c_str()); if (outfile.is_open()) { for (size_t i = 0; i < I3; ++i) { outfile << data_.get_frontal_slice_fwd(i) << std::endl; } outfile.close(); } else { std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::rmse_from_files(const std::string& dir_, const std::string& filename_a_, const std::string& filename_b_ ) { std::string path_a_raw = ""; std::string path_b_raw = ""; concat_path( dir_, filename_a_, path_a_raw ); concat_path( dir_, filename_b_, path_b_raw ); std::ifstream afile; afile.open( path_a_raw.c_str(), std::ios::in); std::ifstream bfile; bfile.open( path_b_raw.c_str(), std::ios::in); double mse_val = 0.0f; double mse_val_avg = 0.0f; double mse_val_i3 = 0.0f; double diff = 0.0f; if (afile.is_open() && bfile.is_open()) { T* a_value; T* b_value; double a_value_f; double b_value_f; size_t value_len = sizeof (T); char* data_a = new char[ value_len ]; char* data_b = new char[ value_len ]; for (size_t i3 = 0; i3 < I3; ++i3) { mse_val = 0.0f; for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { afile.read( data_a, value_len); a_value = (T*)&(data_a[0]); a_value_f = static_cast (*a_value); bfile.read( data_b, value_len); b_value = (T*)&(data_b[0]); b_value_f = static_cast (*b_value); diff = fabs(b_value_f - a_value_f); diff *= diff; mse_val += diff; } } mse_val_avg = mse_val; mse_val_avg /= double(I1); mse_val_avg /= double(I2); mse_val_i3 += mse_val_avg; } afile.close(); bfile.close(); } else { afile.close(); bfile.close(); std::cout << "no file open" << std::endl; } mse_val_i3 /= double(I3); return sqrt(mse_val_i3); } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_hooi.hpp000066400000000000000000000332131231531733200243550ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Rafa Ballester * * The higher-order orthogonal iteration (HOOI) is also known as Tucker-ALS (Tuck-ALS) * The t3_hooi implements a HOOI for a third-order tensor * references: * - Tucker, 1966: Some mathematical notes on three-mode factor analysis, Psychometrika. * - De Lathauwer, De Moor, Vandewalle, 2000a: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - De Lathauwer, De Moor, Vandewalle, 2000b: On the Best rank-1 and Rank-(R_1, R_2, ..., R_N) Approximation and Applications of Higher-Order Tensors, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * - Bader & Kolda, 2006: Algorithm 862: Matlab tensor classes for fast algorithm prototyping. ACM Transactions on Mathematical Software. * */ #ifndef __VMML__T3_HOOI__HPP__ #define __VMML__T3_HOOI__HPP__ #include #include #include #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T = float > class t3_hooi { public: typedef tensor3< I1, I2, I3, T > t3_type; typedef tensor3< R1, R2, R3, T > t3_core_type; typedef matrix< I1, R1, T > u1_type; typedef matrix< I2, R2, T > u2_type; typedef matrix< I3, R3, T > u3_type; typedef matrix< R1, I1, T > u1_t_type; typedef matrix< R2, I2, T > u2_t_type; typedef matrix< R3, I3, T > u3_t_type; /* higher-order orthogonal iteration (HOOI) is a truncated HOSVD decompositions, i.e., the HOSVD components are of lower-ranks. An optimal rank-reduction is performed with an alternating least-squares (ALS) algorithm, which minimizes the error between the approximated and orignal tensor based on the Frobenius norm see: De Lathauwer et al, 2000b; On the best rank-1 and rank-(RRR) approximation of higher-order tensors. the HOOI can be computed based on (a) n-mode PCA, i.e., an eigenvalue decomposition on the covariance matrix of every mode's matriciziation, and (b) by performing a 2D SVD on the matricization of every mode. Matrix matricization means that a tensor I1xI2xI3 is unfolded/sliced into one matrix with the dimensions I1xI2I3, which corresponds to a matrizitation alonge mode I1. */ template< typename T_init> static tensor_stats als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const double& max_f_norm_ = 0.0, const size_t max_iterations = 10, const float tolerance = 1e-04); //core not needed template< typename T_init> static tensor_stats als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, T_init init, const double& max_f_norm_ = 0.0, const size_t max_iterations = 10, const float tolerance = 1e-04); /* derive core implemented according to core = data x_1 U1_pinv x_2 U2_pinv x_3 U3_pinv, where x_1 ... x_3 are n-mode products and U1_pinv ... U3_pinv are inverted basis matrices the inversion is done with a matrix pseudoinverse computation */ static void derive_core(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, t3_core_type& core_); //faster: but only if basis matrices are orthogonal static void derive_core_orthogonal_bases(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, t3_core_type& core_); // init functors struct init_hosvd { inline void operator()(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type & u3_) { t3_hosvd< R1, R2, R3, I1, I2, I3, T >::apply_mode2(data_, u2_); t3_hosvd< R1, R2, R3, I1, I2, I3, T >::apply_mode3(data_, u3_); } }; struct init_random { inline void operator()(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type & u3_) { srand(time(NULL)); u2_.set_random(); u3_.set_random(); u2_ /= u2_.frobenius_norm(); u3_ /= u3_.frobenius_norm(); } }; struct init_dct { inline void operator()(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type & u3_) { u2_.set_dct(); u3_.set_dct(); } }; protected: static void optimize_mode1(const t3_type& data_, const u2_type& u2_, const u3_type& u3_, tensor3< I1, R2, R3, T >& projection_, tensor3< I1, R2, I3, T >& tmp_); static void optimize_mode2(const t3_type& data_, const u1_type& u1_, const u3_type& u3_, tensor3< R1, I2, R3, T >& projection_, tensor3< R1, I2, I3, T >& tmp_); static void optimize_mode3(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, tensor3< R1, R2, I3, T >& projection_, tensor3< R1, I2, I3, T >& tmp_); }; //end class t3_hooi #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T > #define VMML_TEMPLATE_CLASSNAME t3_hooi< R1, R2, R3, I1, I2, I3, T > VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, T_init init, const double& max_f_norm_, const size_t max_iterations, const float tolerance) { t3_core_type core; core.zero(); return als(data_, u1_, u2_, u3_, core, init, max_f_norm_, max_iterations, tolerance); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const double& max_f_norm_, const size_t max_iterations_, const float tolerance_) { tensor_stats result; //intialize basis matrices init(data_, u1_, u2_, u3_); core_.zero(); T max_f_norm = 0.0; T f_norm, fit, fitchange, fitold, normresidual; if (tolerance_ > 0) { max_f_norm = max_f_norm_; if (max_f_norm <= 0.0) { max_f_norm = data_.frobenius_norm(); } fit = 0; //removed to save computation /*if ( (max_f_norm != 0) && (max_f_norm > f_norm) ) { fit = 1 - (normresidual / max_f_norm); } else { fit = 1; }*/ fitchange = 1; fitold = fit; normresidual = 0; } tensor3< I1, R2, R3, T > projection1; tensor3< R1, I2, R3, T > projection2; tensor3< R1, R2, I3, T > projection3; tensor3< I1, R2, I3, T > tmp1; tensor3< R1, I2, I3, T > tmp2; #if TUCKER_LOG std::cout << "HOOI ALS (for tensor3) " << std::endl << "initial fit: " << fit << ", " << "frobenius norm original: " << max_f_norm << std::endl; #endif size_t i = 0; while (i < max_iterations_ && (tolerance_ < 0 || fitchange >= tolerance_)) { //do until converges fitold = fit; //optimize modes optimize_mode1(data_, u2_, u3_, projection1, tmp1); t3_hosvd< R1, R2, R3, I1, R2, R3, T >::apply_mode1(projection1, u1_); optimize_mode2(data_, u1_, u3_, projection2, tmp2); t3_hosvd< R1, R2, R3, R1, I2, R3, T >::apply_mode2(projection2, u2_); optimize_mode3(data_, u1_, u2_, projection3, tmp2); t3_hosvd< R1, R2, R3, R1, R2, I3, T >::apply_mode3(projection3, u3_); t3_ttm::multiply_horizontal_bwd(projection3, transpose(u3_), core_); if (tolerance_ > 0) { f_norm = core_.frobenius_norm(); normresidual = sqrt( fabs(max_f_norm * max_f_norm - f_norm * f_norm) ); fit = 1 - (normresidual / max_f_norm); fitchange = fabs(fitold - fit); #if TUCKER_LOG std::cout << "iteration '" << i << "', fit: " << fit << ", fitdelta: " << fitchange << ", frobenius norm of core: " << f_norm << std::endl; #endif } ++i; } result.set_n_iterations(i); return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode1(const t3_type& data_, const u2_type& u2_, const u3_type& u3_, tensor3< I1, R2, R3, T >& projection_, tensor3< I1, R2, I3, T >& tmp_) { u2_t_type* u2_inv = new u2_t_type; u3_t_type* u3_inv = new u3_t_type; u2_.transpose_to(*u2_inv); u3_.transpose_to(*u3_inv); #if 1 //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) t3_ttm::multiply_frontal_bwd(data_, *u2_inv, tmp_); t3_ttm::multiply_horizontal_bwd(tmp_, *u3_inv, projection_); #else //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized t3_ttm::multiply_horizontal_fwd(data_, *u2_inv, tmp_); t3_ttm::multiply_lateral_fwd(tmp_, *u3_inv, projection_); #endif delete u2_inv; delete u3_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode2(const t3_type& data_, const u1_type& u1_, const u3_type& u3_, tensor3< R1, I2, R3, T >& projection_, tensor3< R1, I2, I3, T >& tmp_) { u1_t_type* u1_inv = new u1_t_type(); u3_t_type* u3_inv = new u3_t_type(); u1_.transpose_to(*u1_inv); u3_.transpose_to(*u3_inv); #if 0 //backward cyclic matricization (after Lathauwer et al., 2000a) t3_ttm::multiply_lateral_bwd(data_, *u1_inv, tmp_); t3_ttm::multiply_horizontal_bwd(tmp_, *u3_inv, projection_); #else //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized t3_ttm::multiply_frontal_fwd(data_, *u1_inv, tmp_); t3_ttm::multiply_lateral_fwd(tmp_, *u3_inv, projection_); #endif delete u1_inv; delete u3_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode3(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, tensor3< R1, R2, I3, T >& projection_, tensor3< R1, I2, I3, T >& tmp_) { u1_t_type* u1_inv = new u1_t_type; u2_t_type* u2_inv = new u2_t_type; u1_.transpose_to(*u1_inv); u2_.transpose_to(*u2_inv); #if 0 //backward cyclic matricization (after Lathauwer et al., 2000a) t3_ttm::multiply_lateral_bwd(data_, *u1_inv, tmp_); t3_ttm::multiply_frontal_bwd(tmp_, *u2_inv, projection_); #else //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized t3_ttm::multiply_frontal_fwd(data_, *u1_inv, tmp_); t3_ttm::multiply_horizontal_fwd(tmp_, *u2_inv, projection_); #endif delete u1_inv; delete u2_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::derive_core_orthogonal_bases(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, t3_core_type& core_) { u1_t_type* u1_inv = new u1_t_type; u2_t_type* u2_inv = new u2_t_type; u3_t_type* u3_inv = new u3_t_type; u1_.transpose_to(*u1_inv); u2_.transpose_to(*u2_inv); u3_.transpose_to(*u3_inv); t3_ttm::full_tensor3_matrix_multiplication(data_, *u1_inv, *u2_inv, *u3_inv, core_); delete u1_inv; delete u2_inv; delete u3_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::derive_core(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, t3_core_type& core_) { #if 1 //faster approach //compute pseudo inverse for matrices u1-u3 u1_type* u1_pinv_t = new u1_type; u2_type* u2_pinv_t = new u2_type; u3_type* u3_pinv_t = new u3_type; compute_pseudoinverse< u1_type > compute_pinv_u1; compute_pinv_u1(u1_, *u1_pinv_t); compute_pseudoinverse< u2_type > compute_pinv_u2; compute_pinv_u2(u2_, *u2_pinv_t); compute_pseudoinverse< u3_type > compute_pinv_u3; compute_pinv_u3(u3_, *u3_pinv_t); u1_t_type* u1_pinv = new u1_t_type; u2_t_type* u2_pinv = new u2_t_type; u3_t_type* u3_pinv = new u3_t_type; u1_pinv_t->transpose_to(*u1_pinv); u2_pinv_t->transpose_to(*u2_pinv); u3_pinv_t->transpose_to(*u3_pinv); t3_ttm::full_tensor3_matrix_multiplication(data_, *u1_pinv, *u2_pinv, *u3_pinv, core_); delete u1_pinv; delete u2_pinv; delete u3_pinv; delete u1_pinv_t; delete u2_pinv_t; delete u3_pinv_t; #else //previous version of compute core for (size_t r3 = 0; r3 < R3; ++r3) { for (size_t r1 = 0; r1 < R1; ++r1) { for (size_t r2 = 0; r2 < R2; ++r2) { float_t sum_i1_i2_i3 = 0.0; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { sum_i1_i2_i3 += u1_.at(i1, r1) * u2_.at(i2, r2) * u3_.at(i3, r3) * T(data_.at(i1, i2, i3)); } } } core_.at(r1, r2, r3) = sum_i1_i2_i3; } } } #endif } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_hopm.hpp000066400000000000000000000400451231531733200243630ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Rafa Ballester * * the higher-order power method (HOPM) is also known as CP-ALS (ALS: alternating least squares) * CP stands for Candecomp/Parafac (1970) * references: * - Carroll & Chang, 1970: Analysis of Individual Differences in Multidimensional Scaling via an N-way generalization of ``Eckart--Young'' decompositions, Psychometrika. * - Harshman, 1970: Foundations of the PARAFAC procedure: Models and conditions for an 'explanatory' multi-modal factor analysis, UCLA Working Papers in Phonetics. * - De Lathauwer, De Moor, Vandewalle, 2000: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * - Bader & Kolda, 2006: Algorithm 862: Matlab tensor classes for fast algorithm prototyping. ACM Transactions on Mathematical Software. * */ #ifndef __VMML__T3_HOPM__HPP__ #define __VMML__T3_HOPM__HPP__ #include #include #include #include #include #include #include namespace vmml { template< size_t R, size_t I1, size_t I2, size_t I3, typename T = float > class t3_hopm { public: typedef tensor3< I1, I2, I3, T > t3_type; typedef vector< R, T > lambda_type; typedef matrix< I1, R, T > u1_type; typedef matrix< I2, R, T > u2_type; typedef matrix< I3, R, T > u3_type; typedef matrix< R, I1, T > u1_inv_type; typedef matrix< R, I2, T > u2_inv_type; typedef matrix< R, I3, T > u3_inv_type; typedef matrix< I1, I2*I3, T > u1_unfolded_type; typedef matrix< I2, I1*I3, T > u2_unfolded_type; typedef matrix< I3, I1*I2, T > u3_unfolded_type; typedef matrix< R, R, T > m_r2_type; typedef typename lambda_type::iterator lvalue_iterator; typedef typename lambda_type::const_iterator lvalue_const_iterator; typedef std::pair< T, size_t > lambda_pair_type; //higher-order power method (lathauwer et al., 2000b) template< typename T_init > static tensor_stats als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); static void reconstruct(t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_); //ktensor = kruskal tensor, i.e., lambda, U1, U2, U3 static double norm_ktensor(const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_); // init functors struct init_hosvd { inline void operator()(const t3_type& data_, u2_type& u2_, u3_type & u3_) { t3_hosvd< R, R, R, I1, I2, I3, T >::apply_mode2(data_, u2_); t3_hosvd< R, R, R, I1, I2, I3, T >::apply_mode3(data_, u3_); } }; struct init_random { inline void operator()(const t3_type& data_, u2_type& u2_, u3_type & u3_) { srand(time(NULL)); u2_.set_random(); u3_.set_random(); } }; //FIXME: check test on linux #if 1 struct init_dct { inline void operator()(const t3_type& data_, u2_type& u2_, u3_type & u3_) { u2_.set_dct(); u3_.set_dct(); } }; #endif protected: static void optimize_mode1(const t3_type& data_, u1_type& u1, const u2_type& u2_, const u3_type& u3_, lambda_type& lambdas_); static void optimize_mode2(const t3_type& data_, const u1_type& u1_, u2_type& u2_, const u3_type& u3_, lambda_type& lambdas_); static void optimize_mode3(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, u3_type& u3_, lambda_type& lambdas_); template< size_t J, size_t K, size_t L > static void optimize(const matrix< J, K*L, T >& unfolding_, matrix< J, R, T >& uj_, const matrix< K, R, T >& uk_, const matrix< L, R, T >& ul_, vector< R, T>& lambdas_ ); static void sort_dec(u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_); // comparison functor struct lambda_compare { inline bool operator()(const lambda_pair_type& a, const lambda_pair_type & b) { return fabs(a.first) > fabs(b.first); } }; }; #define VMML_TEMPLATE_STRING template< size_t R, size_t I1, size_t I2, size_t I3, typename T > #define VMML_TEMPLATE_CLASSNAME t3_hopm< R, I1, I2, I3, T > VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_, T_init init, const size_t max_iterations_, const float tolerance_) { tensor_stats result; t3_type* approximated_data = new t3_type; t3_type* residual_data = new t3_type; residual_data->zero(); T max_f_norm = 0.0; T fit = 0.; T fitchange, norm2, innerprod, fitold, normresidual; if (tolerance_ > 0) { max_f_norm = data_.frobenius_norm(); fit = 0; if (max_f_norm == 0) fit = 1; fitchange = 1; norm2 = innerprod = 0; fitold = fit; normresidual = 0; } //intialize u1-u3 //inital guess not needed for u1 since it will be computed in the first optimization step init(data_, u2_, u3_); assert(validator::is_valid(u2_) && validator::is_valid(u3_)); assert(validator::is_valid(lambdas_)); #if CP_LOG std::ostringstream convert; convert << R; std::cout << convert.str() + "-R rank CP ALS: HOPM (for tensor3) " << std::endl; #endif size_t i = 0; while (i < max_iterations_ && (tolerance_ < 0 || fitchange >= tolerance_)) //do until converges { fitold = fit; // timer myTimer; // myTimer.start(); optimize_mode1(data_, u1_, u2_, u3_, lambdas_); //#if CP_LOG // std::cerr << myTimer.get_seconds() << " "; // myTimer.start(); //#endif optimize_mode2(data_, u1_, u2_, u3_, lambdas_); #if CP_LOG // std::cerr << myTimer.get_seconds() << " "; // myTimer.start(); #endif optimize_mode3(data_, u1_, u2_, u3_, lambdas_); //#if CP_LOG // std::cerr << myTimer.get_seconds() << " "; //#endif if (tolerance_ > 0) { norm2 = norm_ktensor(u1_, u2_, u3_, lambdas_); T val2 = 0; for( size_t j = 0; j < lambdas_.size(); ++j) { matrix res1; t3_ttv::multiply_first_mode(data_, u1_.get_column(j), res1); vector res2 = res1 * u3_.get_column(j); val2 += lambdas_.at(j) * (res2.dot(u2_.get_column(j))); } innerprod = 2 * val2; // ||X-P|| = sqrt( ||X||^2 + ||P||^2 - 2 * X.P ); normresidual = sqrt(max_f_norm * max_f_norm + norm2 * norm2 - innerprod); fit = 1 - (normresidual / max_f_norm); fitchange = fabs(fitold - fit); #if CP_LOG // std::cerr << myTimer.get_seconds() << " "; std::cout << "iteration '" << i << "', fit: " << fit << ", fitdelta: " << fit - fitold << ", normresidual: " << normresidual; if (fit - fitold < 0) std::cout << " *fit is worsening*"; std::cout << std::endl; #endif } #if 0 myTimer.start(); //Reconstruct tensor and measure norm of approximation //slower version since cp reconstruction is slow reconstruct(*approximated_data, u1_, u2_, u3_, lambdas_); // approx_norm = approximated_data->frobenius_norm(); *residual_data = data_ - *approximated_data; normresidual = residual_data->frobenius_norm(); std::cerr << myTimer.get_seconds() << " "; #endif ++i; } // end ALS result.set_n_iterations(i); //sort lambdas by decreasing magnitude sort_dec(u1_, u2_, u3_, lambdas_); delete residual_data; delete approximated_data; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode1(const t3_type& data_, u1_type& u1_, const u2_type& u2_, const u3_type& u3_, lambda_type& lambdas_) { u1_unfolded_type* unfolding = new u1_unfolded_type; // -> u1 //data_.horizontal_unfolding_bwd( *unfolding ); //lathauwer data_.frontal_unfolding_fwd(*unfolding); assert(validator::is_valid(u2_) && validator::is_valid(u3_)); optimize(*unfolding, u1_, u2_, u3_, lambdas_); delete unfolding; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode2(const t3_type& data_, const u1_type& u1_, u2_type& u2_, const u3_type& u3_, lambda_type& lambdas_) { u2_unfolded_type* unfolding = new u2_unfolded_type; // -> u2 data_.frontal_unfolding_bwd(*unfolding); //lathauwer //data_.horizontal_unfolding_fwd( *unfolding ); assert(validator::is_valid(u1_) && validator::is_valid(u3_)); optimize(*unfolding, u2_, u1_, u3_, lambdas_); delete unfolding; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode3(const t3_type& data_, const u1_type& u1_, const u2_type& u2_, u3_type& u3_, lambda_type& lambdas_) { u3_unfolded_type* unfolding = new u3_unfolded_type; //-> u3 //data_.horizontal_unfolding_bwd( *unfolding );//lathauwer data_.lateral_unfolding_fwd(*unfolding); assert(validator::is_valid(u1_) && validator::is_valid(u2_)); optimize(*unfolding, u3_, u1_, u2_, lambdas_); delete unfolding; } VMML_TEMPLATE_STRING template< size_t J, size_t K, size_t L > void VMML_TEMPLATE_CLASSNAME::optimize( const matrix< J, K*L, T >& unfolding_, matrix< J, R, T >& uj_, const matrix< K, R, T >& uk_, const matrix< L, R, T >& ul_, vector< R, T>& lambdas_ ) { typedef matrix< K*L, R, T > krp_matrix_type; krp_matrix_type* krp_prod = new krp_matrix_type; assert(validator::is_valid(uk_) && validator::is_valid(ul_)); ul_.khatri_rao_product(uk_, *krp_prod); matrix< J, R, T >* u_new = new matrix< J, R, T >; blas_dgemm< J, K*L, R, T> blas_dgemm1; blas_dgemm1.compute(unfolding_, *krp_prod, *u_new); //square matrix of U_l and U_k m_r2_type* uk_r = new m_r2_type; m_r2_type* ul_r = new m_r2_type; blas_dgemm< R, K, R, T> blas_dgemm2; blas_dgemm2.compute_t(uk_, *uk_r); assert(validator::is_valid(*uk_r)); blas_dgemm< R, L, R, T> blas_dgemm3; blas_dgemm3.compute_t(ul_, *ul_r); assert(validator::is_valid(*ul_r)); uk_r->multiply_piecewise(*ul_r); assert(validator::is_valid(*uk_r)); m_r2_type* pinv_t = new m_r2_type; compute_pseudoinverse< m_r2_type > compute_pinv; compute_pinv(*uk_r, *pinv_t); blas_dgemm< J, R, R, T> blas_dgemm4; blas_dgemm4.compute_bt(*u_new, *pinv_t, uj_); assert(validator::is_valid(uj_)); *u_new = uj_; u_new->multiply_piecewise(*u_new); //2 norm u_new->columnwise_sum(lambdas_); assert(validator::is_valid(lambdas_)); lambdas_.sqrt_elementwise(); lambda_type* tmp = new lambda_type; *tmp = lambdas_; tmp->reciprocal_safe(); assert(validator::is_valid(*tmp)); m_r2_type* diag_lambdas = new m_r2_type; diag_lambdas->diag(*tmp); matrix< J, R, T >* tmp_uj = new matrix< J, R, T > (uj_); blas_dgemm4.compute(*tmp_uj, *diag_lambdas, uj_); assert(validator::is_valid(uj_)); delete krp_prod; delete uk_r; delete ul_r; delete pinv_t; delete u_new; delete diag_lambdas; delete tmp; delete tmp_uj; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct(t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_) { u1_inv_type* u1_t = new u1_inv_type; u2_inv_type* u2_t = new u2_inv_type; u3_inv_type* u3_t = new u3_inv_type; typedef matrix< R, I2 * I3, T > m_temp_type; m_temp_type* temp = new m_temp_type; u1_.transpose_to(*u1_t); u2_.transpose_to(*u2_t); u3_.transpose_to(*u3_t); data_.reconstruct_CP(lambdas_, *u1_t, *u2_t, *u3_t, *temp); delete temp; delete u1_t; delete u2_t; delete u3_t; } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::norm_ktensor(const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_) { m_r2_type* coeff2_matrix = new m_r2_type; m_r2_type* cov_u1 = new m_r2_type; m_r2_type* cov_u2 = new m_r2_type; m_r2_type* cov_u3 = new m_r2_type; blas_dgemm< R, 1, R, T >* blas_l2 = new blas_dgemm< R, 1, R, T>; blas_l2->compute_vv_outer(lambdas_, lambdas_, *coeff2_matrix); delete blas_l2; blas_dgemm< R, I1, R, T >* blas_u1cov = new blas_dgemm< R, I1, R, T>; blas_u1cov->compute_t(u1_, *cov_u1); delete blas_u1cov; blas_dgemm< R, I2, R, T >* blas_u2cov = new blas_dgemm< R, I2, R, T>; blas_u2cov->compute_t(u2_, *cov_u2); delete blas_u2cov; blas_dgemm< R, I3, R, T >* blas_u3cov = new blas_dgemm< R, I3, R, T>; blas_u3cov->compute_t(u3_, *cov_u3); delete blas_u3cov; coeff2_matrix->multiply_piecewise(*cov_u1); coeff2_matrix->multiply_piecewise(*cov_u2); coeff2_matrix->multiply_piecewise(*cov_u3); double nrm = coeff2_matrix->sum_elements(); delete coeff2_matrix; delete cov_u1; delete cov_u2; delete cov_u3; return sqrt(nrm); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::sort_dec(u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_) { //keep copy of original matrices u1_type *orig_u1 = new u1_type(u1_); u2_type *orig_u2 = new u2_type(u2_); u3_type *orig_u3 = new u3_type(u3_); lambda_type sorted_lvalues; //(1) store permutations of the lambdas (According to larges magnitude std::vector< lambda_pair_type > lambda_permut; lvalue_const_iterator it = lambdas_.begin(), it_end = lambdas_.end(); size_t counter = 0; for (; it != it_end; ++it, ++counter) { lambda_permut.push_back(lambda_pair_type(*it, counter)); } std::sort( lambda_permut.begin(), lambda_permut.end(), lambda_compare() ); //(2) sort the matrix vectors according to lambda permutations and set sorted lambdas typename std::vector< lambda_pair_type >::const_iterator it2 = lambda_permut.begin(), it2_end = lambda_permut.end(); lvalue_iterator lvalues_it = lambdas_.begin(); for (counter = 0; it2 != it2_end; ++it2, ++counter, ++lvalues_it) { *lvalues_it = it2->first; u1_.set_column(counter, orig_u1->get_column(it2->second)); u2_.set_column(counter, orig_u2->get_column(it2->second)); u3_.set_column(counter, orig_u3->get_column(it2->second)); } delete orig_u1; delete orig_u2; delete orig_u3; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_hosvd.hpp000066400000000000000000000252671231531733200245540ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * The Tucker3 tensor class is consists of the same components (core tensor, basis matrices u1-u3) as the tucker3 model described in: * - Tucker, 1966: Some mathematical notes on three-mode factor analysis, Psychometrika. * - Kroonenberg & De Leeuw, 1980: Principal component analysis of three-mode data by means of alternating least squares algorithms. Psychometrika. (TUCKALS) * - De Lathauwer, De Moor, Vandewalle, 2000a: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * - Bader & Kolda, 2006: Algorithm 862: Matlab tensor classes for fast algorithm prototyping. ACM Transactions on Mathematical Software. * */ #ifndef __VMML__T3_HOSVD__HPP__ #define __VMML__T3_HOSVD__HPP__ #include #include #include #include #include enum hosvd_method { eigs_e, svd_e }; namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T = float > class t3_hosvd { public: typedef double T_svd; typedef tensor3< I1, I2, I3, T > t3_type; typedef matrix< I1, R1, T > u1_type; typedef matrix< I2, R2, T > u2_type; typedef matrix< I3, R3, T > u3_type; typedef matrix< I1, I2*I3, T > u1_unfolded_type; typedef matrix< I2, I1*I3, T > u2_unfolded_type; typedef matrix< I3, I1*I2, T > u3_unfolded_type; typedef matrix< I1, I1, T > u1_cov_type; typedef matrix< I2, I2, T > u2_cov_type; typedef matrix< I3, I3, T > u3_cov_type; /* higher-order singular value decomposition (HOSVD) with full rank decomposition (also known as Tucker decomposition). see: De Lathauer et al, 2000a: A multilinear singular value decomposition. the hosvd can be computed (a) with n-mode PCA, i.e., an eigenvalue decomposition on the covariance matrix of every mode's matricization, and (b) by performing a 2D SVD on the matricization of every mode. Matrix matricization means that a tensor I1xI2xI3 is unfolded/sliced into one matrix with the dimensions I1xI2I3, which corresponds to a matrizitation alonge mode I1. other known names for HOSVD: n-mode SVD, 3-mode factor analysis (3MFA, tucker3), 3M-PCA, n-mode PCA, higher-order SVD */ static void apply_mode1( const t3_type& data_, u1_type& u1_, hosvd_method method_ = eigs_e ); static void apply_mode2( const t3_type& data_, u2_type& u2_, hosvd_method method_ = eigs_e ); static void apply_mode3( const t3_type& data_, u3_type& u3_, hosvd_method method_ = eigs_e ); static void apply_all( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, hosvd_method method_ = eigs_e ); static void hosvd( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_ ); static void hoeigs( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_ ); protected: //hosvd template< size_t M, size_t N, size_t R > static void get_svd_u_red( const matrix< M, N, T >& data_, matrix< M, R, T >& u_ ); static void svd_mode1( const t3_type& data_, u1_type& u1_ ); static void svd_mode2( const t3_type& data_, u2_type& u2_ ); static void svd_mode3( const t3_type& data_, u3_type& u3_ ); //hosvd on eigenvalue decomposition = hoeigs template< size_t N, size_t R > static void get_eigs_u_red( const matrix< N, N, T >& data_, matrix< N, R, T >& u_ ); static void eigs_mode1( const t3_type& data_, u1_type& u1_ ); static void eigs_mode2( const t3_type& data_, u2_type& u2_ ); static void eigs_mode3( const t3_type& data_, u3_type& u3_ ); }; //end hosvd class #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T > #define VMML_TEMPLATE_CLASSNAME t3_hosvd< R1, R2, R3, I1, I2, I3, T > VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::hosvd( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_ ) { svd_mode1( data_, u1_ ); svd_mode2( data_, u2_ ); svd_mode3( data_, u3_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::hoeigs( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_ ) { eigs_mode1( data_, u1_ ); eigs_mode2( data_, u2_ ); eigs_mode3( data_, u3_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_all( const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, hosvd_method method_ ) { apply_mode1( data_, u1_, method_ ); apply_mode2( data_, u2_, method_ ); apply_mode3( data_, u3_, method_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode1( const t3_type& data_, u1_type& u1_, hosvd_method method_ ) { switch ( method_ ) { case 0: eigs_mode1( data_, u1_ ); break; case 1: svd_mode1( data_, u1_ ); break; default: eigs_mode1( data_, u1_ ); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode2( const t3_type& data_, u2_type& u2_, hosvd_method method_ ) { switch ( method_ ) { case 0: eigs_mode2( data_, u2_ ); break; case 1: svd_mode2( data_, u2_ ); break; default: eigs_mode2( data_, u2_ ); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode3( const t3_type& data_, u3_type& u3_, hosvd_method method_ ) { switch ( method_ ) { case 0: eigs_mode3( data_, u3_ ); break; case 1: svd_mode3( data_, u3_ ); break; default: eigs_mode3( data_, u3_ ); } } /* SVD along mode 1, 2, and 3*/ VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::svd_mode1( const t3_type& data_, u1_type& u1_ ) { u1_unfolded_type* u = new u1_unfolded_type; // -> u1 data_.lateral_unfolding_bwd( *u ); get_svd_u_red( *u, u1_ ); delete u; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::svd_mode2( const t3_type& data_, u2_type& u2_ ) { u2_unfolded_type* u = new u2_unfolded_type; // -> u2 data_.frontal_unfolding_bwd( *u ); get_svd_u_red( *u, u2_ ); delete u; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::svd_mode3( const t3_type& data_, u3_type& u3_ ) { u3_unfolded_type* u = new u3_unfolded_type; // -> u3 data_.horizontal_unfolding_bwd( *u ); get_svd_u_red( *u, u3_ ); delete u; } /* EIGS for mode 1, 2 and 3*/ VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode1( const t3_type& data_, u1_type& u1_ ) { //unfolding / matricization u1_unfolded_type* m_lateral = new u1_unfolded_type; // -> u1 data_.lateral_unfolding_bwd( *m_lateral ); //covariance matrix of unfolded data u1_cov_type* cov = new u1_cov_type; #if 1 blas_dgemm< I1, I2*I3, I1, T>* blas_cov = new blas_dgemm< I1, I2*I3, I1, T>; blas_cov->compute( *m_lateral, *cov ); #else blas_daxpy< I1, T>* blas_cov = new blas_daxpy< I1, T>; blas_cov->compute_mmm( *m_lateral, *cov ); #endif delete blas_cov; delete m_lateral; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u1_ ); delete cov; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode2( const t3_type& data_, u2_type& u2_ ) { //unfolding / matricization u2_unfolded_type* m_frontal = new u2_unfolded_type; // -> u2 data_.frontal_unfolding_bwd( *m_frontal ); //covariance matrix of unfolded data u2_cov_type* cov = new u2_cov_type; #if 1 blas_dgemm< I2, I1*I3, I2, T>* blas_cov = new blas_dgemm< I2, I1*I3, I2, T>; blas_cov->compute( *m_frontal, *cov ); #else blas_daxpy< I2, T>* blas_cov = new blas_daxpy< I2, T>; blas_cov->compute_mmm( *m_frontal, *cov ); #endif delete blas_cov; delete m_frontal; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u2_ ); delete cov; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode3( const t3_type& data_, u3_type& u3_) { //unfolding / matricization u3_unfolded_type* m_horizontal = new u3_unfolded_type; // -> u3 data_.horizontal_unfolding_bwd( *m_horizontal ); //covariance matrix of unfolded data u3_cov_type* cov = new u3_cov_type; #if 1 blas_dgemm< I3, I1*I2, I3, T>* blas_cov = new blas_dgemm< I3, I1*I2, I3, T>; blas_cov->compute( *m_horizontal, *cov ); #else blas_daxpy< I3, T>* blas_cov = new blas_daxpy< I3, T>; blas_cov->compute_mmm( *m_horizontal, *cov ); #endif delete blas_cov; delete m_horizontal; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u3_ ); delete cov; } /* helper methods for SVD and EIGS*/ VMML_TEMPLATE_STRING template< size_t N, size_t R > void VMML_TEMPLATE_CLASSNAME::get_eigs_u_red( const matrix< N, N, T >& data_, matrix< N, R, T >& u_ ) { typedef matrix< N, N, T_svd > cov_matrix_type; typedef vector< R, T_svd > eigval_type; typedef matrix< N, R, T_svd > eigvec_type; //typedef matrix< N, R, T_coeff > coeff_type; //compute x largest magnitude eigenvalues; x = R eigval_type* eigxvalues = new eigval_type; eigvec_type* eigxvectors = new eigvec_type; lapack_sym_eigs< N, T_svd > eigs; cov_matrix_type* data = new cov_matrix_type; data->cast_from( data_ ); if( eigs.compute_x( *data, *eigxvectors, *eigxvalues) ) { /*if( _is_quantify_coeff ){ coeff_type* evec_quant = new coeff_type; T min_value = 0; T max_value = 0; u_.cast_from( *eigxvectors ); u_.quantize( *evec_quant, min_value, max_value ); evec_quant->dequantize( u_, min_value, max_value ); delete evec_quant; } else */ if ( sizeof( T ) != 4 ){ u_.cast_from( *eigxvectors ); } else { u_ = *eigxvectors; } } else { u_.zero(); } delete eigxvalues; delete eigxvectors; delete data; } VMML_TEMPLATE_STRING template< size_t M, size_t N, size_t R > void VMML_TEMPLATE_CLASSNAME::get_svd_u_red( const matrix< M, N, T >& data_, matrix< M, R, T >& u_ ) { typedef matrix< M, N, T_svd > svd_m_type; //FIXME: typedef matrix< M, N, T_coeff > coeff_type; typedef matrix< M, N, T > m_type; typedef vector< N, T_svd > lambdas_type; svd_m_type* u_double = new svd_m_type; u_double->cast_from( data_ ); //FIXME:: coeff_type* u_quant = new coeff_type; m_type* u_out = new m_type; lambdas_type* lambdas = new lambdas_type; lapack_svd< M, N, T_svd >* svd = new lapack_svd< M, N, T_svd >(); if( svd->compute_and_overwrite_input( *u_double, *lambdas )) { /* if( _is_quantify_coeff ){ T min_value = 0; T max_value = 0; u_comp->cast_from( *u_double ); //FIXME: u_comp->quantize( *u_quant, min_value, max_value ); //FIXME: u_quant->dequantize( *u_internal, min_value, max_value ); } else */ if ( sizeof( T ) != 4 ){ u_out->cast_from( *u_double ); } else { *u_out = *u_double; } u_out->get_sub_matrix( u_ ); } else { u_.zero(); } delete lambdas; delete svd; delete u_double; //delete u_quant; delete u_out; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_ihooi.hpp000066400000000000000000000300271231531733200245260ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafael Ballester * * incremental version of higher-order orthogonal iteration (HOOI), see t3_hooi.hpp * */ #ifndef __VMML__T3_IHOOI_HPP__ #define __VMML__T3_IHOOI_HPP__ #include #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t NBLOCKS, size_t I1, size_t I2, size_t I3, typename T_val = float, typename T_coeff = double > class t3_ihooi { public: typedef tensor3< I1, I2, I3, T_val > t3_type; typedef tensor3< I1, I2, I3, T_coeff > t3_coeff_type; // The output data typedef tensor3< R1, R2, R3, T_val > t3_core_type; typedef matrix< I1, R1, T_val > u1_type; typedef matrix< I2, R2, T_val > u2_type; typedef matrix< I3, R3, T_val > u3_type; // The incremental data, it is iteratively filled and later cast into the output typedef tensor3< R1, R2, R3, T_coeff > t3_core_incr_type; typedef matrix< I1, R1, T_coeff > u1_incr_type; typedef matrix< I2, R2, T_coeff > u2_incr_type; typedef matrix< I3, R3, T_coeff > u3_incr_type; // The pieces that are used at each iteration typedef tensor3< R1 / NBLOCKS, R2 / NBLOCKS, R3 / NBLOCKS, T_coeff > t3_core_tmp_type; typedef matrix< I1, R1 / NBLOCKS, T_coeff > u1_tmp_type; typedef matrix< I2, R2 / NBLOCKS, T_coeff > u2_tmp_type; typedef matrix< I3, R3 / NBLOCKS, T_coeff > u3_tmp_type; // Used to "transport" individual columns between the tmp_type's and the incr_type's typedef matrix< I1, 1, T_coeff > u1_1col_type; typedef matrix< I2, 1, T_coeff > u2_1col_type; typedef matrix< I3, 1, T_coeff > u3_1col_type; // Incremental Tucker-ALS template< typename T_init > static tensor_stats i_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); // Incremental CP-Tucker-ALS: at each iteration, R-rank CP is performed, but a (R1,R2,R3)-Tucker core (R1,R2,R3 <= R) is computed from the resulting matrices. template< size_t R, typename T_init > static tensor_stats i_cp_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04); }; #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t NBLOCKS, size_t I1, size_t I2, size_t I3, typename T_val, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME t3_ihooi< R1, R2, R3, NBLOCKS, I1, I2, I3, T_val, T_coeff > VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::i_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const size_t max_iterations_, const float tolerance) { tensor_stats result; if ((R1 % NBLOCKS != 0) or (R2 % NBLOCKS != 0) or (R3 % NBLOCKS != 0)) { std::ostringstream convert1, convert2, convert3, convert4; convert1 << R1; convert2 << R2; convert3 << R3; convert4 << NBLOCKS; VMMLIB_ERROR("In incremental Tucker, (R1,R2,R3) = (" + convert1.str() + "," + convert2.str() + "," + convert3.str() + "), NBLOCKS = " + convert2.str() + " (must be divisible)", VMMLIB_HERE); } t3_coeff_type* approx_data = new t3_coeff_type; approx_data->zero(); t3_coeff_type* residual_data = new t3_coeff_type; residual_data->cast_from(data_); t3_core_tmp_type* t3_core_tmp = new t3_core_tmp_type; t3_core_tmp->zero(); u1_tmp_type* u1_tmp = new u1_tmp_type; u2_tmp_type* u2_tmp = new u2_tmp_type; u3_tmp_type* u3_tmp = new u3_tmp_type; t3_core_incr_type* t3_core_incr = new t3_core_incr_type; t3_core_incr->zero(); u1_incr_type* u1_incr = new u1_incr_type; u1_incr->zero(); u2_incr_type* u2_incr = new u2_incr_type; u2_incr->zero(); u3_incr_type* u3_incr = new u3_incr_type; u3_incr->zero(); u1_1col_type* u1_1col = new u1_1col_type; u2_1col_type* u2_1col = new u2_1col_type; u3_1col_type* u3_1col = new u3_1col_type; typedef t3_hooi < R1 / NBLOCKS, R2 / NBLOCKS, R3 / NBLOCKS, I1, I2, I3, T_coeff > hooi_type; for (size_t i = 0; i < NBLOCKS; ++i) { #ifdef TUCKER_LOG std::cout << "Incremental Tucker: block number '" << i << "'" << std::endl; #endif // Do Tucker-ALS for this block result += hooi_type::als(*residual_data, *u1_tmp, *u2_tmp, *u3_tmp, *t3_core_tmp, typename hooi_type::init_hosvd(), tolerance); // Copy the newly obtained columns into ui_incr for (size_t r = 0; r < R1 / NBLOCKS; ++r) { u1_tmp->get_column(r, *u1_1col); u1_incr->set_column(i * R1 / NBLOCKS + r, *u1_1col); } for (size_t r = 0; r < R2 / NBLOCKS; ++r) { u2_tmp->get_column(r, *u2_1col); u2_incr->set_column(i * R2 / NBLOCKS + r, *u2_1col); } for (size_t r = 0; r < R3 / NBLOCKS; ++r) { u3_tmp->get_column(r, *u3_1col); u3_incr->set_column(i * R3 / NBLOCKS + r, *u3_1col); } // Copy the newly obtained block core into t3_core_incr t3_core_incr->set_sub_tensor3(*t3_core_tmp, i * R1 / NBLOCKS, i * R2 / NBLOCKS, i * R3 / NBLOCKS); // Reconstruct this t3_core_tmp to set a new residual value. t3_ttm::full_tensor3_matrix_multiplication(*t3_core_tmp, *u1_tmp, *u2_tmp, *u3_tmp, *approx_data); *residual_data = *residual_data - *approx_data; } u1_.cast_from(*u1_incr); u2_.cast_from(*u2_incr); u3_.cast_from(*u3_incr); core_.cast_from(*t3_core_incr); delete u1_1col; delete u2_1col; delete u3_1col; delete t3_core_tmp; delete u1_tmp; delete u2_tmp; delete u3_tmp; delete t3_core_incr; delete u1_incr; delete u2_incr; delete u3_incr; delete residual_data; delete approx_data; return result; } VMML_TEMPLATE_STRING template< size_t R, typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::i_cp_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, t3_core_type& core_, T_init init, const size_t max_iterations_, const float tolerance) { tensor_stats result; if ((R1 % NBLOCKS != 0) or (R2 % NBLOCKS != 0) or (R3 % NBLOCKS != 0)) { std::ostringstream convert1, convert2, convert3, convert4, convert5; convert1 << R; convert2 << R1; convert3 << R2; convert4 << R3; convert5 << NBLOCKS; VMMLIB_ERROR("In incremental CP-Tucker, R = " + convert1.str() + ", (R1,R2,R3) = (" + convert2.str() + "," + convert3.str() + "," + convert4.str() + "), NBLOCKS = " + convert5.str() + " (must be divisible, and R1,R2,R3 <= R)", VMMLIB_HERE); } t3_coeff_type* approx_data = new t3_coeff_type; approx_data->zero(); t3_coeff_type* residual_data = new t3_coeff_type; residual_data->cast_from(data_); t3_core_tmp_type* t3_core_tmp = new t3_core_tmp_type; t3_core_tmp->zero(); u1_tmp_type* u1_tmp = new u1_tmp_type; u1_tmp_type* u1_tmp2 = new u1_tmp_type; u2_tmp_type* u2_tmp = new u2_tmp_type; u2_tmp_type* u2_tmp2 = new u2_tmp_type; u3_tmp_type* u3_tmp = new u3_tmp_type; u3_tmp_type* u3_tmp2 = new u3_tmp_type; t3_core_incr_type* t3_core_incr = new t3_core_incr_type; t3_core_incr->zero(); u1_incr_type* u1_incr = new u1_incr_type; u1_incr->zero(); u2_incr_type* u2_incr = new u2_incr_type; u2_incr->zero(); u3_incr_type* u3_incr = new u3_incr_type; u3_incr->zero(); u1_1col_type* u1_1col = new u1_1col_type; u2_1col_type* u2_1col = new u2_1col_type; u3_1col_type* u3_1col = new u3_1col_type; typedef t3_hopm < R / NBLOCKS, I1, I2, I3, T_coeff > hopm_type; typedef vector < R / NBLOCKS, T_coeff > lambda_tmp_type; lambda_tmp_type* lambdas_tmp = new lambda_tmp_type; typedef matrix < I1, R / NBLOCKS, T_coeff > u1_cp_tmp_type; u1_cp_tmp_type* u1_cp_tmp = new u1_cp_tmp_type; typedef matrix < I2, R / NBLOCKS, T_coeff > u2_cp_tmp_type; u2_cp_tmp_type* u2_cp_tmp = new u2_cp_tmp_type; typedef matrix < I3, R / NBLOCKS, T_coeff > u3_cp_tmp_type; u3_cp_tmp_type* u3_cp_tmp = new u3_cp_tmp_type; typedef matrix < R1 / NBLOCKS, I1, T_coeff > u1_inv_tmp_type; u1_inv_tmp_type* u1_inv_tmp = new u1_inv_tmp_type; typedef matrix < R2 / NBLOCKS, I2, T_coeff > u2_inv_tmp_type; u2_inv_tmp_type* u2_inv_tmp = new u2_inv_tmp_type; typedef matrix < R3 / NBLOCKS, I3, T_coeff > u3_inv_tmp_type; u3_inv_tmp_type* u3_inv_tmp = new u3_inv_tmp_type; for (size_t i = 0; i < NBLOCKS; ++i) { #ifdef TUCKER_LOG std::cout << "Incremental CP-Tucker: block number '" << i << "'" << std::endl; #endif // Do CP-ALS for this block result += hopm_type::als(*residual_data, *u1_cp_tmp, *u2_cp_tmp, *u3_cp_tmp, *lambdas_tmp, typename hopm_type::init_hosvd(), max_iterations_, tolerance); // Compute the pseudoinverses u1_cp_tmp->get_sub_matrix(*u1_tmp, 0, 0); compute_pseudoinverse< u1_tmp_type > compute_pinv1; compute_pinv1(*u1_tmp, *u1_tmp2); u1_tmp2->transpose_to(*u1_inv_tmp); u2_cp_tmp->get_sub_matrix(*u2_tmp, 0, 0); compute_pseudoinverse< u2_tmp_type > compute_pinv2; compute_pinv2(*u2_tmp, *u2_tmp2); u2_tmp2->transpose_to(*u2_inv_tmp); u3_cp_tmp->get_sub_matrix(*u3_tmp, 0, 0); compute_pseudoinverse< u3_tmp_type > compute_pinv3; compute_pinv3(*u3_tmp, *u3_tmp2); u3_tmp2->transpose_to(*u3_inv_tmp); // hooi_type::als(*residual_data, *u1_tmp, *u2_tmp, *u3_tmp, *t3_core_tmp, typename hooi_type::init_hosvd()); // Project the initial data onto the pseudoinverses to get the core t3_ttm::full_tensor3_matrix_multiplication(*residual_data, *u1_inv_tmp, *u2_inv_tmp, *u3_inv_tmp, *t3_core_tmp); // Copy the newly obtained columns into ui_incr for (size_t r = 0; r < R1 / NBLOCKS; ++r) { u1_tmp->get_column(r, *u1_1col); u1_incr->set_column(i * R1 / NBLOCKS + r, *u1_1col); } for (size_t r = 0; r < R2 / NBLOCKS; ++r) { u2_tmp->get_column(r, *u2_1col); u2_incr->set_column(i * R2 / NBLOCKS + r, *u2_1col); } for (size_t r = 0; r < R3 / NBLOCKS; ++r) { u3_tmp->get_column(r, *u3_1col); u3_incr->set_column(i * R3 / NBLOCKS + r, *u3_1col); } // Copy the newly obtained block core into t3_core_incr t3_core_incr->set_sub_tensor3(*t3_core_tmp, i * R1 / NBLOCKS, i * R2 / NBLOCKS, i * R3 / NBLOCKS); // Reconstruct this t3_core_tmp to set a new residual value. t3_ttm::full_tensor3_matrix_multiplication(*t3_core_tmp, *u1_tmp, *u2_tmp, *u3_tmp, *approx_data); *residual_data = *residual_data - *approx_data; } u1_.cast_from(*u1_incr); u2_.cast_from(*u2_incr); u3_.cast_from(*u3_incr); core_.cast_from(*t3_core_incr); delete u1_1col; delete u2_1col; delete u3_1col; delete t3_core_tmp; delete u1_tmp; delete u2_tmp; delete u3_tmp; delete t3_core_incr; delete u1_incr; delete u2_incr; delete u3_incr; delete residual_data; delete approx_data; return result; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif /* T3_IHOOI_HPP */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_ihopm.hpp000066400000000000000000000207451231531733200245410ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Rafa Ballester * * iHOPM stands for incremental higher-order power method. * in other words, it is an incremental rank-r CP-ALS * * CP stands for Candecomp/Parafac (1970); ALS for alternating least squares algorithm * references: * - Carroll & Chang, 1970: Analysis of Individual Differences in Multidimensional Scaling via an N-way generalization of ``Eckart--Young'' decompositions, Psychometrika. * - Harshman, 1970: Foundations of the PARAFAC procedure: Models and conditions for an 'explanatory' multi-modal factor analysis, UCLA Working Papers in Phonetics. * - De Lathauwer, De Moor, Vandewalle, 2000: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * * incremental rank-r approximation: * - Zang & Golub, 2001: Rank-one approximation to higher order tensors, SIAM J. Matrix Anal. Appl. */ #ifndef __VMML__T3_IHOPM__HPP__ #define __VMML__T3_IHOPM__HPP__ #include namespace vmml { template< size_t R, size_t NBLOCKS, size_t I1, size_t I2, size_t I3, typename T_val = float, typename T_coeff = double > class t3_ihopm { public: // typedef tensor3< I1, I2, I3, T_val > t3_type; // typedef tensor3< I1, I2, I3, T_coeff > t3_coeff_type; // // typedef vector< R*NBLOCKS, T_val > lambda_type; // typedef vector< R*NBLOCKS, T_coeff > lambda_incr_type; // typedef vector< R, T_coeff > lambda_tmp_type; // // typedef matrix< I1, R*NBLOCKS, T_val > u1_type; // typedef matrix< I2, R*NBLOCKS, T_val > u2_type; // typedef matrix< I3, R*NBLOCKS, T_val > u3_type; // // typedef matrix< R*NBLOCKS, I1, T_val > u1_inv_type; // typedef matrix< R*NBLOCKS, I2, T_val > u2_inv_type; // typedef matrix< R*NBLOCKS, I3, T_val > u3_inv_type; // // typedef matrix< I1, R*NBLOCKS, T_coeff > u1_incr_type; // typedef matrix< I2, R*NBLOCKS, T_coeff > u2_incr_type; // typedef matrix< I3, R*NBLOCKS, T_coeff > u3_incr_type; // // typedef matrix< I1, R, T_coeff > u1_tmp_type; // typedef matrix< I2, R, T_coeff > u2_tmp_type; // typedef matrix< I3, R, T_coeff > u3_tmp_type; // // typedef matrix< I1, 1, T_coeff > u1_1col_type; // typedef matrix< I2, 1, T_coeff > u2_1col_type; // typedef matrix< I3, 1, T_coeff > u3_1col_type; typedef tensor3< I1, I2, I3, T_val > t3_type; typedef tensor3< I1, I2, I3, T_coeff > t3_coeff_type; typedef vector< R, T_val > lambda_type; typedef vector< R, T_coeff > lambda_incr_type; typedef vector< R / NBLOCKS, T_coeff > lambda_tmp_type; typedef matrix< I1, R, T_val > u1_type; typedef matrix< I2, R, T_val > u2_type; typedef matrix< I3, R, T_val > u3_type; typedef matrix< R, I1, T_val > u1_inv_type; typedef matrix< R, I2, T_val > u2_inv_type; typedef matrix< R, I3, T_val > u3_inv_type; typedef matrix< I1, R, T_coeff > u1_incr_type; typedef matrix< I2, R, T_coeff > u2_incr_type; typedef matrix< I3, R, T_coeff > u3_incr_type; typedef matrix< I1, R / NBLOCKS, T_coeff > u1_tmp_type; typedef matrix< I2, R / NBLOCKS, T_coeff > u2_tmp_type; typedef matrix< I3, R / NBLOCKS, T_coeff > u3_tmp_type; typedef matrix< I1, 1, T_coeff > u1_1col_type; typedef matrix< I2, 1, T_coeff > u2_1col_type; typedef matrix< I3, 1, T_coeff > u3_1col_type; //incremental cp als (zang&golub, 2001) // template< typename T_init > static tensor_stats incremental_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_, const size_t max_iterations_ = 50, const float tolerance = 1e-04); static void reconstruct(t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_); }; #define VMML_TEMPLATE_STRING template< size_t R, size_t NBLOCKS, size_t I1, size_t I2, size_t I3, typename T_val, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME t3_ihopm< R, NBLOCKS, I1, I2, I3, T_val, T_coeff > VMML_TEMPLATE_STRING // template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::incremental_als(const t3_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, lambda_type& lambdas_, const size_t max_iterations_, const float tolerance_) { tensor_stats result; if (R % NBLOCKS != 0) { std::ostringstream convert1, convert2; convert1 << R; convert2 << NBLOCKS; VMMLIB_ERROR("In incremental CP, R = " + convert1.str() + ", NBLOCKS = " + convert2.str() + " (must be divisible)", VMMLIB_HERE); } t3_coeff_type* approx_data = new t3_coeff_type; approx_data->zero(); t3_coeff_type* residual_data = new t3_coeff_type; residual_data->cast_from(data_); lambda_tmp_type* lambdas_tmp = new lambda_tmp_type; lambdas_tmp->set(0); u1_tmp_type* u1_tmp = new u1_tmp_type; u2_tmp_type* u2_tmp = new u2_tmp_type; u3_tmp_type* u3_tmp = new u3_tmp_type; lambda_incr_type* lambdas_incr = new lambda_incr_type; lambdas_incr->set(0); u1_incr_type* u1_incr = new u1_incr_type; u1_incr->zero(); u2_incr_type* u2_incr = new u2_incr_type; u2_incr->zero(); u3_incr_type* u3_incr = new u3_incr_type; u3_incr->zero(); u1_1col_type* u1_1col = new u1_1col_type; u2_1col_type* u2_1col = new u2_1col_type; u3_1col_type* u3_1col = new u3_1col_type; typedef t3_hopm < R / NBLOCKS, I1, I2, I3, T_coeff > hopm_type; for (size_t i = 0; i < NBLOCKS; ++i) { #ifdef CP_LOG std::cout << "Incremental CP: block number '" << i << "'" << std::endl; #endif //init all values to zero u1_tmp->zero(); u2_tmp->zero(); u3_tmp->zero(); *lambdas_tmp = 0.0; approx_data->zero(); result += hopm_type::als(*residual_data, *u1_tmp, *u2_tmp, *u3_tmp, *lambdas_tmp, typename hopm_type::init_hosvd(), max_iterations_, tolerance_); //set lambdas und us to appropriate position size_t r_incr = 0; T_coeff lambda_r = 0; for (size_t r = 0; r < R / NBLOCKS; ++r) { r_incr = i * R / NBLOCKS + r; u1_tmp->get_column(r, *u1_1col); u1_incr->set_column(r_incr, *u1_1col); u2_tmp->get_column(r, *u2_1col); u2_incr->set_column(r_incr, *u2_1col); u3_tmp->get_column(r, *u3_1col); u3_incr->set_column(r_incr, *u3_1col); lambda_r = lambdas_tmp->at(r); lambdas_incr->at(r_incr) = lambda_r; //set lambda } t3_hopm < R / NBLOCKS, I1, I2, I3, T_coeff >::reconstruct(*approx_data, *u1_tmp, *u2_tmp, *u3_tmp, *lambdas_tmp); *residual_data = *residual_data - *approx_data; } u1_.cast_from(*u1_incr); u2_.cast_from(*u2_incr); u3_.cast_from(*u3_incr); lambdas_.cast_from(*lambdas_incr); delete u1_1col; delete u2_1col; delete u3_1col; delete u1_tmp; delete u2_tmp; delete u3_tmp; delete lambdas_tmp; delete u1_incr; delete u2_incr; delete u3_incr; delete lambdas_incr; delete residual_data; delete approx_data; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct(t3_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, const lambda_type& lambdas_) { u1_inv_type* u1_t = new u1_inv_type; u2_inv_type* u2_t = new u2_inv_type; u3_inv_type* u3_t = new u3_inv_type; typedef matrix< R*NBLOCKS, I2 * I3, T_val > m_temp_type; m_temp_type* temp = new m_temp_type; u1_.transpose_to(*u1_t); u2_.transpose_to(*u2_t); u3_.transpose_to(*u3_t); data_.reconstruct_CP(lambdas_, *u1_t, *u2_t, *u3_t, *temp); delete temp; delete u1_t; delete u2_t; delete u3_t; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_ttm.hpp000066400000000000000000000412451231531733200242270ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * Tensor times matrix multiplication for tensor3 (t3) * using BLAS * see e.g.: * - Bader & Kolda, 2006: Algorithm 862: Matlab tensor classes for fast algorithm prototyping. ACM Transactions on Mathematical Software. * */ #ifndef __VMML__T3_TTM__HPP__ #define __VMML__T3_TTM__HPP__ #include #include #ifdef VMMLIB_USE_OPENMP # include #endif namespace vmml { class t3_ttm { public: typedef float T_blas; //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3, typename T > static void full_tensor3_matrix_multiplication( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, tensor3< I1, I2, I3, T >& t3_res_ ); template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3, typename T > static void full_tensor3_matrix_kronecker_mult( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, tensor3< I1, I2, I3, T >& t3_res_ ); //tensor times matrix multiplication along different modes template< size_t I3, size_t J1, size_t J2, size_t J3, typename T > static void multiply_horizontal_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I3, J3, T >& in_slice_, tensor3< J1, J2, I3, T >& t3_res_ ); //output: tensor3< J1, J2, I3, T > template< size_t I1, size_t J1, size_t J2, size_t J3, typename T > static void multiply_lateral_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& in_slice_, tensor3< I1, J2, J3, T >& t3_res_ ); //output: tensor3< I1, J2, J3, T > template< size_t I2, size_t J1, size_t J2, size_t J3, typename T > static void multiply_frontal_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I2, J2, T >& in_slice_, tensor3< J1, I2, J3, T >& t3_res_ ); //output: tensor3< J1, I2, J3, T > //floating point versions (without type casting) choose //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3 > static void full_tensor3_matrix_multiplication( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& U1, const matrix< I2, J2, T_blas >& U2, const matrix< I3, J3, T_blas >& U3, tensor3< I1, I2, I3, T_blas >& t3_res_ ); //tensor times matrix multiplication along different modes (T_blas types) template< size_t I3, size_t J1, size_t J2, size_t J3 > static void multiply_horizontal_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I3, J3, T_blas >& in_slice_, tensor3< J1, J2, I3, T_blas >& t3_res_ ); //output: tensor3< J1, J2, I3, T > template< size_t I1, size_t J1, size_t J2, size_t J3 > static void multiply_lateral_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& in_slice_, tensor3< I1, J2, J3, T_blas >& t3_res_ ); //output: tensor3< I1, J2, J3, T > template< size_t I2, size_t J1, size_t J2, size_t J3 > static void multiply_frontal_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I2, J2, T_blas >& in_slice_, tensor3< J1, I2, J3, T_blas >& t3_res_ ); //output: tensor3< J1, I2, J3, T > //tensor times matrix multiplication along different modes template< size_t I2, size_t J1, size_t J2, size_t J3 > static void multiply_horizontal_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I2, J2, T_blas >& in_slice_, tensor3< J1, I2, J3, T_blas >& t3_res_ ); template< size_t I3, size_t J1, size_t J2, size_t J3 > static void multiply_lateral_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I3, J3, T_blas >& in_slice_, tensor3< J1, J2, I3, T_blas >& t3_res_ ); template< size_t I1, size_t J1, size_t J2, size_t J3 > static void multiply_frontal_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& in_slice_, tensor3< I1, J2, J3, T_blas >& t3_res_ ); //output: tensor3< I1, J2, J3, T > template< size_t I2, size_t J1, size_t J2, size_t J3, typename T > static void multiply_horizontal_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I2, J2, T >& in_slice_, tensor3< J1, I2, J3, T >& t3_res_ ); template< size_t I3, size_t J1, size_t J2, size_t J3, typename T > static void multiply_lateral_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I3, J3, T >& in_slice_, tensor3< J1, J2, I3, T >& t3_res_ ); template< size_t I1, size_t J1, size_t J2, size_t J3, typename T > static void multiply_frontal_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& in_slice_, tensor3< I1, J2, J3, T >& t3_res_ ); //output: tensor3< I1, J2, J3, T > protected: }; //end hosvd class #define VMML_TEMPLATE_CLASSNAME t3_ttm template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::full_tensor3_matrix_multiplication( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, tensor3< I1, I2, I3, T >& t3_res_ ) { tensor3< I1, J2, J3, T> t3_result_1; tensor3< I1, I2, J3, T> t3_result_2; //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) #if 0 //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) multiply_lateral_bwd( t3_in_, U1, t3_result_1 ); multiply_frontal_bwd( t3_result_1, U2, t3_result_2 ); multiply_horizontal_bwd( t3_result_2, U3, t3_res_ ); #else //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized multiply_frontal_fwd( t3_in_, U1, t3_result_1 ); multiply_horizontal_fwd( t3_result_1, U2, t3_result_2 ); multiply_lateral_fwd( t3_result_2, U3, t3_res_ ); #endif } template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::full_tensor3_matrix_kronecker_mult( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, tensor3< I1, I2, I3, T >& t3_res_ ) { //TODO should use blas matrix< J1, J2*J3, T>* core_unfolded = new matrix< J1, J2*J3, T>; t3_in_.lateral_unfolding_bwd( *core_unfolded ); matrix< I1, J2*J3, T>* tmp1 = new matrix< I1, J2*J3, T>; tmp1->multiply( U1, *core_unfolded ); matrix< I2*I3, J2*J3, T>* kron_prod = new matrix< I2*I3, J2*J3, T>; U2.kronecker_product( U3, *kron_prod ); matrix< I1, I2*I3, T>* res_unfolded = new matrix< I1, I2*I3, T>; res_unfolded->multiply( *tmp1, transpose(*kron_prod) ); //std::cout << "reco2 result (matricized): " << std::endl << *res_unfolded << std::endl; //set this from res_unfolded size_t i2 = 0; for( size_t i = 0; i < (I2*I3); ++i, ++i2 ) { if (i2 >= I2) { i2 = 0; } size_t i3 = i % I3; t3_res_.set_column( i2, i3, res_unfolded->get_column(i)); } delete core_unfolded; delete kron_prod; delete tmp1; delete res_unfolded; } //tensor matrix multiplications template< size_t I3, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_horizontal_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I3, J3, T >& in_slice_, tensor3< J1, J2, I3, T >& t3_res_ ) { typedef matrix< I3, J3, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< J1, J2, I3, T_blas > t3_res; t3_res.zero(); multiply_horizontal_bwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } template< size_t I1, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_lateral_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& in_slice_, tensor3< I1, J2, J3, T >& t3_res_ ) { typedef matrix< I1, J1, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< I1, J2, J3, T_blas > t3_res; t3_res.zero(); multiply_lateral_bwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } template< size_t I2, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_frontal_bwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I2, J2, T >& in_slice_, tensor3< J1, I2, J3, T >& t3_res_ ) { typedef matrix< I2, J2, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< J1, I2, J3, T_blas > t3_res; t3_res.zero(); multiply_frontal_bwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } //tensor matrix multiplications template< size_t I2, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_horizontal_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I2, J2, T >& in_slice_, tensor3< J1, I2, J3, T >& t3_res_ ) { typedef matrix< I2, J2, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< J1, I2, J3, T_blas > t3_res; t3_res.zero(); multiply_horizontal_fwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } template< size_t I3, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_lateral_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I3, J3, T >& in_slice_, tensor3< J1, J2, I3, T >& t3_res_ ) { typedef matrix< I3, J3, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< J1, J2, I3, T_blas > t3_res; t3_res.zero(); multiply_lateral_fwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } template< size_t I1, size_t J1, size_t J2, size_t J3, typename T > void VMML_TEMPLATE_CLASSNAME::multiply_frontal_fwd( const tensor3< J1, J2, J3, T >& t3_in_, const matrix< I1, J1, T >& in_slice_, tensor3< I1, J2, J3, T >& t3_res_ ) { typedef matrix< I1, J1, T_blas > slice_t; tensor3< J1, J2, J3, T_blas > t3_in( t3_in_ ); slice_t* in_slice = new slice_t( in_slice_ ); tensor3< I1, J2, J3, T_blas > t3_res; t3_res.zero(); multiply_frontal_fwd( t3_in, *in_slice, t3_res ); t3_res_.cast_from( t3_res ); delete in_slice; } template< size_t I1, size_t I2, size_t I3, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::full_tensor3_matrix_multiplication( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& U1, const matrix< I2, J2, T_blas >& U2, const matrix< I3, J3, T_blas >& U3, tensor3< I1, I2, I3, T_blas >& t3_res_ ) { tensor3< I1, J2, J3, T_blas > t3_result_1; tensor3< I1, I2, J3, T_blas > t3_result_2; #if 0 //backward cyclic matricization/unfolding (after Lathauwer et al., 2000a) multiply_lateral_bwd( t3_in_, U1, t3_result_1 ); multiply_frontal_bwd( t3_result_1, U2, t3_result_2 ); multiply_horizontal_bwd( t3_result_2, U3, t3_res_ ); #else //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized multiply_frontal_fwd( t3_in_, U1, t3_result_1 ); multiply_horizontal_fwd( t3_result_1, U2, t3_result_2 ); multiply_lateral_fwd( t3_result_2, U3, t3_res_ ); #endif } //tensor matrix multiplications (Lathauwer et al. 2000a) template< size_t I3, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_horizontal_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I3, J3, T_blas >& in_slice_, tensor3< J1, J2, I3, T_blas >& t3_res_ ) { typedef matrix< J3, J2, T_blas > slice_t; typedef matrix< I3, J2, T_blas > slice_new_t; typedef blas_dgemm< I3, J3, J2, T_blas > blas_t; #pragma omp parallel for for ( int i1 = 0; i1 < (int)J1; ++i1 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_horizontal_slice_bwd( i1, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_horizontal_slice_bwd( i1, *slice_new ); delete multiplier; delete slice; delete slice_new; } } template< size_t I1, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_lateral_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& in_slice_, tensor3< I1, J2, J3, T_blas >& t3_res_ ) { typedef matrix< J1, J3, T_blas > slice_t; typedef matrix< I1, J3, T_blas > slice_new_t; typedef blas_dgemm< I1, J1, J3, T_blas > blas_t; #pragma omp parallel for for ( int i2 = 0; i2 < (int)J2; ++i2 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_lateral_slice_bwd( i2, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_lateral_slice_bwd( i2, *slice_new ); delete multiplier; delete slice; delete slice_new; } } template< size_t I2, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_frontal_bwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I2, J2, T_blas >& in_slice_, tensor3< J1, I2, J3, T_blas >& t3_res_ ) { typedef matrix< J2, J1, T_blas > slice_t; typedef matrix< I2, J1, T_blas > slice_new_t; typedef blas_dgemm< I2, J2, J1, T_blas > blas_t; #pragma omp parallel for for ( int i3 = 0; i3 < (int)J3; ++i3 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_frontal_slice_bwd( i3, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_frontal_slice_bwd( i3, *slice_new ); delete multiplier; delete slice; delete slice_new; } } //tensor matrix multiplications fwd cycling (Kiers 2000) template< size_t I2, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_horizontal_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I2, J2, T_blas >& in_slice_, tensor3< J1, I2, J3, T_blas >& t3_res_ ) { typedef matrix< J2, J3, T_blas > slice_t; typedef matrix< I2, J3, T_blas > slice_new_t; typedef blas_dgemm< I2, J2, J3, T_blas > blas_t; #pragma omp parallel for for ( int i1 = 0; i1 < (int)J1; ++i1 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_horizontal_slice_fwd( i1, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_horizontal_slice_fwd( i1, *slice_new ); delete multiplier; delete slice; delete slice_new; } } template< size_t I3, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_lateral_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I3, J3, T_blas >& in_slice_, tensor3< J1, J2, I3, T_blas >& t3_res_ ) { typedef matrix< J3, J1, T_blas > slice_t; typedef matrix< I3, J1, T_blas > slice_new_t; typedef blas_dgemm< I3, J3, J1, T_blas > blas_t; #pragma omp parallel for for ( int i2 = 0; i2 < (int)J2; ++i2 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_lateral_slice_fwd( i2, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_lateral_slice_fwd( i2, *slice_new ); delete multiplier; delete slice; delete slice_new; } } template< size_t I1, size_t J1, size_t J2, size_t J3 > void VMML_TEMPLATE_CLASSNAME::multiply_frontal_fwd( const tensor3< J1, J2, J3, T_blas >& t3_in_, const matrix< I1, J1, T_blas >& in_slice_, tensor3< I1, J2, J3, T_blas >& t3_res_ ) { typedef matrix< J1, J2, T_blas > slice_t; typedef matrix< I1, J2, T_blas > slice_new_t; typedef blas_dgemm< I1, J1, J2, T_blas > blas_t; #pragma omp parallel for for ( int i3 = 0; i3 < (int)J3; ++i3 ) { slice_t* slice = new slice_t; slice_new_t* slice_new = new slice_new_t; blas_t* multiplier = new blas_t; t3_in_.get_frontal_slice_fwd( i3, *slice ); multiplier->compute( in_slice_, *slice, *slice_new ); t3_res_.set_frontal_slice_fwd( i3, *slice_new ); delete multiplier; delete slice; delete slice_new; } } #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t3_ttv.hpp000066400000000000000000000026151231531733200242360ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafa Ballester * * Tensor times vector multiplication for tensor3 (t3) * Only mode 1 is implemented. This is used for fast inner product calculation. The basic idea is that the inner product between a tensor X and a 1-rank tensor (expressed as the outer product of three vectors u, v and w) is the same as ((X x u).v).w . * */ #ifndef __VMML__T3_TTV__HPP__ #define __VMML__T3_TTV__HPP__ #include #ifdef VMMLIB_USE_OPENMP # include #endif namespace vmml { class t3_ttv { public: template< size_t I1, size_t I2, size_t I3, typename T > static void multiply_first_mode(const tensor3< I1, I2, I3, T >& t3_in_, const vector< I1, T >& u, matrix< I2, I3, T >& m_res_); protected: }; template< size_t I1, size_t I2, size_t I3, typename T > void t3_ttv::multiply_first_mode(const tensor3< I1, I2, I3, T >& t3_in_, const vector< I1, T >& u, matrix< I2, I3, T >& m_res_ ) { for( unsigned j = 0; j < I2; ++j) { for( unsigned k = 0; k < I3; ++k) { T vtv = 0; for( unsigned i = 0; i < I1; ++i) vtv += t3_in_.at(i, j, k) * u.at(i); m_res_.at(j, k) = vtv; } } } } //end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t4_converter.hpp000066400000000000000000000115041231531733200254260ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author David Klaper * @author Susanne Suter * * class to read/write and convert tensor4 files (from raw, to csv...) * */ #ifndef __VMML__T4_CONVERTER__HPP__ #define __VMML__T4_CONVERTER__HPP__ #include "tensor4.hpp" namespace vmml { template< size_t I1, size_t I2, size_t I3, size_t I4, typename T = float > class t4_converter { public: typedef tensor4< I1, I2, I3, I4, T > t4_t; static void export_to( std::vector< T >& data_ ) ; static void import_from( const std::vector< T >& data_ ) ; static void write_to_raw( const t4_t& data_, const std::string& dir_, const std::string& filename_ ); //TODO: DK done static void read_from_raw( t4_t& data_, const std::string& dir_, const std::string& filename_ ) ; //TODO: DK done static void write_datfile( const std::string& dir_, const std::string& filename_ ); static void write_to_csv( const t4_t& data_, const std::string& dir_, const std::string& filename_ ); //TODO: DK done protected: static void concat_path( const std::string& dir_, const std::string& filename_, std::string& path_ ); }; //end t4_converter #define VMML_TEMPLATE_STRING template< size_t I1, size_t I2, size_t I3, size_t I4, typename T > #define VMML_TEMPLATE_CLASSNAME t4_converter< I1, I2, I3, I4, T > VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::concat_path( const std::string& dir_, const std::string& filename_, std::string& path_ ) { int dir_length = dir_.size() -1; int last_separator = dir_.find_last_of( "/"); path_ = dir_; if (last_separator < dir_length ) { path_.append( "/" ); } path_.append( filename_ ); //check for format if( filename_.find( "raw", filename_.size()-3 ) == std::string::npos) { path_.append( "."); path_.append( "raw" ); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::write_to_csv( const t4_t& data_, const std::string& dir_, const std::string& filename_ ) { std::string path_raw; concat_path(dir_, filename_, path_raw); path_raw.replace(path_raw.size() - 3, 3, "csv"); std::ofstream outfile(path_raw.c_str()); if(outfile.is_open()) { for( size_t i4 = 0; i4 < data_.T3S; ++i4 ) { for( size_t i3 = 0; i3 < data_.SLICES; ++i3 ) { for( size_t i1 = 0; i1 < data_.ROWS; ++i1 ) { for( size_t i2 = 0; i2 < data_.COLS; ++i2 ) { outfile << data_(i1,i2,i3,i4) << ", "; } outfile.seekp( -2, std::ios_base::cur); // remove superfluous comma signs outfile << std::endl; } outfile << std::endl; } outfile << std::endl; } outfile.close(); }else { outfile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::read_from_raw( t4_t& data_, const std::string& dir_, const std::string& filename_ ) { data_.zero(); std::string path_raw; concat_path(dir_, filename_, path_raw); std::ifstream infile; infile.open( path_raw.c_str(), std::ios::in ); if( infile.is_open() ) { size_t max_file_len = (std::numeric_limits::max)() - sizeof(T); size_t len_data = data_.size(); size_t len_read = 0; T* dataptr = data_.get_array_ptr(); char* chardat = new char[ len_data*sizeof(T)]; size_t offset = 0; while(len_data > 0) { if (len_data*sizeof(T) > max_file_len) { size_t mod = max_file_len % sizeof(T); len_read = (max_file_len-mod)/sizeof(T); }else { len_read = len_data; } infile.read( chardat, len_read*sizeof(T) ); for(size_t index = 0; index+offset < data_.size() && index < len_read; ++index) { T* data = (T*)&(chardat[index*sizeof(T)]); dataptr[index+offset] = *data; } offset += len_read; len_data -= len_read; } delete[] chardat; infile.close(); } else { infile.close(); std::cout << "no file open" << std::endl; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::write_to_raw( const t4_t& data_, const std::string& dir_, const std::string& filename_ ) { std::string path_raw; concat_path(dir_, filename_, path_raw); std::ofstream outfile; outfile.open( path_raw.c_str() ); if( outfile.is_open() ) { size_t type_size = sizeof(T); size_t chunk_size = 5; // How many data values are written at once const T* dataptr = data_.get_array_ptr(); for( size_t index = 0; index < data_.size(); index += chunk_size ) { if(chunk_size + index > data_.size()) // only write remaining values { outfile.write( (char*)dataptr+index*type_size, type_size*(data_.size()-index) ); }else // write whole chunk { outfile.write( (char*)dataptr+index*type_size, chunk_size*type_size ); } } outfile.close(); } else { outfile.close(); std::cout << "no file open" << std::endl; } } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t4_hooi.hpp000066400000000000000000000244331231531733200243620ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafa Ballester * */ #ifndef __VMML__T4_HOOI__HPP__ #define __VMML__T4_HOOI__HPP__ #include #include #include #include #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T = float > class t4_hooi { public: typedef tensor4< I1, I2, I3, I4, T > t4_type; typedef tensor4< R1, R2, R3, R4, T > t4_core_type; typedef matrix< I1, R1, T > u1_type; typedef matrix< I2, R2, T > u2_type; typedef matrix< I3, R3, T > u3_type; typedef matrix< I4, R4, T > u4_type; typedef matrix< R1, I1, T > u1_t_type; typedef matrix< R2, I2, T > u2_t_type; typedef matrix< R3, I3, T > u3_t_type; typedef matrix< R4, I4, T > u4_t_type; template< typename T_init> static tensor_stats als(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, u4_type& u4_, T_init init, const double& max_f_norm_ = 0.0, const size_t max_iterations = 10, const float tolerance = 1e-04); template< typename T_init> static tensor_stats als(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, u4_type& u4_, t4_core_type& core_, T_init init, const double& max_f_norm_ = 0.0, const size_t max_iterations = 10, const float tolerance = 1e-04); // init functors struct init_hosvd { inline void operator()(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type & u3_, u4_type & u4_) { t4_hosvd< R1, R2, R3, R4, I1, I2, I3, I4, T >::apply_mode2(data_, u2_); t4_hosvd< R1, R2, R3, R4, I1, I2, I3, I4, T >::apply_mode3(data_, u3_); t4_hosvd< R1, R2, R3, R4, I1, I2, I3, I4, T >::apply_mode4(data_, u4_); } }; struct init_random { inline void operator()(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type & u3_, u4_type & u4_) { srand(time(NULL)); u2_.set_random(); u3_.set_random(); u4_.set_random(); u2_ /= u2_.frobenius_norm(); u3_ /= u3_.frobenius_norm(); u4_ /= u4_.frobenius_norm(); } }; protected: static void optimize_mode1(const t4_type& data_, const u2_type& u2_, const u3_type& u3_, const u4_type& u4_, tensor4< I1, R2, R3, R4, T >& projection_); static void optimize_mode2(const t4_type& data_, const u1_type& u1_, const u3_type& u3_, const u4_type& u4_, tensor4< R1, I2, R3, R4, T >& projection_); static void optimize_mode3(const t4_type& data_, const u1_type& u1_, const u2_type& u2_, const u4_type& u4_, tensor4< R1, R2, I3, R4, T >& projection_); static void optimize_mode4(const t4_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, tensor4< R1, R2, R3, I4, T >& projection_); }; //end class t3_hooi #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T > #define VMML_TEMPLATE_CLASSNAME t4_hooi< R1, R2, R3, R4, I1, I2, I3, I4, T > VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::als(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, u4_type& u4_, T_init init, const double& max_f_norm_, const size_t max_iterations_, const float tolerance_) { t4_core_type core; core.zero(); return als(data_, u1_, u2_, u3_, u4_, core, init, max_f_norm_, max_iterations_, tolerance_); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::als(const t4_type& data_, u1_type& u1_, u2_type& u2_, u3_type& u3_, u4_type& u4_, t4_core_type& core_, T_init init, const double& max_f_norm_, const size_t max_iterations_, const float tolerance_) { tensor_stats result; //intialize basis matrices init(data_, u1_, u2_, u3_, u4_); core_.zero(); T max_f_norm = 0.0; T f_norm, fit, fitchange, fitold, normresidual; if (tolerance_ > 0) { max_f_norm = max_f_norm_; if (max_f_norm <= 0.0) { max_f_norm = data_.frobenius_norm(); } fit = 0; //removed to save computation /*if ( (max_f_norm != 0) && (max_f_norm > f_norm) ) { fit = 1 - (normresidual / max_f_norm); } else { fit = 1; }*/ fitchange = 1; fitold = fit; normresidual = 0; } tensor4< I1, R2, R3, R4, T > projection1; tensor4< R1, I2, R3, R4, T > projection2; tensor4< R1, R2, I3, R4, T > projection3; tensor4< R1, R2, R3, I4, T > projection4; #if TUCKER_LOG std::cout << "HOOI ALS (for tensor3) " << std::endl << "initial fit: " << fit << ", " << "frobenius norm original: " << max_f_norm << std::endl; #endif size_t i = 0; while (i < max_iterations_ && (tolerance_ < 0 || fitchange >= tolerance_)) { //do until converges fitold = fit; //optimize modes optimize_mode1(data_, u2_, u3_, u4_, projection1); t4_hosvd< R1, R2, R3, R4, I1, R2, R3, R4, T >::apply_mode1(projection1, u1_); optimize_mode2(data_, u1_, u3_, u4_, projection2); t4_hosvd< R1, R2, R3, R4, R1, I2, R3, R4, T >::apply_mode2(projection2, u2_); optimize_mode3(data_, u1_, u2_, u4_, projection3); t4_hosvd< R1, R2, R3, R4, R1, R2, I3, R4, T >::apply_mode3(projection3, u3_); optimize_mode4(data_, u1_, u2_, u3_, projection4); t4_hosvd< R1, R2, R3, R4, R1, R2, R3, I4, T >::apply_mode4(projection4, u4_); t4_ttm::mode4_multiply_fwd(projection4, transpose(u4_), core_); if (tolerance_ > 0) { f_norm = core_.frobenius_norm(); normresidual = sqrt( fabs(max_f_norm * max_f_norm - f_norm * f_norm) ); fit = 1 - (normresidual / max_f_norm); fitchange = fabs(fitold - fit); #if TUCKER_LOG std::cout << "iteration '" << i << "', fit: " << fit << ", fitdelta: " << fitchange << ", frobenius norm of core: " << f_norm << std::endl; #endif } ++i; } result.set_n_iterations(i); return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode1(const t4_type& data_, const u2_type& u2_, const u3_type& u3_, const u4_type& u4_, tensor4< I1, R2, R3, R4, T >& projection_) { u2_t_type* u2_inv = new u2_t_type; u3_t_type* u3_inv = new u3_t_type; u4_t_type* u4_inv = new u4_t_type; u2_.transpose_to(*u2_inv); u3_.transpose_to(*u3_inv); u4_.transpose_to(*u4_inv); //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized tensor4< I1, R2, I3, I4, T > tmp1_; tensor4< I1, R2, R3, I4, T > tmp2_; t4_ttm::mode2_multiply_fwd(data_, *u2_inv, tmp1_); t4_ttm::mode3_multiply_fwd(tmp1_, *u3_inv, tmp2_); t4_ttm::mode4_multiply_fwd(tmp2_, *u4_inv, projection_); delete u2_inv; delete u3_inv; delete u4_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode2(const t4_type& data_, const u1_type& u1_, const u3_type& u3_, const u4_type& u4_, tensor4< R1, I2, R3, R4, T >& projection_) { u1_t_type* u1_inv = new u1_t_type; u3_t_type* u3_inv = new u3_t_type; u4_t_type* u4_inv = new u4_t_type; u1_.transpose_to(*u1_inv); u3_.transpose_to(*u3_inv); u4_.transpose_to(*u4_inv); //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized tensor4< R1, I2, I3, I4, T > tmp1_; tensor4< R1, I2, R3, I4, T > tmp2_; t4_ttm::mode1_multiply_fwd(data_, *u1_inv, tmp1_); t4_ttm::mode3_multiply_fwd(tmp1_, *u3_inv, tmp2_); t4_ttm::mode4_multiply_fwd(tmp2_, *u4_inv, projection_); delete u1_inv; delete u3_inv; delete u4_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode3(const t4_type& data_, const u1_type& u1_, const u2_type& u2_, const u4_type& u4_, tensor4< R1, R2, I3, R4, T >& projection_) { u1_t_type* u1_inv = new u1_t_type; u2_t_type* u2_inv = new u2_t_type; u4_t_type* u4_inv = new u4_t_type; u1_.transpose_to(*u1_inv); u2_.transpose_to(*u2_inv); u4_.transpose_to(*u4_inv); //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized tensor4< R1, I2, I3, I4, T > tmp1_; tensor4< R1, R2, I3, I4, T > tmp2_; t4_ttm::mode1_multiply_fwd(data_, *u1_inv, tmp1_); t4_ttm::mode2_multiply_fwd(tmp1_, *u2_inv, tmp2_); t4_ttm::mode4_multiply_fwd(tmp2_, *u4_inv, projection_); delete u1_inv; delete u2_inv; delete u4_inv; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::optimize_mode4(const t4_type& data_, const u1_type& u1_, const u2_type& u2_, const u3_type& u3_, tensor4< R1, R2, R3, I4, T >& projection_) { u1_t_type* u1_inv = new u1_t_type; u2_t_type* u2_inv = new u2_t_type; u3_t_type* u3_inv = new u3_t_type; u1_.transpose_to(*u1_inv); u2_.transpose_to(*u2_inv); u3_.transpose_to(*u3_inv); //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized tensor4< R1, I2, I3, I4, T > tmp1_; tensor4< R1, R2, I3, I4, T > tmp2_; t4_ttm::mode1_multiply_fwd(data_, *u1_inv, tmp1_); t4_ttm::mode2_multiply_fwd(tmp1_, *u2_inv, tmp2_); t4_ttm::mode3_multiply_fwd(tmp2_, *u3_inv, projection_); delete u1_inv; delete u2_inv; delete u3_inv; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t4_hosvd.hpp000066400000000000000000000140141231531733200245410ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafael Ballester * */ #ifndef __VMML__T4_HOSVD__HPP__ #define __VMML__T4_HOSVD__HPP__ #include #include #include #include #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T = float > class t4_hosvd { public: typedef tensor4< I1, I2, I3, I4, T > t4_type; typedef matrix< I1, R1, T > u1_type; typedef matrix< I2, R2, T > u2_type; typedef matrix< I3, R3, T > u3_type; typedef matrix< I4, R4, T > u4_type; typedef matrix< I1, I2*I3*I4, T > u1_unfolded_type; typedef matrix< I2, I1*I3*I4, T > u2_unfolded_type; typedef matrix< I3, I1*I2*I4, T > u3_unfolded_type; typedef matrix< I4, I1*I2*I3, T > u4_unfolded_type; typedef matrix< I1, I1, T > u1_cov_type; typedef matrix< I2, I2, T > u2_cov_type; typedef matrix< I3, I3, T > u3_cov_type; typedef matrix< I4, I4, T > u4_cov_type; static void apply_mode1(const t4_type& data_, u1_type& u1_); static void apply_mode2(const t4_type& data_, u2_type& u2_); static void apply_mode3(const t4_type& data_, u3_type& u3_); static void apply_mode4(const t4_type& data_, u4_type& u4_); protected: //hosvd on eigenvalue decomposition = hoeigs template< size_t N, size_t R > static void get_eigs_u_red( const matrix< N, N, T >& data_, matrix< N, R, T >& u_ ); static void eigs_mode1( const t4_type& data_, u1_type& u1_ ); static void eigs_mode2( const t4_type& data_, u2_type& u2_ ); static void eigs_mode3( const t4_type& data_, u3_type& u3_ ); static void eigs_mode4( const t4_type& data_, u4_type& u4_ ); }; //end hosvd class #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T > #define VMML_TEMPLATE_CLASSNAME t4_hosvd< R1, R2, R3, R4, I1, I2, I3, I4, T > VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode1( const t4_type& data_, u1_type& u1_) { eigs_mode1( data_, u1_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode2( const t4_type& data_, u2_type& u2_) { eigs_mode2( data_, u2_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode3( const t4_type& data_, u3_type& u3_) { eigs_mode3( data_, u3_ ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::apply_mode4( const t4_type& data_, u4_type& u4_) { eigs_mode4( data_, u4_ ); } /* EIGS for mode 1, 2, 3 and 4*/ VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode1( const t4_type& data_, u1_type& u1_ ) { //unfolding / matricization u1_unfolded_type* unfolding = new u1_unfolded_type; data_.mode1_unfolding_fwd( *unfolding ); //covariance matrix of unfolded data u1_cov_type* cov = new u1_cov_type; blas_dgemm< I1, I2*I3*I4, I1, T>* blas_cov = new blas_dgemm< I1, I2*I3*I4, I1, T>; blas_cov->compute( *unfolding, *cov ); delete blas_cov; delete unfolding; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u1_ ); delete cov; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode2( const t4_type& data_, u2_type& u2_ ) { //unfolding / matricization u2_unfolded_type* unfolding = new u2_unfolded_type; data_.mode2_unfolding_fwd( *unfolding ); //covariance matrix of unfolded data u2_cov_type* cov = new u2_cov_type; blas_dgemm< I2, I1*I3*I4, I2, T>* blas_cov = new blas_dgemm< I2, I1*I3*I4, I2, T>; blas_cov->compute( *unfolding, *cov ); delete blas_cov; delete unfolding; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u2_ ); delete cov; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode3( const t4_type& data_, u3_type& u3_) { //unfolding / matricization u3_unfolded_type* unfolding = new u3_unfolded_type; data_.mode3_unfolding_fwd( *unfolding ); //covariance matrix of unfolded data u3_cov_type* cov = new u3_cov_type; blas_dgemm< I3, I1*I2*I4, I3, T>* blas_cov = new blas_dgemm< I3, I1*I2*I4, I3, T>; blas_cov->compute( *unfolding, *cov ); delete blas_cov; delete unfolding; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u3_ ); delete cov; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::eigs_mode4( const t4_type& data_, u4_type& u4_) { //unfolding / matricization u4_unfolded_type* unfolding = new u4_unfolded_type; data_.mode4_unfolding_fwd( *unfolding ); //covariance matrix of unfolded data u4_cov_type* cov = new u4_cov_type; blas_dgemm< I4, I1*I2*I3, I4, T>* blas_cov = new blas_dgemm< I4, I1*I2*I3, I4, T>; blas_cov->compute( *unfolding, *cov ); delete blas_cov; delete unfolding; //compute x largest magnitude eigenvalues; x = R get_eigs_u_red( *cov, u4_ ); delete cov; } /* helper methods for SVD and EIGS*/ VMML_TEMPLATE_STRING template< size_t N, size_t R > void VMML_TEMPLATE_CLASSNAME::get_eigs_u_red( const matrix< N, N, T >& data_, matrix< N, R, T >& u_ ) { typedef matrix< N, N, T > cov_matrix_type; typedef vector< R, T > eigval_type; typedef matrix< N, R, T > eigvec_type; //typedef matrix< N, R, T_coeff > coeff_type; //compute x largest magnitude eigenvalues; x = R eigval_type* eigxvalues = new eigval_type; eigvec_type* eigxvectors = new eigvec_type; lapack_sym_eigs< N, T > eigs; cov_matrix_type* data = new cov_matrix_type; data->cast_from( data_ ); if( !eigs.compute_x( *data, *eigxvectors, *eigxvalues) ) { /*if( _is_quantify_coeff ){ coeff_type* evec_quant = new coeff_type; T min_value = 0; T max_value = 0; u_.cast_from( *eigxvectors ); u_.quantize( *evec_quant, min_value, max_value ); evec_quant->dequantize( u_, min_value, max_value ); delete evec_quant; } else */ std::cerr << "Warning: lapack eigenvector computation returned error code" << std::endl; } u_ = *eigxvectors; delete eigxvalues; delete eigxvectors; delete data; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/t4_ttm.hpp000066400000000000000000000144431231531733200242300ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafael Ballester * * Tensor times matrix multiplication for tensor4 (t4) * using BLAS * see e.g.: * - Bader & Kolda, 2006: Algorithm 862: Matlab tensor classes for fast algorithm prototyping. ACM Transactions on Mathematical Software. * */ #ifndef __VMML__T4_TTM__HPP__ #define __VMML__T4_TTM__HPP__ #include #include #include #ifdef VMMLIB_USE_OPENMP # include #endif namespace vmml { class t4_ttm { public: template< size_t I1, size_t I2, size_t I3, size_t I4, size_t J1, size_t J2, size_t J3, size_t J4, typename T > static void full_tensor4_matrix_multiplication( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, const matrix< I4, J4, T >& U4, tensor4< I1, I2, I3, I4, T >& t4_res_ ); template< size_t I1, size_t J1, size_t J2, size_t J3, size_t J4, typename T > static void mode1_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I1, J1, T >& in_slice_, tensor4< I1, J2, J3, J4, T >& t4_res_ ); template< size_t I2, size_t J1, size_t J2, size_t J3, size_t J4, typename T > static void mode2_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I2, J2, T >& in_slice_, tensor4< J1, I2, J3, J4, T >& t4_res_ ); template< size_t I3, size_t J1, size_t J2, size_t J3, size_t J4, typename T > static void mode3_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I3, J3, T >& in_slice_, tensor4< J1, J2, I3, J4, T >& t4_res_ ); template< size_t I4, size_t J1, size_t J2, size_t J3, size_t J4, typename T > static void mode4_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I4, J4, T >& in_slice_, tensor4< J1, J2, J3, I4, T >& t4_res_ ); protected: }; #define VMML_TEMPLATE_CLASSNAME t4_ttm template< size_t I1, size_t I2, size_t I3, size_t I4, size_t J1, size_t J2, size_t J3, size_t J4, typename T > void VMML_TEMPLATE_CLASSNAME::full_tensor4_matrix_multiplication( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I1, J1, T >& U1, const matrix< I2, J2, T >& U2, const matrix< I3, J3, T >& U3, const matrix< I4, J4, T >& U4, tensor4< I1, I2, I3, I4, T >& t4_res_ ) { tensor4< I1, J2, J3, J4, T> t4_result_1; tensor4< I1, I2, J3, J4, T> t4_result_2; tensor4< I1, I2, I3, J4, T> t4_result_3; //forward cyclic matricization/unfolding (after Kiers, 2000) -> memory optimized mode1_multiply_fwd( t4_in_, U1, t4_result_1 ); mode2_multiply_fwd( t4_result_1, U2, t4_result_2 ); mode3_multiply_fwd( t4_result_2, U3, t4_result_3 ); mode4_multiply_fwd( t4_result_3, U4, t4_res_ ); } // TODO add OpenMP pragmas template< size_t I1, size_t J1, size_t J2, size_t J3, size_t J4, typename T > void VMML_TEMPLATE_CLASSNAME::mode1_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I1, J1, T >& in_slice_, tensor4< I1, J2, J3, J4, T >& t4_res_ ) { for (size_t l = 0; l < J4; ++l) { tensor3< J1, J2, J3, T > temp_input = t4_in_.get_tensor3(l); tensor3< I1, J2, J3, T > temp_output = t4_res_.get_tensor3(l); t3_ttm::multiply_frontal_fwd(temp_input, in_slice_, temp_output); t4_res_.set_tensor3(l,temp_output); } } template< size_t I2, size_t J1, size_t J2, size_t J3, size_t J4, typename T > void VMML_TEMPLATE_CLASSNAME::mode2_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I2, J2, T >& in_slice_, tensor4< J1, I2, J3, J4, T >& t4_res_ ) { for (size_t l = 0; l < J4; ++l) { tensor3< J1, J2, J3, T > temp_input = t4_in_.get_tensor3(l); tensor3< J1, I2, J3, T > temp_output = t4_res_.get_tensor3(l); t3_ttm::multiply_horizontal_fwd(temp_input, in_slice_, temp_output); t4_res_.set_tensor3(l,temp_output); } } template< size_t I3, size_t J1, size_t J2, size_t J3, size_t J4, typename T > void VMML_TEMPLATE_CLASSNAME::mode3_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I3, J3, T >& in_slice_, tensor4< J1, J2, I3, J4, T >& t4_res_ ) { for (size_t l = 0; l < J4; ++l) { tensor3< J1, J2, J3, T > temp_input = t4_in_.get_tensor3(l); tensor3< J1, J2, I3, T > temp_output = t4_res_.get_tensor3(l); t3_ttm::multiply_lateral_fwd(temp_input, in_slice_, temp_output); t4_res_.set_tensor3(l,temp_output); } } template< size_t I4, size_t J1, size_t J2, size_t J3, size_t J4, typename T > void VMML_TEMPLATE_CLASSNAME::mode4_multiply_fwd( const tensor4< J1, J2, J3, J4, T >& t4_in_, const matrix< I4, J4, T >& in_slice_, tensor4< J1, J2, J3, I4, T >& t4_res_ ) { // TODO can it be done more efficiently? for (size_t i = 0; i < J1; ++i) { for (size_t j = 0; j < J2; ++j) { for (size_t k = 0; k < J3; ++k) { for (size_t newL = 0; newL < I4; ++newL) { T sum = 0; for (size_t l = 0; l < J4; ++l) { sum += t4_in_.at(i,j,k,l)*in_slice_.at(newL,l); } t4_res_.at(i,j,k,newL) = sum; } } } } } #undef VMML_TEMPLATE_CLASSNAME }//end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tensor3.hpp000066400000000000000000002202311231531733200244040ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Jonas Boesch * * a tensor is a generalization of a multidimensional array * a tensor3 is a tensor data structure with three modes I1, I2 and I3 */ #ifndef __VMML__TENSOR3__HPP__ #define __VMML__TENSOR3__HPP__ #include // file I/O #include #include #include #include #include #ifdef VMMLIB_USE_OPENMP #include #endif #undef min #undef max namespace vmml { // tensor with three modes, containing a series I3 of I1 x I2 vmml matrices //I1 is number of rows, I2 is number of columns and I3 is number of tubes template< size_t I1, size_t I2, size_t I3, typename T = float > class tensor3 { public: typedef T value_type; typedef T* pointer; typedef T& reference; typedef float T_blas; typedef typename matrix< I1, I2, T>::iterator matrix_iterator; typedef typename vmml::tensor3_iterator< tensor3< I1, I2, I3, T > > iterator; typedef typename vmml::tensor3_const_iterator< tensor3< I1, I2, I3, T > > const_iterator; typedef typename vmml::tensor3_iterator< tensor3< I1, I2, I3, T > > reverse_iterator; typedef typename vmml::tensor3_iterator< tensor3< I1, I2, I3, T > > const_reverse_iterator; typedef matrix< I1, I2, T > front_slice_type; //fwd: forward cylcling (after kiers, 2000) typedef matrix< I3, I1, T > lat_slice_type; typedef matrix< I2, I3, T > horiz_slice_type; typedef matrix< I1, I2*I3, T > fwd_front_unfolding_type; typedef matrix< I2, I3*I1, T > fwd_horiz_unfolding_type; typedef matrix< I3, I1*I2, T > fwd_lat_unfolding_type; typedef matrix< I2, I1, T > bwd_front_slice_type; //bwd: backward cylcling (after lathauwer et al., 2000a) typedef matrix< I1, I3, T > bwd_lat_slice_type; typedef matrix< I3, I2, T > bwd_horiz_slice_type; typedef matrix< I1, I2*I3, T > bwd_lat_unfolding_type; typedef matrix< I2, I1*I3, T > bwd_front_unfolding_type; typedef matrix< I3, I1*I2, T > bwd_horiz_unfolding_type; static const size_t ROWS = I1; static const size_t COLS = I2; static const size_t SLICES = I3; static const size_t MATRIX_SIZE = I1 * I2; static const size_t SIZE = MATRIX_SIZE * I3; static size_t get_array_size_in_bytes(); // WARNING: dangerous. Use before destruction if you want to prevent // a delete call for the assigned T* _array in the destructor. void clear_array_pointer(); // accessors inline T& operator()(size_t i1, size_t i2, size_t i3); inline const T& operator()(size_t i1, size_t i2, size_t i3) const; inline T& at(size_t i1, size_t i2, size_t i3); inline const T& at(size_t i1, size_t i2, size_t i3) const; // element iterators - NOTE: column-major order iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; #if 0 reverse_iterator rbegin(); reverse_iterator rend(); const_reverse_iterator rbegin() const; const_reverse_iterator rend() const; #endif // ctors tensor3(); explicit tensor3(void* memory); tensor3(const tensor3& source); template< typename U > tensor3(const tensor3< I1, I2, I3, U >& source_); template< size_t J1, size_t J2, size_t J3> tensor3(const tensor3< J1, J2, J3, T >& source_); ~tensor3(); size_t size() const; // return I1 * I2 * I3; template< size_t J1, size_t J2, size_t J3 > tensor3 get_sub_tensor3(size_t row_offset, size_t col_offset, size_t slice_offset = 0, typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* = 0) const; template< size_t J1, size_t J2, size_t J3 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* get_sub_tensor3(tensor3& result, size_t row_offset = 0, size_t col_offset = 0, size_t slice_offset = 0) const; template< size_t J1, size_t J2, size_t J3 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* set_sub_tensor3(const tensor3& sub_data_, size_t row_offset = 0, size_t col_offset = 0, size_t slice_offset = 0); void get_sub_tensor3( char* data_, const size_t i1_start, const size_t i1_end, const size_t i2_start, const size_t i2_end, const size_t i3_start, const size_t i3_end ) const; void set_sub_tensor3( const char* data_, const size_t i1_start, const size_t i1_end, const size_t i2_start, const size_t i2_end, const size_t i3_start, const size_t i3_end ); inline void get_I1_vector(size_t i2, size_t i3, vector< I1, T >& data) const; // I1_vector is a column vector with all values i1 at i2 and i3 inline void get_I2_vector(size_t i1, size_t i3, vector< I2, T >& data) const; // I2_vector is a row vector with all values i2 at i1 and i3 inline void get_I3_vector(size_t i1, size_t i2, vector< I3, T >& data) const; // I3_vector is a vector with all values i3 at a given i1 and i2 inline void get_row(size_t i1, size_t i3, vector< I2, T >& data) const; // same as get_I2_vector inline void get_column(size_t i2, size_t i3, vector< I1, T >& data) const; // same as get_I1_vector inline void get_tube(size_t i1, size_t i2, vector< I3, T >& data) const; // same as get_I3_vector inline void set_I1_vector(size_t i2, size_t i3, const vector< I1, T >& data); // I1_vector is a column vector with all values i1 at i2 and i3 inline void set_I2_vector(size_t i1, size_t i3, const vector< I2, T >& data); // I2_vector is a row vector with all values i2 at i1 and i3 inline void set_I3_vector(size_t i1, size_t i2, const vector< I3, T >& data); // I3_vector is a vector with all values i3 at a given i1 and i2 inline void set_row(size_t i1, size_t i3, const vector< I2, T >& data); // same as set_I2_vector inline void set_column(size_t i2, size_t i3, const vector< I1, T >& data); // same as set_I1_vector inline void set_tube(size_t i1, size_t i2, const vector< I3, T >& data); // same as set_I3_vector inline void get_frontal_slice_fwd(size_t i3, front_slice_type& data) const; inline void get_lateral_slice_bwd(size_t i2, bwd_lat_slice_type& data) const; inline void get_horizontal_slice_fwd(size_t i1, horiz_slice_type& data) const; inline void get_frontal_slice_bwd(size_t i3, bwd_front_slice_type& data) const; inline void get_lateral_slice_fwd(size_t i2, lat_slice_type& data) const; inline void get_horizontal_slice_bwd(size_t i1, bwd_horiz_slice_type& data) const; inline void set_frontal_slice_fwd(size_t i3, const front_slice_type& data); inline void set_lateral_slice_bwd(size_t i2, const bwd_lat_slice_type& data); inline void set_horizontal_slice_fwd(size_t i1, const horiz_slice_type& data); inline void set_frontal_slice_bwd(size_t i3, const bwd_front_slice_type& data); inline void set_lateral_slice_fwd(size_t i2, const lat_slice_type& data); inline void set_horizontal_slice_bwd(size_t i1, const bwd_horiz_slice_type& data); inline front_slice_type& get_frontal_slice_fwd(size_t index); inline const front_slice_type& get_frontal_slice_fwd(size_t index) const; // sets all elements to fill_value void operator=(T fill_value); //@SUS: todo void fill(T fill_value); //special case of set method (all values are set to the same value!) //sets all tensor values with random values //set srand(time(NULL)) or srand( seed ) //if seed is set to -1, srand( seed ) was set outside set_random //otherwise srand( seed ) will be called with the given seed void fill_random(int seed = -1); void fill_random_signed(int seed = -1); void fill_increasing_values(); void fill_rand_sym_slices(int seed = -1); void fill_rand_sym(int seed = -1); const tensor3& operator=(const tensor3& source_); template< size_t R > typename enable_if< R == I1 && R == I2 && R == I3 >::type* diag(const vector< R, T >& diag_values_); void range_threshold(tensor3< I1, I2, I3, T >& other_, const T& start_value, const T& end_value) const; template< size_t K1, size_t K2, size_t K3 > void average_8to1(tensor3< K1, K2, K3, T >& other) const; // note: this function copies elements until either the matrix is full or // the iterator equals end_. template< typename input_iterator_t > void set(input_iterator_t begin_, input_iterator_t end_, bool row_major_layout = true); void zero(); T get_min() const; T get_max() const; T get_abs_min() const; T get_abs_max() const; //returns number of non-zeros size_t nnz() const; size_t nnz(const T& threshold_) const; void threshold(const T& threshold_value_); //note: move to t3_converter template< typename TT > void quantize(tensor3< I1, I2, I3, TT >& quantized_, T& min_value_, T& max_value_) const; template< typename TT > void quantize_to(tensor3< I1, I2, I3, TT >& quantized_, tensor3< I1, I2, I3, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const; template< typename TT > void quantize_to(tensor3< I1, I2, I3, TT >& quantized_, const T& min_value_, const T& max_value_) const; template< typename TT > void quantize_log(tensor3< I1, I2, I3, TT >& quantized_, tensor3< I1, I2, I3, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const; template< typename TT > void dequantize(tensor3< I1, I2, I3, TT >& dequantized_, const TT& min_value_, const TT& max_value_) const; template< typename TT > void dequantize_log(tensor3< I1, I2, I3, TT >& dequantized_, const tensor3< I1, I2, I3, char >& signs_, const TT& min_value_, const TT& max_value_) const; template< typename TT > void dequantize(tensor3< I1, I2, I3, TT >& dequantized_, const tensor3< I1, I2, I3, char >& signs_, const TT& min_value_, const TT& max_value_) const; bool operator==(const tensor3& other) const; bool operator!=(const tensor3& other) const; // due to limited precision, two 'idential' tensor3 might seem different. // this function allows to specify a tolerance when comparing matrices. bool equals(const tensor3& other, T tolerance) const; // this version takes a comparison functor to compare the components of // the two tensor3 data structures template< typename compare_t > bool equals(const tensor3& other, compare_t& cmp) const; //NOTE: moved tensor times matrix multiplications (TTM) to t3_ttm //apply spherical weights template< typename float_t> void apply_spherical_weights(tensor3< I1, I2, I3, float_t >& other); void get_sphere(); void horizontal_unfolding_bwd(bwd_horiz_unfolding_type& unfolding) const; void horizontal_unfolding_fwd(fwd_horiz_unfolding_type& unfolding) const; void lateral_unfolding_bwd(bwd_lat_unfolding_type& unfolding) const; void lateral_unfolding_fwd(fwd_lat_unfolding_type& unfolding) const; void frontal_unfolding_bwd(bwd_front_unfolding_type& unfolding) const; void frontal_unfolding_fwd(fwd_front_unfolding_type& unfolding) const; void horizontal_folding_bwd(const bwd_horiz_unfolding_type& unfolding); void lateral_folding_bwd(const bwd_lat_unfolding_type& unfolding); void frontal_folding_bwd(const bwd_front_unfolding_type& unfolding); // reconstruction of a Kruskal tensor => inversion of CP (Candecomp/Parafac) // please note that the parameter U will be overwritten // temp is simply a required workspace matrix, it can be empty or uninitialized // but is passed as parameter to prevent potentially superfluous allocations. template< size_t R > void reconstruct_CP(const vmml::vector< R, T>& lambda, vmml::matrix< R, I1, T >& U, const vmml::matrix< R, I2, T >& V, const vmml::matrix< R, I3, T >& W, vmml::matrix< R, I2 * I3, T >& temp ); //-> tensor outer product template< size_t R, typename TT > double tensor_inner_product( const vmml::vector< R, TT>& lambda, const vmml::matrix< I1, R, TT >& U, const vmml::matrix< I2, R, TT >& V, const vmml::matrix< I3, R, TT >& W) const; //error computation double frobenius_norm() const; double frobenius_norm(const tensor3< I1, I2, I3, T >& other) const; double avg_frobenius_norm() const; double mse(const tensor3< I1, I2, I3, T >& other) const; // mean-squared error double rmse(const tensor3< I1, I2, I3, T >& other) const; //root mean-squared error double compute_psnr(const tensor3< I1, I2, I3, T >& other, const T& max_value_) const; //peak signal-to-noise ratio void mean(T& mean_) const; double mean() const; double variance() const; double stdev() const; template< typename TT > void cast_from(const tensor3< I1, I2, I3, TT >& other); template< size_t J1, size_t J2, size_t J3, typename TT > void cast_from(const tensor3< J1, J2, J3, TT >& other, const long& slice_idx_start_ = 0); template< typename TT > void float_t_to_uint_t(const tensor3< I1, I2, I3, TT >& other); //note: these have been moved to t3_converter //void write_to_raw( const std::string& dir_, const std::string& filename_ ) const; // void read_from_raw( const std::string& dir_, const std::string& filename_ ) ; // void write_datfile( const std::string& dir_, const std::string& filename_ ) const; // void write_to_csv( const std::string& dir_, const std::string& filename_ ) const; // void remove_normals_from_raw( const std::string& dir_, const std::string& filename_ ) ; //void remove_uct_cylinder( const size_t radius_offset_, int seed_ = 0 ) ; inline tensor3 operator+(T scalar) const; inline tensor3 operator-(T scalar) const; void operator+=(T scalar); void operator-=(T scalar); inline tensor3 operator+(const tensor3& other) const; inline tensor3 operator-(const tensor3& other) const; template< size_t J1, size_t J2, size_t J3> typename enable_if< J1 < I1 && J2 < I2 && J3 < I3 >::type* operator+=(const tensor3< J1, J2, J3, T>& other); void operator+=(const tensor3& other); void operator-=(const tensor3& other); // // tensor3-scalar operations / scaling // tensor3 operator*(T scalar); void operator*=(T scalar); tensor3 operator/(T scalar); void operator/=(T scalar); // // matrix-vector operations // // transform column vector by matrix ( vec = matrix * vec ) vector< I1, T > operator*(const vector< I2, T >& other) const; // transform column vector by matrix ( vec = matrix * vec ) // assume homogenous coords, e.g. vec3 = mat4x4 * vec3, with w = 1.0 template< size_t O > vector< O, T > operator*(const vector< O, T >& vector_) const; inline tensor3< I1, I2, I3, T > operator-() const; tensor3< I1, I2, I3, T > negate() const; friend std::ostream& operator <<(std::ostream& os, const tensor3< I1, I2, I3, T >& t3) { for (size_t i = 0; i < I3; ++i) { //os << t3.array[ i ] << "***" << std::endl; os << t3.get_frontal_slice_fwd(i) << " *** " << std::endl; } return os; } // static members static void tensor3_allocate_data(T*& array_); static void tensor3_deallocate_data(T*& array_); static const tensor3< I1, I2, I3, T > ZERO; T* get_array_ptr(); const T* get_array_ptr() const; // computes the array index for direct access inline size_t compute_index(size_t i1, size_t i2, size_t i3) const; protected: front_slice_type& _get_slice(size_t index_); const front_slice_type& _get_slice(size_t index_) const; T* _array; }; // class tensor3 #define VMML_TEMPLATE_STRING template< size_t I1, size_t I2, size_t I3, typename T > #define VMML_TEMPLATE_CLASSNAME tensor3< I1, I2, I3, T > // WARNING: make sure that memory is a pointer to a memory block of // sufficient size (that is, is at least get_array_size_in_bytes()) VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor3(void* memory) : _array(reinterpret_cast (memory)) { assert(_array); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor3() : _array() { tensor3_allocate_data(_array); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor3(const tensor3& source_) : _array() { tensor3_allocate_data(_array); (*this) = source_; } VMML_TEMPLATE_STRING template< typename U > VMML_TEMPLATE_CLASSNAME::tensor3(const tensor3< I1, I2, I3, U >& source_) { const U* s_array = source_.get_array_ptr(); tensor3_allocate_data(_array); for (size_t index = 0; index < I1 * I2 * I3; ++index) { _array[ index ] = static_cast (s_array[ index ]); } } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3 > VMML_TEMPLATE_CLASSNAME::tensor3(const tensor3< J1, J2, J3, T >& source_) { const size_t minL = J1 < I1 ? J1 : I1; const size_t minC = J2 < I2 ? J2 : I2; const size_t minS = J3 < I3 ? J3 : I3; zero(); for (size_t i = 0; i < minL; i++) { for (size_t j = 0; j < minC; j++) { for (size_t k = 0; k < minS; k++) { at(i, j, k) = source_(i, j, k); } } } } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~tensor3() { tensor3_deallocate_data(_array); } VMML_TEMPLATE_STRING inline T& VMML_TEMPLATE_CLASSNAME::at(size_t i1, size_t i2, size_t i3) { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1 || i2 >= I2 || i3 >= I3) VMMLIB_ERROR("at( i1, i2, i3 ) - index out of bounds", VMMLIB_HERE); #endif //col_index * M + row_index return _array[ i3 * MATRIX_SIZE + i2 * ROWS + i1 ]; //return array[ i3 ].at( i1, i2 ); } VMML_TEMPLATE_STRING const inline T& VMML_TEMPLATE_CLASSNAME::at(size_t i1, size_t i2, size_t i3) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1 || i2 >= I2 || i3 >= I3) VMMLIB_ERROR("at( i1, i2, i3 ) - i3 index out of bounds", VMMLIB_HERE); #endif return _array[ i3 * MATRIX_SIZE + i2 * ROWS + i1 ]; //return array[ i3 ].at( i1, i2 ); } VMML_TEMPLATE_STRING inline T& VMML_TEMPLATE_CLASSNAME::operator()(size_t i1, size_t i2, size_t i3) { return at(i1, i2, i3); } VMML_TEMPLATE_STRING const inline T& VMML_TEMPLATE_CLASSNAME::operator()(size_t i1, size_t i2, size_t i3) const { return at(i1, i2, i3); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_I2_vector(size_t i1, size_t i3, vector< I2, T >& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_I1_vector() - i3 index out of bounds.", VMMLIB_HERE); #endif _get_slice(i3).get_row(i1, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_I1_vector(size_t i2, size_t i3, vector< I1, T >& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_I2_vector() - i3 index out of bounds.", VMMLIB_HERE); #endif _get_slice(i3).get_column(i2, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_I3_vector(size_t i1, size_t i2, vector< I3, T >& data) const { for (size_t i3 = 0; i3 < I3; ++i3) { data[ i3 ] = _get_slice(i3).at(i1, i2); } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_row(size_t i1, size_t i3, vector< I2, T >& data) const { get_I2_vector(i1, i3, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_column(size_t i2, size_t i3, vector< I1, T >& data) const { get_I1_vector(i2, i3, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_tube(size_t i1, size_t i2, vector< I3, T >& data) const { get_I3_vector(i1, i2, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_I2_vector(size_t i1, size_t i3, const vector< I2, T >& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("set_I1_vector() - i3 index out of bounds.", VMMLIB_HERE); #endif _get_slice(i3).set_row(i1, data); //@SUS: bug fix } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_I1_vector(size_t i2, size_t i3, const vector< I1, T >& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("set_I2_vector() - i3 index out of bounds.", VMMLIB_HERE); #endif _get_slice(i3).set_column(i2, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_I3_vector(size_t i1, size_t i2, const vector< I3, T >& data) { for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).at(i1, i2) = data[ i3 ]; } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_row(size_t i1, size_t i3, const vector< I2, T >& data) { set_I2_vector(i1, i3, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_column(size_t i2, size_t i3, const vector< I1, T >& data) { set_I1_vector(i2, i3, data); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_tube(size_t i1, size_t i2, const vector< I3, T >& data) { set_I3_vector(i1, i2, data); } VMML_TEMPLATE_STRING inline typename VMML_TEMPLATE_CLASSNAME::front_slice_type& VMML_TEMPLATE_CLASSNAME:: get_frontal_slice_fwd(size_t i3) { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_frontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif return _get_slice(i3); } VMML_TEMPLATE_STRING inline const typename VMML_TEMPLATE_CLASSNAME::front_slice_type& VMML_TEMPLATE_CLASSNAME:: get_frontal_slice_fwd(size_t i3) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_frontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif return _get_slice(i3); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_frontal_slice_fwd(size_t i3, front_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_frontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif data = _get_slice(i3); ; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_lateral_slice_bwd(size_t i2, bwd_lat_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i2 >= I2) VMMLIB_ERROR("get_lateral_slice_bwd() - index out of bounds.", VMMLIB_HERE); #endif for (size_t i3 = 0; i3 < I3; ++i3) { data.set_column(i3, _get_slice(i3).get_column(i2)); } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_horizontal_slice_fwd(size_t i1, horiz_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1) VMMLIB_ERROR("get_horizontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif for (size_t i3 = 0; i3 < I3; ++i3) { data.set_column(i3, _get_slice(i3).get_row(i1)); //or for every i2 get/set column } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_frontal_slice_bwd(size_t i3, bwd_front_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("get_frontal_slice_bwd() - index out of bounds.", VMMLIB_HERE); #endif front_slice_type* data_t = new front_slice_type(); *data_t = _get_slice(i3); data_t->transpose_to(data); delete data_t; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_lateral_slice_fwd(size_t i2, lat_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i2 >= I2) VMMLIB_ERROR("get_lateral_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif bwd_lat_slice_type* data_t = new bwd_lat_slice_type(); for (size_t i3 = 0; i3 < I3; ++i3) { data_t->set_column(i3, _get_slice(i3).get_column(i2)); } data_t->transpose_to(data); delete data_t; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_horizontal_slice_bwd(size_t i1, bwd_horiz_slice_type& data) const { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1) VMMLIB_ERROR("get_horizontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif horiz_slice_type* data_t = new horiz_slice_type(); for (size_t i3 = 0; i3 < I3; ++i3) { data_t->set_column(i3, _get_slice(i3).get_row(i1)); //or for every i2 get/set column } data_t->transpose_to(data); delete data_t; } //setter VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_frontal_slice_fwd(size_t i3, const front_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("set_frontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif _get_slice(i3) = data; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_lateral_slice_bwd(size_t i2, const bwd_lat_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i2 >= I2) VMMLIB_ERROR("set_lateral_slice_bwd() - index out of bounds.", VMMLIB_HERE); #endif for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).set_column(i2, data.get_column(i3)); } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_horizontal_slice_fwd(size_t i1, const horiz_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1) VMMLIB_ERROR("set_horizontal_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).set_row(i1, data.get_column(i3)); } } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_frontal_slice_bwd(size_t i3, const bwd_front_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i3 >= I3) VMMLIB_ERROR("set_frontal_slice_bwd() - index out of bounds.", VMMLIB_HERE); #endif front_slice_type* data_t = new front_slice_type(); data.transpose_to(*data_t); _get_slice(i3) = *data_t; delete data_t; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_lateral_slice_fwd(size_t i2, const lat_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i2 >= I2) VMMLIB_ERROR("set_lateral_slice_fwd() - index out of bounds.", VMMLIB_HERE); #endif bwd_lat_slice_type* data_t = new bwd_lat_slice_type(); data.transpose_to(*data_t); for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).set_column(i2, data_t->get_column(i3)); } delete data_t; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_horizontal_slice_bwd(size_t i1, const bwd_horiz_slice_type& data) { #ifdef VMMLIB_SAFE_ACCESSORS if (i1 >= I1) VMMLIB_ERROR("set_horizontal_slice_bwd() - index out of bounds.", VMMLIB_HERE); #endif horiz_slice_type* data_t = new horiz_slice_type(); data.transpose_to(*data_t); for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).set_row(i1, data_t->get_column(i3)); } delete data_t; } //fill VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill(T fillValue) { for (size_t i3 = 0; i3 < I3; ++i3) { _get_slice(i3).fill(fillValue); } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill_random(int seed) { if (seed >= 0) srand(seed); double fillValue = 0.0f; for (size_t index = 0; index < I1 * I2 * I3; ++index) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= std::numeric_limits< T >::max(); _array[ index ] = static_cast (fillValue); } #if 0 for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= std::numeric_limits< T >::max(); at(i1, i2, i3) = static_cast (fillValue); } } } #endif } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill_random_signed(int seed) { if (seed >= 0) srand(seed); double fillValue = 0.0f; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= std::numeric_limits< T >::max(); T fillValue2 = static_cast (fillValue) % std::numeric_limits< T >::max(); fillValue2 -= std::numeric_limits< T >::max() / 2; at(i1, i2, i3) = fillValue2; } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill_rand_sym(int seed) { if (seed >= 0) srand(seed); assert(I1 == I2); assert(I1 == I3); double fillValue = 0.0f; T t_fill_value = 0; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = i3; i1 < I1; ++i1) { for (size_t i2 = i1; i2 < I2; ++i2) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= std::numeric_limits< T >::max(); //add fillValue += 0.5; for rounding t_fill_value = static_cast (fillValue); at(i1, i2, i3) = t_fill_value; if (i1 != i2 || i1 != i3 || i2 != i3) { if (i1 != i2) at(i2, i1, i3) = t_fill_value; if (i2 != i3) at(i1, i3, i2) = t_fill_value; if (i1 != i3) at(i3, i2, i1) = t_fill_value; if (i1 != i2 && i1 != i3 && i2 != i3) { at(i2, i3, i1) = t_fill_value; at(i3, i1, i2) = t_fill_value; } } } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill_rand_sym_slices(int seed) { if (seed >= 0) srand(seed); assert(I1 == I2); double fillValue = 0.0f; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = i1; i2 < I2; ++i2) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= std::numeric_limits< T >::max(); at(i1, i2, i3) = static_cast (fillValue); at(i2, i1, i3) = static_cast (fillValue); } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: fill_increasing_values() { double fillValue = 0.0f; for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { at(i1, i2, i3) = static_cast (fillValue); fillValue++; } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::range_threshold(tensor3& other_, const T& start_value, const T& end_value) const { for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { T value = at(i1, i2, i3); if (value >= start_value && value <= end_value) other_.at(i1, i2, i3) = static_cast (value); } } } } VMML_TEMPLATE_STRING template< size_t R> typename enable_if< R == I1 && R == I2 && R == I3>::type* VMML_TEMPLATE_CLASSNAME::diag(const vector< R, T >& diag_values_) { zero(); for (size_t r = 0; r < R; ++r) { at(r, r, r) = static_cast (diag_values_.at(r)); } return 0; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::zero() { fill(static_cast (0.0)); } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::operator==(const tensor3< I1, I2, I3, T >& other) const { bool is_ok = true; for (size_t index = 0; index < I1 * I2 * I3; ++index) { if (_array[ index ] != other._array[ index ]) return false; } return true; #if 0 for (size_t i3 = 0; ok && i3 < I3; ++i3) { ok = array[ i3 ] == other.array[ i3 ]; } #endif return is_ok; } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::operator!=(const tensor3< I1, I2, I3, T >& other) const { return !operator==(other); } VMML_TEMPLATE_STRING bool equals(const tensor3< I1, I2, I3, T >& t3_0, const tensor3< I1, I2, I3, T >& t3_1, T tolerance) { return t3_0.equals(t3_1, tolerance); } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::equals(const tensor3< I1, I2, I3, T >& other, T tolerance) const { bool is_ok = true; for (size_t i3 = 0; is_ok && i3 < I3; ++i3) { is_ok = _get_slice(i3).equals(other.get_frontal_slice_fwd(i3), tolerance); } return is_ok; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::size() const { return I1 * I2 * I3; } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3 > tensor3 VMML_TEMPLATE_CLASSNAME:: get_sub_tensor3(size_t row_offset, size_t col_offset, size_t slice_offset, typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type*) const { tensor3< J1, J2, J3, T > result; get_sub_tensor3(result, row_offset, col_offset, slice_offset); return result; } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* VMML_TEMPLATE_CLASSNAME:: get_sub_tensor3(tensor3& result, size_t row_offset, size_t col_offset, size_t slice_offset) const { #ifdef VMMLIB_SAFE_ACCESSORS if (J1 + row_offset > I1 || J2 + col_offset > I2 || J3 + slice_offset > I3) VMMLIB_ERROR("index out of bounds.", VMMLIB_HERE); #endif for (size_t slice = 0; slice < J3; ++slice) { for (size_t row = 0; row < J1; ++row) { for (size_t col = 0; col < J2; ++col) { result.at(row, col, slice) = at(row_offset + row, col_offset + col, slice_offset + slice); } } } return 0; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: get_sub_tensor3( char* data_, const size_t i1_start, const size_t i1_end, const size_t i2_start, const size_t i2_end, const size_t i3_start, const size_t i3_end ) const { T* t_ptr = (T*)&(data_[0]); for ( size_t slice = i3_start; slice <= i3_end; ++slice ) { for ( size_t col = i2_start; col <= i2_end; ++col ) { for ( size_t row = i1_start; row <= i1_end; ++row ) { //std::cout << "at("<< row << "," << col << "," << slice << ") of (" < typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* VMML_TEMPLATE_CLASSNAME:: set_sub_tensor3(const tensor3& sub_data_, size_t row_offset, size_t col_offset, size_t slice_offset) { #ifdef VMMLIB_SAFE_ACCESSORS if (J1 + row_offset > I1 || J2 + col_offset > I2 || J3 + slice_offset > I3) VMMLIB_ERROR("index out of bounds.", VMMLIB_HERE); #endif for (size_t slice = 0; slice < J3; ++slice) { for (size_t row = 0; row < J1; ++row) { for (size_t col = 0; col < J2; ++col) { at(row_offset + row, col_offset + col, slice_offset + slice) = sub_data_.at(row, col, slice); } } } return 0; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: set_sub_tensor3( const char* data_, const size_t i1_start, const size_t i1_end, const size_t i2_start, const size_t i2_end, const size_t i3_start, const size_t i3_end ) { T* t_ptr = (T*)&(data_[0]); for ( size_t slice = i3_start; slice <= i3_end; ++slice ) { for ( size_t col = i2_start; col <= i2_end; ++col ) { for ( size_t row = i1_start; row <= i1_end; ++row ) { //std::cout << "at("<< row << "," << col << "," << slice << ") of (" < void VMML_TEMPLATE_CLASSNAME::set(input_iterator_t begin_, input_iterator_t end_, bool row_major_layout) { input_iterator_t it(begin_); if (row_major_layout) { for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2, ++it) { if (it == end_) return; at(i1, i2, i3) = static_cast (*it); } } } } else { std::copy(it, it + (I1 * I2 * I3), begin()); } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator+(const tensor3< I1, I2, I3, T >& other) const { tensor3< I1, I2, I3, T > result(*this); result += other; return result; } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3> typename enable_if< J1 < I1 && J2 < I2 && J3 < I3 >::type* VMML_TEMPLATE_CLASSNAME::operator+=(const tensor3< J1, J2, J3, T >& other) { for (size_t i3 = 0; i3 < J3; ++i3) { for (size_t i1 = 0; i1 < J1; ++i1) { for (size_t i2 = 0; i2 < J2; ++i2) { at(i1, i2, i3) += other.at(i1, i2, i3); } } } return 0; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator+=(const tensor3< I1, I2, I3, T >& other) { iterator it = begin(), it_end = end(); const_iterator other_it = other.begin(); for (; it != it_end; ++it, ++other_it) { *it += *other_it; } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator-(const tensor3< I1, I2, I3, T >& other) const { tensor3< I1, I2, I3, T > result(*this); result -= other; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator-=(const tensor3< I1, I2, I3, T >& other) { iterator it = begin(), it_end = end(); const_iterator other_it = other.begin(); for (; it != it_end; ++it, ++other_it) { *it -= *other_it; } } //sum with scalar VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator+(T scalar) const { tensor3< I1, I2, I3, T > result(*this); result += scalar; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator+=(T scalar) { iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { *it += scalar; } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator-(T scalar) const { tensor3< I1, I2, I3, T > result(*this); result -= scalar; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator-=(T scalar) { iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { *it -= scalar; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::horizontal_unfolding_bwd(bwd_horiz_unfolding_type& unfolding) const { bwd_horiz_slice_type* horizontal_slice = new bwd_horiz_slice_type(); for (size_t i = 0; i < I1; ++i) { get_horizontal_slice_bwd(i, *horizontal_slice); for (size_t col = 0; col < I2; ++col) { unfolding.set_column(i * I2 + col, horizontal_slice->get_column(col)); } } delete horizontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::horizontal_unfolding_fwd(fwd_horiz_unfolding_type& unfolding) const { horiz_slice_type* horizontal_slice = new horiz_slice_type(); for (size_t i = 0; i < I1; ++i) { get_horizontal_slice_fwd(i, *horizontal_slice); for (size_t col = 0; col < I3; ++col) { unfolding.set_column(i * I3 + col, horizontal_slice->get_column(col)); } } delete horizontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::lateral_unfolding_bwd(bwd_lat_unfolding_type& unfolding) const { bwd_lat_slice_type* lateral_slice = new bwd_lat_slice_type(); for (size_t i = 0; i < I2; ++i) { get_lateral_slice_bwd(i, *lateral_slice); for (size_t col = 0; col < I3; ++col) { unfolding.set_column(i * I3 + col, lateral_slice->get_column(col)); } } delete lateral_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::lateral_unfolding_fwd(fwd_lat_unfolding_type& unfolding) const { lat_slice_type* lateral_slice = new lat_slice_type(); for (size_t i = 0; i < I2; ++i) { get_lateral_slice_fwd(i, *lateral_slice); for (size_t col = 0; col < I1; ++col) { unfolding.set_column(i * I1 + col, lateral_slice->get_column(col)); } } delete lateral_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::frontal_unfolding_bwd(bwd_front_unfolding_type& unfolding) const { bwd_front_slice_type* frontal_slice = new bwd_front_slice_type(); for (size_t i = 0; i < I3; ++i) { get_frontal_slice_bwd(i, *frontal_slice); for (size_t col = 0; col < I1; ++col) { unfolding.set_column(i * I1 + col, frontal_slice->get_column(col)); } } delete frontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::frontal_unfolding_fwd(fwd_front_unfolding_type& unfolding) const { front_slice_type* frontal_slice = new front_slice_type(); for (size_t i = 0; i < I3; ++i) { get_frontal_slice_fwd(i, *frontal_slice); for (size_t col = 0; col < I2; ++col) { unfolding.set_column(i * I2 + col, frontal_slice->get_column(col)); } } delete frontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::horizontal_folding_bwd(const bwd_horiz_unfolding_type& unfolding) { bwd_horiz_slice_type* horizontal_slice = new bwd_horiz_slice_type; for (size_t i = 0; i < I1; ++i) { for (size_t col = 0; col < I2; ++col) { horizontal_slice->set_column(col, unfolding.get_column(i * I2 + col)); } set_horizontal_slice_bwd(i, *horizontal_slice); } delete horizontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::frontal_folding_bwd(const bwd_front_unfolding_type& unfolding) { bwd_front_slice_type* frontal_slice = new bwd_front_slice_type(); for (size_t i = 0; i < I3; ++i) { for (size_t col = 0; col < I1; ++col) { frontal_slice->set_column(col, unfolding.get_column(i * I1 + col)); } set_frontal_slice_bwd(i, *frontal_slice); } delete frontal_slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::lateral_folding_bwd(const bwd_lat_unfolding_type& unfolding) { bwd_lat_slice_type* lateral_slice = new bwd_lat_slice_type(); for (size_t i = 0; i < I2; ++i) { for (size_t col = 0; col < I3; ++col) { lateral_slice->set_column(col, unfolding.get_column(i * I3 + col)); } set_lateral_slice_bwd(i, *lateral_slice); } delete lateral_slice; } VMML_TEMPLATE_STRING tensor3< I1, I2, I3, T > VMML_TEMPLATE_CLASSNAME::operator*(T scalar) { tensor3< I1, I2, I3, T > result; for (size_t index = 0; index < I1 * I2 * I3; ++index) { result._array[ index ] = _array[ index ] * scalar; } #if 0 tensor3< I1, I2, I3, T >* result = (*this); for (size_t i3 = 0; i3 < I3; ++i3) { result.array[ i3 ] = array[ i3 ] * scalar; } return *result; #endif } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator*=(T scalar) { for (size_t index = 0; index < I1 * I2 * I3; ++index) { _array[ index ] *= scalar; } #if 0 for (size_t i3 = 0; i3 < I3; ++i3) { array[ i3 ] *= scalar; } #endif } VMML_TEMPLATE_STRING tensor3< I1, I2, I3, T > VMML_TEMPLATE_CLASSNAME::operator/(T scalar) { tensor3< I1, I2, I3, T > result; for (size_t slice_idx = 0; slice_idx < I3; ++slice_idx) { for (size_t row_index = 0; row_index < I1; ++row_index) { for (size_t col_index = 0; col_index < I2; ++col_index) { result.at(row_index, col_index, slice_idx) = at(row_index, col_index, slice_idx) / scalar; } } } return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator/=(T scalar) { for (size_t slice_idx = 0; slice_idx < I3; ++slice_idx) { for (size_t row_index = 0; row_index < I1; ++row_index) { for (size_t col_index = 0; col_index < I2; ++col_index) { at(row_index, col_index, slice_idx) /= scalar; } } } } VMML_TEMPLATE_STRING inline tensor3< I1, I2, I3, T > VMML_TEMPLATE_CLASSNAME::operator-() const { return negate(); } VMML_TEMPLATE_STRING tensor3< I1, I2, I3, T > VMML_TEMPLATE_CLASSNAME::negate() const { tensor3< I1, I2, I3, T > result; result *= -1.0; return result; } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::frobenius_norm(const tensor3< I1, I2, I3, T>& other_) const { double f_norm = 0.0; T abs_diff = 0; const_iterator it = begin(), it_end = end(); const_iterator it_other = other_.begin(); for (; it != it_end; ++it, ++it_other) { abs_diff = fabs(*it - *it_other); f_norm += abs_diff * abs_diff; } return sqrt(f_norm); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::frobenius_norm() const { double f_norm = 0.0; #if 0 const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) f_norm += *it * *it; #else for (long i3 = 0; i3 < long(I3); ++i3) { for (long i1 = 0; i1 < long(I1); ++i1) { long i2 = 0; for (i2 = 0; i2 < long(I2); ++i2) { f_norm += at(i1, i2, i3) * at(i1, i2, i3); } } } #endif return sqrt(f_norm); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::avg_frobenius_norm() const { double af_norm = 0.0; const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) af_norm += *it * *it; af_norm /= size(); return sqrt(af_norm); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::mse(const tensor3< I1, I2, I3, T >& other) const { double mse_val = 0.0; double diff = 0.0; const_iterator it = begin(), it_end = end(); const_iterator other_it = other.begin(); for (; it != it_end; ++it, ++other_it) { diff = abs(*it) - abs(*other_it); mse_val += diff * diff; } mse_val /= (double) size(); return mse_val; } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::rmse(const tensor3< I1, I2, I3, T >& other) const { return sqrt(mse(other)); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::mean() const { double val = 0; const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { val += double(abs(*it)); } return ( val / size()); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mean(T& mean_) const { mean_ = static_cast (mean()); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::variance() const { double val = 0.0; double sum_val = 0.0; double mean_val = mean(); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { val = double(*it) - mean_val; val *= val; sum_val += val; } return double(sum_val / (size() - 1)); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::stdev() const { return sqrt(variance()); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::compute_psnr(const tensor3< I1, I2, I3, T >& other, const T& max_value_) const { double rmse_val = rmse(other); double psnr_val = log(max_value_ / rmse_val); psnr_val *= 20; return fabs(psnr_val); } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::cast_from(const tensor3< I1, I2, I3, TT >& other) { #if 0 typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::const_iterator tt_const_iterator; iterator it = begin(), it_end = end(); tt_const_iterator other_it = other.begin(); for (; it != it_end; ++it, ++other_it) { *it = static_cast (*other_it); } #else #pragma omp parallel for for (long slice_idx = 0; slice_idx < (long) I3; ++slice_idx) { #pragma omp parallel for for (long row_index = 0; row_index < (long) I1; ++row_index) { #pragma omp parallel for for (long col_index = 0; col_index < (long) I2; ++col_index) { at(row_index, col_index, slice_idx) = static_cast (other.at(row_index, col_index, slice_idx)); } } } #endif } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3, typename TT > void VMML_TEMPLATE_CLASSNAME::cast_from(const tensor3< J1, J2, J3, TT >& other, const long& slice_idx_start_) { #pragma omp parallel for for (long slice_idx = slice_idx_start_; slice_idx < (long) J3; ++slice_idx) { #pragma omp parallel for for (long row_index = 0; row_index < (long) J1; ++row_index) { #pragma omp parallel for for (long col_index = 0; col_index < (long) J2; ++col_index) { at(row_index, col_index, slice_idx) = static_cast (other.at(row_index, col_index, slice_idx)); } } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::float_t_to_uint_t(const tensor3< I1, I2, I3, TT >& other) { typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::const_iterator tt_const_iterator; if (sizeof (T) == 1 || sizeof (T) == 2) { iterator it = begin(), it_end = end(); tt_const_iterator other_it = other.begin(); for (; it != it_end; ++it, ++other_it) { *it = T(std::min(std::max(int(0), int( *other_it + 0.5)), int(std::numeric_limits< T >::max()))); } } else { //std::cout << "Warning: use a different type as target (uint8 or uint16). No converstion done.\n" << std::endl; this->cast_from(other); return; } } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_min() const { T tensor3_min = static_cast (std::numeric_limits::max()); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (*it < tensor3_min) { tensor3_min = *it; } } return tensor3_min; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_max() const { T tensor3_max = static_cast (0); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (*it > tensor3_max) { tensor3_max = *it; } } return tensor3_max; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_abs_min() const { T tensor3_min = static_cast (std::numeric_limits::max()); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (fabs(*it) < fabs(tensor3_min)) { tensor3_min = fabs(*it); } } return tensor3_min; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_abs_max() const { T tensor3_max = static_cast (0); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (fabs(*it) > fabs(tensor3_max)) { tensor3_max = fabs(*it); } } return tensor3_max; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz() const { size_t counter = 0; const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (*it != 0) { ++counter; } } return counter; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz(const T& threshold_) const { size_t counter = 0; const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (fabs(*it) > threshold_) { ++counter; } } return counter; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::threshold(const T& threshold_value_) { iterator it = begin(), it_end = end(); for (; it != it_end; ++it) { if (fabs(*it) <= threshold_value_) { *it = static_cast (0); } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize_to(tensor3< I1, I2, I3, TT >& quantized_, const T& min_value_, const T& max_value_) const { double max_tt_range = double(std::numeric_limits< TT >::max()); double min_tt_range = double(std::numeric_limits< TT >::min()); double tt_range = max_tt_range - min_tt_range; double t_range = max_value_ - min_value_; //std::cout << "tt min= " << min_tt_range << ", tt max= " << max_tt_range << ", t min= " << min_value_ << ", t max= " << max_value_ << std::endl; //std::cout << "tt range=" << tt_range << ", t range= " << t_range << std::endl; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_quant = quantized_.begin(); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it, ++it_quant) { if (std::numeric_limits::is_signed) { *it_quant = TT(std::min(std::max(min_tt_range, double((*it * tt_range / t_range) + 0.5)), max_tt_range)); } else { *it_quant = TT(std::min(std::max(min_tt_range, double(((*it - min_value_) * tt_range / t_range) + 0.5)), max_tt_range)); } //std::cout << "original value= " << double(*it) << ", converted value= " << double(*it_quant ) << std::endl; } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize(tensor3< I1, I2, I3, TT >& quantized_, T& min_value_, T& max_value_) const { min_value_ = get_min(); max_value_ = get_max(); quantize_to(quantized_, min_value_, max_value_); } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize_log(tensor3< I1, I2, I3, TT >& quantized_, tensor3< I1, I2, I3, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const { double max_tt_range = double(tt_range_); double min_tt_range = 0; min_value_ = 0; max_value_ = get_abs_max(); double t_range = max_value_ - min_value_; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_quant = quantized_.begin(); const_iterator it = begin(), it_end = end(); typedef tensor3< I1, I2, I3, char > t3_sign_type; typedef typename t3_sign_type::iterator sign_iterator; sign_iterator it_sign = signs_.begin(); for (; it != it_end; ++it, ++it_quant, ++it_sign) { T value = fabs(*it); *it_sign = ((*it) < 0.f) ? 0 : 1; T quant_value = 0; if (std::numeric_limits::is_signed) { quant_value = log2(1 + value) / log2(1 + t_range) * tt_range_; *it_quant = TT(std::min(std::max(min_tt_range, double(quant_value + 0.5)), max_tt_range)); } else { quant_value = log2(1 + (value - min_value_)) / log2(1 + t_range) * tt_range_; *it_quant = TT(std::min(std::max(min_tt_range, double(quant_value + 0.5)), max_tt_range)); } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize_to(tensor3< I1, I2, I3, TT >& quantized_, tensor3< I1, I2, I3, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const { double max_tt_range = double(tt_range_); double min_tt_range = 0; min_value_ = get_abs_min(); max_value_ = get_abs_max(); double t_range = max_value_ - min_value_; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_quant = quantized_.begin(); const_iterator it = begin(), it_end = end(); typedef tensor3< I1, I2, I3, char > t3_sign_type; typedef typename t3_sign_type::iterator sign_iterator; sign_iterator it_sign = signs_.begin(); for (; it != it_end; ++it, ++it_quant, ++it_sign) { T value = fabs(*it); *it_sign = ((*it) < 0.f) ? 0 : 1; if (std::numeric_limits::is_signed) { *it_quant = TT(std::min(std::max(min_tt_range, double((value * tt_range_ / t_range) + 0.5)), max_tt_range)); } else { *it_quant = TT(std::min(std::max(min_tt_range, double(((value - min_value_) * tt_range_ / t_range) + 0.5)), max_tt_range)); } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::dequantize(tensor3< I1, I2, I3, TT >& dequantized_, const tensor3< I1, I2, I3, char >& signs_, const TT& min_value_, const TT& max_value_) const { T max_t_range = get_max(); T min_t_range = get_min(); long t_range = long(max_t_range) - long(min_t_range); TT tt_range = max_value_ - min_value_; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_dequant = dequantized_.begin(); const_iterator it = begin(), it_end = end(); typedef tensor3< I1, I2, I3, char > t3_sign_type; typedef typename t3_sign_type::const_iterator sign_iterator; sign_iterator it_sign = signs_.begin(); float sign = 0; for (; it != it_end; ++it, ++it_dequant, ++it_sign) { sign = ((*it_sign) == 0) ? -1 : 1; if (std::numeric_limits::is_signed) { *it_dequant = sign * std::min(std::max(min_value_, TT((TT(*it) / t_range) * tt_range)), max_value_); } else { *it_dequant = sign * std::min(std::max(min_value_, TT((((TT(*it) / t_range)) * tt_range) + min_value_)), max_value_); } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::dequantize_log(tensor3< I1, I2, I3, TT >& dequantized_, const tensor3< I1, I2, I3, char >& signs_, const TT& min_value_, const TT& max_value_) const { T max_t_range = get_max(); T min_t_range = get_min(); long t_range = long(max_t_range) - long(min_t_range); TT tt_range = max_value_ - min_value_; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_dequant = dequantized_.begin(); const_iterator it = begin(), it_end = end(); typedef tensor3< I1, I2, I3, char > t3_sign_type; typedef typename t3_sign_type::const_iterator sign_iterator; sign_iterator it_sign = signs_.begin(); float sign = 0; for (; it != it_end; ++it, ++it_dequant, ++it_sign) { TT value = TT(*it); TT dequant_value = 0; sign = ((*it_sign) == 0) ? -1 : 1; if (std::numeric_limits::is_signed) { dequant_value = exp2((value / t_range) * log2(1 + tt_range)) - 1; *it_dequant = sign * (std::min(std::max(min_value_, dequant_value), max_value_)); } else { dequant_value = exp2((value / t_range) * log2(1 + tt_range)) - 1; *it_dequant = sign * (std::min(std::max(min_value_, dequant_value + min_value_), max_value_)); } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::dequantize(tensor3< I1, I2, I3, TT >& dequantized_, const TT& min_value_, const TT& max_value_) const { T max_t_range = get_max(); T min_t_range = get_min(); long t_range = long(max_t_range) - long(min_t_range); TT tt_range = max_value_ - min_value_; typedef tensor3< I1, I2, I3, TT > t3_tt_type; typedef typename t3_tt_type::iterator tt_iterator; tt_iterator it_dequant = dequantized_.begin(); const_iterator it = begin(), it_end = end(); for (; it != it_end; ++it, ++it_dequant) { if (std::numeric_limits::is_signed) { *it_dequant = std::min(std::max(min_value_, TT((TT(*it) / t_range) * tt_range)), max_value_); } else { *it_dequant = std::min(std::max(min_value_, TT((((TT(*it) / t_range)) * tt_range) + min_value_)), max_value_); } } } VMML_TEMPLATE_STRING const VMML_TEMPLATE_CLASSNAME& VMML_TEMPLATE_CLASSNAME::operator=(const VMML_TEMPLATE_CLASSNAME& source_) { memcpy(_array, source_._array, I1 * I2 * I3 * sizeof ( T)); return *this; } #if 0 std::string format_path(const std::string& dir_, const std::string& filename_, const std::string& format_) { std::string path = dir_; int dir_length = dir_.size() - 1; int last_separator = dir_.find_last_of("/"); std::string path = dir_; if (last_separator < dir_length) { path.append("/"); } path.append(filename_); //check for format if (filename_.find(format_, filename_.size() - 3) == (-1)) { path.append("."); path.append(format_); } return path; } #endif VMML_TEMPLATE_STRING vmml::matrix< I1, I2, T >& VMML_TEMPLATE_CLASSNAME:: _get_slice(size_t index_) { typedef matrix< I1, I2, T > matrix_type; return *reinterpret_cast (_array + I1 * I2 * index_); } VMML_TEMPLATE_STRING const vmml::matrix< I1, I2, T >& VMML_TEMPLATE_CLASSNAME:: _get_slice(size_t index_) const { typedef matrix< I1, I2, T > matrix_type; return *reinterpret_cast (_array + I1 * I2 * index_); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: tensor3_allocate_data(T*& array_) { array_ = new T[ I1 * I2 * I3]; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: tensor3_deallocate_data(T*& array_) { if (array_) { delete[] array_; } } VMML_TEMPLATE_STRING T* VMML_TEMPLATE_CLASSNAME::get_array_ptr() { return _array; } VMML_TEMPLATE_STRING const T* VMML_TEMPLATE_CLASSNAME::get_array_ptr() const { return _array; } VMML_TEMPLATE_STRING template< size_t R > void VMML_TEMPLATE_CLASSNAME:: reconstruct_CP( const vmml::vector< R, T>& lambda, vmml::matrix< R, I1, T >& U, const vmml::matrix< R, I2, T >& V, const vmml::matrix< R, I3, T >& W, vmml::matrix< R, I2 * I3, T >& temp ) { for (size_t j = 0; j < I2; j++) { for (size_t k = 0; k < I3; k++) { for (size_t r = 0; r < R; r++) { temp(r, j + k * I2) = V(r, j) * W(r, k); } } } for (size_t i = 0; i < I1; i++) { for (size_t r = 0; r < R; r++) { U(r, i) = lambda[r] * U(r, i); } } vector< R, T > ui; vector< R, T > tmpi; blas_dot< R, T > bdot; for (size_t k = 0; k < I3; k++) { for (size_t j = 0; j < I2; j++) { for (size_t i = 0; i < I1; i++) { T& value = at(i, j, k); value = static_cast (0.0); #if 0 ui = U.get_column(i); tmpi = temp.get_column(j + k * I2); bdot.compute(ui, tmpi, value); #else for (size_t r = 0; r < R; ++r) value += U(r, i) * temp(r, j + k * I2); #endif } } } } VMML_TEMPLATE_STRING template< typename float_t> void VMML_TEMPLATE_CLASSNAME:: apply_spherical_weights(tensor3< I1, I2, I3, float_t >& other) { //piecewise multiplication of every frontal slice with the weights (spherical) for (size_t i3 = 0; i3 < I3; ++i3) { size_t k3 = i3 - I3 / 2; for (size_t i1 = 0; i1 < I1; ++i1) { size_t k1 = i1 - I1 / 2; for (size_t i2 = 0; i2 < I2; ++i2) { size_t k2 = i2 - I2 / 2; float_t weight = (sqrtf(k1 * k1 + k2 * k2 + k3 * k3) + 0.0000001); weight = exp(-weight); //or try exp(- weight * factor) float_t value = static_cast (at(i1, i2, i3)); //value = (value > 35) ? (value - 35) : 0; other.at(i1, i2, i3) = static_cast (weight * value); } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: get_sphere() { for (size_t i3 = 0; i3 < I3; ++i3) { size_t k3 = i3 - I3 / 2; for (size_t i1 = 0; i1 < I1; ++i1) { size_t k1 = i1 - I1 / 2; for (size_t i2 = 0; i2 < I2; ++i2) { size_t k2 = i2 - I2 / 2; float_t radius = sqrtf(k1 * k1 + k2 * k2 + k3 * k3); //FIXME(choose appropriate I if (radius >= (I1 / 2)) at(i1, i2, i3) = 0; } } } } VMML_TEMPLATE_STRING template< size_t R, typename TT > double VMML_TEMPLATE_CLASSNAME::tensor_inner_product( const vmml::vector< R, TT>& lambda, const vmml::matrix< I1, R, TT >& U, const vmml::matrix< I2, R, TT >& V, const vmml::matrix< I3, R, TT >& W) const { T inner_prod(0); for (size_t r = 0; r < R; ++r) { for (size_t k = 0; k < I3; ++k) { for (size_t j = 0; j < I2; ++j) { for (size_t i = 0; i < I1; ++i) { inner_prod += at(i, j, k) * U(i, r) * V(j, r) * W(k, r) * lambda.at(r); } } } } return inner_prod; } VMML_TEMPLATE_STRING template< size_t K1, size_t K2, size_t K3 > void VMML_TEMPLATE_CLASSNAME::average_8to1(tensor3< K1, K2, K3, T >& other) const { assert(I1 / 2 >= K1); assert(I2 / 2 >= K2); assert(I3 / 2 >= K3); typedef matrix< K1, K2, T > other_slice_type; typedef matrix< K1, K2, float > other_slice_float_type; typedef matrix< K1, I2, T> sub_row_slice_type; front_slice_type* slice0 = new front_slice_type; front_slice_type* slice1 = new front_slice_type; sub_row_slice_type* sub_row_slice = new sub_row_slice_type; other_slice_type* slice_other = new other_slice_type; other_slice_float_type* slice_float_other = new other_slice_float_type; other.zero(); for (size_t i3 = 0, k3 = 0; i3 < I3; ++i3, ++k3) { get_frontal_slice_fwd(i3++, *slice0); if (i3 < I3) { get_frontal_slice_fwd(i3, *slice1); *slice0 += *slice1; slice0->sum_rows(*sub_row_slice); sub_row_slice->sum_columns(*slice_other); *slice_float_other = *slice_other; *slice_float_other /= 8.0; *slice_float_other += 0.5; slice_other->cast_from(*slice_float_other); other.set_frontal_slice_fwd(k3, *slice_other); } } delete slice0; delete slice1; delete slice_other; delete sub_row_slice; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::get_array_size_in_bytes() { return (sizeof (T) * SIZE); } // WARNING: dangerous. Use before destruction if you want to prevent // a delete call for the assigned T* _array in the destructor. VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::clear_array_pointer() { _array = 0; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tensor3_iterator.hpp000066400000000000000000000116741231531733200263260ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Jonas Boesch * @author Susanne Suter * * */ #ifndef __VMML__TENSOR3_ITERATOR__HPP__ #define __VMML__TENSOR3_ITERATOR__HPP__ #include namespace vmml { template< typename T > class tensor3_iterator { public: typedef typename T::value_type value_type; typedef typename T::pointer pointer; typedef typename T::reference reference; typedef typename std::forward_iterator_tag iterator_category; typedef size_t difference_type; typedef typename matrix< T::ROWS, T::COLS, typename T::value_type >::iterator matrix_iterator; typedef typename T::front_slice_type slice_type; tensor3_iterator() : _tensor3( 0 ), _matrix_index( 0 ) {}; tensor3_iterator( T& t_, bool begin_ ) : _tensor3( &t_ ), _matrix_index( 0 ) { if ( begin_ ) { _matrix_index = 0; slice_type& slice_ = _tensor3->get_frontal_slice_fwd( _matrix_index ); _matrix_it = slice_.begin(); _matrix_it_end = slice_.end(); } else { _matrix_index = T::SLICES - 1; slice_type& slice_ = _tensor3->get_frontal_slice_fwd( _matrix_index ); _matrix_it = slice_.end(); _matrix_it_end = slice_.begin(); } } value_type& operator*() { return *_matrix_it; } const value_type& operator*() const { return *_matrix_it; } bool operator==( const tensor3_iterator& it_ ) const { return it_._tensor3 == _tensor3 // && it_._matrix_index == _matrix_index && it_._matrix_it == _matrix_it; } bool operator!=( const tensor3_iterator& it_ ) const { return ! operator==(it_); } void operator++() { if ( _tensor3 == 0 ) { VMMLIB_ERROR( "attempt to increase singular iterator", VMMLIB_HERE ); } if ( _matrix_it != _matrix_it_end ) ++_matrix_it; if ( _matrix_it == _matrix_it_end && _matrix_index + 1 < T::SLICES ) { ++_matrix_index; //slice_type& slice_ = _tensor3->get_frontal_slice( _matrix_index ); _matrix_it = _tensor3->get_frontal_slice_fwd( _matrix_index ).begin(); _matrix_it_end = _tensor3->get_frontal_slice_fwd( _matrix_index ).end(); } } protected: matrix_iterator _matrix_it; matrix_iterator _matrix_it_end; T* _tensor3; size_t _matrix_index; }; //end tensor3_iterator class template< typename T > class tensor3_const_iterator { public: typedef typename T::value_type value_type; typedef typename T::pointer pointer; typedef typename T::reference reference; typedef typename std::forward_iterator_tag iterator_category; typedef size_t difference_type; typedef typename matrix< T::ROWS, T::COLS, typename T::value_type >::const_iterator matrix_iterator; typedef typename T::front_slice_type slice_type; tensor3_const_iterator() : _tensor3( 0 ), _matrix_index( 0 ) {}; tensor3_const_iterator( const T& t_, bool begin_ ) : _tensor3( &t_ ), _matrix_index( 0 ) { if ( begin_ ) { _matrix_index = 0; const slice_type& slice_ = _tensor3->get_frontal_slice_fwd( _matrix_index ); _matrix_it = slice_.begin(); _matrix_it_end = slice_.end(); } else { _matrix_index = T::SLICES - 1; const slice_type& slice_ = _tensor3->get_frontal_slice_fwd( _matrix_index ); _matrix_it = slice_.end(); _matrix_it_end = slice_.begin(); } } const value_type& operator*() const { return *_matrix_it; } bool operator==( const tensor3_const_iterator& it_ ) const { return it_._matrix_it == _matrix_it; } bool operator!=( const tensor3_const_iterator& it_ ) const { return it_._matrix_it != _matrix_it; } void operator++() { if ( _tensor3 == 0 ) { VMMLIB_ERROR( "attempt to increase singular iterator", VMMLIB_HERE ); } if ( _matrix_it != _matrix_it_end ) ++_matrix_it; if ( _matrix_it == _matrix_it_end && _matrix_index + 1 < T::SLICES ) { ++_matrix_index; //const slice_type& slice_ = _tensor3->get_frontal_slice( _matrix_index ); _matrix_it = _tensor3->get_frontal_slice_fwd( _matrix_index ).begin(); _matrix_it_end = _tensor3->get_frontal_slice_fwd( _matrix_index ).end(); } } protected: matrix_iterator _matrix_it; matrix_iterator _matrix_it_end; const T* _tensor3; size_t _matrix_index; }; //end tensor3_const_iterator class }// end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tensor4.hpp000066400000000000000000001220311231531733200244040ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author David Klaper * @author Susanne Suter * @author Jonas Boesch * * a tensor is a generalization of a multidimensional array * a tensor4 is a tensor data structure with four modes I1, I2, I3 and I4 */ #ifndef __VMML__TENSOR4__HPP__ #define __VMML__TENSOR4__HPP__ #include // file I/O #include #include "tensor3.hpp" namespace vmml { // tensor with four modes, containing a series I4 x tensor4 as (I3 of I1 x // I2 vmml matrices). I1 is number of rows, I2 is number of columns and I3 // is number of tubes, I4 is number of tensor4s template< size_t I1, size_t I2, size_t I3, size_t I4, typename T = float > class tensor4 { public: typedef T value_type; typedef T* pointer; typedef T& reference; typedef tensor3< I1, I2, I3, T> tensor3_t; //TODO: maybe tensor4 iterator //TODO: unfolding along all modes //TODO: accessors to tensor3 (along all modes) // Average all values along 1 axis tensor3_t& average_I4(tensor3_t& t3) const; typedef matrix< I1, I2*I3*I4, T > mode1_unfolding_type; typedef matrix< I2, I3*I4*I1, T > mode2_unfolding_type; typedef matrix< I3, I4*I1*I2, T > mode3_unfolding_type; typedef matrix< I4, I1*I2*I3, T > mode4_unfolding_type; inline void get_tensor3( const size_t i4_, tensor3_t& t3_data_ ) const; inline tensor3_t& get_tensor3( size_t i4_ ); inline const tensor3_t& get_tensor3( size_t i4_ ) const; inline void set_tensor3( size_t i4_, const tensor3_t& t3_data_ ); static const size_t ROWS = I1; static const size_t COLS = I2; static const size_t SLICES = I3; static const size_t T3S = I4; static const size_t MATRIX_SIZE = I1 * I2; static const size_t T3_SIZE = I1 * I2 * I3; static const size_t SIZE = I1 * I2 * I3 * I4; static size_t get_array_size_in_bytes(); // WARNING: dangerous. Use before destruction if you want to prevent // a delete call for the assigned T* _array in the destructor. void clear_array_pointer(); // accessors inline T& operator()( size_t i1, size_t i2, size_t i3, size_t i4 ); inline const T& operator()( size_t i1, size_t i2, size_t i3, size_t i4 ) const; inline T& at( size_t i1, size_t i2, size_t i3, size_t i4 ); inline const T& at( size_t i1, size_t i2, size_t i3, size_t i4 ) const; // ctors tensor4(); explicit tensor4(void* memory) ; tensor4( const tensor4& source ); template< typename U > tensor4( const tensor4< I1, I2, I3, I4, U >& source_ ); template< size_t J1, size_t J2, size_t J3, size_t J4 > tensor4( const tensor4< J1, J2, J3, J4, T >& source_ ); ~tensor4(); size_t size() const; // return I1 * I2 * I3 * I4; // sets all elements to fill_value void operator=( T fill_value ); void fill( T fill_value ); //special case of set method (all values are set to the same value!) //sets all tensor values with random values //if seed is negative, srand( seed ) should have been set outside fill_random //if seed is 0 or greater srand( seed ) will be called with the given seed void fill_random( int seed = -1 ); void fill_random_signed( int seed = -1 ); void fill_increasing_values( ); const tensor4& operator=( const tensor4& source_ ); // note: this function copies elements until either the matrix is full or // the iterator equals end_. template< typename input_iterator_t > void set( input_iterator_t begin_, input_iterator_t end_, bool row_major_layout = true ); void zero(); T get_min() const; T get_max() const; T get_abs_min() const; T get_abs_max() const; //returns number of non-zeros size_t nnz() const; size_t nnz( const T& threshold_ ) const; void threshold( const T& threshold_value_ ); //error computation double frobenius_norm() const; double frobenius_norm( const tensor4< I1, I2, I3, I4, T >& other ) const; double avg_frobenius_norm() const; double mse( const tensor4< I1, I2, I3, I4, T >& other ) const; // mean-squared error double rmse( const tensor4< I1, I2, I3, I4, T >& other ) const; //root mean-squared error double compute_psnr( const tensor4< I1, I2, I3, I4, T >& other, const T& max_value_ ) const; //peak signal-to-noise ratio void mean( T& mean_ ) const; double mean() const; double variance() const; double stdev() const; template< typename TT > void cast_from( const tensor4< I1, I2, I3, I4, TT >& other ); template< size_t J1, size_t J2, size_t J3, size_t J4, typename TT > void cast_from( const tensor4< J1, J2, J3, J4, TT >& other, const long& slice_idx_start_ = 0 ); template< typename TT > void float_t_to_uint_t( const tensor4< I1, I2, I3, I4, TT >& other ); //check if corresponding tensor values are equal or not bool operator==( const tensor4& other ) const; bool operator!=( const tensor4& other ) const; // due to limited precision, two 'idential' tensor4 might seem different. // this function allows to specify a tolerance when comparing matrices. bool equals( const tensor4& other, T tolerance ) const; // this version takes a comparison functor to compare the components of // the two tensor4 data structures template< typename compare_t > bool equals( const tensor4& other, compare_t& cmp ) const; inline tensor4 operator+( T scalar ) const; inline tensor4 operator-( T scalar ) const; void operator+=( T scalar ); void operator-=( T scalar ); inline tensor4 operator+( const tensor4& other ) const; inline tensor4 operator-( const tensor4& other ) const; template< size_t J1, size_t J2, size_t J3, size_t J4 > typename enable_if< J1 < I1 && J2 < I2 && J3 < I3 && J4 < I4 >::type* operator+=( const tensor4< J1, J2, J3, J4, T>& other ); void operator+=( const tensor4& other ); void operator-=( const tensor4& other ); // // tensor4-scalar operations / scaling // tensor4 operator*( T scalar ); void operator*=( T scalar ); tensor4 operator/( T scalar ); void operator/=( T scalar ); inline tensor4< I1, I2, I3, I4, T > operator-() const; tensor4< I1, I2, I3, I4, T > negate() const; friend std::ostream& operator << ( std::ostream& os, const tensor4< I1,I2,I3,I4,T >& t4 ) { //FIXME: to this directly with tensors //sth like: //os << t4.get_tensor3( i ) << " xxx " << std::endl; for(size_t i4 = 0; i4 < I4; ++i4) { for(size_t i3 = 0; i3 < I3; ++i3) { for(size_t i1 = 0; i1 < I1; ++i1) { os << "("; for(size_t i2 = 0; i2 < I2; ++i2) { if( i2+1 == I2 ) { os << T(t4.at( i1, i2, i3, i4 )) ; } else { os << T(t4.at( i1, i2, i3, i4 )) << ", " ; } } os << ")" << std::endl; } if ( i3+1 < I3 ) os << " *** " << std::endl; } if ( i4 + 1 < I4 ) { os << "---- " << std::endl; } } return os; } template< size_t J1, size_t J2, size_t J3, size_t J4 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 && J4 <= I4 >::type* get_sub_tensor4(tensor4& result, size_t row_offset, size_t col_offset, size_t slice_offset, size_t t3_offset) const; // static members static void tensor4_allocate_data( T*& array_ ); static void tensor4_deallocate_data( T*& array_ ); static const tensor4< I1, I2, I3, I4, T > ZERO; T* get_array_ptr(); const T* get_array_ptr() const; void mode1_unfolding_fwd(mode1_unfolding_type& unfolding) const; void mode2_unfolding_fwd(mode2_unfolding_type& unfolding) const; void mode3_unfolding_fwd(mode3_unfolding_type& unfolding) const; void mode4_unfolding_fwd(mode4_unfolding_type& unfolding) const; // computes the array index for direct access inline size_t compute_index( size_t i1, size_t i2, size_t i3, size_t i4 ) const; template< typename TT > void quantize_log(tensor4< I1, I2, I3, I4, TT >& quantized_, tensor4< I1, I2, I3, I4, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const; protected: tensor3_t& _get_tensor3( size_t index_ ); const tensor3_t& _get_tensor3( size_t index_ ) const; T* _array; }; // class tensor4 #define VMML_TEMPLATE_STRING template< size_t I1, size_t I2, size_t I3, size_t I4, typename T > #define VMML_TEMPLATE_CLASSNAME tensor4< I1, I2, I3, I4, T > // WARNING: make sure that memory is a pointer to a memory block of // sufficient size (that is, is at least get_array_size_in_bytes()) VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor4( void* memory ) : _array( reinterpret_cast( memory ) ) { assert( _array ); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor4() : _array() { tensor4_allocate_data( _array ); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~tensor4() { tensor4_deallocate_data( _array ); } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3, size_t J4 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 && J4 <= I4 >::type* VMML_TEMPLATE_CLASSNAME:: get_sub_tensor4(tensor4& result, size_t row_offset, size_t col_offset, size_t slice_offset, size_t t3_offset) const { #ifdef VMMLIB_SAFE_ACCESSORS if (J1 + row_offset > I1 || J2 + col_offset > I2 || J3 + slice_offset > I3 || J4 + t3_offset > I4) VMMLIB_ERROR("index out of bounds.", VMMLIB_HERE); #endif for (size_t t3 = 0; t3 < J4; ++t3) { for (size_t slice = 0; slice < J3; ++slice) { for (size_t row = 0; row < J1; ++row) { for (size_t col = 0; col < J2; ++col) { result.at(row, col, slice, t3) = at(row_offset + row, col_offset + col, slice_offset + slice, t3_offset + t3); } } } } return 0; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: tensor4_allocate_data( T*& array_ ) { array_ = new T[ I1 * I2 * I3 * I4]; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME:: tensor4_deallocate_data( T*& array_ ) { if (array_) { delete[] array_; } } VMML_TEMPLATE_STRING T* VMML_TEMPLATE_CLASSNAME::get_array_ptr() { return _array; } VMML_TEMPLATE_STRING const T* VMML_TEMPLATE_CLASSNAME::get_array_ptr() const { return _array; } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor4( const tensor4& source_ ) { tensor4_allocate_data( _array ); (*this) = source_; } VMML_TEMPLATE_STRING template< typename U > VMML_TEMPLATE_CLASSNAME::tensor4( const tensor4< I1, I2, I3, I4, U >& source_ ) { const U* s_array = source_.get_array_ptr(); tensor4_allocate_data( _array ); for (size_t index = 0; index < SIZE; ++index) { _array[ index ] = static_cast< T >( s_array[ index ] ); } } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3, size_t J4 > VMML_TEMPLATE_CLASSNAME::tensor4( const tensor4< J1, J2, J3, J4, T >& source_ ) { tensor4_allocate_data( _array ); size_t min1 = J1 < I1 ? J1 : I1; size_t min2 = J2 < I2 ? J2 : I2; size_t min3 = J3 < I3 ? J3 : I3; size_t min4 = J4 < I4 ? J4 : I4; zero(); for(size_t i4 = 0; i4 < min4; ++i4 ) { for(size_t i3 = 0; i3 < min3; ++i3) { for(size_t i2 = 0; i2 < min2; ++i2) { for(size_t i1 = 0; i1 < min1; ++i1) { at(i1, i2, i3, i4) = source_(i1, i2, i3, i4); } } } } } VMML_TEMPLATE_STRING template< typename input_iterator_t > void VMML_TEMPLATE_CLASSNAME::set(input_iterator_t begin_, input_iterator_t end_, bool row_major_layout) { input_iterator_t it(begin_); if (row_major_layout) { for (size_t i4 = 0; i4 < I4; ++i4) { for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2, ++it) { if (it == end_) return; at(i1, i2, i3, i4) = static_cast (*it); } } } } } else { VMMLIB_ERROR( "Tensor4: set() not implemented for non-row major", VMMLIB_HERE ); // TODO // std::copy(it, it + (I1 * I2 * I3), begin()); } } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::equals(const tensor4< I1, I2, I3, I4, T >& other, T tolerance) const { bool is_ok = true; if (T3S != other.T3S) { return false; } for (size_t i4 = 0; is_ok && i4 < I4; ++i4) { is_ok = _get_tensor3(i4).equals(other._get_tensor3(i4), tolerance); } return is_ok; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::size() const { return SIZE; } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::operator==( const tensor4< I1, I2, I3, I4, T >& other ) const { const T* other_array = other.get_array_ptr(); for(size_t index = 0; index < SIZE; ++index) { if(_array[ index ] != other_array[ index] ) { return false; } } return true; } VMML_TEMPLATE_STRING bool VMML_TEMPLATE_CLASSNAME::operator!=( const tensor4< I1, I2, I3, I4, T >& other ) const { return ! operator==( other ); } VMML_TEMPLATE_STRING typename VMML_TEMPLATE_CLASSNAME::tensor3_t& VMML_TEMPLATE_CLASSNAME:: _get_tensor3( size_t index_ ) { tensor3* tens3 = new tensor3( (void *)(_array + I1 * I2 * I3 * index_)); return *tens3; } VMML_TEMPLATE_STRING const typename VMML_TEMPLATE_CLASSNAME::tensor3_t& VMML_TEMPLATE_CLASSNAME:: _get_tensor3( size_t index_ ) const { const tensor3* tens3 = new tensor3( (void *)(_array + I1 * I2 * I3 * index_)); return *tens3; } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: get_tensor3( const size_t i4_, tensor3_t& t3_data_ ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( i4_ >= I4 ) VMMLIB_ERROR( "get_tensor3() - index out of bounds.", VMMLIB_HERE ); #endif t3_data_ = _get_tensor3( i4_ ); } VMML_TEMPLATE_STRING inline typename VMML_TEMPLATE_CLASSNAME::tensor3_t& VMML_TEMPLATE_CLASSNAME:: get_tensor3( size_t i4_ ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( i4_ >= I4 ) VMMLIB_ERROR( "get_tensor3() - index out of bounds.", VMMLIB_HERE ); #endif return _get_tensor3( i4_ ); } VMML_TEMPLATE_STRING inline const typename VMML_TEMPLATE_CLASSNAME::tensor3_t& VMML_TEMPLATE_CLASSNAME:: get_tensor3( size_t i4_ ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( i4_ >= I4 ) VMMLIB_ERROR( "get_tensor3() - index out of bounds.", VMMLIB_HERE ); #endif return _get_tensor3( i4_ ); } VMML_TEMPLATE_STRING inline void VMML_TEMPLATE_CLASSNAME:: set_tensor3( size_t i4_, const tensor3_t& t3_data_ ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( i4_ >= I4 ) VMMLIB_ERROR( "set_tensor3() - index out of bounds.", VMMLIB_HERE ); #endif memcpy(_array + I1*I2*I3*i4_, t3_data_.get_array_ptr(), I1*I2*I3*sizeof(T)); } //fill VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::fill( T fillValue ) { for( size_t i4 = 0; i4 < I4; ++i4 ) { for( size_t i3 = 0; i3 < I3; ++i3 ) { for( size_t i1 = 0; i1 < I1; ++i1 ) { for( size_t i2 = 0; i2 < I2; ++i2 ) { at(i1, i2, i3, i4) = fillValue; } } } } //FIXME: //_get_tensor3( i4 ).fill( fillValue ); } VMML_TEMPLATE_STRING inline T& VMML_TEMPLATE_CLASSNAME::at( size_t i1, size_t i2, size_t i3, size_t i4 ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( i1 >= I1 || i2 >= I2 || i3 >= I3 || i4 >= I4 ) VMMLIB_ERROR( "at( i1, i2, i3, i4 ) - index out of bounds", VMMLIB_HERE ); #endif return _array[ i4 * T3_SIZE + i3 * MATRIX_SIZE + i2 * ROWS + i1 ]; } VMML_TEMPLATE_STRING const inline T& VMML_TEMPLATE_CLASSNAME::at( size_t i1, size_t i2, size_t i3, size_t i4 ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( i1 >= I1 || i2 >= I2 || i3 >= I3 || i4 >= I4 ) VMMLIB_ERROR( "at( i1, i2, i3, i4 ) - index out of bounds", VMMLIB_HERE ); #endif return _array[ i4 * T3_SIZE + i3 * MATRIX_SIZE + i2 * ROWS + i1 ]; } VMML_TEMPLATE_STRING inline T& VMML_TEMPLATE_CLASSNAME::operator()( size_t i1, size_t i2, size_t i3, size_t i4 ) { return at( i1, i2, i3, i4 ); } VMML_TEMPLATE_STRING const inline T& VMML_TEMPLATE_CLASSNAME::operator()( size_t i1, size_t i2, size_t i3, size_t i4 ) const { return at( i1, i2, i3, i4 ); } /*VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::fill( T fill_value ) { for(size_t index = 0; index < SIZE; ++index) { _array[ index ] = fill_value; } }*/ VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator=( T fill_value ) { fill( fill_value ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::zero() { fill( static_cast< T >( 0.0 ) ); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::fill_increasing_values() { double fillValue = 0.0f; for (size_t i4 = 0; i4 < I4; ++i4) { for (size_t i3 = 0; i3 < I3; ++i3) { for (size_t i1 = 0; i1 < I1; ++i1) { for (size_t i2 = 0; i2 < I2; ++i2) { at(i1, i2, i3, i4) = static_cast (fillValue); fillValue++; } } } } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::fill_random(int seed) { if ( seed >= 0 ) srand( seed ); double fillValue = 0.0f; for( size_t index = 0; index < SIZE; ++index ) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= (std::numeric_limits< T >::max)(); _array[ index ] = static_cast< T >( fillValue ) ; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::fill_random_signed(int seed) { if ( seed >= 0 ) srand( seed ); double fillValue = 0.0f; for( size_t index = 0; index < SIZE; ++index ) { fillValue = rand(); fillValue /= RAND_MAX; fillValue *= (std::numeric_limits< T >::max)(); T fillValue2 = static_cast< T >(fillValue) % (std::numeric_limits< T >::max)(); fillValue2 -= (std::numeric_limits< T >::max)()/2; _array[ index ] = fillValue2 ; // test if ever > max/2 or < -max/2 } } VMML_TEMPLATE_STRING const VMML_TEMPLATE_CLASSNAME& VMML_TEMPLATE_CLASSNAME::operator=( const VMML_TEMPLATE_CLASSNAME& source_ ) { if(this != &source_) // avoid self assignment { memcpy( _array, source_._array, I1 * I2 * I3 * I4 * sizeof( T ) ); } return *this; } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::cast_from( const tensor4< I1, I2, I3, I4, TT >& other ) { #pragma omp parallel for for(long tensor_idx = 0; tensor_idx < (long)I4; ++tensor_idx) { #pragma omp parallel for for( long slice_idx = 0; slice_idx < (long)I3; ++slice_idx ) { #pragma omp parallel for for( long row_index = 0; row_index < (long)I1; ++row_index ) { #pragma omp parallel for for( long col_index = 0; col_index < (long)I2; ++col_index ) { at( row_index, col_index, slice_idx, tensor_idx ) = static_cast< T >(other.at( row_index, col_index, slice_idx, tensor_idx )); } } } } } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3, size_t J4, typename TT > void VMML_TEMPLATE_CLASSNAME::cast_from( const tensor4< J1, J2, J3, J4, TT >& other, const long& slice_idx_start_ ) { this->zero(); int j4 = I4 < J4? I4 : J4; int j3 = I3 < J3? I3 : J3; int j2 = I2 < J2? I2 : J2; int j1 = I1 < J1? I1 : J1; #pragma omp parallel for for(long tensor_idx = 0; tensor_idx < (long)j4; ++tensor_idx) { #pragma omp parallel for for( long slice_idx = 0; slice_idx < (long)j3; ++slice_idx ) { #pragma omp parallel for for( long row_index = 0; row_index < (long)j1; ++row_index ) { #pragma omp parallel for for( long col_index = 0; col_index < (long)j2; ++col_index ) { at( row_index, col_index, slice_idx, tensor_idx ) = static_cast< T >(other.at( row_index, col_index, slice_idx, tensor_idx )); } } } } } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::float_t_to_uint_t( const tensor4< I1, I2, I3, I4, TT >& other ) { if( sizeof(T) == 1 || sizeof(T) == 2) { const TT* otherdata = other.get_array_ptr(); for( size_t index = 0;index < SIZE; ++index ) { _array[index] = T( (std::min)( (std::max)(int(0), int( otherdata[index] + 0.5)), int((std::numeric_limits< T >::max)()) )); } } else { this->cast_from( other ); return; } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator+( T scalar ) const { vmml::tensor4 result(*this); result += scalar; return result; } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator-( T scalar ) const { vmml::tensor4 result(*this); result -= scalar; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator+=( T scalar ) { for(size_t index = 0; index < SIZE; ++index) { _array[index] += scalar; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator-=( T scalar ) { for(size_t index = 0; index < SIZE; ++index) { _array[index] -= scalar; } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator+( const tensor4& other ) const { vmml::tensor4 result(*this); result += other; return result; } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator-( const tensor4& other ) const { vmml::tensor4 result(*this); result -= other; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator+=( const tensor4& other ) { const T* dataptr = other.get_array_ptr(); for(size_t index = 0; index < SIZE; ++index) { _array[index] += dataptr[index]; } } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator-=( const tensor4& other ) { const T* dataptr = other.get_array_ptr(); for(size_t index = 0; index < SIZE; ++index) { _array[index] -= dataptr[index]; } } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3, size_t J4 > typename enable_if< J1 < I1 && J2 < I2 && J3 < I3 && J4 < I4 >::type* VMML_TEMPLATE_CLASSNAME::operator+=( const tensor4< J1, J2, J3, J4, T>& other ) { for(size_t i4 = 0; i4 < J4; ++i4) { for( size_t i3 = 0; i3 < J3; ++i3 ) { for( size_t i1 = 0; i1 < J1; ++i1 ) { for( size_t i2 = 0; i2 < J2; ++i2 ) { at( i1, i2, i3, i4 ) += other.at(i1, i2, i3, i4); } } } } return 0; } // // tensor4-scalar operations / scaling // VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator*( T scalar ) { vmml::tensor4 result(*this); result *= scalar; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator*=( T scalar ) { for(size_t index = 0; index < SIZE; ++index) { _array[index] *= scalar; } } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator/( T scalar ) { vmml::tensor4 result(*this); result /= scalar; return result; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::operator/=( T scalar ) { for(size_t index = 0; index < SIZE; ++index) { _array[index] /= scalar; } } VMML_TEMPLATE_STRING inline VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::operator-() const { return negate(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME VMML_TEMPLATE_CLASSNAME::negate() const { vmml::tensor4 result(*this); T* dataptr = result.get_array_ptr(); for(size_t index = 0; index < SIZE; ++index) { dataptr[index] = _array[index] * -1; } return result; } VMML_TEMPLATE_STRING typename VMML_TEMPLATE_CLASSNAME::tensor3_t& VMML_TEMPLATE_CLASSNAME::average_I4(tensor3_t& t3) const { for(size_t i3 = 0; i3 < I3; ++i3) { for( size_t i1 = 0; i1 < I1; ++i1 ) { for( size_t i2 = 0; i2 < I2; ++i2 ) { T sum = 0; for( size_t i4 = 0; i4 < I4; ++i4 ) { sum += at(i1,i2,i3,i4); } t3.at(i1,i2,i3) = sum/I4; } } } return t3; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::get_array_size_in_bytes() { return (sizeof(T) * SIZE); } // WARNING: dangerous. Use before destruction if you want to prevent // a delete call for the assigned T* _array in the destructor. VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::clear_array_pointer() { _array = 0; } // VMML_TEMPLATE_STRING // void // VMML_TEMPLATE_CLASSNAME::mode1_unfolding_fwd(mode1_unfolding_type& unfolding) const { // typedef matrix< I1, I2, T > slice_type; // slice_type* slice = new slice_type(); // for (size_t l = 0; l < I4; ++l) { // tensor3_t t3; // get_tensor3(l,t3); // for (size_t k = 0; k < I3; ++k) { // t3.get_frontal_slice_fwd(k, *slice); // for (size_t j = 0; j < I2; ++j) { // unfolding.set_column(l*I2*I3 + k*I2 + j, slice->get_column(j)); // } // } // } // delete slice; // } // // VMML_TEMPLATE_STRING // void // VMML_TEMPLATE_CLASSNAME::mode2_unfolding_fwd(mode2_unfolding_type& unfolding) const { // typedef matrix< I2, I3, T > slice_type; // slice_type* slice = new slice_type(); // for (size_t i = 0; i < I1; ++i) { // for (size_t l = 0; l < I4; ++l) { // tensor3_t t3; // get_tensor3(l,t3); // t3.get_horizontal_slice_fwd(i, *slice); // for (size_t k = 0; k < I3; ++k) { // unfolding.set_column(i*I3*I4 + l*I3 + k, slice->get_column(k)); // } // } // } // delete slice; // } // // VMML_TEMPLATE_STRING // void // VMML_TEMPLATE_CLASSNAME::mode3_unfolding_fwd(mode3_unfolding_type& unfolding) const { // typedef matrix< I2, I3, T > slice_type; // slice_type* slice = new slice_type(); // for (size_t j = 1; j < I2; ++j) { // for (size_t i = 0; i < I1; ++i) { // for (size_t l = 0; l < I4; ++l) { // tensor3_t t3; // get_tensor3(l,t3); // t3.get_horizontal_slice_fwd(i, *slice); // unfolding.set_column(j*I4*I1 + i*I4 + l, slice->get_column(j)); // } // } // } // delete slice; // } // // VMML_TEMPLATE_STRING // void // VMML_TEMPLATE_CLASSNAME::mode4_unfolding_fwd(mode4_unfolding_type& unfolding) const { // for (size_t k = 1; k < I3; ++k) { // for (size_t j = 0; j < I2; ++j) { // for (size_t i = 0; i < I1; ++i) { // for (size_t l = 0; l < I4; ++l) { // unfolding.at(l,k*I1*I2 + j*I1 + i) = at(i,j,k,l); // } // } // } // } // } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mode1_unfolding_fwd(mode1_unfolding_type& unfolding) const { typedef matrix< I1, I2, T > slice_type; slice_type* slice = new slice_type(); for (size_t l = 0; l < I4; ++l) { tensor3_t t3; get_tensor3(l,t3); for (size_t k = 0; k < I3; ++k) { t3.get_frontal_slice_fwd(k, *slice); for (size_t j = 0; j < I2; ++j) { unfolding.set_column(l*I2*I3 + k*I2 + j, slice->get_column(j)); } } } delete slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mode2_unfolding_fwd(mode2_unfolding_type& unfolding) const { typedef matrix< I2, I3, T > slice_type; slice_type* slice = new slice_type(); for (size_t i = 0; i < I1; ++i) { for (size_t l = 0; l < I4; ++l) { tensor3_t t3; get_tensor3(l,t3); t3.get_horizontal_slice_fwd(i, *slice); for (size_t k = 0; k < I3; ++k) { unfolding.set_column(i*I3*I4 + l*I3 + k, slice->get_column(k)); } } } delete slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mode3_unfolding_fwd(mode3_unfolding_type& unfolding) const { typedef matrix< I2, I3, T > slice_type; slice_type* slice = new slice_type(); for (size_t j = 0; j < I2; ++j) { for (size_t i = 0; i < I1; ++i) { for (size_t l = 0; l < I4; ++l) { tensor3_t t3; get_tensor3(l,t3); t3.get_horizontal_slice_fwd(i, *slice); unfolding.set_column(j*I4*I1 + i*I4 + l, slice->get_row(j)); } } } delete slice; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mode4_unfolding_fwd(mode4_unfolding_type& unfolding) const { for (size_t k = 0; k < I3; ++k) { for (size_t j = 0; j < I2; ++j) { for (size_t i = 0; i < I1; ++i) { for (size_t l = 0; l < I4; ++l) { unfolding.at(l,k*I1*I2 + j*I1 + i) = at(i,j,k,l); } } } } } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::frobenius_norm() const { double f_norm = 0.0; for (long i3 = 0; i3 < long(I3); ++i3) { for (long i4 = 0; i4 < long(I4); ++i4) { for (long i1 = 0; i1 < long(I1); ++i1) { long i2 = 0; for (i2 = 0; i2 < long(I2); ++i2) { f_norm += at(i1, i2, i3, i4) * at(i1, i2, i3, i4); } } } } return sqrt(f_norm); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::frobenius_norm(const tensor4< I1, I2, I3, I4, T>& other_) const { double f_norm = 0.0; T abs_diff = 0; T *it = _array, *it_end = _array + I1*I2*I3*I4; T *it_other = other_._array; for (; it != it_end; ++it, ++it_other) { abs_diff = fabs(*it - *it_other); f_norm += abs_diff * abs_diff; } return sqrt(f_norm); } VMML_TEMPLATE_STRING template< typename TT > void VMML_TEMPLATE_CLASSNAME::quantize_log(tensor4< I1, I2, I3, I4, TT >& quantized_, tensor4< I1, I2, I3, I4, char >& signs_, T& min_value_, T& max_value_, const TT& tt_range_) const { double max_tt_range = double(tt_range_); double min_tt_range = 0; min_value_ = 0; max_value_ = get_abs_max(); double t_range = max_value_ - min_value_; T* it = _array; TT* it_quant = quantized_.get_array_ptr(); char* it_sign = signs_.get_array_ptr(); for (; it != _array+I1*I2*I3*I4; ++it, ++it_quant, ++it_sign) { T value = fabs(*it); *it_sign = ((*it) < 0.f) ? 0 : 1; T quant_value = 0; if (std::numeric_limits::is_signed) { quant_value = log2(1 + value) / log2(1 + t_range) * tt_range_; *it_quant = TT((std::min)((std::max)(min_tt_range, double(quant_value + 0.5)), max_tt_range)); } else { quant_value = log2(1 + (value - min_value_)) / log2(1 + t_range) * tt_range_; *it_quant = TT((std::min)((std::max)(min_tt_range, double(quant_value + 0.5)), max_tt_range)); } } } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::mean() const { double val = 0; T* it = _array, *it_end = _array + I1*I2*I3*I4; for (; it != it_end; ++it) { val += double(abs(*it)); } return ( val / size()); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::mean(T& mean_) const { mean_ = static_cast (mean()); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::variance() const { double val = 0.0; double sum_val = 0.0; double mean_val = mean(); T* it = _array, *it_end = _array+I1*I2*I3*I4; for (; it != it_end; ++it) { val = double(*it) - mean_val; val *= val; sum_val += val; } return double(sum_val / (size() - 1)); } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::stdev() const { return sqrt(variance()); } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_min() const { T tensor4_min = static_cast ((std::numeric_limits::max)()); T *it = _array, *it_end = _array + I1*I2*I3*I4; for (; it != it_end; ++it) { if (*it < tensor4_min) { tensor4_min = *it; } } return tensor4_min; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_max() const { T tensor4_max = static_cast (0); T *it = _array, *it_end = _array + I1*I2*I3*I4; for (; it != it_end; ++it) { if (*it > tensor4_max) { tensor4_max = *it; } } return tensor4_max; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_abs_min() const { T tensor4_min = static_cast ((std::numeric_limits::max)()); T *it = _array, *it_end = _array + I1*I2*I3*I4; for (; it != it_end; ++it) { if (fabs(*it) < fabs(tensor4_min)) { tensor4_min = fabs(*it); } } return tensor4_min; } VMML_TEMPLATE_STRING T VMML_TEMPLATE_CLASSNAME::get_abs_max() const { T tensor4_max = static_cast (0); T *it = _array, *it_end = _array + I1*I2*I3*I4; for (; it != it_end; ++it) { if (fabs(*it) > fabs(tensor4_max)) { tensor4_max = fabs(*it); } } return tensor4_max; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tensor_mmapper.hpp000066400000000000000000000160651231531733200260520ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Jonas Boesch * @author David Klaper * @author Claudio Mura * * class to read/write and convert tensor4 files (from raw, to csv...) * */ #ifndef __VMML__TENSOR_MMAPPER__HPP__ #define __VMML__TENSOR_MMAPPER__HPP__ #include "tensor4.hpp" #include #ifndef _MSC_VER # include #else # include #endif namespace vmml { template< typename T, typename C > // a tensor 3 or 4 type as T and // a corresponding converter as C with the method write_to_raw(tensor& t, string dir, string filename) class tensor_mmapper { public: //tensor_mapper( const std::string& dir_, const std::string& filename, size_t tensor_count = 1 ); //allocate memory mapped file tensor_mmapper( const std::string& dir_, const std::string& filename_, const bool prot_read_, const C& tx_converter ); ~tensor_mmapper(); void get_tensor( T& tensor_ ) { tensor_ = *_tensor; } protected: static std::string concat_path( const std::string& dir_, const std::string& filename_ ); void* t3_allocate_rd_mmap( const std::string& dir_, const std::string& filename_ ); void* t3_allocate_wr_mmap( const std::string& dir_, const std::string& filename_, const C& tx_converter ); #ifdef _WIN32 HANDLE _fd, _fd_mmapped; #else int _fd; // one mmap for all tensors #endif size_t _file_size; // sizeof tensors * tensor_count size_t _tensor_size; void* _data; // ptr to mmapped memory T* _tensor; //std::vector _tensors; }; //end tensor_mmapper #define VMML_TEMPLATE_STRING template< typename T, typename C > #define VMML_TEMPLATE_CLASSNAME tensor_mmapper< T, C > /*VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor_mmapper( const std::string& dir_, const std::string& filename, size_t tensor_count = 1 ) // : init all values { _file_size = ... // open or create file and mmap it _data = ... _tensor_size = ... void* d = _data; for( size_t i = 0; i < tensor_count; ++i ) { _tensors.push_back( new T(d)); d += _tensor_size; } }*/ VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~tensor_mmapper() { if (_tensor) { _tensor->clear_array_pointer(); delete _tensor; } munmap( _data, _file_size ); //get error ::close( _fd ); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tensor_mmapper( const std::string& dir_, const std::string& filename_, const bool prot_read_, const C& tx_converter_ ) : _file_size(0), _data(0), _tensor(0) { _file_size = T::get_array_size_in_bytes(); if ( prot_read_ ) { t3_allocate_rd_mmap( dir_, filename_ ); } else { t3_allocate_wr_mmap( dir_, filename_, tx_converter_ ); } if (_data != 0) { _tensor = new T( _data ); } } VMML_TEMPLATE_STRING void* VMML_TEMPLATE_CLASSNAME:: t3_allocate_rd_mmap( const std::string& dir_, const std::string& filename_ ) { //void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); std::string path = concat_path( dir_, filename_ ); #ifdef _WIN32 _fd = CreateFile( path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( _fd == INVALID_HANDLE_VALUE ) { CloseHandle( _fd ); // FIXME shouldn't we return here? } off_t offset = 0; _fd_mmapped = ( void* )CreateFileMapping( _fd, 0, PAGE_READONLY, 0, 0, NULL ); // FIXME check. The fifth should be either 0 or _file_size if (_fd_mmapped == NULL ) { std::cout << "CreateFileMapping failed" << std::endl; return 0; } _data = MapViewOfFile( _fd_mmapped, FILE_MAP_READ, 0, 0, 0 ); if( _data == NULL ) { std::cout << "MapViewOfFile failed" << std::endl; return 0; } return _data; #else _fd = open( path.c_str(), O_RDONLY, 0 ); if ( _fd == -1 ) { { close(_fd); std::cout << "no file open for memory mapping" << std::endl; // FIXME shouldn't we return here? } } off_t offset = 0; _data = (void*)mmap( 0, _file_size, PROT_READ, MAP_FILE | MAP_SHARED, _fd, offset ); if( _data == MAP_FAILED) { std::cout << "mmap failed" << std::endl; return 0; } return _data; #endif } VMML_TEMPLATE_STRING void* VMML_TEMPLATE_CLASSNAME:: t3_allocate_wr_mmap( const std::string& dir_, const std::string& filename_, const C& tx_converter_ ) { //void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); std::string path = concat_path( dir_, filename_ ); #ifdef _WIN32 _fd = CreateFile( path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( _fd == INVALID_HANDLE_VALUE ) { // Call GetLastError for more information if ( ! _tensor ) { _tensor = new T(); } _tensor->zero(); tx_converter_.write_to_raw( *_tensor, dir_, filename_ ); _fd = CreateFile( path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( _fd == INVALID_HANDLE_VALUE ) { CloseHandle( _fd ); std::cout << "no file open for memory mapping" << std::endl; // FIXME shouldn't we return here? } } off_t offset = 0; _fd_mmapped = ( void* )CreateFileMapping( _fd, 0, PAGE_READWRITE, 0, 0, NULL ); // FIXME check. The fifth should be either 0 or _file_size if (_fd_mmapped == NULL ) { std::cout << "CreateFileMapping failed" << std::endl; return 0; } _data = MapViewOfFile( _fd_mmapped, FILE_MAP_WRITE, 0, 0, 0 ); if( _data == NULL ) { std::cout << "MapViewOfFile failed" << std::endl; return 0; } return _data; #else _fd = open( path.c_str(), O_RDWR, 0 ); if ( _fd == -1 ) { if ( ! _tensor ) { _tensor = new T(); } _tensor->zero(); tx_converter_.write_to_raw( *_tensor, dir_, filename_ ); _fd = open( path.c_str(), O_RDWR, 0 ); if ( _fd == -1 ) { close(_fd); std::cout << "no file open for memory mapping" << std::endl; // FIXME shouldn't we return here? } } off_t offset = 0; _data = (void*)mmap( 0, _file_size, PROT_WRITE, MAP_FILE | MAP_SHARED, _fd, offset ); if( _data == MAP_FAILED) { std::cout << "mmap failed" << std::endl; return 0; } return _data; #endif } VMML_TEMPLATE_STRING std::string VMML_TEMPLATE_CLASSNAME::concat_path( const std::string& dir_, const std::string& filename_ ) { std::string path = ""; int dir_length = dir_.size() -1; #ifdef _WIN32 int last_separator = dir_.find_last_of( "\\"); #else int last_separator = dir_.find_last_of( "/"); #endif path = dir_; if (last_separator < dir_length ) { #ifdef _WIN32 path.append( "\\" ); #else path.append( "/" ); #endif } path.append( filename_ ); // check for format if( filename_.find( "raw", filename_.size()-3 ) == std::string::npos ) { path.append( "."); path.append( "raw" ); } return path; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } //end vmml namespace #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tensor_stats.hpp000066400000000000000000000062771231531733200255530ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafael Ballester * * Class for encapsulating several tensor experimental properties, so that they can be easily returned, manipulated and printed (approximation error, decomposition and reconstruction times, etc.). * */ #include #ifndef __VMML__TENSOR_STATS__HPP__ #define __VMML__TENSOR_STATS__HPP__ namespace vmml { class tensor_stats { public: tensor_stats() { ranks = n_iterations = error = nnz = dec_time = rec_time = 0; } tensor_stats(const tensor_stats& other) { description = other.description; ranks = other.ranks; n_iterations = other.n_iterations; error = other.error; nnz = other.nnz; dec_time = other.dec_time; rec_time = other.rec_time; } inline tensor_stats operator+(const tensor_stats& other) const { tensor_stats result(*this); result += other; return result; } void operator+=(const tensor_stats& other) { ranks += other.ranks; n_iterations += other.n_iterations; error += other.error; nnz += other.nnz; dec_time += other.dec_time; rec_time += other.rec_time; } friend std::ostream& operator <<(std::ostream& os, const tensor_stats& stats) { os << stats.description << " " << stats.ranks << " " << stats.n_iterations << " " << stats.error << " " << stats.nnz << " " << stats.dec_time << " " << stats.rec_time; return os; } std::string get_description() { return description; } std::string get_short_description() { return short_description; } int get_ranks() { return ranks; } int get_n_iterations() { return n_iterations; } double get_error() { return error; } int get_nnz() { return nnz; } double get_dec_time() { return dec_time; } double get_rec_time() { return rec_time; } void set_description( const std::string& desc ) { description = desc; } void set_short_description( const std::string& short_desc ) { short_description = short_desc; } void set_ranks( const int r ) { ranks = r; } void set_n_iterations( const int n_it ) { n_iterations = n_it; } void set_error( const double err ) { error = err; } void set_nnz( const int nnz_ ) { nnz = nnz_; } void set_dec_time( const double dec ) { dec_time = dec; } void set_rec_time( const double rec ) { rec_time = rec; } static std::string get_content() { return "description ranks n_iterations error nnz dec_time rec_time"; } private: std::string description; std::string short_description; // The description, without rank sizes int ranks; int n_iterations; double error; int nnz; double dec_time; double rec_time; }; } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tucker3_exporter.hpp000066400000000000000000000251431231531733200263240ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * Export tool for Tucker3 tensor and quantized Tucker3 tensor * */ #ifndef __VMML__TUCK3_EXPORTER__HPP__ #define __VMML__TUCK3_EXPORTER__HPP__ #include /* FIXME: * * - T_internal * - const input argument for tucker3 data */ namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value = float, typename T_coeff = float > class tucker3_exporter { public: typedef float T_internal; //FIXME! should match with tucker3 tensor typedef tucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > tucker3_type; typedef qtucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > qtucker3_type; typedef tensor3< R1, R2, R3, T_coeff > t3_core_type; typedef typename t3_core_type::iterator t3_core_iterator; typedef typename t3_core_type::const_iterator t3_core_const_iterator; typedef matrix< I1, R1, T_coeff > u1_type; typedef typename u1_type::iterator u1_iterator; typedef typename u1_type::const_iterator u1_const_iterator; typedef matrix< I2, R2, T_coeff > u2_type; typedef typename u2_type::iterator u2_iterator; typedef typename u2_type::const_iterator u2_const_iterator; typedef matrix< I3, R3, T_coeff > u3_type; typedef typename u3_type::iterator u3_iterator; typedef typename u3_type::const_iterator u3_const_iterator; typedef tensor3< R1, R2, R3, char > t3_core_signs_type; template< typename T > static void export_to( std::vector< T >& data_, tucker3_type& tuck3_data_ ); //previous version, but works only with 16bit quantization static void export_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ); //use this version, works with a better quantization for the core tensor: //logarithmic quantization and separate high energy core vale //suitable for voxelwise reconstruction static void export_hot_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ); //use this version for the ttm export/import (core: backward cyclic), without plain hot value static void export_ttm_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ); }; //end tucker3 exporter class #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME tucker3_exporter< R1, R2, R3, I1, I2, I3, T_value, T_coeff > VMML_TEMPLATE_STRING template< typename T > void VMML_TEMPLATE_CLASSNAME::export_to( std::vector< T >& data_, tucker3_type& tuck3_data_ ) { data_.clear(); u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); tuck3_data_.cast_members(); u1_const_iterator it = u1->begin(), it_end = u1->end(); for( ; it != it_end; ++it ) { data_.push_back( static_cast< T >( *it) ); } u2_const_iterator u2_it = u2->begin(), u2_it_end = u2->end(); for( ; u2_it != u2_it_end; ++u2_it ) { data_.push_back(static_cast< T >(*u2_it) ); } u3_const_iterator u3_it = u3->begin(), u3_it_end = u3->end(); for( ; u3_it != u3_it_end; ++u3_it ) { data_.push_back(static_cast< T >( *u3_it) ); } t3_core_iterator it_core = core.begin(), it_core_end = core.end(); for( ; it_core != it_core_end; ++it_core ) { data_.push_back(static_cast< T >( *it_core) ); } delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::export_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ) { //quantize tucker3 components (u1-u3 and core) size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = tuck3_data_.SIZE * sizeof(T_coeff) + 8 * len_t_comp; char * data = new char[ len_export_data ]; size_t end_data = 0; //quantize basis matrices and copy min-max values T_internal u_min, u_max; tuck3_data_.quantize_basis_matrices( u_min, u_max); memcpy( data, &u_min, len_t_comp ); end_data = len_t_comp; memcpy( data + end_data, &u_max, len_t_comp ); end_data += len_t_comp; u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); //quantize core and copy min-max values T_internal core_min, core_max; tuck3_data_.quantize_core( core_min, core_max ); memcpy( data + end_data, &core_min, len_t_comp ); end_data += len_t_comp; memcpy( data + end_data, &core_max, len_t_comp ); end_data += len_t_comp; //copy data for u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( data + end_data, *u1, len_u1 ); end_data += len_u1; //copy data for u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( data + end_data, *u2, len_u2 ); end_data += len_u2; //copy data for u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( data + end_data, *u3, len_u3 ); end_data += len_u3; //copy data for core size_t len_core_slice = R1 * R2 * sizeof( T_coeff ); for (size_t r3 = 0; r3 < R3; ++r3 ) { memcpy( data + end_data, core.get_frontal_slice_fwd( r3 ), len_core_slice ); end_data += len_core_slice; } data_out_.clear(); for( size_t byte = 0; byte < len_export_data; ++byte ) { data_out_.push_back( data[byte] ); } delete[] data; delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::export_hot_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ) { tuck3_data_.enable_quantify_hot(); //quantize tucker3 components (u1-u3 and core) size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = R1*R2*R3 + (R1*I1 + R2*I2 + R3*I3) * sizeof(T_coeff) + 4 * len_t_comp; char * data = new char[ len_export_data ]; size_t end_data = 0; //quantize basis matrices and copy min-max values T_internal u_min, u_max; tuck3_data_.quantize_basis_matrices( u_min, u_max); memcpy( data, &u_min, len_t_comp ); end_data = len_t_comp; memcpy( data + end_data, &u_max, len_t_comp ); end_data += len_t_comp; //quantize core and copy min-max values T_internal core_min, core_max; tuck3_data_.quantize_core( core_min, core_max ); //memcpy( data + end_data, &core_min, len_t_comp ); end_data += len_t_comp; min_value is always zero in log quant memcpy( data + end_data, &core_max, len_t_comp ); end_data += len_t_comp; u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; t3_core_signs_type signs; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); tuck3_data_.get_core_signs( signs ); T_internal hottest_value = tuck3_data_.get_hottest_value(); //copy first value of core tensor separately as a float memcpy( data + end_data, &hottest_value, len_t_comp ); end_data += len_t_comp; //copy data for u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( data + end_data, *u1, len_u1 ); end_data += len_u1; //copy data for u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( data + end_data, *u2, len_u2 ); end_data += len_u2; //copy data for u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( data + end_data, *u3, len_u3 ); end_data += len_u3; //copy data for core size_t len_core_el = 1; //currently 1 bit for sign and 7 bit for values //colume-first iteration unsigned char core_el; for (size_t r3 = 0; r3 < R3; ++r3 ) { for (size_t r2 = 0; r2 < R2; ++r2 ) { for (size_t r1 = 0; r1 < R1; ++r1 ) { core_el = (core.at( r1, r2, r3 ) | (signs.at( r1, r2, r3) * 0x80 )); /*std::cout << "value: " << int(_core.at( r1, r2, r3 )) << " bit " << int( core_el ) << " sign: " << int(_signs.at( r1, r2, r3)) << std::endl;*/ memcpy( data + end_data, &core_el, len_core_el ); ++end_data; } } } data_out_.clear(); for( size_t byte = 0; byte < len_export_data; ++byte ) { data_out_.push_back( data[byte] ); } delete[] data; delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::export_ttm_quantized_to( std::vector& data_out_, qtucker3_type& tuck3_data_ ) { tuck3_data_.enable_quantify_log(); //quantize tucker3 components (u1-u3 and core) size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = R1*R2*R3 + (R1*I1 + R2*I2 + R3*I3) * sizeof(T_coeff) + 3 *len_t_comp; char * data = new char[ len_export_data ]; size_t end_data = 0; //quantize basis matrices and copy min-max values T_internal u_min, u_max; tuck3_data_.quantize_basis_matrices( u_min, u_max); memcpy( data, &u_min, len_t_comp ); end_data = len_t_comp; memcpy( data + end_data, &u_max, len_t_comp ); end_data += len_t_comp; //quantize core and copy min-max values T_internal core_min, core_max; tuck3_data_.quantize_core( core_min, core_max ); //memcpy( data + end_data, &core_min, len_t_comp ); end_data += len_t_comp; min_value is always zero in log quant memcpy( data + end_data, &core_max, len_t_comp ); end_data += len_t_comp; u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; t3_core_signs_type signs; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); tuck3_data_.get_core_signs( signs ); //copy data for u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( data + end_data, *u1, len_u1 ); end_data += len_u1; //copy data for u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( data + end_data, *u2, len_u2 ); end_data += len_u2; //copy data for u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( data + end_data, *u3, len_u3 ); end_data += len_u3; //copy data for core size_t len_core_el = 1; //currently 1 bit for sign and 7 bit for values //colume-first iteration //backward cylcling after lathauwer et al. unsigned char core_el; for (size_t r2 = 0; r2 < R2; ++r2 ) { for (size_t r3 = 0; r3 < R3; ++r3 ) { for (size_t r1 = 0; r1 < R1; ++r1 ) { core_el = (core.at( r1, r2, r3 ) | (signs.at( r1, r2, r3) * 0x80 )); /*std::cout << "value: " << int(_core.at( r1, r2, r3 )) << " bit " << int( core_el ) << " sign: " << int(_signs.at( r1, r2, r3)) << std::endl;*/ memcpy( data + end_data, &core_el, len_core_el ); ++end_data; } } } data_out_.clear(); for( size_t byte = 0; byte < len_export_data; ++byte ) { data_out_.push_back( data[byte] ); } delete[] data; delete u1; delete u2; delete u3; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tucker3_importer.hpp000066400000000000000000000267641231531733200263270ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * * Import tool for Tucker3 tensor and quantized Tucker3 tensor * */ #ifndef __VMML__TUCK3_IMPORTER__HPP__ #define __VMML__TUCK3_IMPORTER__HPP__ #include /* FIXME: * * - T_internal */ namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value = float, typename T_coeff = float > class tucker3_importer { public: typedef float T_internal; //FIXME! should match with tucker3 tensor typedef tucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > tucker3_type; typedef qtucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > qtucker3_type; typedef tensor3< R1, R2, R3, T_coeff > t3_core_type; typedef typename t3_core_type::iterator t3_core_iterator; typedef typename t3_core_type::const_iterator t3_core_const_iterator; typedef matrix< I1, R1, T_coeff > u1_type; typedef typename u1_type::iterator u1_iterator; typedef typename u1_type::const_iterator u1_const_iterator; typedef matrix< I2, R2, T_coeff > u2_type; typedef typename u2_type::iterator u2_iterator; typedef typename u2_type::const_iterator u2_const_iterator; typedef matrix< I3, R3, T_coeff > u3_type; typedef typename u3_type::iterator u3_iterator; typedef typename u3_type::const_iterator u3_const_iterator; typedef matrix< R1, R2, T_coeff > front_core_slice_type; //fwd: forward cylcling (after kiers et al., 2000) typedef tensor3< R1, R2, R3, char > t3_core_signs_type; template< typename T > static void import_from( const std::vector< T >& data_, tucker3_type& tuck3_data_ ); //previous version, but works only with 16bit quantization static void import_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ); //use this version, works with a better quantization for the core tensor: //logarithmic quantization and separate high energy core vale //suitable for voxelwise reconstruction static void import_hot_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ); //use this version for the ttm export/import (core: backward cyclic), without plain hot value static void import_ttm_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ); }; //end tucker3 importer class #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME tucker3_importer< R1, R2, R3, I1, I2, I3, T_value, T_coeff > VMML_TEMPLATE_STRING template< typename T > void VMML_TEMPLATE_CLASSNAME::import_from( const std::vector< T >& data_, tucker3_type& tuck3_data_ ) { size_t i = 0; //iterator over data_ size_t data_size = (size_t) data_.size(); if ( data_size != tuck3_data_.SIZE ) VMMLIB_ERROR( "import_from: the input data must have the size R1xR2xR3 + R1xI1 + R2xI2 + R3xI3 ", VMMLIB_HERE ); u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); u1_iterator it = u1->begin(), it_end = u1->end(); for( ; it != it_end; ++it, ++i ) { *it = static_cast< T >( data_.at(i)); } u2_iterator u2_it = u2->begin(), u2_it_end = u2->end(); for( ; u2_it != u2_it_end; ++u2_it, ++i ) { *u2_it = static_cast< T >( data_.at(i)); } u3_iterator u3_it = u3->begin(), u3_it_end = u3->end(); for( ; u3_it != u3_it_end; ++u3_it, ++i ) { *u3_it = static_cast< T >( data_.at(i)); } t3_core_iterator it_core = core.begin(), it_core_end = core.end(); for( ; it_core != it_core_end; ++it_core, ++i ) { *it_core = static_cast< T >( data_.at(i)); } tuck3_data_.set_u1( *u1 ); tuck3_data_.set_u2( *u2 ); tuck3_data_.set_u3( *u3 ); tuck3_data_.set_core( core ); tuck3_data_.cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::import_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ) { size_t end_data = 0; size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = tuck3_data_.SIZE * sizeof(T_coeff) + 8 * len_t_comp; unsigned char * data = new unsigned char[ len_export_data ]; for( size_t byte = 0; byte < len_export_data; ++byte ) { data[byte] = data_in_.at(byte); } //copy min and max values: u1_min, u1_max, u2_min, u2_max, u3_min, u3_max, core_min, core_max T_internal u_min = 0; T_internal u_max = 0; memcpy( &u_min, data, len_t_comp ); end_data = len_t_comp; memcpy( &u_max, data + end_data, len_t_comp ); end_data += len_t_comp; T_internal core_min = 0; T_internal core_max = 0; memcpy( &core_min, data + end_data, len_t_comp ); end_data += len_t_comp; memcpy( &core_max, data + end_data, len_t_comp ); end_data += len_t_comp; u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); //copy data to u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( *u1, data + end_data, len_u1 ); end_data += len_u1; //copy data to u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( *u2, data + end_data, len_u2 ); end_data += len_u2; //copy data to u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( *u3, data + end_data, len_u3 ); end_data += len_u3; //copy data to core size_t len_core_slice = R1 * R2 * sizeof( T_coeff ); front_core_slice_type* slice = new front_core_slice_type(); for (size_t r3 = 0; r3 < R3; ++r3 ) { memcpy( slice, data + end_data, len_core_slice ); core.set_frontal_slice_fwd( r3, *slice ); end_data += len_core_slice; } tuck3_data_.set_u1( *u1 ); tuck3_data_.set_u2( *u2 ); tuck3_data_.set_u3( *u3 ); tuck3_data_.set_core( core ); //dequantize tucker3 components (u1-u3 and core) tuck3_data_.dequantize_basis_matrices( u_min, u_max, u_min, u_max, u_min, u_max ); tuck3_data_.dequantize_core( core_min, core_max ); delete slice; delete[] data; delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::import_hot_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ) { tuck3_data_.enable_quantify_hot(); size_t end_data = 0; size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = R1*R2*R3 + (R1*I1 + R2*I2 + R3*I3) * sizeof(T_coeff) + 4 * len_t_comp; unsigned char * data = new unsigned char[ len_export_data ]; for( size_t byte = 0; byte < len_export_data; ++byte ) { data[byte] = data_in_.at(byte); } //copy min and max values: u1_min, u1_max, u2_min, u2_max, u3_min, u3_max, core_min, core_max T_internal u_min = 0; T_internal u_max = 0; memcpy( &u_min, data, len_t_comp ); end_data = len_t_comp; memcpy( &u_max, data + end_data, len_t_comp ); end_data += len_t_comp; T_internal core_min = 0; T_internal core_max = 0; //core_min is 0 //memcpy( &core_min, data + end_data, len_t_comp ); end_data += len_t_comp; memcpy( &core_max, data + end_data, len_t_comp ); end_data += len_t_comp; //copy first value of core tensor separately as a float T_internal hottest_value = 0; memcpy( &hottest_value, data + end_data, len_t_comp ); end_data += len_t_comp; tuck3_data_.set_hottest_value( hottest_value ); u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; t3_core_signs_type signs; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); tuck3_data_.get_core_signs( signs ); //copy data to u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( *u1, data + end_data, len_u1 ); end_data += len_u1; //copy data to u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( *u2, data + end_data, len_u2 ); end_data += len_u2; //copy data to u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( *u3, data + end_data, len_u3 ); end_data += len_u3; //copy data to core size_t len_core_el = 1; //currently 1 bit for sign and 7 bit for values unsigned char core_el; for (size_t r3 = 0; r3 < R3; ++r3 ) { for (size_t r2 = 0; r2 < R2; ++r2 ) { for (size_t r1 = 0; r1 < R1; ++r1 ) { memcpy( &core_el, data + end_data, len_core_el ); signs.at( r1, r2, r3 ) = (core_el & 0x80)/128; core.at( r1, r2, r3 ) = core_el & 0x7f ; ++end_data; } } } tuck3_data_.set_u1( *u1 ); tuck3_data_.set_u2( *u2 ); tuck3_data_.set_u3( *u3 ); tuck3_data_.set_core( core ); tuck3_data_.set_core_signs( signs ); //dequantize tucker3 components (u1-u3 and core) tuck3_data_.dequantize_basis_matrices( u_min, u_max, u_min, u_max, u_min, u_max ); tuck3_data_.dequantize_core( core_min, core_max ); delete[] data; delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::import_ttm_quantized_from( const std::vector& data_in_, qtucker3_type& tuck3_data_ ) { tuck3_data_.enable_quantify_log(); size_t end_data = 0; size_t len_t_comp = sizeof( T_internal ); size_t len_export_data = R1*R2*R3 + (R1*I1 + R2*I2 + R3*I3) * sizeof(T_coeff) + 3 * len_t_comp; unsigned char * data = new unsigned char[ len_export_data ]; for( size_t byte = 0; byte < len_export_data; ++byte ) { data[byte] = data_in_.at(byte); } //copy min and max values: u1_min, u1_max, u2_min, u2_max, u3_min, u3_max, core_min, core_max T_internal u_min = 0; T_internal u_max = 0; memcpy( &u_min, data, len_t_comp ); end_data = len_t_comp; memcpy( &u_max, data + end_data, len_t_comp ); end_data += len_t_comp; T_internal core_min = 0; T_internal core_max = 0; //core_min is 0 //memcpy( &core_min, data + end_data, len_t_comp ); end_data += len_t_comp; memcpy( &core_max, data + end_data, len_t_comp ); end_data += len_t_comp; u1_type* u1 = new u1_type; u2_type* u2 = new u2_type; u3_type* u3 = new u3_type; t3_core_type core; t3_core_signs_type signs; tuck3_data_.get_u1( *u1 ); tuck3_data_.get_u2( *u2 ); tuck3_data_.get_u3( *u3 ); tuck3_data_.get_core( core ); tuck3_data_.get_core_signs( signs ); //copy data to u1 size_t len_u1 = I1 * R1 * sizeof( T_coeff ); memcpy( *u1, data + end_data, len_u1 ); end_data += len_u1; //copy data to u2 size_t len_u2 = I2 * R2 * sizeof( T_coeff ); memcpy( *u2, data + end_data, len_u2 ); end_data += len_u2; //copy data to u3 size_t len_u3 = I3 * R3 * sizeof( T_coeff ); memcpy( *u3, data + end_data, len_u3 ); end_data += len_u3; //copy data to core size_t len_core_el = 1; //currently 1 bit for sign and 7 bit for values //backward cyclic after lathauwer et al. unsigned char core_el; for (size_t r2 = 0; r2 < R2; ++r2 ) { for (size_t r3 = 0; r3 < R3; ++r3 ) { for (size_t r1 = 0; r1 < R1; ++r1 ) { memcpy( &core_el, data + end_data, len_core_el ); signs.at( r1, r2, r3 ) = (core_el & 0x80)/128; core.at( r1, r2, r3 ) = core_el & 0x7f ; ++end_data; } } } //std::cout << "signs: " << _signs << std::endl; //std::cout << "_core: " << _core << std::endl; delete[] data; tuck3_data_.set_u1( *u1 ); tuck3_data_.set_u2( *u2 ); tuck3_data_.set_u3( *u3 ); tuck3_data_.set_core( core ); tuck3_data_.set_core_signs( signs ); //dequantize tucker3 components (u1-u3 and core) tuck3_data_.dequantize_basis_matrices( u_min, u_max, u_min, u_max, u_min, u_max ); tuck3_data_.dequantize_core( core_min, core_max ); delete u1; delete u2; delete u3; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tucker3_tensor.hpp000066400000000000000000000564051231531733200257730ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Susanne Suter * @author Jonas Boesch * * The Tucker3 tensor class is consists of the same components (core tensor, basis matrices u1-u3) as the tucker3 model described in: * - Tucker, 1966: Some mathematical notes on three-mode factor analysis, Psychometrika. * - De Lathauwer, De Moor, Vandewalle, 2000a: A multilinear singular value decomposition, SIAM J. Matrix Anal. Appl. * - De Lathauwer, De Moor, Vandewalle, 2000b: On the Best rank-1 and Rank-(R_1, R_2, ..., R_N) Approximation and Applications of Higher-Order Tensors, SIAM J. Matrix Anal. Appl. * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review. * * see also quantized Tucker3 tensor (qtucker3_tensor.hpp) */ #ifndef __VMML__TUCKER3_TENSOR__HPP__ #define __VMML__TUCKER3_TENSOR__HPP__ #include #include namespace vmml { template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value = float, typename T_coeff = double > class tucker3_tensor { public: typedef float T_internal; typedef tucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > tucker3_type; typedef t3_hooi< R1, R2, R3, I1, I2, I3, T_coeff > t3_hooi_type; typedef tensor3< I1, I2, I3, T_value > t3_type; typedef tensor3< R1, R2, R3, T_coeff > t3_core_type; typedef matrix< I1, R1, T_coeff > u1_type; typedef matrix< I2, R2, T_coeff > u2_type; typedef matrix< I3, R3, T_coeff > u3_type; typedef tensor3< I1, I2, I3, T_internal > t3_comp_type; typedef tensor3< R1, R2, R3, T_internal > t3_core_comp_type; typedef matrix< I1, R1, T_internal > u1_comp_type; typedef matrix< I2, R2, T_internal > u2_comp_type; typedef matrix< I3, R3, T_internal > u3_comp_type; static const size_t SIZE = R1*R2*R3 + I1*R1 + I2*R2 + I3*R3; tucker3_tensor(); tucker3_tensor(t3_core_type& core); tucker3_tensor(t3_core_type& core, u1_type& U1, u2_type& U2, u3_type& U3); tucker3_tensor(const t3_type& data_, u1_type& U1, u2_type& U2, u3_type& U3); tucker3_tensor(const tucker3_type& other); ~tucker3_tensor(); void set_core(t3_core_type& core) { _core = t3_core_type(core); _core_comp.cast_from(core); }; void set_u1(u1_type& U1) { *_u1 = U1; _u1_comp->cast_from(U1); }; void set_u2(u2_type& U2) { *_u2 = U2; _u2_comp->cast_from(U2); }; void set_u3(u3_type& U3) { *_u3 = U3; _u3_comp->cast_from(U3); }; t3_core_type get_core() const { return _core; }; //be careful: creates copy! void get_core(t3_core_type& data_) const { data_ = _core; }; void get_u1(u1_type& U1) const { U1 = *_u1; }; void get_u2(u2_type& U2) const { U2 = *_u2; }; void get_u3(u3_type& U3) const { U3 = *_u3; }; void set_core_comp(t3_core_comp_type& core) { _core_comp = t3_core_comp_type(core); _core.cast_from(_core_comp); }; void set_u1_comp(u1_comp_type& U1) { *_u1_comp = U1; _u1->cast_from(U1); }; void set_u2_comp(u2_comp_type& U2) { *_u2_comp = U2; _u2->cast_from(U2); }; void set_u3_comp(u3_comp_type& U3) { *_u3_comp = U3; _u3->cast_from(U3); }; void get_core_comp(t3_core_comp_type& data_) const { data_ = _core_comp; }; void get_u1_comp(u1_comp_type& U1) const { U1 = *_u1_comp; }; void get_u2_comp(u2_comp_type& U2) const { U2 = *_u2_comp; }; void get_u3_comp(u3_comp_type& U3) const { U3 = *_u3_comp; }; //get number of nonzeros for tensor decomposition size_t nnz() const; size_t nnz(const T_value& threshold) const; size_t nnz_core() const; size_t size_core() const; size_t size() const { return SIZE; }; void threshold_core(const size_t& nnz_core_, size_t& nnz_core_is_); void threshold_core(const T_coeff& threshold_value_, size_t& nnz_core_); template< size_t J1, size_t J2, size_t J3 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* set_sub_core(const tensor3& sub_data_, size_t row_offset, size_t col_offset, size_t slice_offset); void reconstruct(t3_type& data_); double error(t3_type& original) const; template< typename T_init> tensor_stats decompose(const t3_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 10); template< typename T_init> tensor_stats tucker_als(const t3_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 1e-04); template< size_t NBLOCKS, typename T_init> tensor_stats i_tucker_als(const t3_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 1e-04); template< size_t R, size_t NBLOCKS, typename T_init> tensor_stats i_cp_tucker_als(const t3_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 1e-04); void als_rand(const t3_type& data_); //template< typename T_init> // void tucker_als(const t3_type& data_, T_init init); // template< size_t NBLOCKS, typename T_init > // void incr_block_diag_als(const t3_type& data_, T_init init); // void incr_block_diag_als( T_init init ); template< size_t K1, size_t K2, size_t K3> void reduce_ranks(const tucker3_tensor< K1, K2, K3, I1, I2, I3, T_value, T_coeff >& other); //call TuckerJI.reduce_ranks(TuckerKI) K1 -> R1, K2 -> R2, K3 -> R3 template< size_t K1, size_t K2, size_t K3> void subsampling(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& factor); template< size_t K1, size_t K2, size_t K3> void subsampling_on_average(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& factor); template< size_t K1, size_t K2, size_t K3> void region_of_interest(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& start_index1, const size_t& end_index1, const size_t& start_index2, const size_t& end_index2, const size_t& start_index3, const size_t& end_index3); friend std::ostream& operator <<(std::ostream& os, const tucker3_type& t3) { t3_core_type core; t3.get_core(core); u1_type* u1 = new u1_type; t3.get_u1(*u1); u2_type* u2 = new u2_type; t3.get_u2(*u2); u3_type* u3 = new u3_type; t3.get_u3(*u3); os << "U1: " << std::endl << *u1 << std::endl << "U2: " << std::endl << *u2 << std::endl << "U3: " << std::endl << *u3 << std::endl << "core: " << std::endl << core << std::endl; delete u1; delete u2; delete u3; return os; } void cast_members(); void cast_comp_members(); protected: tucker3_type operator=(const tucker3_type& other) { return (*this); }; private: //t3_core_type* _core ; u1_type* _u1; u2_type* _u2; u3_type* _u3; t3_core_type _core; //used only internally for computations to have a higher precision t3_core_comp_type _core_comp; u1_comp_type* _u1_comp; u2_comp_type* _u2_comp; u3_comp_type* _u3_comp; }; // class tucker3_tensor #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff > #define VMML_TEMPLATE_CLASSNAME tucker3_tensor< R1, R2, R3, I1, I2, I3, T_value, T_coeff > VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker3_tensor() { _core.zero(); _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _core_comp.zero(); _u1_comp = new u1_comp_type(); _u1_comp->zero(); _u2_comp = new u2_comp_type(); _u2_comp->zero(); _u3_comp = new u3_comp_type(); _u3_comp->zero(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker3_tensor(t3_core_type& core) { _core = core; _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _u1_comp = new u1_comp_type(); _u1_comp->zero(); _u2_comp = new u2_comp_type(); _u2_comp->zero(); _u3_comp = new u3_comp_type(); _u3_comp->zero(); _core_comp.cast_from(core); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker3_tensor(t3_core_type& core, u1_type& U1, u2_type& U2, u3_type& U3) { _core = core; _u1 = new u1_type(U1); _u2 = new u2_type(U2); _u3 = new u3_type(U3); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); cast_comp_members(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker3_tensor(const t3_type& data_, u1_type& U1, u2_type& U2, u3_type& U3) { _u1 = new u1_type(U1); _u2 = new u2_type(U2); _u3 = new u3_type(U3); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); t3_hooi_type::derive_core_orthogonal_bases(data_, *_u1, *_u2, *_u3, _core); cast_comp_members(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker3_tensor(const tucker3_type& other) { _u1 = new u1_type(); _u2 = new u2_type(); _u3 = new u3_type(); _u1_comp = new u1_comp_type(); _u2_comp = new u2_comp_type(); _u3_comp = new u3_comp_type(); other.get_core(_core); other.get_u1(*_u1); other.get_u2(*_u2); other.get_u3(*_u3); cast_comp_members(); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_members() { _u1->cast_from(*_u1_comp); _u2->cast_from(*_u2_comp); _u3->cast_from(*_u3_comp); _core.cast_from(_core_comp); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::cast_comp_members() { _u1_comp->cast_from(*_u1); _u2_comp->cast_from(*_u2); _u3_comp->cast_from(*_u3); _core_comp.cast_from(_core); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz_core() const { return _core_comp.nnz(); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::size_core() const { return _core_comp.size(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~tucker3_tensor() { delete _u1; delete _u2; delete _u3; delete _u1_comp; delete _u2_comp; delete _u3_comp; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct(t3_type& data_) { t3_comp_type data; data.cast_from(data_); t3_ttm::full_tensor3_matrix_multiplication(_core_comp, *_u1_comp, *_u2_comp, *_u3_comp, data); // TODO have a closer look at this. It's mangling the error computation (after the cast, frobenius_norm() changes substantially) //convert reconstructed data, which is in type T_internal (double, float) to T_value (uint8 or uint16) if ((sizeof (T_value) == 1) || (sizeof (T_value) == 2)) { data_.float_t_to_uint_t(data); } else { data_.cast_from(data); } } VMML_TEMPLATE_STRING double VMML_TEMPLATE_CLASSNAME::error(t3_type& original) const { t3_comp_type data; t3_ttm::full_tensor3_matrix_multiplication(_core_comp, *_u1_comp, *_u2_comp, *_u3_comp, data); double err = data.frobenius_norm(original) / original.frobenius_norm() * 100; return err; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::threshold_core(const size_t& nnz_core_, size_t& nnz_core_is_) { nnz_core_is_ = _core_comp.nnz(); T_coeff threshold_value = 0.00001; while (nnz_core_is_ > nnz_core_) { _core_comp.threshold(threshold_value); nnz_core_is_ = _core_comp.nnz(); //threshold value scheme if (threshold_value < 0.01) { threshold_value *= 10; } else if (threshold_value < 0.2) { threshold_value += 0.05; } else if (threshold_value < 1) { threshold_value += 0.25; } else if (threshold_value < 10) { threshold_value += 1; } else if (threshold_value < 50) { threshold_value += 10; } else if (threshold_value < 200) { threshold_value += 50; } else if (threshold_value < 500) { threshold_value += 100; } else if (threshold_value < 2000) { threshold_value += 500; } else if (threshold_value < 5000) { threshold_value += 3000; } else if (threshold_value >= 5000) { threshold_value += 5000; } } _core.cast_from(_core_comp); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::threshold_core(const T_coeff& threshold_value_, size_t& nnz_core_) { _core_comp.threshold(threshold_value_); nnz_core_ = _core_comp.nnz(); _core.cast_from(_core_comp); } VMML_TEMPLATE_STRING template< size_t J1, size_t J2, size_t J3 > typename enable_if< J1 <= I1 && J2 <= I2 && J3 <= I3 >::type* VMML_TEMPLATE_CLASSNAME:: set_sub_core(const tensor3& sub_data_, size_t row_offset, size_t col_offset, size_t slice_offset) { _core_comp.set_sub_tensor3(sub_data_, row_offset, col_offset, slice_offset); _core.cast_from(_core_comp); } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::als_rand(const t3_type& data_) { typedef t3_hooi< R1, R2, R3, I1, I2, I3, T_internal > hooi_type; tucker_als(data_, typename hooi_type::init_random()); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::decompose(const t3_type& data_, T_init init, const size_t max_iterations, const float tolerance) { return tucker_als(data_, init, max_iterations, tolerance); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::tucker_als(const t3_type& data_, T_init init, const size_t max_iterations, const float tolerance) { tensor_stats result; t3_comp_type data; data.cast_from(data_); typedef t3_hooi< R1, R2, R3, I1, I2, I3, T_internal > hooi_type; result += hooi_type::als(data, *_u1_comp, *_u2_comp, *_u3_comp, _core_comp, init, 0, max_iterations, tolerance); cast_members(); return result; } VMML_TEMPLATE_STRING template< size_t NBLOCKS, typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::i_tucker_als(const t3_type& data_, T_init init, const size_t max_iterations, const float tolerance) { tensor_stats result; t3_comp_type data; data.cast_from(data_); typedef t3_ihooi< R1, R2, R3, NBLOCKS, I1, I2, I3, T_internal > ihooi_type; result += ihooi_type::i_als(data, *_u1_comp, *_u2_comp, *_u3_comp, _core_comp, init, 0, max_iterations, tolerance); cast_members(); return result; } VMML_TEMPLATE_STRING template< size_t R, size_t NBLOCKS, typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::i_cp_tucker_als(const t3_type& data_, T_init init, const size_t max_iterations, const float tolerance) { tensor_stats result; t3_comp_type data; data.cast_from(data_); typedef t3_ihooi< R1, R2, R3, NBLOCKS, I1, I2, I3, T_internal > ihooi_type; result += ihooi_type::template i_cp_als < R > (data, *_u1_comp, *_u2_comp, *_u3_comp, _core_comp, init, 0, max_iterations, tolerance); cast_members(); return result; } VMML_TEMPLATE_STRING template< size_t K1, size_t K2, size_t K3> void VMML_TEMPLATE_CLASSNAME::reduce_ranks(const tucker3_tensor< K1, K2, K3, I1, I2, I3, T_value, T_coeff >& other) //TuckerJI.rank_reduction(TuckerKI) K1 -> R1, K2 -> R2, K3 -> R3; I1, I2, I3 stay the same { assert(R1 <= K1); assert(R2 <= K2); assert(R3 <= K3); //reduce basis matrices matrix< I1, K1, T_coeff >* u1 = new matrix< I1, K1, T_coeff > (); other.get_u1(*u1); for (size_t r1 = 0; r1 < R1; ++r1) { _u1->set_column(r1, u1->get_column(r1)); } matrix< I2, K2, T_coeff >* u2 = new matrix< I2, K2, T_coeff > (); other.get_u2(*u2); for (size_t r2 = 0; r2 < R2; ++r2) { _u2->set_column(r2, u2->get_column(r2)); } matrix< I3, K3, T_coeff >* u3 = new matrix< I3, K3, T_coeff > (); other.get_u3(*u3); for (size_t r3 = 0; r3 < R3; ++r3) { _u3->set_column(r3, u3->get_column(r3)); } //reduce core tensor3 other_core; other.get_core(other_core); for (size_t r3 = 0; r3 < R3; ++r3) { for (size_t r1 = 0; r1 < R1; ++r1) { for (size_t r2 = 0; r2 < R2; ++r2) { _core.at(r1, r2, r3) = other_core.at(r1, r2, r3); } } } cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING template< size_t K1, size_t K2, size_t K3> void VMML_TEMPLATE_CLASSNAME::subsampling(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& factor) { assert(I1 <= K1); assert(I1 <= K2); assert(I1 <= K3); //subsample basis matrices matrix< K1, R1, T_coeff >* u1 = new matrix< K1, R1, T_coeff > (); other.get_u1(*u1); for (size_t i1 = 0, i = 0; i1 < K1; i1 += factor, ++i) { _u1->set_row(i, u1->get_row(i1)); } matrix< K2, R2, T_coeff >* u2 = new matrix< K2, R2, T_coeff > (); other.get_u2(*u2); for (size_t i2 = 0, i = 0; i2 < K2; i2 += factor, ++i) { _u2->set_row(i, u2->get_row(i2)); } matrix< K3, R3, T_coeff >* u3 = new matrix< K3, R3, T_coeff > (); other.get_u3(*u3); for (size_t i3 = 0, i = 0; i3 < K3; i3 += factor, ++i) { _u3->set_row(i, u3->get_row(i3)); } other.get_core(_core); cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING template< size_t K1, size_t K2, size_t K3> void VMML_TEMPLATE_CLASSNAME::subsampling_on_average(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& factor) { assert(I1 <= K1); assert(I1 <= K2); assert(I1 <= K3); //subsample basis matrices matrix< K1, R1, T_coeff >* u1 = new matrix< K1, R1, T_coeff > (); other.get_u1(*u1); for (size_t i1 = 0, i = 0; i1 < K1; i1 += factor, ++i) { vector< R1, T_internal > tmp_row = u1->get_row(i1); T_internal num_items_averaged = 1; for (size_t j = i1 + 1; (j < (factor + i1)) & (j < K1); ++j, ++num_items_averaged) tmp_row += u1->get_row(j); tmp_row /= num_items_averaged; _u1->set_row(i, tmp_row); } matrix< K2, R2, T_coeff >* u2 = new matrix< K2, R2, T_coeff > (); other.get_u2(*u2); for (size_t i2 = 0, i = 0; i2 < K2; i2 += factor, ++i) { vector< R2, T_internal > tmp_row = u2->get_row(i2); T_internal num_items_averaged = 1; for (size_t j = i2 + 1; (j < (factor + i2)) & (j < K2); ++j, ++num_items_averaged) tmp_row += u2->get_row(j); tmp_row /= num_items_averaged; _u2->set_row(i, u2->get_row(i2)); } matrix< K3, R3, T_coeff >* u3 = new matrix< K3, R3, T_coeff > (); other.get_u3(*u3); for (size_t i3 = 0, i = 0; i3 < K3; i3 += factor, ++i) { vector< R3, T_internal > tmp_row = u3->get_row(i3); T_internal num_items_averaged = 1; for (size_t j = i3 + 1; (j < (factor + i3)) & (j < K3); ++j, ++num_items_averaged) tmp_row += u3->get_row(j); tmp_row /= num_items_averaged; _u3->set_row(i, u3->get_row(i3)); } other.get_core(_core); cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING template< size_t K1, size_t K2, size_t K3> void VMML_TEMPLATE_CLASSNAME::region_of_interest(const tucker3_tensor< R1, R2, R3, K1, K2, K3, T_value, T_coeff >& other, const size_t& start_index1, const size_t& end_index1, const size_t& start_index2, const size_t& end_index2, const size_t& start_index3, const size_t& end_index3) { assert(I1 <= K1); assert(I1 <= K2); assert(I1 <= K3); assert(start_index1 < end_index1); assert(start_index2 < end_index2); assert(start_index3 < end_index3); assert(end_index1 < K1); assert(end_index2 < K2); assert(end_index3 < K3); //region_of_interes of basis matrices matrix< K1, R1, T_internal >* u1 = new matrix< K1, R1, T_internal > (); other.get_u1_comp(*u1); for (size_t i1 = start_index1, i = 0; i1 < end_index1; ++i1, ++i) { _u1_comp->set_row(i, u1->get_row(i1)); } matrix< K2, R2, T_internal>* u2 = new matrix< K2, R2, T_internal > (); other.get_u2_comp(*u2); for (size_t i2 = start_index2, i = 0; i2 < end_index2; ++i2, ++i) { _u2_comp->set_row(i, u2->get_row(i2)); } matrix< K3, R3, T_internal >* u3 = new matrix< K3, R3, T_internal > (); other.get_u3_comp(*u3); for (size_t i3 = start_index3, i = 0; i3 < end_index3; ++i3, ++i) { _u3_comp->set_row(i, u3->get_row(i3)); } other.get_core_comp(_core_comp); //cast_comp_members(); delete u1; delete u2; delete u3; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz() const { size_t counter = 0; counter += _u1_comp->nnz(); counter += _u2_comp->nnz(); counter += _u3_comp->nnz(); counter += _core_comp.nnz(); return counter; } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz(const T_value& threshold) const { size_t counter = 0; counter += _u1_comp->nnz(threshold); counter += _u2_comp->nnz(threshold); counter += _u3_comp->nnz(threshold); counter += _core_comp.nnz(threshold); return counter; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/tucker4_tensor.hpp000066400000000000000000000071261231531733200257700ustar00rootroot00000000000000/* * VMMLib - Tensor Classes * * @author Rafael Ballester */ #ifndef __VMML__TUCKER4_TENSOR__HPP__ #define __VMML__TUCKER4_TENSOR__HPP__ #include namespace vmml { // T is the input type for the tensor template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T = float> class tucker4_tensor { public: typedef double T_internal; typedef tucker4_tensor< R1, R2, R3, R4, I1, I2, I3, I4, T > tucker4_type; typedef t4_hooi< R1, R2, R3, R4, I1, I2, I3, I4, T > t4_hooi_type; typedef tensor4< I1, I2, I3, I4, T > t4_type; typedef tensor4< R1, R2, R3, R4, T_internal > t4_core_type; typedef matrix< I1, R1, T_internal > u1_type; typedef matrix< I2, R2, T_internal > u2_type; typedef matrix< I3, R3, T_internal > u3_type; typedef matrix< I4, R4, T_internal > u4_type; tucker4_tensor(); ~tucker4_tensor(); size_t nnz_core() const; size_t size_core() const; void reconstruct(t4_type& data_); template< typename T_init> tensor_stats decompose(const t4_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 10); template< typename T_init> tensor_stats tucker_als(const t4_type& data_, T_init init, const size_t max_iterations = 10, const float tolerance = 1e-04); private: //t3_core_type* _core ; u1_type* _u1; u2_type* _u2; u3_type* _u3; u4_type* _u4; t4_core_type _core; }; // class tucker3_tensor #define VMML_TEMPLATE_STRING template< size_t R1, size_t R2, size_t R3, size_t R4, size_t I1, size_t I2, size_t I3, size_t I4, typename T > #define VMML_TEMPLATE_CLASSNAME tucker4_tensor< R1, R2, R3, R4, I1, I2, I3, I4, T > VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::tucker4_tensor() { _core.zero(); _u1 = new u1_type(); _u1->zero(); _u2 = new u2_type(); _u2->zero(); _u3 = new u3_type(); _u3->zero(); _u4 = new u4_type(); _u4->zero(); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::nnz_core() const { return _core.nnz(); } VMML_TEMPLATE_STRING size_t VMML_TEMPLATE_CLASSNAME::size_core() const { return _core.size(); } VMML_TEMPLATE_STRING VMML_TEMPLATE_CLASSNAME::~tucker4_tensor() { delete _u1; delete _u2; delete _u3; delete _u4; } VMML_TEMPLATE_STRING void VMML_TEMPLATE_CLASSNAME::reconstruct(t4_type& data_) { // TODO (maybe try with the reordered summation formula) t4_ttm::full_tensor4_matrix_multiplication(_core, *_u1, *_u2, *_u3, *_u4, data_); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::decompose(const t4_type& data_, T_init init, const size_t max_iterations, const float tolerance) { return tucker_als(data_, init, max_iterations, tolerance); } VMML_TEMPLATE_STRING template< typename T_init> tensor_stats VMML_TEMPLATE_CLASSNAME::tucker_als(const t4_type& data_, T_init init, const size_t max_iterations, const float tolerance) { tensor_stats result; typedef t4_hooi< R1, R2, R3, R4, I1, I2, I3, I4, T_internal > hooi_type; result += hooi_type::als(data_, *_u1, *_u2, *_u3, *_u4, _core, init, 0, max_iterations, tolerance); return result; } #undef VMML_TEMPLATE_STRING #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif /* TUCKER4_TENSOR_HPP */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/util.hpp000066400000000000000000000061741231531733200237740ustar00rootroot00000000000000/* * VMMLib - Vector & Matrix Math Lib * convenience / utility functions * @author David Steiner */ #ifndef __VMML__UTIL__HPP__ #define __VMML__UTIL__HPP__ #include "vector.hpp" #include "matrix.hpp" #include #include #include namespace vmml { #define M_PI_F 3.14159265358979323846f #define M_PI_2_F 1.57079632679489661923f #define M_PI_3_F 1.04719755119659774615f #define M_PI_4_F 0.78539816339744830962f template< typename T, typename U > bool equals( T arg0, U arg1) { return fabs( arg0 - arg1 ) < std::numeric_limits< float >::epsilon(); } // matrix convenience functions template< size_t M, size_t N, typename T > inline matrix< M, N, T > create_translation( const vector< M - 1, T > &arg ) { matrix< M, N, T > ret; identity( ret ); ret.set_translation( arg ); return ret; } template< typename T > inline matrix< 4, 4, T > create_translation( const vector< 3, T > &arg ) { return create_translation< 4, 4 >(arg); } template< size_t M, size_t N, typename T > inline void apply_translation( matrix< M, N, T > &m, T t0, T t1, T t2 ) { m *= create_translation< M, N, T >( vector< M - 1, T >( t0, t1, t2 ) ); } template< size_t M, size_t N, typename T > inline matrix< M, N, T > create_rotation( T angle, const vector< M - 1, T > &axis ) { matrix< M, N, T > ret; identity( ret ); ret.rotate( angle, axis ); return ret; } template< typename T > inline matrix< 4, 4, T > create_rotation( T angle, const vector< 3, T > &axis ) { return create_rotation< 4, 4 >( angle, axis ); } template< size_t M, size_t N, typename T > inline void apply_rotation( matrix< M, N, T > &m, T angle, T t0, T t1, T t2 ) { m *= create_rotation< M, N, T >( angle, vector< M - 1, T >( t0, t1, t2 ) ); } template< size_t M, size_t N, typename T > inline matrix< M, N, T > create_scaling( const vector< N - 1, T > &arg ) { matrix< M, N, T > ret; identity(ret); ret.scale(arg); return ret; } template< typename T > inline matrix< 4, 4, T > const create_scaling( const vector< 3, T > &arg ) { return create_scaling< 4, 4 >(arg); } template< typename T > inline matrix< 4, 4, T > create_scaling( T arg ) { return create_scaling< 4, 4 >( vector< 3, T >( arg ) ); } // vector convenience functions template< size_t M, typename T > inline void zero( vector< M, T > &arg ) { std::fill( arg.begin(), arg.end(), 0 ); } template< size_t M, typename T > vector< M, T > min( const vector< M, T > &arg0, const vector< M, T > &arg1 ) { vector< M, T > ret; zero( ret ); for( size_t i = 0; i < M; ++i ) { if( arg0[i] < arg1[i]) { ret[i] = arg0[i]; } else { ret[i] = arg1[i]; } } return ret; } template< size_t M, typename T > vector< M, T > max( const vector< M, T > &arg0, const vector< M, T > &arg1 ) { vector< M, T > ret; zero( ret ); for( size_t i = 0; i < M; ++i ) { if( arg0[i] >= arg1[i]) { ret[i] = arg0[i]; } else { ret[i] = arg1[i]; } } return ret; } template< size_t M, typename T > T manhattan( const vector< M, T > &arg ) { T ret = 0; for( size_t i = 0; i < M; ++i ) { ret += std::abs(arg[i]); } return ret; } } // namespace vmml #endifrepsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/validator.hpp000066400000000000000000000047061231531733200250030ustar00rootroot00000000000000/* * VMMLib - Vector, Matrix and Tensor Classes * * @author Susanne Suter * * Tool to validate a vector, a matrix or a tensor * */ #ifndef __VMML__VALIDATOR__HPP__ #define __VMML__VALIDATOR__HPP__ #include namespace vmml { class validator { public: template< size_t M, typename T > static bool is_valid( const vector< M, T >& data_ ); template< size_t M, size_t N, typename T > static bool is_valid( const matrix< M, N, T >& data_ ); template< size_t M, size_t N, size_t L, typename T > static bool is_valid( const tensor3< M, N, L, T >& data_ ); }; //end validator class #define VMML_TEMPLATE_CLASSNAME validator template< size_t M, size_t N, size_t L, typename T > bool VMML_TEMPLATE_CLASSNAME::is_valid( const tensor3< M, N, L, T >& data_ ) { typedef typename tensor3< M, N, L, T>::const_iterator const_t3_iterator; bool valid = true; for( const_t3_iterator it = data_.begin(); valid && it != data_.end(); ++it ) { if ( std::isnan( *it ) ) valid = false; if ( std::isinf( *it ) ) valid = false; } #ifdef VMMLIB_THROW_EXCEPTIONS if ( ! valid ) VMMLIB_ERROR( "vector contains nan or inf.", VMMLIB_HERE ); #endif return valid; } template< size_t M, size_t N, typename T > bool VMML_TEMPLATE_CLASSNAME::is_valid( const matrix< M, N, T >& data_ ) { typedef typename matrix< M, N, T>::const_iterator const_m_iterator; bool valid = true; for( const_m_iterator it = data_.begin(); valid && it != data_.end(); ++it ) { if ( std::isnan( *it ) ) valid = false; if ( std::isinf( *it ) ) valid = false; } #ifdef VMMLIB_THROW_EXCEPTIONS if ( ! valid ) VMMLIB_ERROR( "matrix contains nan or inf.", VMMLIB_HERE ); #endif return valid; } template< size_t M, typename T > bool VMML_TEMPLATE_CLASSNAME::is_valid( const vector< M, T >& data_ ) { typedef typename vector< M, T>::const_iterator const_v_iterator; bool valid = true; for( const_v_iterator it = data_.begin(); valid && it != data_.end(); ++it ) { if ( std::isnan( *it ) ) valid = false; if ( std::isinf( *it ) ) valid = false; } #ifdef VMMLIB_THROW_EXCEPTIONS if ( ! valid ) VMMLIB_ERROR( "vector contains nan or inf.", VMMLIB_HERE ); #endif return valid; } #undef VMML_TEMPLATE_CLASSNAME } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/vector.hpp000066400000000000000000001200451231531733200243130ustar00rootroot00000000000000/* * Copyright (c) 2006-2012, Visualization and Multimedia Lab, * University of Zurich * * This file is part of VMMLib * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. Redistributions in binary * form must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials provided * with the distribution. Neither the name of the Visualization and Multimedia * Lab, University of Zurich nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __VMML__VECTOR__HPP__ #define __VMML__VECTOR__HPP__ #include #include #include #include #include #include #include #include #include #include #include namespace vmml { template< size_t M, typename T = float > class vector { public: typedef T value_type; typedef T* pointer; typedef T& reference; typedef T* iterator; typedef const T* const_iterator; typedef std::reverse_iterator< iterator > reverse_iterator; typedef std::reverse_iterator< const_iterator > const_reverse_iterator; static const size_t DIMENSION = M; // iterators inline iterator begin(); inline iterator end(); inline const_iterator begin() const; inline const_iterator end() const; inline reverse_iterator rbegin(); inline reverse_iterator rend(); inline const_reverse_iterator rbegin() const; inline const_reverse_iterator rend() const; #ifndef VMMLIB_NO_CONVERSION_OPERATORS // conversion operators inline operator T*(); inline operator const T*() const; #else inline T& operator[]( size_t index ); inline const T& operator[]( size_t index ) const; #endif // accessors inline T& operator()( size_t index ); inline const T& operator()( size_t index ) const; #if 0 inline T& operator[]( size_t index ); inline const T& operator[]( size_t index ) const; #endif inline T& at( size_t index ); inline const T& at( size_t index ) const; // element accessors for M <= 4; inline T& x(); inline T& y(); inline T& z(); inline T& w(); inline const T& x() const; inline const T& y() const; inline const T& z() const; inline const T& w() const; // pixel color element accessors for M<= 4 inline T& r(); inline T& g(); inline T& b(); inline T& a(); inline const T& r() const; inline const T& g() const; inline const T& b() const; inline const T& a() const; bool operator==( const vector& other ) const; bool operator!=( const vector& other ) const; bool equals( const vector& other, T tolerance = std::numeric_limits< T >::epsilon() ) const; bool operator<( const vector& other ) const; // remember kids: c_arrays are dangerous and evil! const vector& operator=( const T* c_array ); T operator=( T filler ); const vector& operator=( const vector& other ); // returns void to avoid 'silent' loss of precision when chaining template< typename U > void operator=( const vector< M, U >& other ); // to-homogenous-coordinates assignment operator // non-chainable because of sfinae template< size_t N > typename enable_if< N == M - 1 >::type* operator=( const vector< N, T >& source_ ); // from-homogenous-coordinates assignment operator // non-chainable because of sfinae template< size_t N > typename enable_if< N == M + 1 >::type* operator=( const vector< N, T >& source_ ); vector operator*( const vector& other ) const; vector operator/( const vector& other ) const; vector operator+( const vector& other ) const; vector operator-( const vector& other ) const; void operator*=( const vector& other ); void operator/=( const vector& other ); void operator+=( const vector& other ); void operator-=( const vector& other ); vector operator*( const T other ) const; vector operator/( const T other ) const; vector operator+( const T other ) const; vector operator-( const T other ) const; void operator*=( const T other ); void operator/=( const T other ); void operator+=( const T other ); void operator-=( const T other ); vector operator-() const; const vector& negate(); // constructors vector() {}; // std ctor - WARNING: NO INITIALIZATION explicit vector( const T& a ); // sets all components to a; vector( const T& x, const T& y ); vector( const T& x, const T& y, const T& z ); vector( const T& x, const T& y, const T& z, const T& w ); #ifndef SWIG // initializes the first M-1 values from vector_, the last from last_ vector( const vector< M-1, T >& vector_, T last_ ); #endif vector( const T* values ); #ifdef __OSG_MATH template< typename OSGVEC3 > explicit vector( const OSGVEC3& from, typename enable_if< M == 3, OSGVEC3 >::type* = 0 ); #endif // vec< M > with homogeneous coordinates <-> vec< M-1 > conversion ctor // to-homogenous-coordinates ctor template< size_t N > vector( const vector< N, T >& source_, typename enable_if< N == M - 1 >::type* = 0 ); // from-homogenous-coordinates vector template< size_t N > vector( const vector< N, T >& source_, typename enable_if< N == M + 1 >::type* = 0 ); template< typename U > vector( const vector< M, U >& source_ ); void set( T a ); // sets all components to a; #ifndef SWIG void set( const vector< M-1, T >& v, T a ); #endif template< size_t N > void set( const vector< N, T >& v ); // sets the first few components to a certain value void set( T x, T y ); void set( T x, T y, T z ); void set( T x, T y, T z, T w ); template< typename input_iterator_t > void iter_set( input_iterator_t begin_, input_iterator_t end_ ); // compute the cross product of two vectors // note: there's also a free function: // vector<> cross( const vector<>, const vector<> ) // result = vec1.cross( vec2 ) => retval result = vec1 x vec2 template< typename TT > vector cross( const vector< M, TT >& rhs, typename enable_if< M == 3, TT >::type* = 0 ) const; // result.cross( vec1, vec2 ) => (this) = vec1 x vec2 template< typename TT > void cross( const vector< M, TT >& a, const vector< M, TT >& b, typename enable_if< M == 3, TT >::type* = 0 ); // compute the dot product of two vectors // note: there's also a free function: // T dot( const vector<>, const vector<> ); inline T dot( const vector& other ) const; // normalize the vector // note: there's also a free function: // vector<> normalize( const vector<> ); inline T normalize(); //sets all vector components to random values //remember to set srand( seed ); //if seed is set to -1, srand( seed ) was set outside set_random //otherwise srand( seed ) will be called with the given seed void set_random( int seed = -1 ); inline T length() const; inline T squared_length() const; inline T distance( const vector& other_vector_ ) const; inline T squared_distance( const vector& other_vector_ ) const; template< typename TT > vector< 3, T > rotate( const T theta, vector< M, TT > axis, typename enable_if< M == 3, TT >::type* = 0 ) const; // right hand system, CCW triangle // (*this) = normal of v0,v1,v2 void compute_normal( const vector& v0, const vector& v1, const vector& v2 ); // retval = normal of (this), v1, v2 vector compute_normal( const vector& v1, const vector& v2 ) const; template< size_t N > void get_sub_vector( vector< N, T >& sub_v_, size_t offset = 0, typename enable_if< M >= N >::type* = 0 ); template< size_t N > vector< N, T >& get_sub_vector( size_t offset = 0, typename enable_if< M >= N >::type* = 0 ); template< size_t N > const vector< N, T >& get_sub_vector( size_t offset = 0, typename enable_if< M >= N >::type* = 0 ) const; // sphere functions - sphere layout: center xyz, radius w template< typename TT > inline vector< 3, T > project_point_onto_sphere( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* = 0 ) const; // returns a negative distance if the point lies in the sphere template< typename TT > inline T distance_to_sphere( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* = 0 ) const; // plane functions - plane layout; normal xyz, distance w template< typename TT > inline T distance_to_plane( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* = 0 ) const; template< typename TT > inline vector< 3, T > project_point_onto_plane( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* = 0 ) const; // returns the index of the minimal resp. maximal value in the vector size_t find_min_index() const; size_t find_max_index() const; // returns the index of the minimal resp. maximal value in the vector size_t find_abs_min_index() const; size_t find_abs_max_index() const; // returns minimal resp. maximal value in the vector T& find_min(); T& find_max(); const T& find_min() const; const T& find_max() const; void clamp( const T& min = 0.0, const T& max = 1.0 ); template< typename TT > void scale_to( vector< M, TT >& scaled_vector, T min_value = -1.0, T max_value = 1.0 ) const; inline static size_t size(); // returns M bool is_unit_vector() const; // perturbs each component by randomly + or - the perturbation parameter void perturb( T perturbation = 0.0001 ); void sqrt_elementwise(); double norm() const; //l2 norm // computes the reciprocal value for each component, x = 1/x; // WARNING: might result in nans if division by 0! void reciprocal(); // computes the reciprocal value for each component, x = 1/x; // checks every component for 0, sets to max value if zero. void reciprocal_safe(); template< typename TT > void cast_from( const vector< M, TT >& other ); size_t nnz() const; // test each component of the vector for isnan and isinf // inline bool is_valid() const; -> moved to class validator friend std::ostream& operator<< ( std::ostream& os, const vector& vector_ ) { #ifdef EQFABRIC_API_H const std::ios::fmtflags flags = os.flags(); const int prec = os.precision(); os.setf( std::ios::right, std::ios::adjustfield ); os.precision( 5 ); os << "[ "; for( size_t index = 0; index < M; ++index ) os << std::setw(10) << vector_.at( index ) << " "; os << "]"; os.precision( prec ); os.setf( flags ); #else os << "("; size_t index = 0; for( ; index < M - 1; ++index ) { os << vector_.at( index ) << ", "; } os << vector_.at( index ) << ") "; #endif return os; } // storage VMMLIB_ALIGN( T array[ M ] ); #ifndef SWIG // Vector3 defaults static const vector FORWARD; static const vector BACKWARD; static const vector UP; static const vector DOWN; static const vector LEFT; static const vector RIGHT; static const vector ONE; static const vector ZERO; // Unit vectors static const vector UNIT_X; static const vector UNIT_Y; static const vector UNIT_Z; #endif }; // class vector // // typedefs and statics // #ifndef VMMLIB_NO_TYPEDEFS typedef vector< 2, float > vec2f; typedef vector< 2, double > vec2d; typedef vector< 3, float > vec3f; typedef vector< 3, double > vec3d; typedef vector< 4, float > vec4f; typedef vector< 4, double > vec4d; #endif #ifndef SWIG template< size_t M, typename T > const vector< M, T > vector< M, T >::FORWARD( 0, 0, -1 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::BACKWARD( 0, 0, 1 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::UP( 0, 1, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::DOWN( 0, -1, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::LEFT( -1, 0, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::RIGHT( 1, 0, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::ONE( static_cast< T >( 1 )); template< size_t M, typename T > const vector< M, T > vector< M, T >::ZERO( static_cast< T >( 0 )); template< size_t M, typename T > const vector< M, T > vector< M, T >::UNIT_X( 1, 0, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::UNIT_Y( 0, 1, 0 ); template< size_t M, typename T > const vector< M, T > vector< M, T >::UNIT_Z( 0, 0, 1 ); #endif // // some free functions for convenience // template< size_t M, typename T > bool equals( const vector< M, T >& a, const vector< M, T >& b ) { return a.equals( b ); } // allows float * vector, not only vector * float template< size_t M, typename T > static vector< M, T > operator* ( T factor, const vector< M, T >& vector_ ) { return vector_ * factor; } template< size_t M, typename T > inline T dot( const vector< M, T >& first, const vector< M, T >& second ) { return first.dot( second ); } template< size_t M, typename T > inline vector< M, T > cross( const vector< 3, T >& a, const vector< 3, T >& b ) { return a.cross( b ); } template< size_t M, typename T > inline vector< M, T > normalize( const vector< M, T >& vector_ ) { vector< M, T > v( vector_ ); v.normalize(); return v; } template< typename T > inline vector< 4, T > compute_plane( const vector< 3, T >& a, const vector< 3, T >& b, const vector< 3, T >& c ) { const vector< 3, T > cb = b - c; const vector< 3, T > ba = a - b; vector< 4, T > plane = cb.cross( ba ); plane.normalize(); plane.w() = -plane.x() * a.x() - plane.y() * a.y() - plane.z() * a.z(); return plane; } template< size_t M, typename T > vector< M, T >::vector( const T& _a ) { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { *it = _a; } } template< size_t M, typename T > vector< M, T >::vector( const T& _x, const T& _y ) { array[ 0 ] = _x; array[ 1 ] = _y; } template< size_t M, typename T > vector< M, T >::vector( const T& _x, const T& _y, const T& _z ) { array[ 0 ] = _x; array[ 1 ] = _y; array[ 2 ] = _z; } template< size_t M, typename T > vector< M, T >::vector( const T& _x, const T& _y, const T& _z, const T& _w ) { array[ 0 ] = _x; array[ 1 ] = _y; array[ 2 ] = _z; array[ 3 ] = _w; } template< size_t M, typename T > vector< M, T >::vector( const T* values ) { memcpy( array, values, M * sizeof( T )); } #ifdef __OSG_MATH template< size_t M, typename T > template< typename OSGVEC3 > vector< M, T >::vector( const OSGVEC3& from, typename enable_if< M == 3, OSGVEC3 >::type* ) { array[ 0 ] = from.x(); array[ 1 ] = from.y(); array[ 2 ] = from.z(); } #endif #ifndef SWIG template< size_t M, typename T > // initializes the first M-1 values from vector_, the last from last_ vector< M, T >::vector( const vector< M-1, T >& vector_, T last_ ) { typename vector< M-1, T >::const_iterator it = vector_.begin(), it_end = vector_.end(); iterator my_it = begin(); for( ; it != it_end; ++it, ++my_it ) { (*my_it) = *it; } (*my_it) = last_; } #endif // to-homogenous-coordinates ctor template< size_t M, typename T > template< size_t N > vector< M, T >::vector( const vector< N, T >& source_, typename enable_if< N == M - 1 >::type* ) { (*this) = source_; } // from-homogenous-coordinates ctor template< size_t M, typename T > template< size_t N > vector< M, T >::vector( const vector< N, T >& source_, typename enable_if< N == M + 1 >::type* ) { (*this) = source_; } template< size_t M, typename T > template< typename U > vector< M, T >::vector( const vector< M, U >& source_ ) { (*this) = source_; } template< size_t M, typename T > void vector< M, T >::set( T _a ) { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { *it = _a; } } #ifndef SWIG template< size_t M, typename T > void vector< M, T >::set( const vector< M-1, T >& v, T _a ) { memcpy( array, v.array, sizeof( T ) * (M-1) ); at( M-1 ) = _a; } #endif template< size_t M, typename T > template< size_t N > void vector< M, T >::set( const vector< N, T >& v ) { size_t minimum = M; if (N < M) minimum = N; memcpy( array, v.array, sizeof( T ) * minimum ); } template< size_t M, typename T > void vector< M, T >::set( T _x, T _y ) { array[ 0 ] = _x; array[ 1 ] = _y; } template< size_t M, typename T > void vector< M, T >::set( T _x, T _y, T _z ) { array[ 0 ] = _x; array[ 1 ] = _y; array[ 2 ] = _z; } template< size_t M, typename T > void vector< M, T >::set( T _x, T _y, T _z, T _w ) { array[ 0 ] = _x; array[ 1 ] = _y; array[ 2 ] = _z; array[ 3 ] = _w; } template< size_t M, typename T > inline T& vector< M, T >::operator()( size_t index ) { return at( index ); } template< size_t M, typename T > inline const T& vector< M, T >::operator()( size_t index ) const { return at( index ); } template< size_t M, typename T > inline T& vector< M, T >::at( size_t index ) { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= M ) { VMMLIB_ERROR( "at() - index out of bounds", VMMLIB_HERE ); } #endif return array[ index ]; } template< size_t M, typename T > inline const T& vector< M, T >::at( size_t index ) const { #ifdef VMMLIB_SAFE_ACCESSORS if ( index >= M ) { VMMLIB_ERROR( "at() - index out of bounds", VMMLIB_HERE ); } #endif return array[ index ]; } #ifndef VMMLIB_NO_CONVERSION_OPERATORS template< size_t M, typename T > vector< M, T >::operator T*() { return array; } template< size_t M, typename T > vector< M, T >::operator const T*() const { return array; } #else template< size_t M, typename T > T& vector< M, T >::operator[]( size_t index ) { return at( index ); } template< size_t M, typename T > const T& vector< M, T >::operator[]( size_t index ) const { return at( index ); } #endif #if 0 template< size_t M, typename T > inline T& vector< M, T >::operator[]( size_t index ) { return at( index ); } template< size_t M, typename T > inline const T& vector< M, T >::operator[]( size_t index ) const { return at( index ); } #endif template< size_t M, typename T > vector< M, T > vector< M, T >::operator*( const vector< M, T >& other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) * other.at( index ); } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator/( const vector< M, T >& other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) / other.at( index ); } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator+( const vector< M, T >& other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) + other.at( index ); } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator-( const vector< M, T >& other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) - other.at( index ); } return result; } template< size_t M, typename T > void vector< M, T >::operator*=( const vector< M, T >& other ) { for( size_t index = 0; index < M; ++index ) { at( index ) *= other.at( index ); } } template< size_t M, typename T > void vector< M, T >::operator/=( const vector< M, T >& other ) { for( size_t index = 0; index < M; ++index ) { at( index ) /= other.at( index ); } } template< size_t M, typename T > void vector< M, T >::operator+=( const vector< M, T >& other ) { for( size_t index = 0; index < M; ++index ) { at( index ) += other.at( index ); } } template< size_t M, typename T > void vector< M, T >::operator-=( const vector< M, T >& other ) { for( size_t index = 0; index < M; ++index ) { at( index ) -= other.at( index ); } } template< size_t M, typename T > vector< M, T > vector< M, T >::operator*( const T other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) * other; } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator/( const T other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) / other; } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator+( const T other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) + other; } return result; } template< size_t M, typename T > vector< M, T > vector< M, T >::operator-( const T other ) const { vector< M, T > result; for( size_t index = 0; index < M; ++index ) { result.at( index ) = at( index ) - other; } return result; } template< size_t M, typename T > void vector< M, T >::operator*=( const T other ) { for( size_t index = 0; index < M; ++index ) { at( index ) *= other; } } template< size_t M, typename T > void vector< M, T >::operator/=( const T other ) { for( size_t index = 0; index < M; ++index ) { at( index ) /= other; } } template< size_t M, typename T > void vector< M, T >::operator+=( const T other ) { for( size_t index = 0; index < M; ++index ) { at( index ) += other; } } template< size_t M, typename T > void vector< M, T >::operator-=( const T other ) { for( size_t index = 0; index < M; ++index ) { at( index ) -= other; } } template< size_t M, typename T > vector< M, T > vector< M, T >::operator-() const { vector< M, T > v( *this ); return v.negate(); } template< size_t M, typename T > const vector< M, T >& vector< M, T >::negate() { for( size_t index = 0; index < M; ++index ) { array[ index ] = -array[ index ]; } return *this; } template< size_t M, typename T > inline T& vector< M, T >::x() { return array[ 0 ]; } template< size_t M, typename T > inline T& vector< M, T >::y() { return array[ 1 ]; } template< size_t M, typename T > inline T& vector< M, T >::z() { return array[ 2 ]; } template< size_t M, typename T > inline T& vector< M, T >::w() { return array[ 3 ]; } template< size_t M, typename T > inline const T& vector< M, T >::x() const { return array[ 0 ]; } template< size_t M, typename T > inline const T& vector< M, T >::y() const { return array[ 1 ]; } template< size_t M, typename T > inline const T& vector< M, T >::z() const { return array[ 2 ]; } template< size_t M, typename T > inline const T& vector< M, T >::w() const { return array[ 3 ]; } template< size_t M, typename T > inline T& vector< M, T >::r() { return array[ 0 ]; } template< size_t M, typename T > inline T& vector< M, T >::g() { return array[ 1 ]; } template< size_t M, typename T > inline T& vector< M, T >::b() { return array[ 2 ]; } template< size_t M, typename T > inline T& vector< M, T >::a() { return array[ 3 ]; } template< size_t M, typename T > inline const T& vector< M, T >::r() const { return array[ 0 ]; } template< size_t M, typename T > inline const T& vector< M, T >::g() const { return array[ 1 ]; } template< size_t M, typename T > inline const T& vector< M, T >::b() const { return array[ 2 ]; } template< size_t M, typename T > inline const T& vector< M, T >::a() const { return array[ 3 ]; } // result = vec1.cross( vec2 ) => result = vec1 x vec2 template< size_t M, typename T > template< typename TT > inline vector< M, T > vector< M, T >::cross( const vector< M, TT >& rhs, typename enable_if< M == 3, TT >::type* ) const { vector< M, T > result; result.cross( *this, rhs ); return result; } // result.cross( vec1, vec2 ) => (this) = vec1 x vec2 template< size_t M, typename T > template< typename TT > void vector< M, T >::cross( const vector< M, TT >& aa, const vector< M, TT >& bb, typename enable_if< M == 3, TT >::type* ) { array[ 0 ] = aa.y() * bb.z() - aa.z() * bb.y(); array[ 1 ] = aa.z() * bb.x() - aa.x() * bb.z(); array[ 2 ] = aa.x() * bb.y() - aa.y() * bb.x(); } template< size_t M, typename T > inline T vector< M, T >::dot( const vector< M, T >& other ) const { T tmp = 0.0; for( size_t index = 0; index < M; ++index ) tmp += at( index ) * other.at( index ); return tmp; } template< size_t M, typename T > inline T vector< M, T >::normalize() { const T len = length(); if ( len == 0 ) return 0; const T tmp = 1.0 / len; (*this) *= tmp; return len; } template< size_t M, typename T > inline T vector< M, T >::length() const { return sqrt( squared_length() ); } template< size_t M, typename T > inline T vector< M, T >::squared_length() const { T _squared_length = 0.0; for( const_iterator it = begin(), it_end = end(); it != it_end; ++it ) _squared_length += (*it) * (*it); return _squared_length; } template< size_t M, typename T > inline T vector< M, T >::distance( const vector< M, T >& other_vector_ ) const { return sqrt( squared_distance( other_vector_ ) ); } template< size_t M, typename T > inline T vector< M, T >::squared_distance( const vector< M, T >& other_vector_ ) const { vector< M, T > tmp( *this ); tmp -= other_vector_; return tmp.squared_length(); } template< size_t M, typename T > void vector< M, T >::compute_normal( const vector< M, T >& aa, const vector< M, T >& bb, const vector< M, T >& cc ) { vector< M, T > u,v; // right hand system, CCW triangle u = bb - aa; v = cc - aa; cross( u, v ); normalize(); } template< size_t M, typename T > vector< M, T > vector< M, T >::compute_normal( const vector< M, T >& bb, const vector< M, T >& cc ) const { vector< M, T > tmp; tmp.compute_normal( *this, bb, cc); return tmp; } template< size_t M, typename T > template< typename TT > vector< 3, T > vector< M, T >::rotate( const T theta, vector< M, TT > axis, typename enable_if< M == 3, TT >::type* ) const { axis.normalize(); const T costheta = std::cos( theta ); const T sintheta = std::sin( theta ); return vector< 3, T >( (costheta + ( 1.0f - costheta ) * axis.x() * axis.x() ) * x() + (( 1 - costheta ) * axis.x() * axis.y() - axis.z() * sintheta ) * y() + (( 1 - costheta ) * axis.x() * axis.z() + axis.y() * sintheta ) * z(), (( 1 - costheta ) * axis.x() * axis.y() + axis.z() * sintheta ) * x() + ( costheta + ( 1 - costheta ) * axis.y() * axis.y() ) * y() + (( 1 - costheta ) * axis.y() * axis.z() - axis.x() * sintheta ) * z(), (( 1 - costheta ) * axis.x() * axis.z() - axis.y() * sintheta ) * x() + (( 1 - costheta ) * axis.y() * axis.z() + axis.x() * sintheta ) * y() + ( costheta + ( 1 - costheta ) * axis.z() * axis.z() ) * z() ); } // sphere layout: center xyz, radius w template< size_t M, typename T > template< typename TT > inline vector< 3, T > vector< M, T >:: project_point_onto_sphere( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* ) const { const vector< 3, T >& _center = get_sub_vector< 3 >( 0 ); vector< 3, T > projected_point( point ); projected_point -= _center; projected_point.normalize(); projected_point *= w(); return _center + projected_point; } // sphere layout: center xyz, radius w template< size_t M, typename T > template< typename TT > inline T vector< M, T >:: distance_to_sphere( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* ) const { const vector< 3, T >& center_ = get_sub_vector< 3 >( 0 ); return ( point - center_ ).length() - w(); } template< size_t M, typename T > template< size_t N > void vector< M, T >::get_sub_vector( vector< N, T >& sub_v, size_t offset, typename enable_if< M >= N >::type* ) { assert( offset <= M - N ); sub_v = reinterpret_cast< vector< N, T >& >( *( begin() + offset ) ); } template< size_t M, typename T > template< size_t N > inline vector< N, T >& vector< M, T >::get_sub_vector( size_t offset, typename enable_if< M >= N >::type* ) { assert( offset <= M - N ); return reinterpret_cast< vector< N, T >& >( *( begin() + offset ) ); } template< size_t M, typename T > template< size_t N > inline const vector< N, T >& vector< M, T >::get_sub_vector( size_t offset, typename enable_if< M >= N >::type* ) const { assert( offset <= M - N ); return reinterpret_cast< const vector< N, T >& >( *( begin() + offset ) ); } // plane: normal xyz, distance w template< size_t M, typename T > template< typename TT > inline T vector< M, T >::distance_to_plane( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* ) const { const vector< 3, T >& normal = get_sub_vector< 3 >( 0 ); return normal.dot( point ) + w(); } // plane: normal xyz, distance w template< size_t M, typename T > template< typename TT > vector< 3, T > vector< M, T >::project_point_onto_plane( const vector< 3, TT >& point, typename enable_if< M == 4, TT >::type* ) const { const vector< 3, T >& normal = get_sub_vector< 3 >( 0 ); return point - ( normal * distance_to_plane( point ) ); } template< size_t M, typename T > bool vector< M, T >::operator==( const vector< M, T >& other ) const { return memcmp( array, other.array, sizeof( array )) == 0; } template< size_t M, typename T > bool vector< M, T >::operator!=( const vector< M, T >& other ) const { return ! this->operator==( other ); } template< size_t M, typename T > bool vector< M, T >:: equals( const vector< M, T >& other, T tolerance ) const { bool is_ok = true; for( size_t index = 0; is_ok && index < M; ++index ) { is_ok = fabs( at( index ) - other( index ) ) < tolerance; } return is_ok; } template< size_t M, typename T > bool vector< M, T >::operator<( const vector< M, T >& other ) const { for(size_t index = 0; index < M; ++index ) { if (at( index ) < other.at( index )) return true; if (other.at( index ) < at( index )) return false; } return false; } // to-homogenous-coordinates assignment operator // non-chainable because of sfinae template< size_t M, typename T > template< size_t N > typename enable_if< N == M - 1 >::type* vector< M, T >:: operator=( const vector< N, T >& source_ ) { std::copy( source_.begin(), source_.end(), begin() ); at( M - 1 ) = static_cast< T >( 1.0 ); return 0; } // from-homogenous-coordinates assignment operator // non-chainable because of sfinae template< size_t M, typename T > template< size_t N > typename enable_if< N == M + 1 >::type* vector< M, T >:: operator=( const vector< N, T >& source_ ) { const T w_reci = static_cast< T >( 1.0 ) / source_( M ); iterator it = begin(), it_end = end(); for( size_t index = 0; it != it_end; ++it, ++index ) { *it = source_( index ) * w_reci; } return 0; } template< size_t M, typename T > const vector< M, T >& vector< M, T >::operator=( const T* c_array ) { iter_set( c_array, c_array + M ); return *this; } template< size_t M, typename T > T vector< M, T >::operator=( T filler_value ) { for( size_t index = 0; index < M; ++index ) { at( index ) = filler_value; } return filler_value; } template< size_t M, typename T > const vector< M, T >& vector< M, T >::operator=( const vector< M, T >& other ) { if( this != &other ) memcpy( array, other.array, M * sizeof( T ) ); return *this; } // returns void to avoid 'silent' loss of precision when chaining template< size_t M, typename T > template< typename U > void vector< M, T >::operator=( const vector< M, U >& source_ ) { typedef typename vector< M, U >::const_iterator u_c_iter; u_c_iter it = source_.begin(), it_end = source_.end(); for( iterator my_it = begin(); it != it_end; ++it, ++my_it ) { *my_it = static_cast< T >( *it ); } } template< size_t M, typename T > template< typename input_iterator_t > void vector< M, T >::iter_set( input_iterator_t begin_, input_iterator_t end_ ) { input_iterator_t in_it = begin_; iterator it = begin(), it_end = end(); for( ; it != it_end && in_it != end_; ++it, ++in_it ) { (*it) = static_cast< T >( *in_it ); } } template< size_t M, typename T > void vector< M, T >::clamp( const T& min, const T& max ) { for( size_t i = 0; i < M; ++i ) { if( array[i] < min ) array[i] = min; if( array[i] > max ) array[i] = max; } } template< size_t M, typename T > template< typename TT > void vector< M, T >::scale_to( vector< M, TT >& result_, T min_value, T max_value ) const { T range = max_value-min_value; T half_range = range * 0.5; T scale = ( 1.0 / range ) * static_cast< T >( std::numeric_limits< TT >::max() ); for( size_t index = 0; index < M; ++index ) { result_.at( index ) = static_cast< TT >( ( at( index ) + half_range ) * scale ); } } template< size_t M, typename T > inline size_t vector< M, T >::size() { return M; } template< size_t M, typename T > size_t vector< M, T >::find_min_index() const { return std::min_element( begin(), end() ) - begin(); } template< size_t M, typename T > size_t vector< M, T >::find_max_index() const { return std::max_element( begin(), end() ) - begin(); } template< size_t M, typename T > size_t vector< M, T >::find_abs_min_index() const { return std::min_element( begin(), end(), vmml::math::abs_less< T >() ) - begin(); } template< size_t M, typename T > size_t vector< M, T >::find_abs_max_index() const { return std::max_element( begin(), end(), vmml::math::abs_greater< T >() ) - begin(); } template< size_t M, typename T > T& vector< M, T >::find_min() { return *std::min_element( begin(), end() ); } template< size_t M, typename T > const T& vector< M, T >::find_min() const { return *std::min_element( begin(), end() ); } template< size_t M, typename T > T& vector< M, T >::find_max() { return *std::max_element( begin(), end() ); } template< size_t M, typename T > const T& vector< M, T >::find_max() const { return *std::max_element( begin(), end() ); } template< size_t M, typename T > inline typename vector< M, T >::iterator vector< M, T >::begin() { return array; } template< size_t M, typename T > inline typename vector< M, T >::iterator vector< M, T >::end() { return array + M; ; } template< size_t M, typename T > inline typename vector< M, T >::const_iterator vector< M, T >::begin() const { return array; } template< size_t M, typename T > inline typename vector< M, T >::const_iterator vector< M, T >::end() const { return array + M; ; } template< size_t M, typename T > inline typename vector< M, T >::reverse_iterator vector< M, T >::rbegin() { return array + M - 1; } template< size_t M, typename T > inline typename vector< M, T >::reverse_iterator vector< M, T >::rend() { return array - 1; } template< size_t M, typename T > inline typename vector< M, T >::const_reverse_iterator vector< M, T >::rbegin() const { return array + M - 1; } template< size_t M, typename T > inline typename vector< M, T >::const_reverse_iterator vector< M, T >::rend() const { return array - 1; } template< size_t M, typename T > bool vector< M, T >::is_unit_vector() const { const_iterator it = begin(), it_end = end(); bool one = false; for( ; it != it_end; ++it ) { if ( *it == 1.0 ) { if ( one ) return false; one = true; } else if ( *it != 0.0 ) { return false; } } return one; } template< size_t M, typename T > void vector< M, T >::perturb( T perturbation ) { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { (*it) += ( rand() & 1u ) ? perturbation : -perturbation; } } template< size_t M, typename T > void vector< M, T >::sqrt_elementwise() { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { (*it) = sqrt(*it); } } template< size_t M, typename T > void vector< M, T >::reciprocal() { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { (*it) = static_cast< T >( 1.0 ) / (*it); } } template< size_t M, typename T > void vector< M, T >::reciprocal_safe() { for( iterator it = begin(), it_end = end(); it != it_end; ++it ) { T& v = *it; if ( v == static_cast< T >( 0 ) ) v = std::numeric_limits< T >::max(); else v = static_cast< T >( 1.0 ) / v; } } template< size_t M, typename T > template< typename TT > void vector< M, T >::cast_from( const vector< M, TT >& other ) { typedef vmml::vector< M, TT > vector_tt_type ; typedef typename vector_tt_type::const_iterator tt_const_iterator; iterator it = begin(), it_end = end(); tt_const_iterator other_it = other.begin(); for( ; it != it_end; ++it, ++other_it ) { *it = static_cast< T >( *other_it ); } } template< size_t M, typename T > size_t vector< M, T >::nnz() const { size_t counter = 0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it) { if ( *it != 0 ) { ++counter; } } return counter; } template< size_t M, typename T > double vector< M, T >::norm( ) const { double norm_v = 0.0; const_iterator it = begin(), it_end = end(); for( ; it != it_end; ++it ) { norm_v += *it * *it; } return sqrt(norm_v); } template< size_t M, typename T > void vector< M, T >::set_random( int seed ) { if ( seed >= 0 ) srand( seed ); double fillValue = 0.0f; for( size_t i = 0; i < M; ++i ) { fillValue = rand(); fillValue /= RAND_MAX; at( i ) = -1.0 + 2.0 * static_cast< double >( fillValue ) ; } } } // namespace vmml #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/vector_traits.hpp000066400000000000000000000017651231531733200257100ustar00rootroot00000000000000// Copyright (c) 2010 Daniel Pfeifer #ifndef __VMML_VECTOR_TRAITS_HPP__ #define __VMML_VECTOR_TRAITS_HPP__ #include #include namespace boost { namespace la { template struct vector_traits > { typedef vmml::vector vector_type; static const int dim = M; typedef T scalar_type; template static scalar_type r(const vector_type& v) { BOOST_STATIC_ASSERT(I >= 0); BOOST_STATIC_ASSERT(I < dim); return v.array[I]; } template static scalar_type& w(vector_type& v) { BOOST_STATIC_ASSERT(I >= 0); BOOST_STATIC_ASSERT(I < dim); return v.array[I]; } static scalar_type ir(int i, const vector_type& v) { BOOST_ASSERT(i >= 0); BOOST_ASSERT(i < dim); return v.array[i]; } static scalar_type& iw(int i, vector_type& v) { BOOST_ASSERT(i >= 0); BOOST_ASSERT(i < dim); return v.array[i]; } }; } // namespace la } // namespace boost #endif /* VMML_VECTOR_TRAITS_HPP */ repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/version.hpp000066400000000000000000000045221231531733200244770ustar00rootroot00000000000000 /** * VMMLib - Vector & Matrix Math Lib * * @author Stefan Eilemann * @license revised BSD license, check LICENSE */ #ifndef VMMLIB_VERSION_H #define VMMLIB_VERSION_H namespace vmml { // vmmlib version macros and functions /** The current major version. @version 1.5 */ # define VMMLIB_VERSION_MAJOR @VERSION_MAJOR@ /** The current minor version. @version 1.5 */ # define VMMLIB_VERSION_MINOR @VERSION_MINOR@ /** The current patch level. @version 1.5 */ # define VMMLIB_VERSION_PATCH @VERSION_PATCH@ /** True if the current version is newer than the given one. @version 1.5 */ # define VMMLIB_VERSION_GT( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR>MAJOR) || \ (VMMLIB_VERSION_MAJOR==MAJOR && \ (VMMLIB_VERSION_MINOR>MINOR || \ (VMMLIB_VERSION_MINOR==MINOR && VMMLIB_VERSION_PATCH>PATCH)))) /** True if the current version is equal or newer to the given. @version 1.5 */ # define VMMLIB_VERSION_GE( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR>MAJOR) || \ (VMMLIB_VERSION_MAJOR==MAJOR && \ (VMMLIB_VERSION_MINOR>MINOR || \ (VMMLIB_VERSION_MINOR==MINOR && VMMLIB_VERSION_PATCH>=PATCH)))) /** True if the current version is older than the given one. @version 1.5 */ # define VMMLIB_VERSION_LT( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR * @license revised BSD license, check LICENSE */ #ifndef VMMLIB_VERSION_H #define VMMLIB_VERSION_H namespace vmml { // vmmlib version macros and functions /** The current major version. @version 1.5 */ # define VMMLIB_VERSION_MAJOR @VERSION_MAJOR@ /** The current minor version. @version 1.5 */ # define VMMLIB_VERSION_MINOR @VERSION_MINOR@ /** The current patch level. @version 1.5 */ # define VMMLIB_VERSION_PATCH @VERSION_PATCH@ /** True if the current version is newer than the given one. @version 1.5 */ # define VMMLIB_VERSION_GT( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR>MAJOR) || \ (VMMLIB_VERSION_MAJOR==MAJOR && \ (VMMLIB_VERSION_MINOR>MINOR || \ (VMMLIB_VERSION_MINOR==MINOR && VMMLIB_VERSION_PATCH>PATCH)))) /** True if the current version is equal or newer to the given. @version 1.5 */ # define VMMLIB_VERSION_GE( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR>MAJOR) || \ (VMMLIB_VERSION_MAJOR==MAJOR && \ (VMMLIB_VERSION_MINOR>MINOR || \ (VMMLIB_VERSION_MINOR==MINOR && VMMLIB_VERSION_PATCH>=PATCH)))) /** True if the current version is older than the given one. @version 1.5 */ # define VMMLIB_VERSION_LT( MAJOR, MINOR, PATCH ) \ ( (VMMLIB_VERSION_MAJOR #include #include #include #include #include #include #include #endif repsnapper-2.3.2a5/libraries/vmmlib/include/vmmlib/vmmlib_config.hpp000066400000000000000000000022421231531733200256220ustar00rootroot00000000000000#ifndef __VMML__VMMLIB_CONFIG__HPP__ #define __VMML__VMMLIB_CONFIG__HPP__ // #define VMMLIB_NO_SFINAE #ifdef _MSC_VER # ifndef HAVE_SSIZE_T # include typedef SSIZE_T ssize_t; # define HAVE_SSIZE_T # endif #endif // enabling this switch will have the following effect: // operator T* will not be compiled, but for vectors, // operator[] will instead be used. This means you can // use vec[2] as before, but things like glVertex3fv( vec ) // will not work anymore. //#define VMMLIB_NO_CONVERSION_OPERATORS //#define VMMLIB_DONT_FORCE_ALIGNMENT #ifndef VMMLIB_CUSTOM_CONFIG # ifndef NDEBUG # define VMMLIB_SAFE_ACCESSORS # endif # define VMMLIB_THROW_EXCEPTIONS # ifdef VMMLIB_DONT_FORCE_ALIGNMENT # define VMMLIB_ALIGN( var ) var # else # ifdef __GNUC__ # define VMMLIB_ALIGN( var ) var __attribute__((aligned(16))) # elif defined WIN32 # define VMMLIB_ALIGN( var ) __declspec (align (16)) var # else # error "Alignment macro undefined" # endif # endif #else // we define VMMLIB_ALIGN in case it's not defined in the custom config # ifndef VMMLIB_ALIGN # define VMMLIB_ALIGN( var ) var # endif #endif #endif repsnapper-2.3.2a5/libraries/vmmlib/pack_release.sh000077500000000000000000000024141231531733200223430ustar00rootroot00000000000000#!/bin/bash # # @author Susanne Suter if [ -z "$1" ]; then echo "usage: ./"$0" [release-tag]"; exit 1; fi export EXCLUDING_PATTERN="*.sw* *.svn* *.DS_Store* *.o*" export INCLUDE_DIR="include/vmmlib" export TESTS_DIR="tests" export README_FILES="README AUTHORS LICENSE.txt ACKNOWLEDGEMENTS" export PROJECT_FILES="vmmlib.xcodeproj Makefile Makefile.atlas CMakeLists.txt" export RELEASE_NUM=$1 echo "finished init" ################ # ZIP CREATION # ################ zip_release() { # zipping the include and test files excluding VIM # swap files and SVN directories zip -x ${EXCLUDING_PATTERN} \ -r ../vmmlib-${RELEASE_NUM}.zip \ ${INCLUDE_DIR} \ ${TESTS_DIR} \ ${README_FILES} \ ${PROJECT_FILES} } ################ # TGZ CREATION # ################ tgz_release() { # tar gzipping the include and test files excluding VIM # swap files and SVN directories tar cvfz \ ../vmmlib-${RELEASE_NUM}.tgz \ --exclude="*.o" \ --exclude="*.DS_Store" \ --exclude="*.svn*" \ --transform "s|^|vmmlib-${RELEASE_NUM}/|" \ ${INCLUDE_DIR} \ ${TESTS_DIR} \ ${README_FILES} \ ${PROJECT_FILES} } ########## # CALLS ## ########## zip_release echo "finished zipping" tgz_release echo "finished tgzipping" repsnapper-2.3.2a5/licenses/000077500000000000000000000000001231531733200157305ustar00rootroot00000000000000repsnapper-2.3.2a5/licenses/BSL-1.0.txt000066400000000000000000000024721231531733200174120ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. repsnapper-2.3.2a5/licenses/GPL-2.0.txt000066400000000000000000000432541231531733200174200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. repsnapper-2.3.2a5/licenses/LGPL-2.0.txt000066400000000000000000000614471231531733200175400ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! repsnapper-2.3.2a5/licenses/MIT.txt000066400000000000000000000020001231531733200171120ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. repsnapper-2.3.2a5/licenses/vmmlib-license.txt000066400000000000000000000030211231531733200213730ustar00rootroot00000000000000Copyright (c) 2006, Visualization and Multimedia Lab, University of Zurich All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Visualization and Multimedia Lab, University of Zurich nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. repsnapper-2.3.2a5/licensing.txt000066400000000000000000000015641231531733200166450ustar00rootroot00000000000000RepSnapper is copyright Kulitorum and others, and is licensed under the terms of the GPL version 2.0 (see the file licenses/GPL-2.0.txt) Segments of the code fall under other licenses, as detailed below. VMMLib is licensed under a revised 3-clause BSD license as detailed in the file licenses/vmmlib-license.txt arcball.cpp and arcball.h are (C) 1999-2003 Tatewake.com and licensed under the MIT license as noted in the file licenses/MIT.txt Several functions in slicer/geometry.cpp are licensed as follows: Copyright 2001 softSurfer, 2012-13 Dan Sunday This code may be freely used, distributed and modified for any purpose providing that this copyright notice is included with it. SoftSurfer makes no warranty for this code, and cannot be held liable for any real or imagined damage resulting from its use. Users of this code must verify correctness for their application. repsnapper-2.3.2a5/m4/000077500000000000000000000000001231531733200144435ustar00rootroot00000000000000repsnapper-2.3.2a5/m4/.gitignore000066400000000000000000000000001231531733200164210ustar00rootroot00000000000000repsnapper-2.3.2a5/po/000077500000000000000000000000001231531733200145415ustar00rootroot00000000000000repsnapper-2.3.2a5/po/.gitignore000066400000000000000000000000171231531733200165270ustar00rootroot00000000000000repsnapper.pot repsnapper-2.3.2a5/po/LINGUAS000066400000000000000000000000761231531733200155710ustar00rootroot00000000000000# TRANSLATORS: # add your translation here ... en_GB de_DE ar repsnapper-2.3.2a5/po/POTFILES.in000066400000000000000000000015441231531733200163220ustar00rootroot00000000000000# # List of source files containing translatable strings. # Please keep this file sorted alphabetically. # [encoding: UTF-8] repsnapper.desktop.in src/arcball.cpp src/files.cpp src/flatshape.cpp src/model.cpp src/model_slice.cpp src/objtree.h src/objtree.cpp src/platform.cpp src/render.cpp src/repsnapper.cpp src/settings.cpp src/settings.h src/shape.cpp src/triangle.cpp src/gcode/command.cpp src/gcode/gcode.cpp src/gcode/gcodestate.cpp src/ui/connectview.cpp src/ui/filechooser.cpp src/ui/progress.cpp src/ui/widgets.cpp src/ui/view.cpp src/printer/printer.cpp src/printer/printer_serial.cpp src/printer/threaded_printer_serial.cpp src/slicer/clipping.cpp src/slicer/infill.cpp src/slicer/infill.h src/slicer/layer.cpp src/slicer/poly.cpp src/slicer/printlines.cpp src/slicer/printlines.h src/slicer/printlines_antiooze.cpp [type: gettext/glade]src/repsnapper.ui repsnapper-2.3.2a5/po/ar.po000066400000000000000000001245411231531733200155120ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Ibrahim Saed , 2014. #: ../src/slicer/printlines.h:33 msgid "" msgstr "" "Project-Id-Version: repsnapper 1.9.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-16 04:58+0200\n" "PO-Revision-Date: 2014-03-07 14:06+0200\n" "Last-Translator: Ibrahim Saed \n" "Language-Team: arabeyes.org\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Virtaal 0.7.1\n" #: ../repsnapper.desktop.in.h:1 msgid "Controls your 3D plastic printer" msgstr "للتحكم بطابعة البلاستيك ثلاثية الأبعاد" #: ../repsnapper.desktop.in.h:2 msgid "RepRap control software" msgstr "برنامج التحكم برِب راب" #: ../repsnapper.desktop.in.h:3 msgid "repsnapper" msgstr "رِب سنابر" #: ../src/files.cpp:117 msgid "Unrecognized file - " msgstr "ملف غير مُعرّف - " #: ../src/files.cpp:118 msgid "Known extensions: " msgstr "الامتدادات المعروفة: " #: ../src/files.cpp:148 msgid "Error: Unable to open file - " msgstr "خطأ: تعذّر فتح الملف - " #: ../src/files.cpp:184 ../src/files.cpp:264 ../src/files.cpp:652 msgid "Error: Unable to open stl file - " msgstr "خطأ: تعذّر فتح ملف stl - " #: ../src/files.cpp:230 msgid "Unexpected EOF reading STL file - " msgstr "" #. cerr << "loading ascii " << endl; #. cerr << " locale " << std::locale().name() << endl; #: ../src/files.cpp:305 msgid "Unnamed" msgstr "غير مُسمّى" #: ../src/files.cpp:365 msgid "Error: Facet keyword not found in STL text!" msgstr "" #: ../src/files.cpp:374 msgid "Error: normal keyword not found in STL text!" msgstr "" #: ../src/files.cpp:391 msgid "Error: Outer/Loop keywords not found!" msgstr "" #: ../src/files.cpp:405 msgid "Error: Vertex keyword not found" msgstr "" #: ../src/files.cpp:415 msgid "Error: Endloop or endfacet keyword not found" msgstr "" #: ../src/files.cpp:443 msgid "Error: Unable to open vrml file - " msgstr "خطأ: تعذّر فتح ملف vrml - " #: ../src/flatshape.cpp:254 msgid "Split Polygons" msgstr "فصل المضلعات" #: ../src/model.cpp:87 msgid "not yet implemented\n" msgstr "" #: ../src/model.cpp:312 msgid "Reading GCode" msgstr "يقرأ الجي كود" #. display whole layer if flat shapes #. if (shapes.back()->dimensions() == 2) #. gcode.layerchanges.push_back(0); #: ../src/model.cpp:314 ../src/model_slice.cpp:899 ../src/model_slice.cpp:978 #: ../src/model_slice.cpp:1000 ../src/ui/view.cpp:1988 #: ../src/printer/printer.cpp:664 ../src/printer/printer_iochannel.cpp:454 #: ../src/printer/printer_libreprap.cpp:386 msgid "Done" msgstr "تم" #: ../src/model.cpp:587 msgid "_upper" msgstr "_العلوي" #: ../src/model.cpp:588 msgid "_lower" msgstr "_السفلي" #: ../src/model_slice.cpp:243 msgid "Cleanup" msgstr "" #: ../src/model_slice.cpp:318 msgid "Slicing" msgstr "" #. not bottom layer #: ../src/model_slice.cpp:470 msgid "Skins" msgstr "" #: ../src/model_slice.cpp:500 msgid "Find Uncovered" msgstr "" #: ../src/model_slice.cpp:565 msgid "Uncovered Shells" msgstr "" #: ../src/model_slice.cpp:601 msgid "Merging Full Polygons" msgstr "" #: ../src/model_slice.cpp:660 ../src/slicer/printlines.h:34 msgid "Support" msgstr "التدعيم" #: ../src/model_slice.cpp:719 ../src/repsnapper.ui.h:242 msgid "Shells" msgstr "القشور" #: ../src/model_slice.cpp:755 ../src/slicer/printlines.h:33 #: ../src/repsnapper.ui.h:134 msgid "Infill" msgstr "الملء" #: ../src/model_slice.cpp:847 msgid "Making Lines" msgstr "إنشاء الخطوط" #: ../src/model_slice.cpp:849 msgid "Millimeters" msgstr "مليمترات" #: ../src/model_slice.cpp:850 msgid "Absolute Pos" msgstr "" #: ../src/model_slice.cpp:852 msgid "Relative E Code" msgstr "" #: ../src/model_slice.cpp:854 msgid "Absolute E Code" msgstr "" #: ../src/model_slice.cpp:905 msgid "Time Estimation: " msgstr "الوقت المُقدّر: " #: ../src/model_slice.cpp:906 ../src/model_slice.cpp:915 msgid "h" msgstr "س" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 msgid "m" msgstr "د" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 #: ../src/ui/progress.cpp:97 msgid "s" msgstr "ث" #: ../src/model_slice.cpp:914 msgid " / GCode Estimation: " msgstr " / الوقت المُقدّر لإنتاج الجي كود: " #: ../src/model_slice.cpp:920 msgid " - total extruded: " msgstr " - إجمالي المبثوق: " #: ../src/model_slice.cpp:984 msgid "Saving Files" msgstr "حفظ الملفات" #: ../src/objtree.h:41 msgid "Unnamed object" msgstr "جسم غير مُسمّى" #: ../src/objtree.cpp:65 msgid "" "Cannot add a 3-dimensional Shape to a 2-dimensional Model and vice versa" msgstr "لا يمكن إضافة شكل ثلاث الأبعاد إلى نموذج ثنائي الأبعاد والعكس" #: ../src/objtree.cpp:138 msgid "Unsaved file" msgstr "ملف غير محفوظ" #: ../src/render.cpp:72 msgid "failed to init gl area\n" msgstr "" #: ../src/repsnapper.cpp:57 ../src/repsnapper.cpp:62 #, c-format msgid "Version: %s\n" msgstr "الإصدارة: %s\n" #: ../src/repsnapper.cpp:63 #, c-format msgid "" "Usage: repsnapper [OPTION]... [FILE]...\n" "Start reprap control software and load [FILES]\n" "Options:\n" " -t, --no-gui act as a head-less renderer\n" " -i, --input [file] read input Model [file]\n" " -b, --binary [file] batch convert input file to binary STL\n" " -o, --output [file] if not head-less (-t),\n" " enter non-printing GUI mode\n" " only able to output gcode to [file]\n" " --svg [file] slice to SVG file\n" " --ssvg [file] slice to single layer SVG files [file]NNNN.svg\n" " -s, --settings [file] read render settings [file]\n" " -h, --help show this help\n" "\n" "Report bugs to #repsnapper, irc.freenode.net\n" "\n" msgstr "" #: ../src/repsnapper.cpp:192 msgid "Couldn't create user config directory!" msgstr "" #: ../src/repsnapper.cpp:213 ../src/repsnapper.cpp:236 msgid "Couldn't find global configuration!" msgstr "" #: ../src/repsnapper.cpp:215 ../src/repsnapper.cpp:238 msgid "It is likely that repsnapper is not correctly installed." msgstr "على ما يبدوا أن رِب سنابر لم يتم تثبيته بشكل سليم." #. Fall back to global config #: ../src/repsnapper.cpp:230 msgid "Unable to create user config" msgstr "" #: ../src/repsnapper.cpp:232 msgid "" "\n" "Falling back to global config. Settings will not be saved." msgstr "" #: ../src/repsnapper.cpp:247 msgid "Failed to locate config" msgstr "" #: ../src/repsnapper.cpp:307 msgid "No output file given" msgstr "" #: ../src/settings.cpp:683 ../src/settings.cpp:1046 msgid "corrupt setting type" msgstr "نوع إعدادات معطوب" #: ../src/settings.cpp:700 msgid "Failed to load settings from file '" msgstr "فشل في تحميل الإعدادات من ملف '" #: ../src/settings.cpp:704 msgid "Exception " msgstr "استثناء " #: ../src/settings.cpp:704 msgid " loading settings from file '" msgstr " تحميل الإعدادات من ملف '" #: ../src/settings.cpp:708 msgid "Parsing config from '" msgstr "" #: ../src/settings.cpp:892 ../src/settings.cpp:987 msgid "Missing boolean config item " msgstr "" #: ../src/settings.cpp:903 ../src/settings.cpp:932 ../src/settings.cpp:1036 #: ../src/settings.cpp:1366 msgid "Missing user interface item " msgstr "" #: ../src/settings.cpp:941 msgid "corrupt setting type\n" msgstr "نوع إعدادات معطوب\n" #: ../src/settings.cpp:1000 msgid "Missing GUI element " msgstr "" #. PlaceOnPlatform(); #: ../src/shape.cpp:59 msgid "Shape has volume " msgstr "الشكل يحوز حجما قدره " #: ../src/shape.cpp:59 msgid " mm^3 and " msgstr " مم^3 ويحتوي " #: ../src/shape.cpp:60 msgid " triangles" msgstr " مثلثا(ت)" #: ../src/shape.cpp:107 msgid "Split Shapes" msgstr "فصل الأشكال" #: ../src/shape.cpp:113 msgid "Split: Sorting Triangles ..." msgstr "الفصل: ترتيب المثلثات ..." #: ../src/shape.cpp:147 msgid "Split: Building shapes ..." msgstr "الفصل: بناء الأشكال ..." #: ../src/shape.cpp:158 msgid "Shape " msgstr "شكل " #. copy #: ../src/gcode/command.cpp:336 msgid " xy part" msgstr "" #. copy #: ../src/gcode/command.cpp:338 msgid " z part" msgstr "" #: ../src/gcode/command.cpp:377 msgid " Z-Change" msgstr "" #: ../src/gcode/command.cpp:388 msgid " Move Only" msgstr " انتقال فقط" #: ../src/gcode/command.cpp:405 msgid " Select Extruder" msgstr " اختيار الباثق" #: ../src/gcode/command.cpp:409 msgid " Reset Extrusion" msgstr "" #: ../src/gcode/gcode.cpp:174 msgid "Loading GCode" msgstr "تحميل الجي كود" #: ../src/gcode/gcode.cpp:648 msgid "Collecting GCode" msgstr "تجميع الجي كود" #. pure extrusions #: ../src/gcode/gcodestate.cpp:215 msgid "Extrusion only " msgstr "" #: ../src/gcode/gcodestate.cpp:220 msgid "Absolute Extrusion" msgstr "" #: ../src/ui/connectview.cpp:39 msgid "Disconnecting..." msgstr "يقطع الاتصال..." #: ../src/ui/connectview.cpp:45 msgid "Connect" msgstr "اتصل" #: ../src/ui/connectview.cpp:51 msgid "Connecting..." msgstr "يتصل..." #: ../src/ui/connectview.cpp:57 msgid "Disconnect" msgstr "اقطع الاتصال" #: ../src/ui/connectview.cpp:111 msgid "Port:" msgstr "المنفذ:" #. file patterns #: ../src/ui/filechooser.cpp:41 msgid "All Files" msgstr "كل الملفات" #: ../src/ui/filechooser.cpp:44 msgid "Models" msgstr "نماذج" #: ../src/ui/filechooser.cpp:54 ../src/ui/filechooser.cpp:101 #: ../src/repsnapper.ui.h:124 msgid "GCode" msgstr "جي كود" #: ../src/ui/filechooser.cpp:60 ../src/ui/filechooser.cpp:107 msgid "Settings" msgstr "الإعدادات" #: ../src/ui/filechooser.cpp:112 msgid "SVG" msgstr "SVG" #: ../src/ui/filechooser.cpp:118 ../src/repsnapper.ui.h:177 msgid "Model" msgstr "النموذج" #: ../src/ui/filechooser.cpp:133 msgid "Load" msgstr "تحميل" #: ../src/ui/filechooser.cpp:147 msgid "Save" msgstr "حفظ" #. seconds #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " done in " msgstr " اكتمل في " #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " seconds" msgstr " ثوان" #: ../src/ui/progress.cpp:90 ../src/ui/progress.cpp:91 msgid "h " msgstr "س " #: ../src/ui/progress.cpp:95 msgid "m " msgstr "د " #: ../src/ui/widgets.cpp:142 msgid "Nozzle:" msgstr "الفوهة:" #: ../src/ui/widgets.cpp:142 msgid "Bed:" msgstr "المنصة:" #: ../src/ui/widgets.cpp:146 msgid "-- °C" msgstr "-- °م" #. add(*manage (new Gtk::Label(_("°C")))); #: ../src/ui/widgets.cpp:150 msgid "Target:" msgstr "الهدف:" #: ../src/ui/widgets.cpp:166 ../src/ui/widgets.cpp:187 msgid "Off" msgstr "" #: ../src/ui/widgets.cpp:185 msgid "On" msgstr "" #: ../src/ui/widgets.cpp:265 msgid "Home" msgstr "" #: ../src/ui/view.cpp:113 msgid "Complete print before converting" msgstr "أكمل الطباعة قبل التحويل" #: ../src/ui/view.cpp:114 msgid "Converting to GCode while printing will abort the print" msgstr "التحويل إلى جي كود أثناء الطباعة سيؤدي لإحباط عملية الطباعة الحالية" #: ../src/ui/view.cpp:185 ../src/ui/view.cpp:274 msgid "Complete print before reading" msgstr "أكمل الطباعة قبل القراءة" #: ../src/ui/view.cpp:186 ../src/ui/view.cpp:275 msgid "Reading GCode while printing will abort the print" msgstr "قراءة الجي كود أثناء الطباعة سيؤدي لإحباط عملية الطباعة الحالية" #: ../src/ui/view.cpp:209 ../src/ui/view.cpp:236 ../src/ui/view.cpp:255 #: ../src/ui/view.cpp:653 msgid "Overwrite File?" msgstr "الكتابة على الملف؟" #: ../src/ui/view.cpp:326 msgid "Error reading UI description!!" msgstr "خطأ في قراءة وصف واجهة الاستخدام!!" #: ../src/ui/view.cpp:336 msgid "Couldn't find UI description!" msgstr "تعذّر إيجاد وصف واجهة الاستخدام!" #: ../src/ui/view.cpp:338 msgid "Check that repsnapper has been correctly installed." msgstr "تفقد ما إذا كان رِب سنابر قد تم تثبيته بشكل سليم." #: ../src/ui/view.cpp:349 msgid "Error loading UI!" msgstr "خطأ في تحميل واجهة الاستخدام!" #: ../src/ui/view.cpp:946 msgid "Reset Printer?" msgstr "إعادة إعداد الطابعة؟" #: ../src/ui/view.cpp:1370 msgid "Output File: " msgstr "ملف المخرجات: " #: ../src/printer/printer.cpp:378 ../src/printer/printer.cpp:425 #: ../src/printer/printer_iochannel.cpp:274 #: ../src/printer/printer_libreprap.cpp:213 msgid "Cannot disconnect" msgstr "لا يمكن قطع الاتصال" #: ../src/printer/printer.cpp:379 ../src/printer/printer.cpp:426 #: ../src/printer/printer_iochannel.cpp:275 #: ../src/printer/printer_libreprap.cpp:214 msgid "printer is printing" msgstr "الطابعة قيد الطباعة حاليا" #: ../src/printer/printer.cpp:416 ../src/printer/printer_libreprap.cpp:204 msgid "Failed to connect to device" msgstr "فشل في الاتصال بالجهاز" #: ../src/printer/printer.cpp:417 ../src/printer/printer_libreprap.cpp:205 msgid "an error occured while connecting" msgstr "حدث خطأ أثناء الاتصال" #: ../src/printer/printer.cpp:485 ../src/printer/printer_iochannel.cpp:329 #: ../src/printer/printer_libreprap.cpp:273 msgid "" "Already printing.\n" "Cannot start printing" msgstr "" "الطابعة قيد الطباعة حاليا.\n" "لا يمكن البدء بالطباعة" #: ../src/printer/printer.cpp:501 ../src/printer/printer.cpp:507 #: ../src/printer/printer_iochannel.cpp:339 #: ../src/printer/printer_libreprap.cpp:284 msgid "" "Not connected to printer.\n" "Cannot start printing" msgstr "" "غير متصل بالطابعة.\n" "لا يمكن البدء بالطباعة" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "Can't send command" msgstr "تعذّر إرسال الأمر" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "You must first connect to a device!" msgstr "ينبغي عليك الاتصال بالجهاز أولا!" #: ../src/printer/printer.cpp:644 ../src/printer/printer_libreprap.cpp:367 msgid "" "Not connected to printer.\n" "Cannot stop printing" msgstr "" "غير متصل بالطابعة.\n" "لا يمكن إيقاف الطباعة" #: ../src/printer/printer.cpp:660 ../src/printer/printer_iochannel.cpp:450 #: ../src/printer/printer_libreprap.cpp:382 msgid "Printing" msgstr "" #: ../src/printer/printer.cpp:747 ../src/printer/printer_libreprap.cpp:433 msgid "Error reading from device!" msgstr "خطأ في القراءة من الجهاز!" #: ../src/printer/printer.cpp:753 ../src/printer/printer_libreprap.cpp:439 msgid "Error writing to device!" msgstr "خطأ في الكتابة إلى الجهاز!" #: ../src/printer/printer2.cpp:29 msgid "Can't switch power while printing" msgstr "" #: ../src/printer/printer2.cpp:43 msgid "Can't go home while printing" msgstr "" #: ../src/printer/printer2.cpp:55 msgid "Home called with unknown axis" msgstr "" #: ../src/printer/printer2.cpp:65 ../src/printer/printer2.cpp:95 msgid "Can't move manually while printing" msgstr "" #: ../src/printer/printer2.cpp:85 msgid "Move called with unknown axis" msgstr "" #: ../src/printer/printer2.cpp:114 msgid "Goto called with unknown axis" msgstr "" #: ../src/printer/reprap_serial.cpp:172 msgid "Already Connected to Printer" msgstr "متصل حاليا بالطابعة" #: ../src/printer/reprap_serial.cpp:451 ../src/printer/reprap_serial.cpp:458 msgid "Printing error" msgstr "خطأ في الطباعة" #: ../src/printer/reprap_serial.cpp:451 msgid "Not connected" msgstr "غير متصل" #: ../src/printer/reprap_serial.cpp:458 msgid "Wrong line number" msgstr "" #: ../src/printer/reprap_serial.cpp:570 msgid "no reset on Windows" msgstr "" #. these are available for user selection (order must be same as types): #: ../src/slicer/infill.h:37 msgid "Parallel" msgstr "متوازي" #: ../src/slicer/infill.h:37 msgid "Zigzag" msgstr "متعرج" #: ../src/slicer/infill.h:37 msgid "Hexagons" msgstr "مسدسات" #: ../src/slicer/infill.h:37 ../src/repsnapper.ui.h:200 msgid "Polygons" msgstr "مضلعات" #: ../src/slicer/infill.h:37 msgid "Hilbert Curve" msgstr "منحنى هيلبرت" #: ../src/slicer/printlines.cpp:1665 msgid "Making GCode" msgstr "إنتاج الجي كود" #: ../src/slicer/printlines.h:33 msgid "Shell" msgstr "القشرة" #: ../src/slicer/printlines.h:33 msgid "Skin" msgstr "" #: ../src/slicer/printlines.h:34 ../src/repsnapper.ui.h:250 msgid "Skirt" msgstr "" #: ../src/slicer/printlines.h:34 msgid "Bridge" msgstr "" #: ../src/slicer/printlines.h:34 msgid "Command" msgstr "" #: ../src/repsnapper.ui.h:1 msgid " " msgstr " " #: ../src/repsnapper.ui.h:2 msgid " th Layer" msgstr "" #: ../src/repsnapper.ui.h:3 msgid "(C) 2008-2012 its contributors " msgstr "" #: ../src/repsnapper.ui.h:4 msgid "+" msgstr "+" #: ../src/repsnapper.ui.h:5 msgid "-" msgstr "-" #: ../src/repsnapper.ui.h:6 msgid "1" msgstr "1" #: ../src/repsnapper.ui.h:7 msgid "2" msgstr "2" #: ../src/repsnapper.ui.h:8 msgid "3" msgstr "3" #: ../src/repsnapper.ui.h:9 msgid "4" msgstr "4" #: ../src/repsnapper.ui.h:10 msgid "" msgstr "" #: ../src/repsnapper.ui.h:11 msgid "Acceleration" msgstr "التسريع" #: ../src/repsnapper.ui.h:12 msgid "Antiooze Retract" msgstr "" #: ../src/repsnapper.ui.h:13 msgid "Axis Moving Speeds (mm/sec)" msgstr "سرعات حركة المحور (مم/ث)" #: ../src/repsnapper.ui.h:14 msgid "Base" msgstr "القاعدة" #: ../src/repsnapper.ui.h:15 msgid "Comms Debug" msgstr "" #: ../src/repsnapper.ui.h:16 msgid "Cooling" msgstr "التبريد" #: ../src/repsnapper.ui.h:17 msgid "Custom Actions" msgstr "إجراءات مخصصة" #: ../src/repsnapper.ui.h:18 msgid "Debug GCode" msgstr "تنقيح الجي كود" #: ../src/repsnapper.ui.h:19 msgid "Debugging" msgstr "التنقيح" #: ../src/repsnapper.ui.h:20 msgid "Extruder Settings" msgstr "إعدادات الباثق" #: ../src/repsnapper.ui.h:21 msgid "First Layer(s)" msgstr "الطبقات الأولية" #: ../src/repsnapper.ui.h:22 msgid "GCode Postprocessor" msgstr "" #: ../src/repsnapper.ui.h:23 msgid "GCode Rendering" msgstr "تصيير الجي كود" #: ../src/repsnapper.ui.h:24 msgid "General" msgstr "عام" #: ../src/repsnapper.ui.h:25 msgid "Geometry" msgstr "" #: ../src/repsnapper.ui.h:26 msgid "Infill Debug" msgstr "تنقيح الملء" #: ../src/repsnapper.ui.h:27 msgid "Infill" msgstr "ملء المناطق المصمتة" #: ../src/repsnapper.ui.h:28 msgid "Interface" msgstr "الواجهة" #: ../src/repsnapper.ui.h:29 msgid "Layer Debug" msgstr "تنقيح الطبقات" #: ../src/repsnapper.ui.h:30 msgid "Lighting" msgstr "" #: ../src/repsnapper.ui.h:31 msgid "Object" msgstr "الجسم" #: ../src/repsnapper.ui.h:32 msgid "Output" msgstr "المخرجات" #: ../src/repsnapper.ui.h:33 msgid "Parameters" msgstr "المتغيرات" #: ../src/repsnapper.ui.h:34 msgid "Printer" msgstr "الطابعة" #: ../src/repsnapper.ui.h:35 msgid "Raft" msgstr "" #: ../src/repsnapper.ui.h:36 msgid "STL Rendering Colors" msgstr "" #: ../src/repsnapper.ui.h:37 msgid "Serial Communications" msgstr "" #: ../src/repsnapper.ui.h:38 msgid "Speeds (mm/sec)" msgstr "السرعات (مم/ث)" #: ../src/repsnapper.ui.h:39 msgid "Temperature" msgstr "درجة الحرارة" #: ../src/repsnapper.ui.h:40 msgid "?" msgstr "؟" #: ../src/repsnapper.ui.h:41 msgid "Acceleration Distance:" msgstr "مسافة التسريع:" #: ../src/repsnapper.ui.h:42 msgid "Adjust Luminance to Indicate Speed" msgstr "" #: ../src/repsnapper.ui.h:43 msgid "All" msgstr "الكل" #: ../src/repsnapper.ui.h:44 msgid "Alternate Infill Percent:" msgstr "" #: ../src/repsnapper.ui.h:45 msgid "Alternate Infill every " msgstr "" #: ../src/repsnapper.ui.h:46 msgid "Always done when using Support" msgstr "" #: ../src/repsnapper.ui.h:47 msgid "Amount (mm)" msgstr "القيمة (مم)" #: ../src/repsnapper.ui.h:48 msgid "Amount (mm):" msgstr "القيمة (مم):" #: ../src/repsnapper.ui.h:49 msgid "Arcs GCode (G2,G3)" msgstr "" #: ../src/repsnapper.ui.h:50 msgid "Around All Objects" msgstr "حول كل الأجسام" #: ../src/repsnapper.ui.h:51 msgid "Arrows" msgstr "الأسهم" #: ../src/repsnapper.ui.h:52 msgid "Auto" msgstr "آلي" #: ../src/repsnapper.ui.h:53 msgid "Axis Control" msgstr "التحكم في المحاور" #: ../src/repsnapper.ui.h:54 msgid "Base Rotation (°):" msgstr "دوران القاعدة (°):" #: ../src/repsnapper.ui.h:55 msgid "Border" msgstr "الحدود" #: ../src/repsnapper.ui.h:56 msgid "Borders" msgstr "الحدود" #: ../src/repsnapper.ui.h:57 msgid "Bounding Boxes" msgstr "صناديق التحويط" #: ../src/repsnapper.ui.h:58 msgid "Bridges Extrusion Factor:" msgstr "معامل البثق للجسور:" #: ../src/repsnapper.ui.h:59 msgid "Build Volume" msgstr "حجم البناء" #: ../src/repsnapper.ui.h:60 msgid "Calibrate mm as input" msgstr "" #: ../src/repsnapper.ui.h:61 msgid "Change image" msgstr "تغيير الصورة" #: ../src/repsnapper.ui.h:62 msgid "Choose Endpoints Colour" msgstr "اختر لون نقاط النهاية" #: ../src/repsnapper.ui.h:63 msgid "Choose Extrusion Colour" msgstr "اختر لون البثق" #: ../src/repsnapper.ui.h:64 msgid "Choose Head Movement Colour" msgstr "اختر لون حركة الرأس" #: ../src/repsnapper.ui.h:65 msgid "Choose Normals Colour" msgstr "اختر لون المتعامدات" #: ../src/repsnapper.ui.h:66 msgid "Choose Polygon Colour" msgstr "اختر لون المضلع" #: ../src/repsnapper.ui.h:67 msgid "Choose Wireframe Colour" msgstr "اختر لون خيوط الاطار" #: ../src/repsnapper.ui.h:68 msgid "Clear Now" msgstr "نظّف الآن" #: ../src/repsnapper.ui.h:69 msgid "Clear on Print Start" msgstr "تنظيف عند بدء الطباعة" #: ../src/repsnapper.ui.h:70 msgid "Clone Settings" msgstr "" #: ../src/repsnapper.ui.h:71 msgid "Colour" msgstr "اللون" #: ../src/repsnapper.ui.h:72 msgid "Communication" msgstr "الاتصال" #: ../src/repsnapper.ui.h:73 msgid "Copy" msgstr "نسخ" #: ../src/repsnapper.ui.h:74 msgid "Custom Button" msgstr "زرّ مُخصص" #: ../src/repsnapper.ui.h:75 msgid "D_uplicate" msgstr "ت_كرار" #: ../src/repsnapper.ui.h:76 msgid "Debug" msgstr "التنقيح" #: ../src/repsnapper.ui.h:77 msgid "Debug Arcs" msgstr "تنقيح الأقواس " #: ../src/repsnapper.ui.h:78 msgid "Debug Infill" msgstr "تنقيح الملء" #: ../src/repsnapper.ui.h:79 msgid "Decor" msgstr "التشطيب" #: ../src/repsnapper.ui.h:80 msgid "Decor Layers:" msgstr "طبقات التشطيب:" #: ../src/repsnapper.ui.h:81 msgid "Decoration:" msgstr "التشطيب:" #: ../src/repsnapper.ui.h:82 msgid "Delete" msgstr "حذف" #: ../src/repsnapper.ui.h:83 msgid "Dimensions" msgstr "الأبعاد" #: ../src/repsnapper.ui.h:84 msgid "Disable Bridges" msgstr "تعطيل الجسور" #: ../src/repsnapper.ui.h:85 msgid "Display" msgstr "عرض" #: ../src/repsnapper.ui.h:86 msgid "Display Colour" msgstr "لون العرض" #: ../src/repsnapper.ui.h:87 msgid "Display Settings" msgstr "إعدادات العرض" #: ../src/repsnapper.ui.h:88 msgid "Distance" msgstr "المسافة" #: ../src/repsnapper.ui.h:89 msgid "Distance (mm):" msgstr "المسافة (مم):" #: ../src/repsnapper.ui.h:90 msgid "Distance Between Lines" msgstr "المسافة بين الخطوط" #: ../src/repsnapper.ui.h:91 msgid "Divide" msgstr "تقسيم" #: ../src/repsnapper.ui.h:92 msgid "Draw GCode" msgstr "رسم الجي كود" #: ../src/repsnapper.ui.h:93 msgid "Draw Layers" msgstr "رسم الطبقات" #: ../src/repsnapper.ui.h:94 msgid "Draw Line Numbers" msgstr "رسم أرقام الخطوط" #: ../src/repsnapper.ui.h:95 msgid "Draw Polygon Numbers" msgstr "رسم أرقام المضلعات" #: ../src/repsnapper.ui.h:96 msgid "Draw Vertex Numbers" msgstr "رسم أرقام الرؤوس" #: ../src/repsnapper.ui.h:97 msgid "E max" msgstr "" #: ../src/repsnapper.ui.h:98 msgid "Echo" msgstr "" #: ../src/repsnapper.ui.h:99 msgid "Edit" msgstr "تعديل" #: ../src/repsnapper.ui.h:100 msgid "Enable Acceleration" msgstr "تفعيل التسريع" #: ../src/repsnapper.ui.h:101 msgid "Enable Antiooze Retract" msgstr "" #: ../src/repsnapper.ui.h:102 msgid "Enable Debug" msgstr "تفعيل التنقيح" #: ../src/repsnapper.ui.h:103 msgid "Enable Lights" msgstr "" #: ../src/repsnapper.ui.h:104 msgid "Enable Raft" msgstr "" #: ../src/repsnapper.ui.h:105 msgid "End" msgstr "النهاية" #: ../src/repsnapper.ui.h:106 msgid "Endpoints" msgstr "نقاط النهاية" #: ../src/repsnapper.ui.h:107 msgid "Errors/Warnings" msgstr "الأخطاء/التحذيرات" #: ../src/repsnapper.ui.h:108 msgid "Exit Repsnapper" msgstr "اخرج من رِب سنابر" #: ../src/repsnapper.ui.h:109 msgid "Extruded Lines" msgstr "خطوط المبثوق" #: ../src/repsnapper.ui.h:110 msgid "Extruders" msgstr "الباثقات" #: ../src/repsnapper.ui.h:111 msgid "Extrusion Factor:" msgstr "مُعامل البثق:" #: ../src/repsnapper.ui.h:112 msgid "Extrusion Multiplier" msgstr "" #: ../src/repsnapper.ui.h:113 msgid "Extrusion Ratio" msgstr "مُعدّل البثق" #: ../src/repsnapper.ui.h:114 msgid "Extrusion Width/Height Ratio" msgstr "مُعدّل عرض/ارتفاع البثق" #: ../src/repsnapper.ui.h:115 msgid "Fan Control" msgstr "تحكم المروحة" #: ../src/repsnapper.ui.h:116 msgid "Fan Enabled" msgstr "تفعيل المروحة" #: ../src/repsnapper.ui.h:117 msgid "Fan Level" msgstr "مستوى المروحة" #: ../src/repsnapper.ui.h:118 msgid "Filament Diameter" msgstr "قُطر خيوط الطباعة" #: ../src/repsnapper.ui.h:119 msgid "Files" msgstr "الملفات" #: ../src/repsnapper.ui.h:120 msgid "Fill Layer Areas" msgstr "" #: ../src/repsnapper.ui.h:121 msgid "Fill Skirt Area" msgstr "" #: ../src/repsnapper.ui.h:122 msgid "From/Single:" msgstr "من/منفرد:" #: ../src/repsnapper.ui.h:123 msgid "Fullscreen" msgstr "ملء الشاشة" #: ../src/repsnapper.ui.h:125 msgid "GCode Letter" msgstr "حرف الجي كود" #: ../src/repsnapper.ui.h:126 msgid "GCode when Printing" msgstr "جي كود عند الطباعة" #: ../src/repsnapper.ui.h:127 msgid "Generate _GCode" msgstr "إنتاج ال_جي كود" #: ../src/repsnapper.ui.h:128 msgid "Hardware Settings" msgstr "إعدادات العتاد" #: ../src/repsnapper.ui.h:129 msgid "Height (mm):" msgstr "الارتفاع (مم):" #: ../src/repsnapper.ui.h:130 msgid "Height:" msgstr "الارتفاع:" #: ../src/repsnapper.ui.h:131 msgid "Highlight Strength" msgstr "" #: ../src/repsnapper.ui.h:132 msgid "Hollow" msgstr "تجويف" #: ../src/repsnapper.ui.h:133 msgid "Home All" msgstr "" #: ../src/repsnapper.ui.h:136 #, no-c-format msgid "Infill %" msgstr "الملء %" #: ../src/repsnapper.ui.h:137 msgid "Infill Distance:" msgstr "مسافة الملء:" #: ../src/repsnapper.ui.h:138 msgid "Infill Overlap:" msgstr "تداخل الملء:" #: ../src/repsnapper.ui.h:139 msgid "Invert Normals" msgstr "عكس المتعامدات" #: ../src/repsnapper.ui.h:140 msgid "Kick" msgstr "" #: ../src/repsnapper.ui.h:141 msgid "LGPLv2+, GPLv2+, and other licenses, see licenses.txt" msgstr "LGPLv2+ و GPLv2+ وترخيصات أخرى، أنظر licenses.txt" #: ../src/repsnapper.ui.h:142 msgid "Larger Than Object (mm)" msgstr "أكبر من الجسم (مم)" #: ../src/repsnapper.ui.h:143 msgid "Layer Height:" msgstr "ارتفاع الطبقة:" #: ../src/repsnapper.ui.h:144 msgid "Layer Preview" msgstr "استعراض الطبقة" #: ../src/repsnapper.ui.h:145 msgid "Length" msgstr "الطول" #: ../src/repsnapper.ui.h:146 msgid "Length (mm)" msgstr "الطول (مم)" #: ../src/repsnapper.ui.h:147 msgid "Lift Z on all moves" msgstr "" #: ../src/repsnapper.ui.h:148 msgid "Load GCode" msgstr "تحميل الجي كود" #: ../src/repsnapper.ui.h:149 msgid "Load Model" msgstr "تحميل نموذج" #: ../src/repsnapper.ui.h:150 msgid "Load STL" msgstr "تحميل STL" #: ../src/repsnapper.ui.h:151 msgid "Load Settings" msgstr "تحميل إعدادات" #: ../src/repsnapper.ui.h:152 msgid "Load _GCode" msgstr "تحميل _جي كود" #: ../src/repsnapper.ui.h:153 msgid "Load _STL" msgstr "تحميل _STL" #: ../src/repsnapper.ui.h:154 msgid "Load a file of control codes" msgstr "تحميل ملف أكواد التحكم" #: ../src/repsnapper.ui.h:155 msgid "Load an STL file" msgstr "تحميل ملف STL" #: ../src/repsnapper.ui.h:156 msgid "Load application settings profile" msgstr "" #: ../src/repsnapper.ui.h:157 msgid "Logging" msgstr "تسجيل" #: ../src/repsnapper.ui.h:158 msgid "Logs" msgstr "السجلات" #: ../src/repsnapper.ui.h:159 msgid "Make enough solid layers to reach minimum thickness (mm)" msgstr "صُنع طبقات كافية للوصول إلى أقل سماكة (مم)" #: ../src/repsnapper.ui.h:160 msgid "Max" msgstr "الأكبر" #: ../src/repsnapper.ui.h:161 msgid "Max. Angles:" msgstr "أكبر زاوية:" #: ../src/repsnapper.ui.h:162 msgid "Max. Overhang Speed (mm/sec):" msgstr "" #: ../src/repsnapper.ui.h:163 msgid "Max. Speed:" msgstr "أكبر سرعة:" #: ../src/repsnapper.ui.h:164 msgid "Maximum Line Width (~Nozzle Diameter)" msgstr "أكبر عرض للخط (~قُطر الفوهة)" #: ../src/repsnapper.ui.h:165 msgid "Merge" msgstr "دمج" #: ../src/repsnapper.ui.h:166 msgid "Milling Settings" msgstr "إعدادات التفريز" #: ../src/repsnapper.ui.h:167 msgid "Min" msgstr "الأقل" #: ../src/repsnapper.ui.h:168 msgid "Min. Angle:" msgstr "أقل زاوية:" #: ../src/repsnapper.ui.h:169 msgid "Min. Arc Length (mm):" msgstr "أقل طول للقوس (مم):" #: ../src/repsnapper.ui.h:170 msgid "Min. Speed:" msgstr "أقل سرعة:" #: ../src/repsnapper.ui.h:171 msgid "Minimum Distance (mm):" msgstr "أقل مسافة (مم):" #: ../src/repsnapper.ui.h:172 msgid "Minimum Infill Distance (line widths)" msgstr "أقل مسافة ملء (عروض الخط)" #: ../src/repsnapper.ui.h:173 msgid "Minimum Line Width (~Nozzle Diameter)" msgstr "أصغر عرض للخط (~قُطر الفوهة)" #: ../src/repsnapper.ui.h:174 msgid "Minimum Shell Time (s):" msgstr "أقل زمن للقشرة (بالثواني):" #: ../src/repsnapper.ui.h:175 msgid "Minimum Time per Layer (s):" msgstr "أقل زمن لكل طبقة (بالثواني):" #: ../src/repsnapper.ui.h:176 msgid "Mirror" msgstr "مرآة" #: ../src/repsnapper.ui.h:178 msgid "Monitor Temperature" msgstr "مراقبة درجة الحرارة" #: ../src/repsnapper.ui.h:179 msgid "Move Head Colour" msgstr "" #: ../src/repsnapper.ui.h:180 msgid "Move between nearest points of polygons" msgstr "" #: ../src/repsnapper.ui.h:181 msgid "Moves" msgstr "الانتقالات" #: ../src/repsnapper.ui.h:182 msgid "" "Multiple Objects are combined and saved binary..\n" "Otherwise the STL will contain separate Objects and it will be in ASCII mode " "(some programs won't be able to read them)" msgstr "" #: ../src/repsnapper.ui.h:184 msgid "Name" msgstr "الاسم" #: ../src/repsnapper.ui.h:185 msgid "New" msgstr "جديد" #: ../src/repsnapper.ui.h:186 msgid "Next Layer" msgstr "الطبقة التالية" #: ../src/repsnapper.ui.h:187 msgid "No Covers" msgstr "" #: ../src/repsnapper.ui.h:188 msgid "Normal Fill:" msgstr "" #: ../src/repsnapper.ui.h:189 msgid "Normals" msgstr "المتعامدات" #: ../src/repsnapper.ui.h:190 msgid "Number of Layers" msgstr "عدد الطبقات" #: ../src/repsnapper.ui.h:191 msgid "Number of first Layers:" msgstr "عدد الطبقات الأولى:" #: ../src/repsnapper.ui.h:192 msgid "Number of lines of output to retain for each scrollback buffer" msgstr "" #: ../src/repsnapper.ui.h:193 msgid "Offset Outer Shells by (mm):" msgstr "إزاحة القشور الخارجية بمقدار (مم):" #: ../src/repsnapper.ui.h:194 msgid "On Platform" msgstr "على المنصة" #: ../src/repsnapper.ui.h:195 msgid "Open the Preferences Dialog" msgstr "فتح نافذة التفضيلات" #: ../src/repsnapper.ui.h:196 msgid "Optimization" msgstr "التحسين" #: ../src/repsnapper.ui.h:197 msgid "Otherwise use different GCode Letters" msgstr "" #: ../src/repsnapper.ui.h:198 msgid "Output Progress to Terminal" msgstr "" #: ../src/repsnapper.ui.h:199 msgid "Pause" msgstr "إلباث" #: ../src/repsnapper.ui.h:201 msgid "Power On" msgstr "تشغيل" #: ../src/repsnapper.ui.h:202 msgid "Preferences" msgstr "التفضيلات" #: ../src/repsnapper.ui.h:203 msgid "Preview" msgstr "استعراض" #: ../src/repsnapper.ui.h:204 msgid "Preview/Live Extrude Color" msgstr "" #: ../src/repsnapper.ui.h:205 msgid "Print" msgstr "طباعة" #: ../src/repsnapper.ui.h:206 msgid "Printer" msgstr "الطابعة" #: ../src/repsnapper.ui.h:207 msgid "Printer Buffer Size (Lines of GCode)" msgstr "" #: ../src/repsnapper.ui.h:208 msgid "Progress" msgstr "" #: ../src/repsnapper.ui.h:209 msgid "Purge" msgstr "" #: ../src/repsnapper.ui.h:210 msgid "Quit" msgstr "مغادرة" #: ../src/repsnapper.ui.h:211 msgid "Raft" msgstr "" #: ../src/repsnapper.ui.h:212 msgid "Randomize Lines" msgstr "" #: ../src/repsnapper.ui.h:213 msgid "Recommended value for FiveD is 4" msgstr "" #: ../src/repsnapper.ui.h:214 msgid "Relative Ecode" msgstr "" #: ../src/repsnapper.ui.h:215 msgid "Remove" msgstr "إزالة" #: ../src/repsnapper.ui.h:216 msgid "Reset" msgstr "إعادة الإعداد" #: ../src/repsnapper.ui.h:217 msgid "Reset Printer" msgstr "إعادة إعداد الطابعة" #: ../src/repsnapper.ui.h:218 msgid "Result" msgstr "النتيجة" #: ../src/repsnapper.ui.h:219 msgid "Rotate:" msgstr "تدوير:" #: ../src/repsnapper.ui.h:220 msgid "Rotation" msgstr "الدوران" #: ../src/repsnapper.ui.h:221 msgid "Rotation per Layer" msgstr "الدوران لكل طبقة" #: ../src/repsnapper.ui.h:222 msgid "Rotation per Layer (°):" msgstr "الدوران لكل طبقة (°):" #: ../src/repsnapper.ui.h:223 msgid "Rotation:" msgstr "الدوران:" #: ../src/repsnapper.ui.h:224 msgid "Round Corners" msgstr "تدوير الأركان" #: ../src/repsnapper.ui.h:225 msgid "Save GCode and Close" msgstr "احفظ الجي كود وأغلق" #: ../src/repsnapper.ui.h:226 msgid "Save STL as Single Object" msgstr "حفظ STL كجسم منفرد" #: ../src/repsnapper.ui.h:227 msgid "Save Settings" msgstr "حفظ الإعدادات" #: ../src/repsnapper.ui.h:228 msgid "Save Settings As" msgstr "حفظ الإعدادات كـ" #: ../src/repsnapper.ui.h:229 msgid "Save application settings profile" msgstr "" #: ../src/repsnapper.ui.h:230 msgid "Save as STL/AMF" msgstr "حفظ كـ STL/AMF" #: ../src/repsnapper.ui.h:231 msgid "Save settings in a custom file" msgstr "حفظ الإعدادات في ملف مخصص" #: ../src/repsnapper.ui.h:232 msgid "Scale:" msgstr "تحجيم:" #: ../src/repsnapper.ui.h:233 msgid "Scrollback" msgstr "" #: ../src/repsnapper.ui.h:234 msgid "Selected Only" msgstr "المُختار فقط" #: ../src/repsnapper.ui.h:235 msgid "Send GCode" msgstr "ارسل الجي كود" #: ../src/repsnapper.ui.h:236 msgid "Send Speed on Every GCode Command" msgstr "إرسال السرعة عند كل أمر جي كود" #: ../src/repsnapper.ui.h:237 msgid "Serial Link Speed" msgstr "" #: ../src/repsnapper.ui.h:238 msgid "Serial _Build" msgstr "" #: ../src/repsnapper.ui.h:239 msgid "Serial comms debug" msgstr "" #: ../src/repsnapper.ui.h:240 msgid "Settings set" msgstr "" #: ../src/repsnapper.ui.h:241 msgid "Shade Wireframe" msgstr "" #: ../src/repsnapper.ui.h:243 msgid "Shells:" msgstr "القشور:" #: ../src/repsnapper.ui.h:244 msgid "Show Extruder Number on GCode" msgstr "عرض رقم الباثق في الجي كود" #: ../src/repsnapper.ui.h:245 msgid "Show GCode with Extruder Offset" msgstr "" #: ../src/repsnapper.ui.h:246 msgid "Show Layer Overhang Areas" msgstr "" #: ../src/repsnapper.ui.h:247 msgid "Single Layer SVGs" msgstr "" #: ../src/repsnapper.ui.h:248 msgid "Size" msgstr "الحجم" #: ../src/repsnapper.ui.h:249 msgid "Skins:" msgstr "" #: ../src/repsnapper.ui.h:251 msgid "Slice to S_VG" msgstr "" #: ../src/repsnapper.ui.h:252 msgid "Solid Fill:" msgstr "" #: ../src/repsnapper.ui.h:253 msgid "Solid Thickness:" msgstr "" #: ../src/repsnapper.ui.h:254 msgid "Speed (mm/s)" msgstr "السرعة (مم/ث)" #: ../src/repsnapper.ui.h:255 msgid "Speed (mm/sec):" msgstr "السرعة (مم/ث):" #: ../src/repsnapper.ui.h:256 msgid "Speed Ratio:" msgstr "مُعدّل السرعة:" #: ../src/repsnapper.ui.h:257 msgid "Speeds are handled as mm/sec" msgstr "يتم التعامل مع السرعات بوحدات مم/ث (ملي متر لكل ثانية)" #: ../src/repsnapper.ui.h:258 msgid "Split" msgstr "فصل" #: ../src/repsnapper.ui.h:259 msgid "Start" msgstr "البداية" #: ../src/repsnapper.ui.h:260 msgid "Summary" msgstr "" #: ../src/repsnapper.ui.h:261 msgid "Summary of Hardware Settings" msgstr "" #: ../src/repsnapper.ui.h:262 msgid "Support:" msgstr "التدعيم:" #: ../src/repsnapper.ui.h:263 msgid "Surface" msgstr "السطح" #: ../src/repsnapper.ui.h:264 msgid "Surface Normals" msgstr "المتعامدات على السطح" #: ../src/repsnapper.ui.h:265 msgid "Temperature Ratio" msgstr "مُعدّل درجة الحرارة" #: ../src/repsnapper.ui.h:266 msgid "Thickness Ratio" msgstr "مُعدّل السماكة" #: ../src/repsnapper.ui.h:267 msgid "To Platform" msgstr "" #: ../src/repsnapper.ui.h:268 msgid "To:" msgstr "إلى:" #: ../src/repsnapper.ui.h:269 msgid "Tool Diameter" msgstr "قطر الأداة" #: ../src/repsnapper.ui.h:270 msgid "Translate:" msgstr "إزاحة:" #: ../src/repsnapper.ui.h:271 msgid "Twist:" msgstr "الالتواء:" #: ../src/repsnapper.ui.h:272 msgid "Update Interval (sec)" msgstr "فترة التحديث (بالثواني)" #: ../src/repsnapper.ui.h:273 msgid "Use Extruder:" msgstr "استخدام الباثق:" #: ../src/repsnapper.ui.h:274 msgid "Use T Command to Change Extruder" msgstr "" #: ../src/repsnapper.ui.h:275 msgid "Use this Extruder for Support" msgstr "استخدام هذا الباثق لمادة التدعيم" #: ../src/repsnapper.ui.h:276 msgid "Validate Connection" msgstr "التحقق من الاتصال" #: ../src/repsnapper.ui.h:277 msgid "Variable Slicing" msgstr "" #: ../src/repsnapper.ui.h:278 msgid "Very First Layer Height Ratio" msgstr "" #: ../src/repsnapper.ui.h:279 msgid "Website" msgstr "موقع الويب" #: ../src/repsnapper.ui.h:280 msgid "Widen:" msgstr "" #: ../src/repsnapper.ui.h:281 msgid "Wireframe" msgstr "خطوط الإطار" #: ../src/repsnapper.ui.h:282 msgid "X" msgstr "س" #: ../src/repsnapper.ui.h:283 msgid "X +0.1 mm" msgstr "س +0.1 مم" #: ../src/repsnapper.ui.h:284 msgid "X +1 mm" msgstr "س +1 مم" #: ../src/repsnapper.ui.h:285 msgid "X +10 mm" msgstr "س +10 مم" #: ../src/repsnapper.ui.h:286 msgid "X -0.1 mm" msgstr "س -0.1 مم" #: ../src/repsnapper.ui.h:287 msgid "X -1 mm" msgstr "س -1 مم" #: ../src/repsnapper.ui.h:288 msgid "X -10 mm" msgstr "س -10 مم" #: ../src/repsnapper.ui.h:289 msgid "X Offset (mm)" msgstr "إزاحة س (مم)" #: ../src/repsnapper.ui.h:290 msgid "X+" msgstr "س+" #: ../src/repsnapper.ui.h:291 msgid "X-" msgstr "س-" #: ../src/repsnapper.ui.h:292 msgid "X/Y Axes:" msgstr "محاور س/ص:" #: ../src/repsnapper.ui.h:293 msgid "X:" msgstr "س:" #: ../src/repsnapper.ui.h:294 msgid "Y" msgstr "ص" #: ../src/repsnapper.ui.h:295 msgid "Y +0.1 mm" msgstr "ص +0.1 مم" #: ../src/repsnapper.ui.h:296 msgid "Y +1 mm" msgstr "ص +1 مم" #: ../src/repsnapper.ui.h:297 msgid "Y +10 mm" msgstr "ص +10 مم" #: ../src/repsnapper.ui.h:298 msgid "Y -0.1 mm" msgstr "ص -0.1 مم" #: ../src/repsnapper.ui.h:299 msgid "Y -1 mm" msgstr "ص -1 مم" #: ../src/repsnapper.ui.h:300 msgid "Y -10 mm" msgstr "ص -10 مم" #: ../src/repsnapper.ui.h:301 msgid "Y Offset (mm)" msgstr "إزاحة ص (مم)" #: ../src/repsnapper.ui.h:302 msgid "Y+" msgstr "ص+" #: ../src/repsnapper.ui.h:303 msgid "Y-" msgstr "ص-" #: ../src/repsnapper.ui.h:304 msgid "Y:" msgstr "ص:" #: ../src/repsnapper.ui.h:305 msgid "Z" msgstr "ع" #: ../src/repsnapper.ui.h:306 msgid "Z +0.1 mm" msgstr "ع +0.1 مم" #: ../src/repsnapper.ui.h:307 msgid "Z +1 mm" msgstr "ع +1 مم" #: ../src/repsnapper.ui.h:308 msgid "Z +10 mm" msgstr "ع +10 مم" #: ../src/repsnapper.ui.h:309 msgid "Z -0.1 mm" msgstr "ع -0.1 مم" #: ../src/repsnapper.ui.h:310 msgid "Z -1 mm" msgstr "ع -1 مم" #: ../src/repsnapper.ui.h:311 msgid "Z -10 mm" msgstr "ع -10 مم" #: ../src/repsnapper.ui.h:312 msgid "Z Axis:" msgstr "محور ع:" #: ../src/repsnapper.ui.h:313 msgid "Z Down" msgstr "" #: ../src/repsnapper.ui.h:314 msgid "Z Up" msgstr "" #: ../src/repsnapper.ui.h:315 msgid "Z lift on move (mm):" msgstr "" #: ../src/repsnapper.ui.h:316 msgid "Z+" msgstr "ع+" #: ../src/repsnapper.ui.h:317 msgid "Z-" msgstr "ع-" #: ../src/repsnapper.ui.h:318 msgid "Z:" msgstr "ع:" #: ../src/repsnapper.ui.h:319 msgid "_About" msgstr "_عن التطبيق" #: ../src/repsnapper.ui.h:320 msgid "_Autoplace" msgstr "_وضع آلي" #: ../src/repsnapper.ui.h:321 msgid "_Calibrate" msgstr "م_عايرة" #: ../src/repsnapper.ui.h:322 msgid "_Edit" msgstr "ت_حرير" #: ../src/repsnapper.ui.h:323 msgid "_File" msgstr "_ملف" #: ../src/repsnapper.ui.h:324 msgid "_Help" msgstr "م_ساعدة" #: ../src/repsnapper.ui.h:325 msgid "_Load GCode" msgstr "ت_حميل جي كود" #: ../src/repsnapper.ui.h:326 msgid "_Preferences" msgstr "الت_فضيلات" #: ../src/repsnapper.ui.h:327 msgid "_Quit" msgstr "م_غادرة" #: ../src/repsnapper.ui.h:328 msgid "_Save GCode" msgstr "_حفظ الجي كود" #: ../src/repsnapper.ui.h:329 msgid "_Support" msgstr "الت_دعيم" #: ../src/repsnapper.ui.h:330 msgid "label" msgstr "" #: ../src/repsnapper.ui.h:331 msgid "lines" msgstr "" #: ../src/repsnapper.ui.h:332 msgid "mm" msgstr "مم" #: ../src/repsnapper.ui.h:333 msgid "repsnapper Preferences" msgstr "تفضيلات رِب سنابر" repsnapper-2.3.2a5/po/de_DE.po000066400000000000000000001461131231531733200160470ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #: ../src/slicer/printlines.h:33 msgid "" msgstr "" "Project-Id-Version: repsnapper 1.9.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-16 04:58+0200\n" "PO-Revision-Date: 2012-10-16 05:01+0200\n" "Last-Translator: martin.dieringer@gmx.de\n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../repsnapper.desktop.in.h:1 msgid "Controls your 3D plastic printer" msgstr "Steuerung des 3D-Druckers" #: ../repsnapper.desktop.in.h:2 msgid "RepRap control software" msgstr "RepRap-Steuerung" #: ../repsnapper.desktop.in.h:3 msgid "repsnapper" msgstr "repsnapper" #: ../src/files.cpp:117 msgid "Unrecognized file - " msgstr "unbekannte Datei: " #: ../src/files.cpp:118 msgid "Known extensions: " msgstr "Bekannte Erw.: " #: ../src/files.cpp:148 msgid "Error: Unable to open file - " msgstr "Fehler: Kann Datei nicht öffnen: " #: ../src/files.cpp:184 ../src/files.cpp:264 ../src/files.cpp:652 msgid "Error: Unable to open stl file - " msgstr "Fehler: Kann STL-Datei nicht öffnen: " #: ../src/files.cpp:230 msgid "Unexpected EOF reading STL file - " msgstr "Dateiende beim Lesen der STL-Datei - " #. cerr << "loading ascii " << endl; #. cerr << " locale " << std::locale().name() << endl; #: ../src/files.cpp:305 msgid "Unnamed" msgstr "Unbenannt" #: ../src/files.cpp:365 msgid "Error: Facet keyword not found in STL text!" msgstr "Fehler: kein \"Facet\" in STL" #: ../src/files.cpp:374 msgid "Error: normal keyword not found in STL text!" msgstr "Fehler: kein \"normal\" in STL" #: ../src/files.cpp:391 msgid "Error: Outer/Loop keywords not found!" msgstr "Fehler: Kein \"outer/loop\" gefunden" #: ../src/files.cpp:405 msgid "Error: Vertex keyword not found" msgstr "Fehler: kein \"Vertex\"" #: ../src/files.cpp:415 msgid "Error: Endloop or endfacet keyword not found" msgstr "Fehler: Kein \"Endloop\" oder \"endfacet\"" #: ../src/files.cpp:443 msgid "Error: Unable to open vrml file - " msgstr "Fehler: kann VRML-Datei nich laden: " #: ../src/flatshape.cpp:254 msgid "Split Polygons" msgstr "Polygone teilen" #: ../src/model.cpp:87 msgid "not yet implemented\n" msgstr "noch nicht implementiert\n" #: ../src/model.cpp:312 msgid "Reading GCode" msgstr "Lade GCode" #. display whole layer if flat shapes #. if (shapes.back()->dimensions() == 2) #. gcode.layerchanges.push_back(0); #: ../src/model.cpp:314 ../src/model_slice.cpp:899 ../src/model_slice.cpp:978 #: ../src/model_slice.cpp:1000 ../src/ui/view.cpp:1988 #: ../src/printer/printer.cpp:664 ../src/printer/printer_iochannel.cpp:454 #: ../src/printer/printer_libreprap.cpp:386 msgid "Done" msgstr "Fertig" #: ../src/model.cpp:587 msgid "_upper" msgstr "_oben" #: ../src/model.cpp:588 msgid "_lower" msgstr "_unten" #: ../src/model_slice.cpp:243 msgid "Cleanup" msgstr "Bereinigen" #: ../src/model_slice.cpp:318 msgid "Slicing" msgstr "Schichten" #. not bottom layer #: ../src/model_slice.cpp:470 msgid "Skins" msgstr "" #: ../src/model_slice.cpp:500 msgid "Find Uncovered" msgstr "Unbedeckte Flächen finden" #: ../src/model_slice.cpp:565 msgid "Uncovered Shells" msgstr "Unbedeckte Flächen" #: ../src/model_slice.cpp:601 msgid "Merging Full Polygons" msgstr "Volle Polygone verbinden" #: ../src/model_slice.cpp:660 ../src/slicer/printlines.h:34 msgid "Support" msgstr "Gerüst" #: ../src/model_slice.cpp:719 ../src/repsnapper.ui.h:242 msgid "Shells" msgstr "Hüllen" #: ../src/model_slice.cpp:755 ../src/slicer/printlines.h:33 #: ../src/repsnapper.ui.h:134 msgid "Infill" msgstr "Füllung" #: ../src/model_slice.cpp:847 msgid "Making Lines" msgstr "Erzeuge Linien" #: ../src/model_slice.cpp:849 msgid "Millimeters" msgstr "Millimeter" #: ../src/model_slice.cpp:850 msgid "Absolute Pos" msgstr "Absolute Pos" #: ../src/model_slice.cpp:852 msgid "Relative E Code" msgstr "Relativer E-Code" #: ../src/model_slice.cpp:854 msgid "Absolute E Code" msgstr "Absoluter E-Code" #: ../src/model_slice.cpp:905 msgid "Time Estimation: " msgstr "Geschätzte Dauer: " #: ../src/model_slice.cpp:906 ../src/model_slice.cpp:915 msgid "h" msgstr "h" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 msgid "m" msgstr "m" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 #: ../src/ui/progress.cpp:97 msgid "s" msgstr "s" #: ../src/model_slice.cpp:914 msgid " / GCode Estimation: " msgstr " / GCode-Schätzung: " #: ../src/model_slice.cpp:920 msgid " - total extruded: " msgstr " - Gesamtfilament: " #: ../src/model_slice.cpp:984 msgid "Saving Files" msgstr "Speichern der Dateien" #: ../src/objtree.h:41 msgid "Unnamed object" msgstr "Unbenanntes Objekt" #: ../src/objtree.cpp:65 msgid "" "Cannot add a 3-dimensional Shape to a 2-dimensional Model and vice versa" msgstr "3-dimensionales Objekt geht nicht zusammen mit 2-dimensionalem" #: ../src/objtree.cpp:138 msgid "Unsaved file" msgstr "Ungespeicherte Datei" #: ../src/render.cpp:72 msgid "failed to init gl area\n" msgstr "GL konnte nicht initialisiert werden\n" #: ../src/repsnapper.cpp:57 ../src/repsnapper.cpp:62 #, c-format msgid "Version: %s\n" msgstr "" #: ../src/repsnapper.cpp:63 #, c-format msgid "" "Usage: repsnapper [OPTION]... [FILE]...\n" "Start reprap control software and load [FILES]\n" "Options:\n" " -t, --no-gui act as a head-less renderer\n" " -i, --input [file] read input Model [file]\n" " -b, --binary [file] batch convert input file to binary STL\n" " -o, --output [file] if not head-less (-t),\n" " enter non-printing GUI mode\n" " only able to output gcode to [file]\n" " --svg [file] slice to SVG file\n" " --ssvg [file] slice to single layer SVG files [file]NNNN.svg\n" " -s, --settings [file] read render settings [file]\n" " -h, --help show this help\n" "\n" "Report bugs to #repsnapper, irc.freenode.net\n" "\n" msgstr "" "\"Befehl: repsnapper [OPTION]... [DATEI]...\\n\"\n" "\"Starte Programm und lade [DATEI]en\\n\"\n" "\"Optionen:\\n\"\n" "\" -t, --no-gui Kommandozeile, ohne grafische Oberfläche\\n\"\n" "\" -i, --input [datei] von [datei] laden\\n\"\n" "\" -b, --binary [datei] Konvertiere datei in binaeres STL\\n\"\n" "\" -o, --output [datei] GCode in [datei] ausgeben\\n\"\n" "\" ohne \"-t\": GUI-Modus für Pronterface\\n\"\n" "\" --svg [datei] Schichten in SVG-Datei\\n\"\n" "\" --ssvg [datei] Einzelschichten in SVG-Dateien [datei]NNNN.svg\\n" "\"\n" "\" -s, --settings [datei] Einstellungen von [datei] laden\\n\"\n" "\" -h, --help Hilfe anzeigen\\n\"\n" "\"\\n\"\n" "\"Bugs bitte melden in #repsnapper, irc.freenode.net\\n\"\n" "\"\\n\"\n" #: ../src/repsnapper.cpp:192 msgid "Couldn't create user config directory!" msgstr "Konnte Verzeichnis für Benutzer-Konfiguration nicht anlegen!" #: ../src/repsnapper.cpp:213 ../src/repsnapper.cpp:236 msgid "Couldn't find global configuration!" msgstr "Konnte Grundeinstellung nicht finden!" #: ../src/repsnapper.cpp:215 ../src/repsnapper.cpp:238 msgid "It is likely that repsnapper is not correctly installed." msgstr "Wahrscheinlich wurde repsnapper nicht korrekt installiert." #. Fall back to global config #: ../src/repsnapper.cpp:230 msgid "Unable to create user config" msgstr "Kann keine Benutzer-Konfiguration erstellen" #: ../src/repsnapper.cpp:232 msgid "" "\n" "Falling back to global config. Settings will not be saved." msgstr "" "\n" "\n" "Setze auf Grundeinstellung zurück. Einstellungen werden nicht gespeichert" #: ../src/repsnapper.cpp:247 msgid "Failed to locate config" msgstr "Kann Konfiguration nicht finden" #: ../src/repsnapper.cpp:307 msgid "No output file given" msgstr "Keine Ausgabedatei angegeben" #: ../src/settings.cpp:683 ../src/settings.cpp:1046 msgid "corrupt setting type" msgstr "Defekte Einstellung" #: ../src/settings.cpp:700 msgid "Failed to load settings from file '" msgstr "Konnte Einstellungen nicht einlesen: '" #: ../src/settings.cpp:704 msgid "Exception " msgstr "Fehler " #: ../src/settings.cpp:704 msgid " loading settings from file '" msgstr " beim einlesen der Datei '" #: ../src/settings.cpp:708 msgid "Parsing config from '" msgstr "Lese Einstellungen von '" #: ../src/settings.cpp:892 ../src/settings.cpp:987 msgid "Missing boolean config item " msgstr "Boolsche Einstellung fehlt: " #: ../src/settings.cpp:903 ../src/settings.cpp:932 ../src/settings.cpp:1036 #: ../src/settings.cpp:1366 msgid "Missing user interface item " msgstr "GUI-Element fehlt: " #: ../src/settings.cpp:941 msgid "corrupt setting type\n" msgstr "Defekte Einstellung\n" #: ../src/settings.cpp:1000 msgid "Missing GUI element " msgstr "GUI-Element fehlt: " #. PlaceOnPlatform(); #: ../src/shape.cpp:59 msgid "Shape has volume " msgstr "Teil hat ein Volumen von " #: ../src/shape.cpp:59 msgid " mm^3 and " msgstr "mm^3 und " #: ../src/shape.cpp:60 msgid " triangles" msgstr " Dreiecke" #: ../src/shape.cpp:107 msgid "Split Shapes" msgstr "Teilen" #: ../src/shape.cpp:113 msgid "Split: Sorting Triangles ..." msgstr "Dreicke sortieren ..." #: ../src/shape.cpp:147 msgid "Split: Building shapes ..." msgstr "Zerlegen ..." #: ../src/shape.cpp:158 msgid "Shape " msgstr "Teil " #. copy #: ../src/gcode/command.cpp:336 msgid " xy part" msgstr " xy-Teil" #. copy #: ../src/gcode/command.cpp:338 msgid " z part" msgstr " z-Teil" #: ../src/gcode/command.cpp:377 msgid " Z-Change" msgstr " Z-Schritt" #: ../src/gcode/command.cpp:388 msgid " Move Only" msgstr " Nur Bewegung" #: ../src/gcode/command.cpp:405 msgid " Select Extruder" msgstr "Extruder wählen" #: ../src/gcode/command.cpp:409 msgid " Reset Extrusion" msgstr "Extrusion zurücketzen" #: ../src/gcode/gcode.cpp:174 msgid "Loading GCode" msgstr "Lade GCode" #: ../src/gcode/gcode.cpp:648 msgid "Collecting GCode" msgstr "Sammle GCode" #. pure extrusions #: ../src/gcode/gcodestate.cpp:215 msgid "Extrusion only " msgstr "Nur Extrusion" #: ../src/gcode/gcodestate.cpp:220 msgid "Absolute Extrusion" msgstr "Absoluter E-Code" #: ../src/ui/connectview.cpp:39 msgid "Disconnecting..." msgstr "Trenne ..." #: ../src/ui/connectview.cpp:45 msgid "Connect" msgstr "Verbinden" #: ../src/ui/connectview.cpp:51 msgid "Connecting..." msgstr "Verbinde ..." #: ../src/ui/connectview.cpp:57 msgid "Disconnect" msgstr "Trennen" #: ../src/ui/connectview.cpp:111 msgid "Port:" msgstr "Port:" #. file patterns #: ../src/ui/filechooser.cpp:41 msgid "All Files" msgstr "Alle Dateien" #: ../src/ui/filechooser.cpp:44 msgid "Models" msgstr "Modelle" #: ../src/ui/filechooser.cpp:54 ../src/ui/filechooser.cpp:101 #: ../src/repsnapper.ui.h:124 msgid "GCode" msgstr "GCode" #: ../src/ui/filechooser.cpp:60 ../src/ui/filechooser.cpp:107 msgid "Settings" msgstr "Einstellungen" #: ../src/ui/filechooser.cpp:112 msgid "SVG" msgstr "" #: ../src/ui/filechooser.cpp:118 ../src/repsnapper.ui.h:177 msgid "Model" msgstr "Modell" #: ../src/ui/filechooser.cpp:133 msgid "Load" msgstr "Lade" #: ../src/ui/filechooser.cpp:147 msgid "Save" msgstr "Speichere" #. seconds #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " done in " msgstr " fertig " #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " seconds" msgstr " Sek" #: ../src/ui/progress.cpp:90 ../src/ui/progress.cpp:91 msgid "h " msgstr "h " #: ../src/ui/progress.cpp:95 msgid "m " msgstr "m " #: ../src/ui/widgets.cpp:142 msgid "Nozzle:" msgstr "Düse:" #: ../src/ui/widgets.cpp:142 msgid "Bed:" msgstr "Plattform:" #: ../src/ui/widgets.cpp:146 msgid "-- °C" msgstr "" #. add(*manage (new Gtk::Label(_("°C")))); #: ../src/ui/widgets.cpp:150 msgid "Target:" msgstr "Sollwert:" #: ../src/ui/widgets.cpp:166 ../src/ui/widgets.cpp:187 msgid "Off" msgstr "Aus" #: ../src/ui/widgets.cpp:185 msgid "On" msgstr "An" #: ../src/ui/widgets.cpp:265 msgid "Home" msgstr "Startposition" #: ../src/ui/view.cpp:113 msgid "Complete print before converting" msgstr "Druck fertigstellen vor Umwandlung" #: ../src/ui/view.cpp:114 msgid "Converting to GCode while printing will abort the print" msgstr "GCode-Erstellung würde den laufenden Druck abbrechen" #: ../src/ui/view.cpp:185 ../src/ui/view.cpp:274 msgid "Complete print before reading" msgstr "Druck fertigstellen vor dem Einlesen" #: ../src/ui/view.cpp:186 ../src/ui/view.cpp:275 msgid "Reading GCode while printing will abort the print" msgstr "GCode zu laden, würde den Druck abbrechen" #: ../src/ui/view.cpp:209 ../src/ui/view.cpp:236 ../src/ui/view.cpp:255 #: ../src/ui/view.cpp:653 msgid "Overwrite File?" msgstr "Datei überschreiben?" #: ../src/ui/view.cpp:326 msgid "Error reading UI description!!" msgstr "Fehler in UI-Beschreibung!!" #: ../src/ui/view.cpp:336 msgid "Couldn't find UI description!" msgstr "Keine UI-Beschreibung gefunden!" #: ../src/ui/view.cpp:338 msgid "Check that repsnapper has been correctly installed." msgstr "Installation überprüfen" #: ../src/ui/view.cpp:349 msgid "Error loading UI!" msgstr "Fehler beim Laden der UI-Beschreibung!" #: ../src/ui/view.cpp:946 msgid "Reset Printer?" msgstr "Drucker zurücksetzen?" #: ../src/ui/view.cpp:1370 msgid "Output File: " msgstr "Ausgabedatei:" #: ../src/printer/printer.cpp:378 ../src/printer/printer.cpp:425 #: ../src/printer/printer_iochannel.cpp:274 #: ../src/printer/printer_libreprap.cpp:213 msgid "Cannot disconnect" msgstr "Kann nicht trennen" #: ../src/printer/printer.cpp:379 ../src/printer/printer.cpp:426 #: ../src/printer/printer_iochannel.cpp:275 #: ../src/printer/printer_libreprap.cpp:214 msgid "printer is printing" msgstr "Drucker druckt" #: ../src/printer/printer.cpp:416 ../src/printer/printer_libreprap.cpp:204 msgid "Failed to connect to device" msgstr "Konnte nicht mit dem Gerät verbinden" #: ../src/printer/printer.cpp:417 ../src/printer/printer_libreprap.cpp:205 msgid "an error occured while connecting" msgstr "Kann nicht in Ausgangsposition, während gedruckt wird" #: ../src/printer/printer.cpp:485 ../src/printer/printer_iochannel.cpp:329 #: ../src/printer/printer_libreprap.cpp:273 msgid "" "Already printing.\n" "Cannot start printing" msgstr "" "Es wird schon gedruckt.\n" "Druck kann nicht starten" #: ../src/printer/printer.cpp:501 ../src/printer/printer.cpp:507 #: ../src/printer/printer_iochannel.cpp:339 #: ../src/printer/printer_libreprap.cpp:284 msgid "" "Not connected to printer.\n" "Cannot start printing" msgstr "" "Nicht verbunden.\n" "Kann nicht drucken" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "Can't send command" msgstr "Kann Befehl nicht senden" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "You must first connect to a device!" msgstr "Nicht verbunden" #: ../src/printer/printer.cpp:644 ../src/printer/printer_libreprap.cpp:367 msgid "" "Not connected to printer.\n" "Cannot stop printing" msgstr "" "Nicht verbunden.\n" "Kann nicht drucken" #: ../src/printer/printer.cpp:660 ../src/printer/printer_iochannel.cpp:450 #: ../src/printer/printer_libreprap.cpp:382 msgid "Printing" msgstr "Druckt" #: ../src/printer/printer.cpp:747 ../src/printer/printer_libreprap.cpp:433 msgid "Error reading from device!" msgstr "Fehler beim Lesen vom Gerät!" #: ../src/printer/printer.cpp:753 ../src/printer/printer_libreprap.cpp:439 msgid "Error writing to device!" msgstr "Fehler beim Schreiben zum Gerät" #: ../src/printer/printer2.cpp:29 msgid "Can't switch power while printing" msgstr "Kann nicht ein- oder ausschalten, während gedruckt wird" #: ../src/printer/printer2.cpp:43 msgid "Can't go home while printing" msgstr "Kann nicht in Ausgangsposition, während gedruckt wird" #: ../src/printer/printer2.cpp:55 msgid "Home called with unknown axis" msgstr "Ausgangsposition ohne Achse?" #: ../src/printer/printer2.cpp:65 ../src/printer/printer2.cpp:95 msgid "Can't move manually while printing" msgstr "Kann nicht bewegen, während gedruckt wird" #: ../src/printer/printer2.cpp:85 msgid "Move called with unknown axis" msgstr "Bewegung mit unbekannter Achse" #: ../src/printer/printer2.cpp:114 msgid "Goto called with unknown axis" msgstr "Ziel angegeben ohne Achse" #: ../src/printer/reprap_serial.cpp:172 msgid "Already Connected to Printer" msgstr "Schon verbunden" #: ../src/printer/reprap_serial.cpp:451 ../src/printer/reprap_serial.cpp:458 msgid "Printing error" msgstr "Druckfehler" #: ../src/printer/reprap_serial.cpp:451 msgid "Not connected" msgstr "Nicht verbunden" #: ../src/printer/reprap_serial.cpp:458 msgid "Wrong line number" msgstr "Falsche Zeilennummer" #: ../src/printer/reprap_serial.cpp:570 msgid "no reset on Windows" msgstr "Kein Reset unter Windows" #. these are available for user selection (order must be same as types): #: ../src/slicer/infill.h:37 msgid "Parallel" msgstr "Linien" #: ../src/slicer/infill.h:37 msgid "Zigzag" msgstr "Zickzack" #: ../src/slicer/infill.h:37 msgid "Hexagons" msgstr "Hexagone" #: ../src/slicer/infill.h:37 ../src/repsnapper.ui.h:200 msgid "Polygons" msgstr "Polygone" #: ../src/slicer/infill.h:37 msgid "Hilbert Curve" msgstr "Hilbertkurve" #: ../src/slicer/printlines.cpp:1665 msgid "Making GCode" msgstr "Erzeuge GCode" #: ../src/slicer/printlines.h:33 msgid "Shell" msgstr "Hülle" #: ../src/slicer/printlines.h:33 msgid "Skin" msgstr "" #: ../src/slicer/printlines.h:34 ../src/repsnapper.ui.h:250 msgid "Skirt" msgstr "" #: ../src/slicer/printlines.h:34 msgid "Bridge" msgstr "Brücke" #: ../src/slicer/printlines.h:34 msgid "Command" msgstr "Befehl" #: ../src/repsnapper.ui.h:1 msgid " " msgstr " " #: ../src/repsnapper.ui.h:2 msgid " th Layer" msgstr " te Schicht" #: ../src/repsnapper.ui.h:3 msgid "(C) 2008-2012 its contributors " msgstr "(C) 2008-2012 bei den Mitwirkenden " #: ../src/repsnapper.ui.h:4 msgid "+" msgstr "" #: ../src/repsnapper.ui.h:5 msgid "-" msgstr "" #: ../src/repsnapper.ui.h:6 msgid "1" msgstr "" #: ../src/repsnapper.ui.h:7 msgid "2" msgstr "" #: ../src/repsnapper.ui.h:8 msgid "3" msgstr "" #: ../src/repsnapper.ui.h:9 msgid "4" msgstr "" #: ../src/repsnapper.ui.h:10 msgid "" msgstr "" #: ../src/repsnapper.ui.h:11 msgid "Acceleration" msgstr "Beschleunigung" #: ../src/repsnapper.ui.h:12 msgid "Antiooze Retract" msgstr "Filamentrückzug" #: ../src/repsnapper.ui.h:13 msgid "Axis Moving Speeds (mm/sec)" msgstr "Achsengeschwindigkeiten (mm/s)" #: ../src/repsnapper.ui.h:14 msgid "Base" msgstr "Unterlage" #: ../src/repsnapper.ui.h:15 msgid "Comms Debug" msgstr "Kommunikation debuggen" #: ../src/repsnapper.ui.h:16 msgid "Cooling" msgstr "Kühlung" #: ../src/repsnapper.ui.h:17 msgid "Custom Actions" msgstr "Eigene Befehle" #: ../src/repsnapper.ui.h:18 msgid "Debug GCode" msgstr "GCode debuggen" #: ../src/repsnapper.ui.h:19 msgid "Debugging" msgstr "" #: ../src/repsnapper.ui.h:20 msgid "Extruder Settings" msgstr "Extruder-Einstellungen" #: ../src/repsnapper.ui.h:21 msgid "First Layer(s)" msgstr "Erste Schicht(en)" #: ../src/repsnapper.ui.h:22 msgid "GCode Postprocessor" msgstr "" #: ../src/repsnapper.ui.h:23 msgid "GCode Rendering" msgstr "GCode-Darstellung" #: ../src/repsnapper.ui.h:24 msgid "General" msgstr "Allgemein" #: ../src/repsnapper.ui.h:25 msgid "Geometry" msgstr "Geometrie" #: ../src/repsnapper.ui.h:26 msgid "Infill Debug" msgstr "Füllung debuggen" #: ../src/repsnapper.ui.h:27 msgid "Infill" msgstr "Füllung" #: ../src/repsnapper.ui.h:28 msgid "Interface" msgstr "Zwischenschicht" #: ../src/repsnapper.ui.h:29 msgid "Layer Debug" msgstr "Schichten-Debug" #: ../src/repsnapper.ui.h:30 msgid "Lighting" msgstr "Beleuchtung" #: ../src/repsnapper.ui.h:31 msgid "Object" msgstr "Objekt" #: ../src/repsnapper.ui.h:32 msgid "Output" msgstr "Ausgabe" #: ../src/repsnapper.ui.h:33 msgid "Parameters" msgstr "Parameter" #: ../src/repsnapper.ui.h:34 msgid "Printer" msgstr "Drucker" #: ../src/repsnapper.ui.h:35 msgid "Raft" msgstr "Unterlage" #: ../src/repsnapper.ui.h:36 msgid "STL Rendering Colors" msgstr "STL-Darstellung" #: ../src/repsnapper.ui.h:37 msgid "Serial Communications" msgstr "Schnittstellenkommunikation" #: ../src/repsnapper.ui.h:38 msgid "Speeds (mm/sec)" msgstr "Geschwindigkeiten (mm/s)" #: ../src/repsnapper.ui.h:39 msgid "Temperature" msgstr "Temperatur" #: ../src/repsnapper.ui.h:40 msgid "?" msgstr "" #: ../src/repsnapper.ui.h:41 msgid "Acceleration Distance:" msgstr "Beschleunigungsstrecke" #: ../src/repsnapper.ui.h:42 msgid "Adjust Luminance to Indicate Speed" msgstr "Geschwindigkeit durch Luminanz darstellen" #: ../src/repsnapper.ui.h:43 msgid "All" msgstr "Alle" #: ../src/repsnapper.ui.h:44 msgid "Alternate Infill Percent:" msgstr "Alternative Füllung (%):" #: ../src/repsnapper.ui.h:45 msgid "Alternate Infill every " msgstr "Alternative Füllung jede " #: ../src/repsnapper.ui.h:46 msgid "Always done when using Support" msgstr "Immer wenn Gerüst verwendet wird" #: ../src/repsnapper.ui.h:47 msgid "Amount (mm)" msgstr "Rückzug (mm)" #: ../src/repsnapper.ui.h:48 msgid "Amount (mm):" msgstr "Rückzug (mm):" #: ../src/repsnapper.ui.h:49 msgid "Arcs GCode (G2,G3)" msgstr "GCode-Bögen (G2,G3)" #: ../src/repsnapper.ui.h:50 msgid "Around All Objects" msgstr "Um alle Objekte" #: ../src/repsnapper.ui.h:51 msgid "Arrows" msgstr "Pfeile" #: ../src/repsnapper.ui.h:52 msgid "Auto" msgstr "" #: ../src/repsnapper.ui.h:53 msgid "Axis Control" msgstr "Achsensteuerung" #: ../src/repsnapper.ui.h:54 msgid "Base Rotation (°):" msgstr "Gesamtdrehung (°):" #: ../src/repsnapper.ui.h:55 msgid "Border" msgstr "Rand" #: ../src/repsnapper.ui.h:56 msgid "Borders" msgstr "Rand" #: ../src/repsnapper.ui.h:57 msgid "Bounding Boxes" msgstr "Begrenzungen" #: ../src/repsnapper.ui.h:58 msgid "Bridges Extrusion Factor:" msgstr "Brücken-Extrusionsfaktor:" #: ../src/repsnapper.ui.h:59 msgid "Build Volume" msgstr "Volumen" #: ../src/repsnapper.ui.h:60 msgid "Calibrate mm as input" msgstr "mm des Filaments" #: ../src/repsnapper.ui.h:61 msgid "Change image" msgstr "Bild ändern" #: ../src/repsnapper.ui.h:62 msgid "Choose Endpoints Colour" msgstr "Endpunktfarbe" #: ../src/repsnapper.ui.h:63 msgid "Choose Extrusion Colour" msgstr "Extrusionsfarbe" #: ../src/repsnapper.ui.h:64 msgid "Choose Head Movement Colour" msgstr "Bewegungsfarbe" #: ../src/repsnapper.ui.h:65 msgid "Choose Normals Colour" msgstr "Normalenfarbe" #: ../src/repsnapper.ui.h:66 msgid "Choose Polygon Colour" msgstr "Polygonfarbe" #: ../src/repsnapper.ui.h:67 msgid "Choose Wireframe Colour" msgstr "Drahtmodellfarbe" #: ../src/repsnapper.ui.h:68 msgid "Clear Now" msgstr "Alles Löschen" #: ../src/repsnapper.ui.h:69 msgid "Clear on Print Start" msgstr "Vor Drucken löschen" #: ../src/repsnapper.ui.h:70 msgid "Clone Settings" msgstr "Einstellungen speichern" #: ../src/repsnapper.ui.h:71 msgid "Colour" msgstr "Farbe" #: ../src/repsnapper.ui.h:72 msgid "Communication" msgstr "Kommunikation" #: ../src/repsnapper.ui.h:73 msgid "Copy" msgstr "Kopieren" #: ../src/repsnapper.ui.h:74 msgid "Custom Button" msgstr "Eigener Befehl" #: ../src/repsnapper.ui.h:75 msgid "D_uplicate" msgstr "D_uplizieren" #: ../src/repsnapper.ui.h:76 msgid "Debug" msgstr "Debuggen" #: ../src/repsnapper.ui.h:77 msgid "Debug Arcs" msgstr "Bögen debuggen" #: ../src/repsnapper.ui.h:78 msgid "Debug Infill" msgstr "Füllung Debuggen" #: ../src/repsnapper.ui.h:79 msgid "Decor" msgstr "Dekor" #: ../src/repsnapper.ui.h:80 msgid "Decor Layers:" msgstr "Dekorschichten:" #: ../src/repsnapper.ui.h:81 msgid "Decoration:" msgstr "Dekor:" #: ../src/repsnapper.ui.h:82 msgid "Delete" msgstr "Löschen" #: ../src/repsnapper.ui.h:83 msgid "Dimensions" msgstr "Maße" #: ../src/repsnapper.ui.h:84 msgid "Disable Bridges" msgstr "Brücken deaktivieren" #: ../src/repsnapper.ui.h:85 msgid "Display" msgstr "Anzeige" #: ../src/repsnapper.ui.h:86 msgid "Display Colour" msgstr "Farbe" #: ../src/repsnapper.ui.h:87 msgid "Display Settings" msgstr "Ansicht" #: ../src/repsnapper.ui.h:88 msgid "Distance" msgstr "Abstand" #: ../src/repsnapper.ui.h:89 msgid "Distance (mm):" msgstr "Abstand (mm):" #: ../src/repsnapper.ui.h:90 msgid "Distance Between Lines" msgstr "Abstand zwischen Linien" #: ../src/repsnapper.ui.h:91 msgid "Divide" msgstr "Aufteilen" #: ../src/repsnapper.ui.h:92 msgid "Draw GCode" msgstr "GCode zeigen" #: ../src/repsnapper.ui.h:93 msgid "Draw Layers" msgstr "Schichten zeigen" #: ../src/repsnapper.ui.h:94 msgid "Draw Line Numbers" msgstr "Liniennummern zeigen" #: ../src/repsnapper.ui.h:95 msgid "Draw Polygon Numbers" msgstr "Polygonnummern zeigen" #: ../src/repsnapper.ui.h:96 msgid "Draw Vertex Numbers" msgstr "Punktnummern zeigen" #: ../src/repsnapper.ui.h:97 msgid "E max" msgstr "" #: ../src/repsnapper.ui.h:98 msgid "Echo" msgstr "" #: ../src/repsnapper.ui.h:99 msgid "Edit" msgstr "Bearbeiten" #: ../src/repsnapper.ui.h:100 msgid "Enable Acceleration" msgstr "Beschleunigung aktivieren" #: ../src/repsnapper.ui.h:101 msgid "Enable Antiooze Retract" msgstr "Filamentrückzug aktivieren" #: ../src/repsnapper.ui.h:102 msgid "Enable Debug" msgstr "Debuggen" #: ../src/repsnapper.ui.h:103 msgid "Enable Lights" msgstr "Beleuchtung aktivieren" #: ../src/repsnapper.ui.h:104 msgid "Enable Raft" msgstr "Unterlage erstellen" #: ../src/repsnapper.ui.h:105 msgid "End" msgstr "Ende" #: ../src/repsnapper.ui.h:106 msgid "Endpoints" msgstr "Endpunkte" #: ../src/repsnapper.ui.h:107 msgid "Errors/Warnings" msgstr "Fehler/Warnungen" #: ../src/repsnapper.ui.h:108 msgid "Exit Repsnapper" msgstr "Repsnapper beenden" #: ../src/repsnapper.ui.h:109 msgid "Extruded Lines" msgstr "Extrudierte Linien" #: ../src/repsnapper.ui.h:110 msgid "Extruders" msgstr "Extruder" #: ../src/repsnapper.ui.h:111 msgid "Extrusion Factor:" msgstr "Extrusionsfaktor:" #: ../src/repsnapper.ui.h:112 msgid "Extrusion Multiplier" msgstr "Gesamtextrudierfaktor" #: ../src/repsnapper.ui.h:113 msgid "Extrusion Ratio" msgstr "Extrusionsfaktor" #: ../src/repsnapper.ui.h:114 msgid "Extrusion Width/Height Ratio" msgstr "Extrusionsbreite/-höhe" #: ../src/repsnapper.ui.h:115 msgid "Fan Control" msgstr "Lüftersteuerung" #: ../src/repsnapper.ui.h:116 msgid "Fan Enabled" msgstr "Lüfter an" #: ../src/repsnapper.ui.h:117 msgid "Fan Level" msgstr "Lüfterstärke" #: ../src/repsnapper.ui.h:118 msgid "Filament Diameter" msgstr "Filamentdurchmesser" #: ../src/repsnapper.ui.h:119 msgid "Files" msgstr "Dateien" #: ../src/repsnapper.ui.h:120 msgid "Fill Layer Areas" msgstr "Schichten füllen" #: ../src/repsnapper.ui.h:121 msgid "Fill Skirt Area" msgstr "Skirt füllen" #: ../src/repsnapper.ui.h:122 msgid "From/Single:" msgstr "Von/Einzeln:" #: ../src/repsnapper.ui.h:123 msgid "Fullscreen" msgstr "Vollbild" #: ../src/repsnapper.ui.h:125 msgid "GCode Letter" msgstr "GCode-Zeichen" #: ../src/repsnapper.ui.h:126 msgid "GCode when Printing" msgstr "GCode, während gedruckt wird" #: ../src/repsnapper.ui.h:127 msgid "Generate _GCode" msgstr "_GCode erzeugen" #: ../src/repsnapper.ui.h:128 msgid "Hardware Settings" msgstr "Gerät" #: ../src/repsnapper.ui.h:129 msgid "Height (mm):" msgstr "Höhe (mm):" #: ../src/repsnapper.ui.h:130 msgid "Height:" msgstr "Höhe:" #: ../src/repsnapper.ui.h:131 msgid "Highlight Strength" msgstr "Stärke der Hervorhebung" #: ../src/repsnapper.ui.h:132 msgid "Hollow" msgstr "Hohlform" #: ../src/repsnapper.ui.h:133 msgid "Home All" msgstr "Alle in Ausgangsposition" #: ../src/repsnapper.ui.h:136 #, no-c-format msgid "Infill %" msgstr "Füllung %" #: ../src/repsnapper.ui.h:137 msgid "Infill Distance:" msgstr "Füllungsabstand:" #: ../src/repsnapper.ui.h:138 msgid "Infill Overlap:" msgstr "Füllungsüberhang:" #: ../src/repsnapper.ui.h:139 msgid "Invert Normals" msgstr "Normalen umkehren" #: ../src/repsnapper.ui.h:140 msgid "Kick" msgstr "" #: ../src/repsnapper.ui.h:141 msgid "LGPLv2+, GPLv2+, and other licenses, see licenses.txt" msgstr "LGPLv2+, GPLv2+ und andere Lizenzen, siehe licenses.txt" #: ../src/repsnapper.ui.h:142 msgid "Larger Than Object (mm)" msgstr "Größer als Objekt (mm)" #: ../src/repsnapper.ui.h:143 msgid "Layer Height:" msgstr "Schichtdicke:" #: ../src/repsnapper.ui.h:144 msgid "Layer Preview" msgstr "Vorschau" #: ../src/repsnapper.ui.h:145 msgid "Length" msgstr "Länge" #: ../src/repsnapper.ui.h:146 msgid "Length (mm)" msgstr "Länge (mm)" #: ../src/repsnapper.ui.h:147 msgid "Lift Z on all moves" msgstr "Alle Bewegungen anheben" #: ../src/repsnapper.ui.h:148 msgid "Load GCode" msgstr "GCode laden" #: ../src/repsnapper.ui.h:149 msgid "Load Model" msgstr "Modell laden" #: ../src/repsnapper.ui.h:150 msgid "Load STL" msgstr "STL laden" #: ../src/repsnapper.ui.h:151 msgid "Load Settings" msgstr "Einstellungen laden" #: ../src/repsnapper.ui.h:152 msgid "Load _GCode" msgstr "_GCode laden" #: ../src/repsnapper.ui.h:153 msgid "Load _STL" msgstr "_STL laden" #: ../src/repsnapper.ui.h:154 msgid "Load a file of control codes" msgstr "Lädt eine GCode-Datei" #: ../src/repsnapper.ui.h:155 msgid "Load an STL file" msgstr "STL laden" #: ../src/repsnapper.ui.h:156 msgid "Load application settings profile" msgstr "Konfigurationsdatei laden" #: ../src/repsnapper.ui.h:157 msgid "Logging" msgstr "" #: ../src/repsnapper.ui.h:158 msgid "Logs" msgstr "" #: ../src/repsnapper.ui.h:159 msgid "Make enough solid layers to reach minimum thickness (mm)" msgstr "So viele Schichten erzeugen, wie für diese Dicke benötigt werden (mm)" #: ../src/repsnapper.ui.h:160 msgid "Max" msgstr "" #: ../src/repsnapper.ui.h:161 msgid "Max. Angles:" msgstr "Max. Winkel" #: ../src/repsnapper.ui.h:162 msgid "Max. Overhang Speed (mm/sec):" msgstr "Max. Geschw. bei Überhang (mm/s):" #: ../src/repsnapper.ui.h:163 msgid "Max. Speed:" msgstr "Max. Geschw." #: ../src/repsnapper.ui.h:164 msgid "Maximum Line Width (~Nozzle Diameter)" msgstr "Maximale Linienbreite (~Düsendurchmesser)" #: ../src/repsnapper.ui.h:165 msgid "Merge" msgstr "Vereinigen" #: ../src/repsnapper.ui.h:166 msgid "Milling Settings" msgstr "Fräsen" #: ../src/repsnapper.ui.h:167 msgid "Min" msgstr "" #: ../src/repsnapper.ui.h:168 msgid "Min. Angle:" msgstr "Min. Winkel" #: ../src/repsnapper.ui.h:169 msgid "Min. Arc Length (mm):" msgstr "Ab Bogenlänge (mm)" #: ../src/repsnapper.ui.h:170 msgid "Min. Speed:" msgstr "Min. Geschw." #: ../src/repsnapper.ui.h:171 msgid "Minimum Distance (mm):" msgstr "Ab Distanz (mm):" #: ../src/repsnapper.ui.h:172 msgid "Minimum Infill Distance (line widths)" msgstr "Minimaler Füllungsabstand (Linienbreiten)" #: ../src/repsnapper.ui.h:173 msgid "Minimum Line Width (~Nozzle Diameter)" msgstr "Minimale Linienbreite (~Düsendurchmesser)" #: ../src/repsnapper.ui.h:174 msgid "Minimum Shell Time (s):" msgstr "Mindestzeit pro Hülle (s):" #: ../src/repsnapper.ui.h:175 msgid "Minimum Time per Layer (s):" msgstr "Mindestzeit pro Schicht (s):" #: ../src/repsnapper.ui.h:176 msgid "Mirror" msgstr "Spiegeln" #: ../src/repsnapper.ui.h:178 msgid "Monitor Temperature" msgstr "Temp. überwachen" #: ../src/repsnapper.ui.h:179 msgid "Move Head Colour" msgstr "Farbe Bewegung" #: ../src/repsnapper.ui.h:180 msgid "Move between nearest points of polygons" msgstr "Bewegung nach kürzester Verbindung" #: ../src/repsnapper.ui.h:181 msgid "Moves" msgstr "Bewegungen" #: ../src/repsnapper.ui.h:182 msgid "" "Multiple Objects are combined and saved binary..\n" "Otherwise the STL will contain separate Objects and it will be in ASCII mode " "(some programs won't be able to read them)" msgstr "" #: ../src/repsnapper.ui.h:184 msgid "Name" msgstr "" #: ../src/repsnapper.ui.h:185 msgid "New" msgstr "Neu" #: ../src/repsnapper.ui.h:186 msgid "Next Layer" msgstr "Schichtwechsel" #: ../src/repsnapper.ui.h:187 msgid "No Covers" msgstr "Ohne Abdeckung" #: ../src/repsnapper.ui.h:188 msgid "Normal Fill:" msgstr "Normale Füllung:" #: ../src/repsnapper.ui.h:189 msgid "Normals" msgstr "Normalen" #: ../src/repsnapper.ui.h:190 msgid "Number of Layers" msgstr "Anzahl Schichten" #: ../src/repsnapper.ui.h:191 msgid "Number of first Layers:" msgstr "Anzahl Grundschichten" #: ../src/repsnapper.ui.h:192 msgid "Number of lines of output to retain for each scrollback buffer" msgstr "Zeilenanzahl, die im Puffer bleiben soll" #: ../src/repsnapper.ui.h:193 msgid "Offset Outer Shells by (mm):" msgstr "Außenhülle versetzen (mm):" #: ../src/repsnapper.ui.h:194 msgid "On Platform" msgstr "Auf Plattform" #: ../src/repsnapper.ui.h:195 msgid "Open the Preferences Dialog" msgstr "Öffnet den Einstellungsdialog" #: ../src/repsnapper.ui.h:196 msgid "Optimization" msgstr "Optimierung" #: ../src/repsnapper.ui.h:197 msgid "Otherwise use different GCode Letters" msgstr "Andernfalls mit verschiedenen GCode-Zeichen" #: ../src/repsnapper.ui.h:198 msgid "Output Progress to Terminal" msgstr "Status im Terminal ausgeben" #: ../src/repsnapper.ui.h:199 msgid "Pause" msgstr "Pause" #: ../src/repsnapper.ui.h:201 msgid "Power On" msgstr "Anschalten" #: ../src/repsnapper.ui.h:202 msgid "Preferences" msgstr "_Einstellungen" #: ../src/repsnapper.ui.h:203 msgid "Preview" msgstr "Vorschau" #: ../src/repsnapper.ui.h:204 msgid "Preview/Live Extrude Color" msgstr "Vorschau/Live-Extrudierfarbe" #: ../src/repsnapper.ui.h:205 msgid "Print" msgstr "Drucken" #: ../src/repsnapper.ui.h:206 msgid "Printer" msgstr "Drucker" #: ../src/repsnapper.ui.h:207 msgid "Printer Buffer Size (Lines of GCode)" msgstr "Puffergröße (GCode-Zeilen)" #: ../src/repsnapper.ui.h:208 msgid "Progress" msgstr "Status" #: ../src/repsnapper.ui.h:209 msgid "Purge" msgstr "Auswerfen" #: ../src/repsnapper.ui.h:210 msgid "Quit" msgstr "Beenden" #: ../src/repsnapper.ui.h:211 msgid "Raft" msgstr "Unterlage" #: ../src/repsnapper.ui.h:212 msgid "Randomize Lines" msgstr "Linien randomisieren" #: ../src/repsnapper.ui.h:213 msgid "Recommended value for FiveD is 4" msgstr "Empfohlen für FiveD: 4" #: ../src/repsnapper.ui.h:214 msgid "Relative Ecode" msgstr "Relativer E-Code" #: ../src/repsnapper.ui.h:215 msgid "Remove" msgstr "Entfernen" #: ../src/repsnapper.ui.h:216 msgid "Reset" msgstr "Zurücksetzen" #: ../src/repsnapper.ui.h:217 msgid "Reset Printer" msgstr "Drucker zurücksetzen" #: ../src/repsnapper.ui.h:218 msgid "Result" msgstr "Ergebnis" #: ../src/repsnapper.ui.h:219 msgid "Rotate:" msgstr "Drehen:" #: ../src/repsnapper.ui.h:220 msgid "Rotation" msgstr "Drehung" #: ../src/repsnapper.ui.h:221 msgid "Rotation per Layer" msgstr "Drehung pro Schicht" #: ../src/repsnapper.ui.h:222 msgid "Rotation per Layer (°):" msgstr "Drehung pro Schicht (°):" #: ../src/repsnapper.ui.h:223 msgid "Rotation:" msgstr "Drehung:" #: ../src/repsnapper.ui.h:224 msgid "Round Corners" msgstr "Ecken abrunden" #: ../src/repsnapper.ui.h:225 msgid "Save GCode and Close" msgstr "GCode speichern und Ende" #: ../src/repsnapper.ui.h:226 msgid "Save STL as Single Object" msgstr "Alles als ein Gesamtobjekt speichern" #: ../src/repsnapper.ui.h:227 msgid "Save Settings" msgstr "Einstellungen speichern" #: ../src/repsnapper.ui.h:228 msgid "Save Settings As" msgstr "Einstellungen speichern unter ..." #: ../src/repsnapper.ui.h:229 msgid "Save application settings profile" msgstr "Konfigurationsdatei speichern" #: ../src/repsnapper.ui.h:230 msgid "Save as STL/AMF" msgstr "Modell als STL/AMF speichern" #: ../src/repsnapper.ui.h:231 msgid "Save settings in a custom file" msgstr "Konfigurationsdatei angeben" #: ../src/repsnapper.ui.h:232 msgid "Scale:" msgstr "Skalieren:" #: ../src/repsnapper.ui.h:233 msgid "Scrollback" msgstr "" #: ../src/repsnapper.ui.h:234 msgid "Selected Only" msgstr "Nur markierte" #: ../src/repsnapper.ui.h:235 msgid "Send GCode" msgstr "GCode senden" #: ../src/repsnapper.ui.h:236 msgid "Send Speed on Every GCode Command" msgstr "Geschwindigkeit mit jedem GCode-Befehl" #: ../src/repsnapper.ui.h:237 msgid "Serial Link Speed" msgstr "Geschwindigkeit der seriellen Schnittstelle" #: ../src/repsnapper.ui.h:238 msgid "Serial _Build" msgstr "Se_riell erstellen" #: ../src/repsnapper.ui.h:239 msgid "Serial comms debug" msgstr "Schittstelle debuggen" #: ../src/repsnapper.ui.h:240 msgid "Settings set" msgstr "Einstellungen" #: ../src/repsnapper.ui.h:241 msgid "Shade Wireframe" msgstr "Drahtmodell schattieren" #: ../src/repsnapper.ui.h:243 msgid "Shells:" msgstr "Hüllen:" #: ../src/repsnapper.ui.h:244 msgid "Show Extruder Number on GCode" msgstr "Extruder-Nummer bei GCode zeigen" #: ../src/repsnapper.ui.h:245 msgid "Show GCode with Extruder Offset" msgstr "GCode mit Extruder-Versatz zeigen" #: ../src/repsnapper.ui.h:246 msgid "Show Layer Overhang Areas" msgstr "Überhänge zeigen" #: ../src/repsnapper.ui.h:247 msgid "Single Layer SVGs" msgstr "Einzelne Schichten" #: ../src/repsnapper.ui.h:248 msgid "Size" msgstr "Größe" #: ../src/repsnapper.ui.h:249 msgid "Skins:" msgstr "" #: ../src/repsnapper.ui.h:251 msgid "Slice to S_VG" msgstr "Schichten-SVG" #: ../src/repsnapper.ui.h:252 msgid "Solid Fill:" msgstr "Volle Füllung:" #: ../src/repsnapper.ui.h:253 msgid "Solid Thickness:" msgstr "Voll füllen bis" #: ../src/repsnapper.ui.h:254 msgid "Speed (mm/s)" msgstr "Geschwindigkeit (mm/s):" #: ../src/repsnapper.ui.h:255 msgid "Speed (mm/sec):" msgstr "Geschwindigkeit (mm/s):" #: ../src/repsnapper.ui.h:256 msgid "Speed Ratio:" msgstr "Rel. Geschwindigkeit:" #: ../src/repsnapper.ui.h:257 msgid "Speeds are handled as mm/sec" msgstr "Geschwindigkeiten in mm/s" #: ../src/repsnapper.ui.h:258 msgid "Split" msgstr "Teilen" #: ../src/repsnapper.ui.h:259 msgid "Start" msgstr "Starten" #: ../src/repsnapper.ui.h:260 msgid "Summary" msgstr "Zusammenfassung" #: ../src/repsnapper.ui.h:261 msgid "Summary of Hardware Settings" msgstr "Gerät" #: ../src/repsnapper.ui.h:262 msgid "Support:" msgstr "Gerüst:" #: ../src/repsnapper.ui.h:263 msgid "Surface" msgstr "Oberfläche" #: ../src/repsnapper.ui.h:264 msgid "Surface Normals" msgstr "Flächennormalen" #: ../src/repsnapper.ui.h:265 msgid "Temperature Ratio" msgstr "Temperaturverhältnis" #: ../src/repsnapper.ui.h:266 msgid "Thickness Ratio" msgstr "Schichtdickenverhältnis" #: ../src/repsnapper.ui.h:267 msgid "To Platform" msgstr "Auf Plattform" #: ../src/repsnapper.ui.h:268 msgid "To:" msgstr "Bis:" #: ../src/repsnapper.ui.h:269 msgid "Tool Diameter" msgstr "Werkzeugdurchmesser" #: ../src/repsnapper.ui.h:270 msgid "Translate:" msgstr "Verschieben:" #: ../src/repsnapper.ui.h:271 msgid "Twist:" msgstr "Verdrehen:" #: ../src/repsnapper.ui.h:272 msgid "Update Interval (sec)" msgstr "Aktualisierung (s)" #: ../src/repsnapper.ui.h:273 msgid "Use Extruder:" msgstr "Extruder:" #: ../src/repsnapper.ui.h:274 msgid "Use T Command to Change Extruder" msgstr "Extruderwechsel mit T-Befehl" #: ../src/repsnapper.ui.h:275 msgid "Use this Extruder for Support" msgstr "Diesen Extruder für Gerüst verwenden" #: ../src/repsnapper.ui.h:276 msgid "Validate Connection" msgstr "Verbindung prüfen" #: ../src/repsnapper.ui.h:277 msgid "Variable Slicing" msgstr "Variable Schichten" #: ../src/repsnapper.ui.h:278 msgid "Very First Layer Height Ratio" msgstr "Rel. Höhe der allerersten Schicht" #: ../src/repsnapper.ui.h:279 msgid "Website" msgstr "" #: ../src/repsnapper.ui.h:280 msgid "Widen:" msgstr "Verbreitern:" #: ../src/repsnapper.ui.h:281 msgid "Wireframe" msgstr "Drahtmodell" #: ../src/repsnapper.ui.h:282 msgid "X" msgstr "" #: ../src/repsnapper.ui.h:283 msgid "X +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:284 msgid "X +1 mm" msgstr "" #: ../src/repsnapper.ui.h:285 msgid "X +10 mm" msgstr "" #: ../src/repsnapper.ui.h:286 msgid "X -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:287 msgid "X -1 mm" msgstr "" #: ../src/repsnapper.ui.h:288 msgid "X -10 mm" msgstr "" #: ../src/repsnapper.ui.h:289 msgid "X Offset (mm)" msgstr "" #: ../src/repsnapper.ui.h:290 msgid "X+" msgstr "" #: ../src/repsnapper.ui.h:291 msgid "X-" msgstr "" #: ../src/repsnapper.ui.h:292 msgid "X/Y Axes:" msgstr "X/Y-Achsen:" #: ../src/repsnapper.ui.h:293 msgid "X:" msgstr "" #: ../src/repsnapper.ui.h:294 msgid "Y" msgstr "" #: ../src/repsnapper.ui.h:295 msgid "Y +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:296 msgid "Y +1 mm" msgstr "" #: ../src/repsnapper.ui.h:297 msgid "Y +10 mm" msgstr "" #: ../src/repsnapper.ui.h:298 msgid "Y -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:299 msgid "Y -1 mm" msgstr "" #: ../src/repsnapper.ui.h:300 msgid "Y -10 mm" msgstr "" #: ../src/repsnapper.ui.h:301 msgid "Y Offset (mm)" msgstr "" #: ../src/repsnapper.ui.h:302 msgid "Y+" msgstr "" #: ../src/repsnapper.ui.h:303 msgid "Y-" msgstr "" #: ../src/repsnapper.ui.h:304 msgid "Y:" msgstr "" #: ../src/repsnapper.ui.h:305 msgid "Z" msgstr "" #: ../src/repsnapper.ui.h:306 msgid "Z +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:307 msgid "Z +1 mm" msgstr "" #: ../src/repsnapper.ui.h:308 msgid "Z +10 mm" msgstr "" #: ../src/repsnapper.ui.h:309 msgid "Z -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:310 msgid "Z -1 mm" msgstr "" #: ../src/repsnapper.ui.h:311 msgid "Z -10 mm" msgstr "" #: ../src/repsnapper.ui.h:312 msgid "Z Axis:" msgstr "Z-Achse:" #: ../src/repsnapper.ui.h:313 msgid "Z Down" msgstr "" #: ../src/repsnapper.ui.h:314 msgid "Z Up" msgstr "" #: ../src/repsnapper.ui.h:315 msgid "Z lift on move (mm):" msgstr "Anheben bei Bewegung (mm):" #: ../src/repsnapper.ui.h:316 msgid "Z+" msgstr "" #: ../src/repsnapper.ui.h:317 msgid "Z-" msgstr "" #: ../src/repsnapper.ui.h:318 msgid "Z:" msgstr "" #: ../src/repsnapper.ui.h:319 msgid "_About" msgstr "Ü_ber" #: ../src/repsnapper.ui.h:320 msgid "_Autoplace" msgstr "_Autom. platzieren" #: ../src/repsnapper.ui.h:321 msgid "_Calibrate" msgstr "_Kalibrieren" #: ../src/repsnapper.ui.h:322 msgid "_Edit" msgstr "_Bearbeiten" #: ../src/repsnapper.ui.h:323 msgid "_File" msgstr "_Datei" #: ../src/repsnapper.ui.h:324 msgid "_Help" msgstr "_Hilfe" #: ../src/repsnapper.ui.h:325 msgid "_Load GCode" msgstr "GCode laden" #: ../src/repsnapper.ui.h:326 msgid "_Preferences" msgstr "_Einstellungen" #: ../src/repsnapper.ui.h:327 msgid "_Quit" msgstr "Beenden" #: ../src/repsnapper.ui.h:328 msgid "_Save GCode" msgstr "GCode speichern" #: ../src/repsnapper.ui.h:329 msgid "_Support" msgstr "Gerüs_t" #: ../src/repsnapper.ui.h:330 msgid "label" msgstr "" #: ../src/repsnapper.ui.h:331 msgid "lines" msgstr "Zeilen" #: ../src/repsnapper.ui.h:332 msgid "mm" msgstr "" #: ../src/repsnapper.ui.h:333 msgid "repsnapper Preferences" msgstr "repsnapper-Einstellungen" #~ msgid "Extruder" #~ msgstr "Extruder" #~ msgid "Reverse Extrude" #~ msgstr "Extrudierung umkehren" #~ msgid "Overall Factor" #~ msgstr "Globaler Faktor" #~ msgid "Use Filament lenght" #~ msgstr "Filamentlänge benutzen" #~ msgid "Use this letter for this extruder in Gcode" #~ msgstr "Diesen Buchstaben im Gcode für diesen Extruder verwenden" #~ msgid "aimed width to height of extruded line" #~ msgstr "Angestrebtes Verhältnis Breite zu Höhe der extrudierten Linie" #~ msgid "Moving GCode" #~ msgstr "GCode versetzen" #~ msgid "Extrude Colour" #~ msgstr "Extrusionsfarbe" #~ msgid "Extruded Material Width Ratio:" #~ msgstr "Breite zu Höhe des extrudierten Materials" #~ msgid "Extrusion Settings" #~ msgstr "Extrusion" #~ msgid "Line width in proportion to layer height" #~ msgstr "Linienbreite im Verhältnis zur Höhe bzw. Schichtdicke" #~ msgid "" #~ "Manual tweak-able to increase or decrease the flow rate beyond what is " #~ "specified above." #~ msgstr "Zusätzliche manuelle Kalibrierung für Flussrate" #~ msgid "Maximum E speed the extruder can stand" #~ msgstr "Maximalgeschwindigkeit, die der Extruder aushält" #~ msgid "Print Speed Multiplier" #~ msgstr "Geschwindigkeitsfaktor" #~ msgid "" #~ "Whether the 'mm' we generate in gcode are measured as mm of cold input " #~ "filament, if not set is of hot output extrudate. More modern repraps can " #~ "adapt their output and layer height by measuring the input flow rate and " #~ "altering the layer height dynamically. If this is set, you also need to " #~ "set the filament diameter." #~ msgstr "" #~ "GCode enthält die Längen in Einheiten des Filaments, oder des " #~ "extrudierten\n" #~ "Materials. " #~ msgid "Speed (mm/min)" #~ msgstr "Geschwindigkeit (mm/min)" #~ msgid "Restart" #~ msgstr "Neustart" #~ msgid "Continue" #~ msgstr "Fortfahren" #~ msgid "_Print" #~ msgstr "_Drucken" #~ msgid "No VRML file file passed to loadASCIIVRML" #~ msgstr "Keine VRML-Datei an loadASCIIVRML gegeben" #~ msgid "None ASCII STL file passed to loadASCIIFile" #~ msgstr "Keine ASCII-Datei in loadASCIIFile" #~ msgid "Could not read file in ASCII mode, trying Binary: " #~ msgstr "Kann nicht als ASCII laden, versuche binär:" #~ msgid "Printed" #~ msgstr "Gedruckt" #~ msgid "Error (%d) '%s' - user popup ?" #~ msgstr "Fehler (%d) '%s' - Fenster?" #~ msgid "GCode Postprocessor Command (must handle stdin and stdout):" #~ msgstr "" #~ "GCode-Postprozessor-Programm (muss Stdeing. nach Stdausg. konvertieren)" #~ msgid "Readable Files" #~ msgstr "Lesbare Dateien" #~ msgid "One Layer per File" #~ msgstr "Eine Schicht pro Datei" #~ msgid "Choose settings filename" #~ msgstr "Einstellungsdatei wählen" #~ msgid "Choose GCODE filename" #~ msgstr "GCODE-Datei wählen" #~ msgid "Choose SVG filename" #~ msgstr "SVG-Datei wählen" #~ msgid "Choose filename" #~ msgstr "Datei wählen" #~ msgid " hrs," #~ msgstr " Std," #~ msgid " hr," #~ msgstr " Std," #~ msgid " min " #~ msgstr " Min " #~ msgid "left)" #~ msgstr ")" #~ msgid "Heat On" #~ msgstr "Heizung an" #~ msgid "Temp. (°C)" #~ msgstr "Temp. (°C)" #~ msgid "" #~ msgstr "" #~ msgid "Autoplace on loading" #~ msgstr "_Autom. platzieren" #~ msgid "Divide at Z=0" #~ msgstr "Bei Z=0 aufteilen" #~ msgid "Draw Models: " #~ msgstr "Objekte zeigen: " #~ msgid "Machine Code" #~ msgstr "GCode" #~ msgid "No Infill" #~ msgstr "Ohne Füllung" #~ msgid "Printer Controls" #~ msgstr "Drucker" #~ msgid "Rearrange all not currently selected shapes" #~ msgstr "Objekte neu anordnen" #~ msgid "Slice only and save to SVG file" #~ msgstr "Nur Schichten in SVG speichern" #~ msgid "Slice only currently selected shapes" #~ msgstr "Nur gewählte Objekte" #~ msgid "Verical subdivisions of outer shells" #~ msgstr "Vertikale Unterteilung der äußeren Hülle" #~ msgid " shapes " #~ msgstr " Teile " #~ msgid " " #~ msgstr " " #~ msgid "" #~ "Arc start distance from corner\n" #~ "(line width ratio)" #~ msgstr "" #~ "Entfernung Bogenansatz von der Ecke\n" #~ "(in Linienbreiten)" #~ msgid "For drawing/milling" #~ msgstr "Zeichnen/Fräsen" #~ msgid "" #~ "If an arc is shorter, will be replaced by 2 straight lines.\n" #~ "(Firmware minimum arc size)" #~ msgstr "" #~ "Wenn ein Bogen kürzer ist, wird er durch 2 Linien ersetzt\n" #~ "(Minimale Bogenlänge der Druckerfirmware)" #~ msgid "Make Corners into arcs" #~ msgstr "Ecken in Bögen umwandeln" #~ msgid "Maximum angle between consecutive lines" #~ msgstr "Maximaler Winkel zwischen aufeinanderfolgenden Linien" #~ msgid "On-Halt Ratio" #~ msgstr "Anteil bei Halt" #~ msgid "Raft Settings" #~ msgstr "Unterlage" #~ msgid "Converting" #~ msgstr "Konvertiere" #~ msgid "Sort Printed Lines by Length" #~ msgstr "Gedruckte Linien nach Länge sortieren" #~ msgid "how much should be retracted and repushed while halting" #~ msgstr "Anteil Rückzug und Vorschub während des Haltens" #~ msgid "Auto Rotate" #~ msgstr "Automatisch drehen" #~ msgid "" #~ "Build each Object separately, one after another\n" #~ "\n" #~ "THERE MUST BE ENOUGH OBJECT DISTANCE FOR \n" #~ "THE HEAD MOVING DOWN!\n" #~ msgstr "" #~ "Objekte hintereinander erstellen\n" #~ "\n" #~ "AUF AUSREICHENDEN OBJEKTABSTAND ACHTEN!\n" #~ "\n" #~ msgid "Infill Percent" #~ msgstr "Füllung (%)" #~ msgid "Make decoration infill on top layers" #~ msgstr "Dekorative Füllung bei Deckschichten" #~ msgid "Object Rotation:" #~ msgstr "Drehen:" #~ msgid "Object Scaling:" #~ msgstr "Skalieren:" #~ msgid "Size" #~ msgstr "Größe" #~ msgid "Material/Distance Ratio" #~ msgstr "Material-Abstands-Verhältnis" #~ msgid "Number of Interface Layers" #~ msgstr "Anzahl Zwischenschichten" #~ msgid "Solid Tops and Bottoms" #~ msgstr "Ober- und Unterseiten voll" #~ msgid "Text Output" #~ msgstr "Textausgabe" #~ msgid "Alternate Layers every:" #~ msgstr "Altern. Füllung jede ..te Schicht:" #~ msgid "Bridges are sometimes buggy" #~ msgstr "Brücken können fehlerhaft sein" #~ msgid "On top and bottom layers" #~ msgstr "Oberste und unterste Schichten" #~ msgid "Filament Retract move" #~ msgstr "Filamentrückzug Bewegung" #~ msgid "Filament Retract pushback" #~ msgstr "Filamentrückzug Ende" #~ msgid "Repush Ratio" #~ msgstr "Zurückschieben (Anteil)" #~ msgid "No input file given (use -i)" #~ msgstr "Keine Eingabedatei angegeben (-i)" #, fuzzy #~ msgid "Incremental E Code" #~ msgstr "Relative Extrudierlängen" #~ msgid "Full Fill" #~ msgstr "Komplette Füllung" #~ msgid "" #~ "If you have a really obsolete reprap without a stepper controlled " #~ "extruder you need to turn this on." #~ msgstr "Bei älterem Modell ohne Schrittmotor am Extruder" #~ msgid "Incremental Ecode" #~ msgstr "Relative Extrudierlängen" #~ msgid "Use 3D GCode" #~ msgstr "3D-GCode verwenden" #~ msgid "From:" #~ msgstr "Von:" #~ msgid "Dec. Infill Distance" #~ msgstr "Füllungsabstand Dekor" #~ msgid "Support Fill" #~ msgstr "Gerüstfüllung" #~ msgid "Cooling:" #~ msgstr "Kühlung" #~ msgid "" #~ "Draws a line around everything up to the given height to help keeping " #~ "warm. \n" #~ "Distance is twice the Infill Distance." #~ msgstr "" #~ "Eine Umrandung um alle Objekte erstellen\n" #~ "Abstand im doppelten Füllungsabstand" #~ msgid "Good for fast moving printers with bowden extruder" #~ msgstr "Für schnelle Drucker mit Bowden-Extruder" #~ msgid "The rotation of the first layer's infill and the support." #~ msgstr "Drehung der Füllung der ersten Schicht" #~ msgid "Send" #~ msgstr "Senden" #~ msgid "New Button" #~ msgstr "Neuer Befehl" #~ msgid "Bed" #~ msgstr "Grundplatte" #~ msgid "Level: 0-255" #~ msgstr "Stärke: 0-255" #~ msgid "Temperature Settings" #~ msgstr "Temperatur" #~ msgid "" #~ "Free parts of layers (number given by Shell Count) will be completely " #~ "filled" #~ msgstr "" #~ "Freiliegende Flächen (so viele wie Anzahl Hüllen) werden komplett gefüllt" #~ msgid "" #~ "Subdivide layers depending on steepness. Maximum divisions given by " #~ "Number of Skins" #~ msgstr "Schichten je nach Steigung unterteilen." #~ msgid " hr" #~ msgstr " Std" #~ msgid "unknown shrinking algorithm" #~ msgstr "unbekannter Schrumpfalgorithmus" #~ msgid "Reset E for the remaining print" #~ msgstr "E zurücksetzen für verbleibenden Druck" #~ msgid "Scale the selected object" #~ msgstr "Gewähltes Objekt skalieren" #~ msgid "Cutting Plane Debug" #~ msgstr "Debug Schnittebene" #~ msgid "Shrinking Quality" #~ msgstr "Schrumpf-Qualität" #~ msgid "" #~ "A comma separated list of layer numbers that should use the alternate " #~ "infill distance." #~ msgstr "Liste mit Schichtnummern, die alternativ gefüllt werden sollen" #~ msgid "Algorithm" #~ msgstr "Algorithmus" #~ msgid "Draw Cutting Plane" #~ msgstr "Schicht darstellen" #~ msgid "Draw Infill Hatching" #~ msgstr "Füllung darstellen" #~ msgid "Drawing Range End" #~ msgstr "Zeichne Bereichsende" #~ msgid "Drawing Range Start" #~ msgstr "Zeichne Bereichsanfang" #~ msgid "Enable Shell Only (No Infill)" #~ msgstr "Nur Hülle (keine Füllung)" #~ msgid "Fan Voltage" #~ msgstr "Lüfter-Stärke" #~ msgid "Shell Count" #~ msgstr "Anzahl Hüllen" repsnapper-2.3.2a5/po/en_GB.po000066400000000000000000001041021231531733200160510ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #: ../src/slicer/printlines.h:33 #, fuzzy msgid "" msgstr "" "Project-Id-Version: repsnapper 1.9.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-10-16 04:58+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: michael.meeks@novell.com\n" "Language-Team: British English \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../repsnapper.desktop.in.h:1 msgid "Controls your 3D plastic printer" msgstr "" #: ../repsnapper.desktop.in.h:2 msgid "RepRap control software" msgstr "" #: ../repsnapper.desktop.in.h:3 msgid "repsnapper" msgstr "" #: ../src/files.cpp:117 msgid "Unrecognized file - " msgstr "" #: ../src/files.cpp:118 msgid "Known extensions: " msgstr "" #: ../src/files.cpp:148 msgid "Error: Unable to open file - " msgstr "" #: ../src/files.cpp:184 ../src/files.cpp:264 ../src/files.cpp:652 msgid "Error: Unable to open stl file - " msgstr "" #: ../src/files.cpp:230 msgid "Unexpected EOF reading STL file - " msgstr "" #. cerr << "loading ascii " << endl; #. cerr << " locale " << std::locale().name() << endl; #: ../src/files.cpp:305 msgid "Unnamed" msgstr "" #: ../src/files.cpp:365 msgid "Error: Facet keyword not found in STL text!" msgstr "" #: ../src/files.cpp:374 msgid "Error: normal keyword not found in STL text!" msgstr "" #: ../src/files.cpp:391 msgid "Error: Outer/Loop keywords not found!" msgstr "" #: ../src/files.cpp:405 msgid "Error: Vertex keyword not found" msgstr "" #: ../src/files.cpp:415 msgid "Error: Endloop or endfacet keyword not found" msgstr "" #: ../src/files.cpp:443 msgid "Error: Unable to open vrml file - " msgstr "" #: ../src/flatshape.cpp:254 msgid "Split Polygons" msgstr "" #: ../src/model.cpp:87 msgid "not yet implemented\n" msgstr "" #: ../src/model.cpp:312 msgid "Reading GCode" msgstr "" #. display whole layer if flat shapes #. if (shapes.back()->dimensions() == 2) #. gcode.layerchanges.push_back(0); #: ../src/model.cpp:314 ../src/model_slice.cpp:899 ../src/model_slice.cpp:978 #: ../src/model_slice.cpp:1000 ../src/ui/view.cpp:1988 #: ../src/printer/printer.cpp:664 ../src/printer/printer_iochannel.cpp:454 #: ../src/printer/printer_libreprap.cpp:386 msgid "Done" msgstr "" #: ../src/model.cpp:587 msgid "_upper" msgstr "" #: ../src/model.cpp:588 msgid "_lower" msgstr "" #: ../src/model_slice.cpp:243 msgid "Cleanup" msgstr "" #: ../src/model_slice.cpp:318 msgid "Slicing" msgstr "" #. not bottom layer #: ../src/model_slice.cpp:470 msgid "Skins" msgstr "" #: ../src/model_slice.cpp:500 msgid "Find Uncovered" msgstr "" #: ../src/model_slice.cpp:565 msgid "Uncovered Shells" msgstr "" #: ../src/model_slice.cpp:601 msgid "Merging Full Polygons" msgstr "" #: ../src/model_slice.cpp:660 ../src/slicer/printlines.h:34 msgid "Support" msgstr "" #: ../src/model_slice.cpp:719 ../src/repsnapper.ui.h:242 msgid "Shells" msgstr "" #: ../src/model_slice.cpp:755 ../src/slicer/printlines.h:33 #: ../src/repsnapper.ui.h:134 msgid "Infill" msgstr "" #: ../src/model_slice.cpp:847 msgid "Making Lines" msgstr "" #: ../src/model_slice.cpp:849 msgid "Millimeters" msgstr "" #: ../src/model_slice.cpp:850 msgid "Absolute Pos" msgstr "" #: ../src/model_slice.cpp:852 msgid "Relative E Code" msgstr "" #: ../src/model_slice.cpp:854 msgid "Absolute E Code" msgstr "" #: ../src/model_slice.cpp:905 msgid "Time Estimation: " msgstr "" #: ../src/model_slice.cpp:906 ../src/model_slice.cpp:915 msgid "h" msgstr "" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 msgid "m" msgstr "" #: ../src/model_slice.cpp:907 ../src/model_slice.cpp:916 #: ../src/ui/progress.cpp:97 msgid "s" msgstr "" #: ../src/model_slice.cpp:914 msgid " / GCode Estimation: " msgstr "" #: ../src/model_slice.cpp:920 msgid " - total extruded: " msgstr "" #: ../src/model_slice.cpp:984 msgid "Saving Files" msgstr "" #: ../src/objtree.h:41 msgid "Unnamed object" msgstr "" #: ../src/objtree.cpp:65 msgid "" "Cannot add a 3-dimensional Shape to a 2-dimensional Model and vice versa" msgstr "" #: ../src/objtree.cpp:138 msgid "Unsaved file" msgstr "" #: ../src/render.cpp:72 msgid "failed to init gl area\n" msgstr "" #: ../src/repsnapper.cpp:57 ../src/repsnapper.cpp:62 #, c-format msgid "Version: %s\n" msgstr "" #: ../src/repsnapper.cpp:63 #, c-format msgid "" "Usage: repsnapper [OPTION]... [FILE]...\n" "Start reprap control software and load [FILES]\n" "Options:\n" " -t, --no-gui act as a head-less renderer\n" " -i, --input [file] read input Model [file]\n" " -b, --binary [file] batch convert input file to binary STL\n" " -o, --output [file] if not head-less (-t),\n" " enter non-printing GUI mode\n" " only able to output gcode to [file]\n" " --svg [file] slice to SVG file\n" " --ssvg [file] slice to single layer SVG files [file]NNNN.svg\n" " -s, --settings [file] read render settings [file]\n" " -h, --help show this help\n" "\n" "Report bugs to #repsnapper, irc.freenode.net\n" "\n" msgstr "" #: ../src/repsnapper.cpp:192 msgid "Couldn't create user config directory!" msgstr "" #: ../src/repsnapper.cpp:213 ../src/repsnapper.cpp:236 msgid "Couldn't find global configuration!" msgstr "" #: ../src/repsnapper.cpp:215 ../src/repsnapper.cpp:238 msgid "It is likely that repsnapper is not correctly installed." msgstr "" #. Fall back to global config #: ../src/repsnapper.cpp:230 msgid "Unable to create user config" msgstr "" #: ../src/repsnapper.cpp:232 msgid "" "\n" "Falling back to global config. Settings will not be saved." msgstr "" #: ../src/repsnapper.cpp:247 msgid "Failed to locate config" msgstr "" #: ../src/repsnapper.cpp:307 msgid "No output file given" msgstr "" #: ../src/settings.cpp:683 ../src/settings.cpp:1046 msgid "corrupt setting type" msgstr "" #: ../src/settings.cpp:700 msgid "Failed to load settings from file '" msgstr "" #: ../src/settings.cpp:704 msgid "Exception " msgstr "" #: ../src/settings.cpp:704 msgid " loading settings from file '" msgstr "" #: ../src/settings.cpp:708 msgid "Parsing config from '" msgstr "" #: ../src/settings.cpp:892 ../src/settings.cpp:987 msgid "Missing boolean config item " msgstr "" #: ../src/settings.cpp:903 ../src/settings.cpp:932 ../src/settings.cpp:1036 #: ../src/settings.cpp:1366 msgid "Missing user interface item " msgstr "" #: ../src/settings.cpp:941 msgid "corrupt setting type\n" msgstr "" #: ../src/settings.cpp:1000 msgid "Missing GUI element " msgstr "" #. PlaceOnPlatform(); #: ../src/shape.cpp:59 msgid "Shape has volume " msgstr "" #: ../src/shape.cpp:59 msgid " mm^3 and " msgstr "" #: ../src/shape.cpp:60 msgid " triangles" msgstr "" #: ../src/shape.cpp:107 msgid "Split Shapes" msgstr "" #: ../src/shape.cpp:113 msgid "Split: Sorting Triangles ..." msgstr "" #: ../src/shape.cpp:147 msgid "Split: Building shapes ..." msgstr "" #: ../src/shape.cpp:158 msgid "Shape " msgstr "" #. copy #: ../src/gcode/command.cpp:336 msgid " xy part" msgstr "" #. copy #: ../src/gcode/command.cpp:338 msgid " z part" msgstr "" #: ../src/gcode/command.cpp:377 msgid " Z-Change" msgstr "" #: ../src/gcode/command.cpp:388 msgid " Move Only" msgstr "" #: ../src/gcode/command.cpp:405 msgid " Select Extruder" msgstr "" #: ../src/gcode/command.cpp:409 msgid " Reset Extrusion" msgstr "" #: ../src/gcode/gcode.cpp:174 msgid "Loading GCode" msgstr "" #: ../src/gcode/gcode.cpp:648 msgid "Collecting GCode" msgstr "" #. pure extrusions #: ../src/gcode/gcodestate.cpp:215 msgid "Extrusion only " msgstr "" #: ../src/gcode/gcodestate.cpp:220 msgid "Absolute Extrusion" msgstr "" #: ../src/ui/connectview.cpp:39 msgid "Disconnecting..." msgstr "" #: ../src/ui/connectview.cpp:45 msgid "Connect" msgstr "" #: ../src/ui/connectview.cpp:51 msgid "Connecting..." msgstr "" #: ../src/ui/connectview.cpp:57 msgid "Disconnect" msgstr "" #: ../src/ui/connectview.cpp:111 msgid "Port:" msgstr "" #. file patterns #: ../src/ui/filechooser.cpp:41 msgid "All Files" msgstr "" #: ../src/ui/filechooser.cpp:44 msgid "Models" msgstr "" #: ../src/ui/filechooser.cpp:54 ../src/ui/filechooser.cpp:101 #: ../src/repsnapper.ui.h:124 msgid "GCode" msgstr "" #: ../src/ui/filechooser.cpp:60 ../src/ui/filechooser.cpp:107 msgid "Settings" msgstr "" #: ../src/ui/filechooser.cpp:112 msgid "SVG" msgstr "" #: ../src/ui/filechooser.cpp:118 ../src/repsnapper.ui.h:177 msgid "Model" msgstr "" #: ../src/ui/filechooser.cpp:133 msgid "Load" msgstr "" #: ../src/ui/filechooser.cpp:147 msgid "Save" msgstr "" #. seconds #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " done in " msgstr "" #: ../src/ui/progress.cpp:57 ../src/ui/progress.cpp:76 msgid " seconds" msgstr "" #: ../src/ui/progress.cpp:90 ../src/ui/progress.cpp:91 msgid "h " msgstr "" #: ../src/ui/progress.cpp:95 msgid "m " msgstr "" #: ../src/ui/widgets.cpp:142 msgid "Nozzle:" msgstr "" #: ../src/ui/widgets.cpp:142 msgid "Bed:" msgstr "" #: ../src/ui/widgets.cpp:146 msgid "-- °C" msgstr "" #. add(*manage (new Gtk::Label(_("°C")))); #: ../src/ui/widgets.cpp:150 msgid "Target:" msgstr "" #: ../src/ui/widgets.cpp:166 ../src/ui/widgets.cpp:187 msgid "Off" msgstr "" #: ../src/ui/widgets.cpp:185 msgid "On" msgstr "" #: ../src/ui/widgets.cpp:265 msgid "Home" msgstr "" #: ../src/ui/view.cpp:113 msgid "Complete print before converting" msgstr "" #: ../src/ui/view.cpp:114 msgid "Converting to GCode while printing will abort the print" msgstr "" #: ../src/ui/view.cpp:185 ../src/ui/view.cpp:274 msgid "Complete print before reading" msgstr "" #: ../src/ui/view.cpp:186 ../src/ui/view.cpp:275 msgid "Reading GCode while printing will abort the print" msgstr "" #: ../src/ui/view.cpp:209 ../src/ui/view.cpp:236 ../src/ui/view.cpp:255 #: ../src/ui/view.cpp:653 msgid "Overwrite File?" msgstr "" #: ../src/ui/view.cpp:326 msgid "Error reading UI description!!" msgstr "" #: ../src/ui/view.cpp:336 msgid "Couldn't find UI description!" msgstr "" #: ../src/ui/view.cpp:338 msgid "Check that repsnapper has been correctly installed." msgstr "" #: ../src/ui/view.cpp:349 msgid "Error loading UI!" msgstr "" #: ../src/ui/view.cpp:946 msgid "Reset Printer?" msgstr "" #: ../src/ui/view.cpp:1370 msgid "Output File: " msgstr "" #: ../src/printer/printer.cpp:378 ../src/printer/printer.cpp:425 #: ../src/printer/printer_iochannel.cpp:274 #: ../src/printer/printer_libreprap.cpp:213 msgid "Cannot disconnect" msgstr "" #: ../src/printer/printer.cpp:379 ../src/printer/printer.cpp:426 #: ../src/printer/printer_iochannel.cpp:275 #: ../src/printer/printer_libreprap.cpp:214 msgid "printer is printing" msgstr "" #: ../src/printer/printer.cpp:416 ../src/printer/printer_libreprap.cpp:204 msgid "Failed to connect to device" msgstr "" #: ../src/printer/printer.cpp:417 ../src/printer/printer_libreprap.cpp:205 msgid "an error occured while connecting" msgstr "" #: ../src/printer/printer.cpp:485 ../src/printer/printer_iochannel.cpp:329 #: ../src/printer/printer_libreprap.cpp:273 msgid "" "Already printing.\n" "Cannot start printing" msgstr "" #: ../src/printer/printer.cpp:501 ../src/printer/printer.cpp:507 #: ../src/printer/printer_iochannel.cpp:339 #: ../src/printer/printer_libreprap.cpp:284 msgid "" "Not connected to printer.\n" "Cannot start printing" msgstr "" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "Can't send command" msgstr "" #: ../src/printer/printer.cpp:623 ../src/printer/printer_libreprap.cpp:353 msgid "You must first connect to a device!" msgstr "" #: ../src/printer/printer.cpp:644 ../src/printer/printer_libreprap.cpp:367 msgid "" "Not connected to printer.\n" "Cannot stop printing" msgstr "" #: ../src/printer/printer.cpp:660 ../src/printer/printer_iochannel.cpp:450 #: ../src/printer/printer_libreprap.cpp:382 msgid "Printing" msgstr "" #: ../src/printer/printer.cpp:747 ../src/printer/printer_libreprap.cpp:433 msgid "Error reading from device!" msgstr "" #: ../src/printer/printer.cpp:753 ../src/printer/printer_libreprap.cpp:439 msgid "Error writing to device!" msgstr "" #: ../src/printer/printer2.cpp:29 msgid "Can't switch power while printing" msgstr "" #: ../src/printer/printer2.cpp:43 msgid "Can't go home while printing" msgstr "" #: ../src/printer/printer2.cpp:55 msgid "Home called with unknown axis" msgstr "" #: ../src/printer/printer2.cpp:65 ../src/printer/printer2.cpp:95 msgid "Can't move manually while printing" msgstr "" #: ../src/printer/printer2.cpp:85 msgid "Move called with unknown axis" msgstr "" #: ../src/printer/printer2.cpp:114 msgid "Goto called with unknown axis" msgstr "" #: ../src/printer/reprap_serial.cpp:172 msgid "Already Connected to Printer" msgstr "" #: ../src/printer/reprap_serial.cpp:451 ../src/printer/reprap_serial.cpp:458 msgid "Printing error" msgstr "" #: ../src/printer/reprap_serial.cpp:451 msgid "Not connected" msgstr "" #: ../src/printer/reprap_serial.cpp:458 msgid "Wrong line number" msgstr "" #: ../src/printer/reprap_serial.cpp:570 msgid "no reset on Windows" msgstr "" #. these are available for user selection (order must be same as types): #: ../src/slicer/infill.h:37 msgid "Parallel" msgstr "" #: ../src/slicer/infill.h:37 msgid "Zigzag" msgstr "" #: ../src/slicer/infill.h:37 msgid "Hexagons" msgstr "" #: ../src/slicer/infill.h:37 ../src/repsnapper.ui.h:200 msgid "Polygons" msgstr "" #: ../src/slicer/infill.h:37 msgid "Hilbert Curve" msgstr "" #: ../src/slicer/printlines.cpp:1665 msgid "Making GCode" msgstr "" #: ../src/slicer/printlines.h:33 msgid "Shell" msgstr "" #: ../src/slicer/printlines.h:33 msgid "Skin" msgstr "" #: ../src/slicer/printlines.h:34 ../src/repsnapper.ui.h:250 msgid "Skirt" msgstr "" #: ../src/slicer/printlines.h:34 msgid "Bridge" msgstr "" #: ../src/slicer/printlines.h:34 msgid "Command" msgstr "" #: ../src/repsnapper.ui.h:1 msgid " " msgstr "" #: ../src/repsnapper.ui.h:2 msgid " th Layer" msgstr "" #: ../src/repsnapper.ui.h:3 msgid "(C) 2008-2012 its contributors " msgstr "" #: ../src/repsnapper.ui.h:4 msgid "+" msgstr "" #: ../src/repsnapper.ui.h:5 msgid "-" msgstr "" #: ../src/repsnapper.ui.h:6 msgid "1" msgstr "" #: ../src/repsnapper.ui.h:7 msgid "2" msgstr "" #: ../src/repsnapper.ui.h:8 msgid "3" msgstr "" #: ../src/repsnapper.ui.h:9 msgid "4" msgstr "" #: ../src/repsnapper.ui.h:10 msgid "" msgstr "" #: ../src/repsnapper.ui.h:11 msgid "Acceleration" msgstr "" #: ../src/repsnapper.ui.h:12 msgid "Antiooze Retract" msgstr "" #: ../src/repsnapper.ui.h:13 msgid "Axis Moving Speeds (mm/sec)" msgstr "" #: ../src/repsnapper.ui.h:14 msgid "Base" msgstr "" #: ../src/repsnapper.ui.h:15 msgid "Comms Debug" msgstr "" #: ../src/repsnapper.ui.h:16 msgid "Cooling" msgstr "" #: ../src/repsnapper.ui.h:17 msgid "Custom Actions" msgstr "" #: ../src/repsnapper.ui.h:18 msgid "Debug GCode" msgstr "" #: ../src/repsnapper.ui.h:19 msgid "Debugging" msgstr "" #: ../src/repsnapper.ui.h:20 msgid "Extruder Settings" msgstr "" #: ../src/repsnapper.ui.h:21 msgid "First Layer(s)" msgstr "" #: ../src/repsnapper.ui.h:22 msgid "GCode Postprocessor" msgstr "" #: ../src/repsnapper.ui.h:23 msgid "GCode Rendering" msgstr "" #: ../src/repsnapper.ui.h:24 msgid "General" msgstr "" #: ../src/repsnapper.ui.h:25 msgid "Geometry" msgstr "" #: ../src/repsnapper.ui.h:26 msgid "Infill Debug" msgstr "" #: ../src/repsnapper.ui.h:27 msgid "Infill" msgstr "" #: ../src/repsnapper.ui.h:28 msgid "Interface" msgstr "" #: ../src/repsnapper.ui.h:29 msgid "Layer Debug" msgstr "" #: ../src/repsnapper.ui.h:30 msgid "Lighting" msgstr "" #: ../src/repsnapper.ui.h:31 msgid "Object" msgstr "" #: ../src/repsnapper.ui.h:32 msgid "Output" msgstr "" #: ../src/repsnapper.ui.h:33 msgid "Parameters" msgstr "" #: ../src/repsnapper.ui.h:34 msgid "Printer" msgstr "" #: ../src/repsnapper.ui.h:35 msgid "Raft" msgstr "" #: ../src/repsnapper.ui.h:36 msgid "STL Rendering Colors" msgstr "" #: ../src/repsnapper.ui.h:37 msgid "Serial Communications" msgstr "" #: ../src/repsnapper.ui.h:38 msgid "Speeds (mm/sec)" msgstr "" #: ../src/repsnapper.ui.h:39 msgid "Temperature" msgstr "" #: ../src/repsnapper.ui.h:40 msgid "?" msgstr "" #: ../src/repsnapper.ui.h:41 msgid "Acceleration Distance:" msgstr "" #: ../src/repsnapper.ui.h:42 msgid "Adjust Luminance to Indicate Speed" msgstr "" #: ../src/repsnapper.ui.h:43 msgid "All" msgstr "" #: ../src/repsnapper.ui.h:44 msgid "Alternate Infill Percent:" msgstr "" #: ../src/repsnapper.ui.h:45 msgid "Alternate Infill every " msgstr "" #: ../src/repsnapper.ui.h:46 msgid "Always done when using Support" msgstr "" #: ../src/repsnapper.ui.h:47 msgid "Amount (mm)" msgstr "" #: ../src/repsnapper.ui.h:48 msgid "Amount (mm):" msgstr "" #: ../src/repsnapper.ui.h:49 msgid "Arcs GCode (G2,G3)" msgstr "" #: ../src/repsnapper.ui.h:50 msgid "Around All Objects" msgstr "" #: ../src/repsnapper.ui.h:51 msgid "Arrows" msgstr "" #: ../src/repsnapper.ui.h:52 msgid "Auto" msgstr "" #: ../src/repsnapper.ui.h:53 msgid "Axis Control" msgstr "" #: ../src/repsnapper.ui.h:54 msgid "Base Rotation (°):" msgstr "" #: ../src/repsnapper.ui.h:55 msgid "Border" msgstr "" #: ../src/repsnapper.ui.h:56 msgid "Borders" msgstr "" #: ../src/repsnapper.ui.h:57 msgid "Bounding Boxes" msgstr "" #: ../src/repsnapper.ui.h:58 msgid "Bridges Extrusion Factor:" msgstr "" #: ../src/repsnapper.ui.h:59 msgid "Build Volume" msgstr "" #: ../src/repsnapper.ui.h:60 msgid "Calibrate mm as input" msgstr "" #: ../src/repsnapper.ui.h:61 msgid "Change image" msgstr "" #: ../src/repsnapper.ui.h:62 msgid "Choose Endpoints Colour" msgstr "" #: ../src/repsnapper.ui.h:63 msgid "Choose Extrusion Colour" msgstr "" #: ../src/repsnapper.ui.h:64 msgid "Choose Head Movement Colour" msgstr "" #: ../src/repsnapper.ui.h:65 msgid "Choose Normals Colour" msgstr "" #: ../src/repsnapper.ui.h:66 msgid "Choose Polygon Colour" msgstr "" #: ../src/repsnapper.ui.h:67 msgid "Choose Wireframe Colour" msgstr "" #: ../src/repsnapper.ui.h:68 msgid "Clear Now" msgstr "" #: ../src/repsnapper.ui.h:69 msgid "Clear on Print Start" msgstr "" #: ../src/repsnapper.ui.h:70 msgid "Clone Settings" msgstr "" #: ../src/repsnapper.ui.h:71 msgid "Colour" msgstr "" #: ../src/repsnapper.ui.h:72 msgid "Communication" msgstr "" #: ../src/repsnapper.ui.h:73 msgid "Copy" msgstr "" #: ../src/repsnapper.ui.h:74 msgid "Custom Button" msgstr "" #: ../src/repsnapper.ui.h:75 msgid "D_uplicate" msgstr "" #: ../src/repsnapper.ui.h:76 msgid "Debug" msgstr "" #: ../src/repsnapper.ui.h:77 msgid "Debug Arcs" msgstr "" #: ../src/repsnapper.ui.h:78 msgid "Debug Infill" msgstr "" #: ../src/repsnapper.ui.h:79 msgid "Decor" msgstr "" #: ../src/repsnapper.ui.h:80 msgid "Decor Layers:" msgstr "" #: ../src/repsnapper.ui.h:81 msgid "Decoration:" msgstr "" #: ../src/repsnapper.ui.h:82 msgid "Delete" msgstr "" #: ../src/repsnapper.ui.h:83 msgid "Dimensions" msgstr "" #: ../src/repsnapper.ui.h:84 msgid "Disable Bridges" msgstr "" #: ../src/repsnapper.ui.h:85 msgid "Display" msgstr "" #: ../src/repsnapper.ui.h:86 msgid "Display Colour" msgstr "" #: ../src/repsnapper.ui.h:87 msgid "Display Settings" msgstr "" #: ../src/repsnapper.ui.h:88 msgid "Distance" msgstr "" #: ../src/repsnapper.ui.h:89 msgid "Distance (mm):" msgstr "" #: ../src/repsnapper.ui.h:90 msgid "Distance Between Lines" msgstr "" #: ../src/repsnapper.ui.h:91 msgid "Divide" msgstr "" #: ../src/repsnapper.ui.h:92 msgid "Draw GCode" msgstr "" #: ../src/repsnapper.ui.h:93 msgid "Draw Layers" msgstr "" #: ../src/repsnapper.ui.h:94 msgid "Draw Line Numbers" msgstr "" #: ../src/repsnapper.ui.h:95 msgid "Draw Polygon Numbers" msgstr "" #: ../src/repsnapper.ui.h:96 msgid "Draw Vertex Numbers" msgstr "" #: ../src/repsnapper.ui.h:97 msgid "E max" msgstr "" #: ../src/repsnapper.ui.h:98 msgid "Echo" msgstr "" #: ../src/repsnapper.ui.h:99 msgid "Edit" msgstr "" #: ../src/repsnapper.ui.h:100 msgid "Enable Acceleration" msgstr "" #: ../src/repsnapper.ui.h:101 msgid "Enable Antiooze Retract" msgstr "" #: ../src/repsnapper.ui.h:102 msgid "Enable Debug" msgstr "" #: ../src/repsnapper.ui.h:103 msgid "Enable Lights" msgstr "" #: ../src/repsnapper.ui.h:104 msgid "Enable Raft" msgstr "" #: ../src/repsnapper.ui.h:105 msgid "End" msgstr "" #: ../src/repsnapper.ui.h:106 msgid "Endpoints" msgstr "" #: ../src/repsnapper.ui.h:107 msgid "Errors/Warnings" msgstr "" #: ../src/repsnapper.ui.h:108 msgid "Exit Repsnapper" msgstr "" #: ../src/repsnapper.ui.h:109 msgid "Extruded Lines" msgstr "" #: ../src/repsnapper.ui.h:110 msgid "Extruders" msgstr "" #: ../src/repsnapper.ui.h:111 msgid "Extrusion Factor:" msgstr "" #: ../src/repsnapper.ui.h:112 msgid "Extrusion Multiplier" msgstr "" #: ../src/repsnapper.ui.h:113 msgid "Extrusion Ratio" msgstr "" #: ../src/repsnapper.ui.h:114 msgid "Extrusion Width/Height Ratio" msgstr "" #: ../src/repsnapper.ui.h:115 msgid "Fan Control" msgstr "" #: ../src/repsnapper.ui.h:116 msgid "Fan Enabled" msgstr "" #: ../src/repsnapper.ui.h:117 msgid "Fan Level" msgstr "" #: ../src/repsnapper.ui.h:118 msgid "Filament Diameter" msgstr "" #: ../src/repsnapper.ui.h:119 msgid "Files" msgstr "" #: ../src/repsnapper.ui.h:120 msgid "Fill Layer Areas" msgstr "" #: ../src/repsnapper.ui.h:121 msgid "Fill Skirt Area" msgstr "" #: ../src/repsnapper.ui.h:122 msgid "From/Single:" msgstr "" #: ../src/repsnapper.ui.h:123 msgid "Fullscreen" msgstr "" #: ../src/repsnapper.ui.h:125 msgid "GCode Letter" msgstr "" #: ../src/repsnapper.ui.h:126 msgid "GCode when Printing" msgstr "" #: ../src/repsnapper.ui.h:127 msgid "Generate _GCode" msgstr "" #: ../src/repsnapper.ui.h:128 msgid "Hardware Settings" msgstr "" #: ../src/repsnapper.ui.h:129 msgid "Height (mm):" msgstr "" #: ../src/repsnapper.ui.h:130 msgid "Height:" msgstr "" #: ../src/repsnapper.ui.h:131 msgid "Highlight Strength" msgstr "" #: ../src/repsnapper.ui.h:132 msgid "Hollow" msgstr "" #: ../src/repsnapper.ui.h:133 msgid "Home All" msgstr "" #: ../src/repsnapper.ui.h:136 #, no-c-format msgid "Infill %" msgstr "" #: ../src/repsnapper.ui.h:137 msgid "Infill Distance:" msgstr "" #: ../src/repsnapper.ui.h:138 msgid "Infill Overlap:" msgstr "" #: ../src/repsnapper.ui.h:139 msgid "Invert Normals" msgstr "" #: ../src/repsnapper.ui.h:140 msgid "Kick" msgstr "" #: ../src/repsnapper.ui.h:141 msgid "LGPLv2+, GPLv2+, and other licenses, see licenses.txt" msgstr "" #: ../src/repsnapper.ui.h:142 msgid "Larger Than Object (mm)" msgstr "" #: ../src/repsnapper.ui.h:143 msgid "Layer Height:" msgstr "" #: ../src/repsnapper.ui.h:144 msgid "Layer Preview" msgstr "" #: ../src/repsnapper.ui.h:145 msgid "Length" msgstr "" #: ../src/repsnapper.ui.h:146 msgid "Length (mm)" msgstr "" #: ../src/repsnapper.ui.h:147 msgid "Lift Z on all moves" msgstr "" #: ../src/repsnapper.ui.h:148 msgid "Load GCode" msgstr "" #: ../src/repsnapper.ui.h:149 msgid "Load Model" msgstr "" #: ../src/repsnapper.ui.h:150 msgid "Load STL" msgstr "" #: ../src/repsnapper.ui.h:151 msgid "Load Settings" msgstr "" #: ../src/repsnapper.ui.h:152 msgid "Load _GCode" msgstr "" #: ../src/repsnapper.ui.h:153 msgid "Load _STL" msgstr "" #: ../src/repsnapper.ui.h:154 msgid "Load a file of control codes" msgstr "" #: ../src/repsnapper.ui.h:155 msgid "Load an STL file" msgstr "" #: ../src/repsnapper.ui.h:156 msgid "Load application settings profile" msgstr "" #: ../src/repsnapper.ui.h:157 msgid "Logging" msgstr "" #: ../src/repsnapper.ui.h:158 msgid "Logs" msgstr "" #: ../src/repsnapper.ui.h:159 msgid "Make enough solid layers to reach minimum thickness (mm)" msgstr "" #: ../src/repsnapper.ui.h:160 msgid "Max" msgstr "" #: ../src/repsnapper.ui.h:161 msgid "Max. Angles:" msgstr "" #: ../src/repsnapper.ui.h:162 msgid "Max. Overhang Speed (mm/sec):" msgstr "" #: ../src/repsnapper.ui.h:163 msgid "Max. Speed:" msgstr "" #: ../src/repsnapper.ui.h:164 msgid "Maximum Line Width (~Nozzle Diameter)" msgstr "" #: ../src/repsnapper.ui.h:165 msgid "Merge" msgstr "" #: ../src/repsnapper.ui.h:166 msgid "Milling Settings" msgstr "" #: ../src/repsnapper.ui.h:167 msgid "Min" msgstr "" #: ../src/repsnapper.ui.h:168 msgid "Min. Angle:" msgstr "" #: ../src/repsnapper.ui.h:169 msgid "Min. Arc Length (mm):" msgstr "" #: ../src/repsnapper.ui.h:170 msgid "Min. Speed:" msgstr "" #: ../src/repsnapper.ui.h:171 msgid "Minimum Distance (mm):" msgstr "" #: ../src/repsnapper.ui.h:172 msgid "Minimum Infill Distance (line widths)" msgstr "" #: ../src/repsnapper.ui.h:173 msgid "Minimum Line Width (~Nozzle Diameter)" msgstr "" #: ../src/repsnapper.ui.h:174 msgid "Minimum Shell Time (s):" msgstr "" #: ../src/repsnapper.ui.h:175 msgid "Minimum Time per Layer (s):" msgstr "" #: ../src/repsnapper.ui.h:176 msgid "Mirror" msgstr "" #: ../src/repsnapper.ui.h:178 msgid "Monitor Temperature" msgstr "" #: ../src/repsnapper.ui.h:179 msgid "Move Head Colour" msgstr "" #: ../src/repsnapper.ui.h:180 msgid "Move between nearest points of polygons" msgstr "" #: ../src/repsnapper.ui.h:181 msgid "Moves" msgstr "" #: ../src/repsnapper.ui.h:182 msgid "" "Multiple Objects are combined and saved binary..\n" "Otherwise the STL will contain separate Objects and it will be in ASCII mode " "(some programs won't be able to read them)" msgstr "" #: ../src/repsnapper.ui.h:184 msgid "Name" msgstr "" #: ../src/repsnapper.ui.h:185 msgid "New" msgstr "" #: ../src/repsnapper.ui.h:186 msgid "Next Layer" msgstr "" #: ../src/repsnapper.ui.h:187 msgid "No Covers" msgstr "" #: ../src/repsnapper.ui.h:188 msgid "Normal Fill:" msgstr "" #: ../src/repsnapper.ui.h:189 msgid "Normals" msgstr "" #: ../src/repsnapper.ui.h:190 msgid "Number of Layers" msgstr "" #: ../src/repsnapper.ui.h:191 msgid "Number of first Layers:" msgstr "" #: ../src/repsnapper.ui.h:192 msgid "Number of lines of output to retain for each scrollback buffer" msgstr "" #: ../src/repsnapper.ui.h:193 msgid "Offset Outer Shells by (mm):" msgstr "" #: ../src/repsnapper.ui.h:194 msgid "On Platform" msgstr "" #: ../src/repsnapper.ui.h:195 msgid "Open the Preferences Dialog" msgstr "" #: ../src/repsnapper.ui.h:196 msgid "Optimization" msgstr "" #: ../src/repsnapper.ui.h:197 msgid "Otherwise use different GCode Letters" msgstr "" #: ../src/repsnapper.ui.h:198 msgid "Output Progress to Terminal" msgstr "" #: ../src/repsnapper.ui.h:199 msgid "Pause" msgstr "" #: ../src/repsnapper.ui.h:201 msgid "Power On" msgstr "" #: ../src/repsnapper.ui.h:202 msgid "Preferences" msgstr "" #: ../src/repsnapper.ui.h:203 msgid "Preview" msgstr "" #: ../src/repsnapper.ui.h:204 msgid "Preview/Live Extrude Color" msgstr "" #: ../src/repsnapper.ui.h:205 msgid "Print" msgstr "" #: ../src/repsnapper.ui.h:206 msgid "Printer" msgstr "" #: ../src/repsnapper.ui.h:207 msgid "Printer Buffer Size (Lines of GCode)" msgstr "" #: ../src/repsnapper.ui.h:208 msgid "Progress" msgstr "" #: ../src/repsnapper.ui.h:209 msgid "Purge" msgstr "" #: ../src/repsnapper.ui.h:210 msgid "Quit" msgstr "" #: ../src/repsnapper.ui.h:211 msgid "Raft" msgstr "" #: ../src/repsnapper.ui.h:212 msgid "Randomize Lines" msgstr "" #: ../src/repsnapper.ui.h:213 msgid "Recommended value for FiveD is 4" msgstr "" #: ../src/repsnapper.ui.h:214 msgid "Relative Ecode" msgstr "" #: ../src/repsnapper.ui.h:215 msgid "Remove" msgstr "" #: ../src/repsnapper.ui.h:216 msgid "Reset" msgstr "" #: ../src/repsnapper.ui.h:217 msgid "Reset Printer" msgstr "" #: ../src/repsnapper.ui.h:218 msgid "Result" msgstr "" #: ../src/repsnapper.ui.h:219 msgid "Rotate:" msgstr "" #: ../src/repsnapper.ui.h:220 msgid "Rotation" msgstr "" #: ../src/repsnapper.ui.h:221 msgid "Rotation per Layer" msgstr "" #: ../src/repsnapper.ui.h:222 msgid "Rotation per Layer (°):" msgstr "" #: ../src/repsnapper.ui.h:223 msgid "Rotation:" msgstr "" #: ../src/repsnapper.ui.h:224 msgid "Round Corners" msgstr "" #: ../src/repsnapper.ui.h:225 msgid "Save GCode and Close" msgstr "" #: ../src/repsnapper.ui.h:226 msgid "Save STL as Single Object" msgstr "" #: ../src/repsnapper.ui.h:227 msgid "Save Settings" msgstr "" #: ../src/repsnapper.ui.h:228 msgid "Save Settings As" msgstr "" #: ../src/repsnapper.ui.h:229 msgid "Save application settings profile" msgstr "" #: ../src/repsnapper.ui.h:230 msgid "Save as STL/AMF" msgstr "" #: ../src/repsnapper.ui.h:231 msgid "Save settings in a custom file" msgstr "" #: ../src/repsnapper.ui.h:232 msgid "Scale:" msgstr "" #: ../src/repsnapper.ui.h:233 msgid "Scrollback" msgstr "" #: ../src/repsnapper.ui.h:234 msgid "Selected Only" msgstr "" #: ../src/repsnapper.ui.h:235 msgid "Send GCode" msgstr "" #: ../src/repsnapper.ui.h:236 msgid "Send Speed on Every GCode Command" msgstr "" #: ../src/repsnapper.ui.h:237 msgid "Serial Link Speed" msgstr "" #: ../src/repsnapper.ui.h:238 msgid "Serial _Build" msgstr "" #: ../src/repsnapper.ui.h:239 msgid "Serial comms debug" msgstr "" #: ../src/repsnapper.ui.h:240 msgid "Settings set" msgstr "" #: ../src/repsnapper.ui.h:241 msgid "Shade Wireframe" msgstr "" #: ../src/repsnapper.ui.h:243 msgid "Shells:" msgstr "" #: ../src/repsnapper.ui.h:244 msgid "Show Extruder Number on GCode" msgstr "" #: ../src/repsnapper.ui.h:245 msgid "Show GCode with Extruder Offset" msgstr "" #: ../src/repsnapper.ui.h:246 msgid "Show Layer Overhang Areas" msgstr "" #: ../src/repsnapper.ui.h:247 msgid "Single Layer SVGs" msgstr "" #: ../src/repsnapper.ui.h:248 msgid "Size" msgstr "" #: ../src/repsnapper.ui.h:249 msgid "Skins:" msgstr "" #: ../src/repsnapper.ui.h:251 msgid "Slice to S_VG" msgstr "" #: ../src/repsnapper.ui.h:252 msgid "Solid Fill:" msgstr "" #: ../src/repsnapper.ui.h:253 msgid "Solid Thickness:" msgstr "" #: ../src/repsnapper.ui.h:254 msgid "Speed (mm/s)" msgstr "" #: ../src/repsnapper.ui.h:255 msgid "Speed (mm/sec):" msgstr "" #: ../src/repsnapper.ui.h:256 msgid "Speed Ratio:" msgstr "" #: ../src/repsnapper.ui.h:257 msgid "Speeds are handled as mm/sec" msgstr "" #: ../src/repsnapper.ui.h:258 msgid "Split" msgstr "" #: ../src/repsnapper.ui.h:259 msgid "Start" msgstr "" #: ../src/repsnapper.ui.h:260 msgid "Summary" msgstr "" #: ../src/repsnapper.ui.h:261 msgid "Summary of Hardware Settings" msgstr "" #: ../src/repsnapper.ui.h:262 msgid "Support:" msgstr "" #: ../src/repsnapper.ui.h:263 msgid "Surface" msgstr "" #: ../src/repsnapper.ui.h:264 msgid "Surface Normals" msgstr "" #: ../src/repsnapper.ui.h:265 msgid "Temperature Ratio" msgstr "" #: ../src/repsnapper.ui.h:266 msgid "Thickness Ratio" msgstr "" #: ../src/repsnapper.ui.h:267 msgid "To Platform" msgstr "" #: ../src/repsnapper.ui.h:268 msgid "To:" msgstr "" #: ../src/repsnapper.ui.h:269 msgid "Tool Diameter" msgstr "" #: ../src/repsnapper.ui.h:270 msgid "Translate:" msgstr "" #: ../src/repsnapper.ui.h:271 msgid "Twist:" msgstr "" #: ../src/repsnapper.ui.h:272 msgid "Update Interval (sec)" msgstr "" #: ../src/repsnapper.ui.h:273 msgid "Use Extruder:" msgstr "" #: ../src/repsnapper.ui.h:274 msgid "Use T Command to Change Extruder" msgstr "" #: ../src/repsnapper.ui.h:275 msgid "Use this Extruder for Support" msgstr "" #: ../src/repsnapper.ui.h:276 msgid "Validate Connection" msgstr "" #: ../src/repsnapper.ui.h:277 msgid "Variable Slicing" msgstr "" #: ../src/repsnapper.ui.h:278 msgid "Very First Layer Height Ratio" msgstr "" #: ../src/repsnapper.ui.h:279 msgid "Website" msgstr "" #: ../src/repsnapper.ui.h:280 msgid "Widen:" msgstr "" #: ../src/repsnapper.ui.h:281 msgid "Wireframe" msgstr "" #: ../src/repsnapper.ui.h:282 msgid "X" msgstr "" #: ../src/repsnapper.ui.h:283 msgid "X +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:284 msgid "X +1 mm" msgstr "" #: ../src/repsnapper.ui.h:285 msgid "X +10 mm" msgstr "" #: ../src/repsnapper.ui.h:286 msgid "X -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:287 msgid "X -1 mm" msgstr "" #: ../src/repsnapper.ui.h:288 msgid "X -10 mm" msgstr "" #: ../src/repsnapper.ui.h:289 msgid "X Offset (mm)" msgstr "" #: ../src/repsnapper.ui.h:290 msgid "X+" msgstr "" #: ../src/repsnapper.ui.h:291 msgid "X-" msgstr "" #: ../src/repsnapper.ui.h:292 msgid "X/Y Axes:" msgstr "" #: ../src/repsnapper.ui.h:293 msgid "X:" msgstr "" #: ../src/repsnapper.ui.h:294 msgid "Y" msgstr "" #: ../src/repsnapper.ui.h:295 msgid "Y +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:296 msgid "Y +1 mm" msgstr "" #: ../src/repsnapper.ui.h:297 msgid "Y +10 mm" msgstr "" #: ../src/repsnapper.ui.h:298 msgid "Y -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:299 msgid "Y -1 mm" msgstr "" #: ../src/repsnapper.ui.h:300 msgid "Y -10 mm" msgstr "" #: ../src/repsnapper.ui.h:301 msgid "Y Offset (mm)" msgstr "" #: ../src/repsnapper.ui.h:302 msgid "Y+" msgstr "" #: ../src/repsnapper.ui.h:303 msgid "Y-" msgstr "" #: ../src/repsnapper.ui.h:304 msgid "Y:" msgstr "" #: ../src/repsnapper.ui.h:305 msgid "Z" msgstr "" #: ../src/repsnapper.ui.h:306 msgid "Z +0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:307 msgid "Z +1 mm" msgstr "" #: ../src/repsnapper.ui.h:308 msgid "Z +10 mm" msgstr "" #: ../src/repsnapper.ui.h:309 msgid "Z -0.1 mm" msgstr "" #: ../src/repsnapper.ui.h:310 msgid "Z -1 mm" msgstr "" #: ../src/repsnapper.ui.h:311 msgid "Z -10 mm" msgstr "" #: ../src/repsnapper.ui.h:312 msgid "Z Axis:" msgstr "" #: ../src/repsnapper.ui.h:313 msgid "Z Down" msgstr "" #: ../src/repsnapper.ui.h:314 msgid "Z Up" msgstr "" #: ../src/repsnapper.ui.h:315 msgid "Z lift on move (mm):" msgstr "" #: ../src/repsnapper.ui.h:316 msgid "Z+" msgstr "" #: ../src/repsnapper.ui.h:317 msgid "Z-" msgstr "" #: ../src/repsnapper.ui.h:318 msgid "Z:" msgstr "" #: ../src/repsnapper.ui.h:319 msgid "_About" msgstr "" #: ../src/repsnapper.ui.h:320 msgid "_Autoplace" msgstr "" #: ../src/repsnapper.ui.h:321 msgid "_Calibrate" msgstr "" #: ../src/repsnapper.ui.h:322 msgid "_Edit" msgstr "" #: ../src/repsnapper.ui.h:323 msgid "_File" msgstr "" #: ../src/repsnapper.ui.h:324 msgid "_Help" msgstr "" #: ../src/repsnapper.ui.h:325 msgid "_Load GCode" msgstr "" #: ../src/repsnapper.ui.h:326 msgid "_Preferences" msgstr "" #: ../src/repsnapper.ui.h:327 msgid "_Quit" msgstr "" #: ../src/repsnapper.ui.h:328 msgid "_Save GCode" msgstr "" #: ../src/repsnapper.ui.h:329 msgid "_Support" msgstr "" #: ../src/repsnapper.ui.h:330 msgid "label" msgstr "" #: ../src/repsnapper.ui.h:331 msgid "lines" msgstr "" #: ../src/repsnapper.ui.h:332 msgid "mm" msgstr "" #: ../src/repsnapper.ui.h:333 msgid "repsnapper Preferences" msgstr "" repsnapper-2.3.2a5/repsnapper.appdata.xml.in000066400000000000000000000013621231531733200210440ustar00rootroot00000000000000 repsnapper.desktop CC0 Repsnapper <_p> RepSnapper is an alternative host software for controlling the RepRap open source 3D printer. <_p> OpenGL User Interface (GTK), Slicer and Toolpath Generator written in C++. See also http://reprap.org/wiki/RepSnapper_Manual:Introduction http://reprap.org/mediawiki/images/6/6b/Repsnapper.png https://github.com/timschmidt/repsnapper repsnapper-2.3.2a5/repsnapper.desktop.in000066400000000000000000000003731231531733200203050ustar00rootroot00000000000000[Desktop Entry] Version=1.0 _Name=repsnapper _GenericName=RepRap control software _Comment=Controls your 3D plastic printer Exec=repsnapper %F_OR_U Icon=repsnapper Terminal=false Type=Application Categories=GTK;Utility;Engineering; StartupNotify=true repsnapper-2.3.2a5/src/000077500000000000000000000000001231531733200147125ustar00rootroot00000000000000repsnapper-2.3.2a5/src/Info.plist.default000066400000000000000000000011311231531733200203010ustar00rootroot00000000000000 CFBundleName RepSnapper CFBundleDisplayName RepSnapper CFBundleIdentifier org.reprap.repsnapper CFBundleVersion 0.0.0 CFBundlePackageType APPL CFBundleSignature rpsn CFBundleExecutable repsnapper-osx.sh repsnapper-2.3.2a5/src/Makefile000066400000000000000000000002331231531733200163500ustar00rootroot00000000000000# Delegate everything to the toplevel makefile # this is only here so 'make' works in src/ all: @$(MAKE) -C .. $@ # Catch all rule %: @$(MAKE) -C .. $@ repsnapper-2.3.2a5/src/Makefile.am000066400000000000000000000045531231531733200167550ustar00rootroot00000000000000# # Combined Makefile for Linux and OS/X # # # Copyright 2009+ Joachim Glauche # # This file is part of RepSnapper and is made available under # the terms of the GNU General Public License, version 2, or at your # option, any later version, incorporated herein by reference. bin_PROGRAMS = repsnapper LIB_DIR=$(top_srcdir)/libraries WARNING_FLAGS = -Wall -Wsign-compare -Wno-invalid-offsetof repsnapper_CPPFLAGS = \ -I$(LIB_DIR)/vmmlib/include \ -I$(LIB_DIR)/lmfit/lmfit-5.0/lib \ -I$(top_srcdir) \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/slicer \ -I$(top_builddir)/src \ -I$(LIB_DIR) \ -DHAVE_GTK $(CFLAGS) $(EXTRA_CFLAGS) -I$(LIB_DIR) $(GTKMM_CFLAGS) \ -DRSDATADIR='$(repsnapperdatadir)' \ -DSYSCONFDIR='$(repsnapperconfdir)' \ -DLOCALEDIR='"$(localedir)"' \ $(XMLPP_CFLAGS) \ $(OPENMP_CFLAGS) \ $(LIBZIP_CFLAGS) \ -g -O3 $(WARNING_FLAGS) SHARED_SRC= \ src/transform3d.cpp \ src/platform.cpp \ src/objtree.cpp \ src/model.cpp \ src/model_slice.cpp \ src/shape.cpp \ src/flatshape.cpp \ src/triangle.cpp \ src/gllight.cpp \ src/arcball.cpp \ src/render.cpp \ src/files.cpp \ src/settings.cpp SHARED_INC= \ src/transform3d.h \ src/arcball.h \ src/gllight.h \ src/miniball.h \ src/model.h \ src/objtree.h \ src/shape.h \ src/triangle.h \ src/flatshape.h \ src/files.h \ src/stdafx.h \ src/platform.h \ src/render.h \ src/settings.h \ src/types.h include src/ui/Makefile.am include src/slicer/Makefile.am include src/gcode/Makefile.am include src/printer/Makefile.am # TEST_SOURCES=unittest.cpp repsnapper_SOURCES = $(SHARED_SRC) $(SHARED_INC) src/repsnapper.cpp src/gitversion.h: FORCE $(AM_V_GEN)sh $(top_builddir)/tools/gitversion.sh $(top_builddir)/src/gitversion.h $(top_srcdir)/src/gitversion.h FORCE: built_header_make=src/gitversion.h BUILT_SOURCES += $(built_header_make) EXTRA_DIST += $(built_header_make) repsnapper_LDFLAGS = $(EXTRA_LDFLAGS) repsnapper_LDADD = $(CLIPPER_LIBS) libpoly2tri.la liblmfit.la libamf.la $(OPENMP_CFLAGS) $(OPENVRML_LIBS) $(GTKMM_LIBS) $(GL_LIBS) $(XMLPP_LIBS) $(LIBZIP_LIBS) $(BOOST_LDFLAGS) repsnapperdatadir = $(datadir)/@PACKAGE@ dist_repsnapperdata_DATA = src/repsnapper.ui src/repsnapper.svg repsnapperconfdir = $(sysconfdir)/xdg/@PACKAGE@ dist_repsnapperconf_DATA = src/repsnapper.conf repsnappericondir = $(datadir)/icons/hicolor/scalable/apps/ dist_repsnappericon_DATA = src/repsnapper.svg repsnapper-2.3.2a5/src/Makefile.win000066400000000000000000000166541231531733200171620ustar00rootroot00000000000000# Makefile # Palomides: #CC=i586-mingw32msvc-gcc #CXX=i586-mingw32msvc-g++ #LD=i586-mingw32msvc-ld #AR=i586-mingw32msvc-ar #AS=i586-mingw32msvc-as #NM=i586-mingw32msvc-nm #STRIP=i586-mingw32msvc-strip #RANLIB=i586-mingw32msvc-ranlib #DLLTOOL=i586-mingw32msvc-dlltool #OBJDUMP=i586-mingw32msvc-objdump #RC=i586-mingw32msvc-windres # Fedora 13: CC=i686-pc-mingw32-gcc CXX=i686-pc-mingw32-g++ LD=i686-pc-mingw32-ld AR=i686-pc-mingw32-ar AS=i686-pc-mingw32-as NM=i686-pc-mingw32-nm STRIP=i686-pc-mingw32-strip RANLIB=i686-pc-mingw32-ranlib DLLTOOL=i686-pc-mingw32-dlltool OBJDUMP=i686-pc-mingw32-objdump RC=i686-pc-mingw32-windres LIB_DIR=../libraries CFLAGS+=-DSIMULATOR -W -I$(LIB_DIR)/Boost1.40 -O0 -I../ -D_CRT_SECURE_NO_DEPRECATE -I$(LIB_DIR)/fltk-1.1.10 -I$(LIB_DIR)/vmmlib/include -I$(LIB_DIR)/glut-3.7.6/include -I$(LIB_DIR)/ann_1.1.1/include -DWIN32 -I$(LIB_DIR)/ -D_DEBUG -D_WINDOWS -DWIN32_LEAN_AND_MEAN -DVC_EXTRA_LEAN -I$(LIB_DIR)/polylib -DWIN32_EXTRA_LEAN -g -I/usr/i586-mingw32msvc/include -I/usr/i586-mingw32msvc/lib -I$(LIB_DIR)/libconfig-1.3.2 LDFLAGS+=-L$(LIB_DIR)/boost1.40 LDFLAGS+=-L$(LIB_DIR)/polylib LDFLAGS+=-L$(LIB_DIR)/fltk-1.1.10 LDFLAGS+=-L$(LIB_DIR)/vmmlib LDFLAGS+=-L$(LIB_DIR)/CGAL_3.5/CGAL-3.5 LDFLAGS+=-L$(LIB_DIR)/glut-3.7.6 LDFLAGS+=-L$(LIB_DIR)/ann_1.1.1/include LDFLAGS+=-L$(LIB_DIR)/libconfig-1.3.2/lib # Palomides: #LDFLAGS+=-L"/usr/i586-mingw32msvc/lib" # Fedora 13: LDFLAGS+=-L"/usr/i686-pc-mingw32/lib" LDFLAGS+=-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwsock32 -lcomctl32 -lws2_32 -limm32 -lwinmm -lopengl32 -lstdc++ -lgcc -lctl3d32 -lwsock32 -lopengl32 -lglu32 LDFLAGS+=-lpolylib -lconfig++ -lGLU -lGL -lfltk -lfltk_gl -lfltk_forms -lglut -lboost_thread-mt -lboost_system-mt ifeq ($(TARGET),) TARGET=RELEASE endif WARNING_FLAGS = -Wall EXEC=RepSnapper.exe EXEC_DEBUG=RepSnapper_debug.exe ifeq ($(TARGET),RELEASE) CFLAGS ?= -O2 $(WARNING_FLAGS) EXECUTABLE=$(EXEC) else CFLAGS ?= -g -O0 $(WARNING_FLAGS) EXECUTABLE=$(EXEC_DEBUG) endif GENERATED=ui.cxx ui.h MAIN_SOURCES=repsnapper.cpp TEST_SOURCES=unittest.cpp SHARED_SOURCES=asyncserial.cpp stl.cpp reprapserial.cpp \ processcontroller.cpp printer.cpp modelviewcontroller.cpp \ gllight.cpp gcode.cpp arcball.cpp stdafx.cpp ui.cxx \ rfo.cpp flu_dnd.cpp flu_pixmaps.cpp flu_simplestring.cpp \ flu_tree_browser.cpp ivcon.cpp file.cpp platform.cpp HEADERS=arcball.h asyncserial.h convert.h flu_dnd.h flu_enumerations.h \ flu_export.h flu_pixmaps.h flu_simplestring.h flu_tree_browser.h \ gcode.h gllight.h ivcon.h miniball.h modelviewcontroller.h \ printer.h processcontroller.h reprapserial.h rfo.h \ stdafx.h stl.h triangle.h ui.h platform.h SHARED_OBJECTS=$(subst .c,.o,$(subst .cxx,.o,$(subst .cpp,.o,$(SHARED_SOURCES)))) MAIN_OBJECTS=$(subst .c,.o,$(subst .cxx,.o,$(subst .cpp,.o,$(MAIN_SOURCES)))) $(SHARED_OBJECTS) TEST_OBJECTS=$(subst .c,.o,$(subst .cxx,.o,$(subst .cpp,.o,$(TEST_SOURCES)))) $(SHARED_OBJECTS) all: $(EXECUTABLE) $(EXECUTABLE): poly_lib $(MAIN_OBJECTS) $(CXX) ${INC} $(MAIN_OBJECTS) $(LDFLAGS) -o $@ unittest : poly_lib $(TEST_OBJECTS) $(CXX) ${INC} $(TEST_OBJECTS) $(LDFLAGS) $(TEST_LDFLAGS) -o $@ %.cxx %.h:%.fl rm -f $@ # fluid doesn't remove on failure. fluid -c $< %.o:%.cxx $(CXX) ${INC} -c $(CFLAGS) $< -o $@ %.o:%.cpp $(CXX) ${INC} -c $(CFLAGS) $< -o $@ %.o:%.c $(CC) ${INC} -c $(CFLAGS) $< -o $@ poly_lib: make -C $(LIB_DIR)/polylib/ all boost_lib: cd $(LIB_DIR)/Boost1.40/ && configure --host=i586-mingw32msvc --prefix=/usr/i586-mingw32msvc make -C $(LIB_DIR)/Boost1.40 libconfig_lib: PATH=/usr/i586-mingw32msvc/bin:$(PATH) cd $(LIB_DIR)/libconfig-1.3.2/ && ./configure --host=i586-mingw32msvc --prefix=$(realpath $(LIB_DIR)/libconfig-1.3.2/) make -C $(LIB_DIR)/libconfig-1.3.2/ all make -C $(LIB_DIR)/libconfig-1.3.2/ install check: unittest ./unittest clean: rm -f $(SHARED_OBJECTS) $(MAIN_OBJECTS) $(TEST_OBJECTS) \ $(EXEC) $(EXEC_DEBUG) $(GENERATED) unittest make -i -C $(LIB_DIR)/polylib/ clean make -C $(LIB_DIR)/libconfig-1.3.2/ distclean asyncserial.o: stdafx.h config.h platform.h arcball.h ivcon.h asyncserial.h repsnapper.o: stdafx.h config.h platform.h arcball.h ivcon.h repsnapper.o: modelviewcontroller.h ui.h file.h flu_tree_browser.h repsnapper.o: flu_enumerations.h flu_export.h flu_simplestring.h gcode.h stl.h repsnapper.o: processcontroller.h printer.h rfo.h gllight.h reprapserial.h repsnapper.o: asyncserial.h stl.o: stdafx.h config.h platform.h arcball.h ivcon.h stl.h gcode.h ui.h stl.o: file.h modelviewcontroller.h processcontroller.h printer.h rfo.h stl.o: flu_tree_browser.h flu_enumerations.h flu_export.h flu_simplestring.h stl.o: gllight.h reprapserial.h asyncserial.h reprapserial.o: stdafx.h config.h platform.h arcball.h ivcon.h reprapserial.h reprapserial.o: ui.h file.h modelviewcontroller.h gcode.h stl.h reprapserial.o: processcontroller.h printer.h rfo.h flu_tree_browser.h reprapserial.o: flu_enumerations.h flu_export.h flu_simplestring.h gllight.h reprapserial.o: asyncserial.h convert.h processcontroller.o: stdafx.h config.h platform.h arcball.h ivcon.h processcontroller.o: modelviewcontroller.h ui.h file.h flu_tree_browser.h processcontroller.o: flu_enumerations.h flu_export.h flu_simplestring.h processcontroller.o: gcode.h stl.h processcontroller.h printer.h rfo.h processcontroller.o: gllight.h reprapserial.h asyncserial.h printer.o: stdafx.h config.h platform.h arcball.h ivcon.h processcontroller.h printer.o: printer.h gcode.h rfo.h flu_tree_browser.h flu_enumerations.h printer.o: flu_export.h flu_simplestring.h stl.h modelviewcontroller.o: stdafx.h config.h platform.h arcball.h ivcon.h modelviewcontroller.o: modelviewcontroller.h ui.h file.h flu_tree_browser.h modelviewcontroller.o: flu_enumerations.h flu_export.h flu_simplestring.h modelviewcontroller.o: gcode.h stl.h processcontroller.h printer.h rfo.h modelviewcontroller.o: gllight.h reprapserial.h asyncserial.h gllight.o: stdafx.h config.h platform.h arcball.h ivcon.h gllight.h gcode.o: stdafx.h config.h platform.h arcball.h ivcon.h gcode.h ui.h file.h gcode.o: modelviewcontroller.h stl.h processcontroller.h printer.h rfo.h gcode.o: flu_tree_browser.h flu_enumerations.h flu_export.h flu_simplestring.h gcode.o: gllight.h reprapserial.h asyncserial.h arcball.o: stdafx.h config.h platform.h arcball.h ivcon.h stdafx.o: stdafx.h config.h platform.h arcball.h ivcon.h stl.h ui.o: ui.h config.h stdafx.h platform.h arcball.h ivcon.h file.h ui.o: modelviewcontroller.h gcode.h stl.h processcontroller.h printer.h rfo.h ui.o: flu_tree_browser.h flu_enumerations.h flu_export.h flu_simplestring.h ui.o: gllight.h reprapserial.h asyncserial.h rfo.o: stdafx.h config.h platform.h arcball.h ivcon.h ui.h file.h rfo.o: modelviewcontroller.h gcode.h stl.h processcontroller.h printer.h rfo.o: rfo.h flu_tree_browser.h flu_enumerations.h flu_export.h rfo.o: flu_simplestring.h gllight.h reprapserial.h asyncserial.h flu_pixmaps.h flu_dnd.o: flu_dnd.h flu_enumerations.h flu_export.h flu_pixmaps.o: flu_pixmaps.h flu_export.h flu_simplestring.o: flu_simplestring.h flu_enumerations.h flu_export.h flu_tree_browser.o: flu_tree_browser.h flu_enumerations.h flu_export.h flu_tree_browser.o: flu_simplestring.h flu_pixmaps.h ivcon.o: ivcon.h file.o: stdafx.h config.h platform.h arcball.h ivcon.h file.h file.o: modelviewcontroller.h ui.h flu_tree_browser.h flu_enumerations.h file.o: flu_export.h flu_simplestring.h gcode.h stl.h processcontroller.h file.o: printer.h rfo.h gllight.h reprapserial.h asyncserial.h repsnapper-2.3.2a5/src/arcball.cpp000066400000000000000000000136031231531733200170210ustar00rootroot00000000000000/** KempoApi: The Turloc Toolkit *****************************/ /** * * **/ /** ** ** Filename: arcball.cpp **/ /** ** Version: Common **/ /** ** **/ /** **/ /** Arcball class for mouse manipulation. **/ /** **/ /** **/ /** **/ /** **/ /** (C) 1999-2003 Tatewake.com **/ /** History: **/ /** 08/17/2003 - (TJG) - Creation **/ /** 09/23/2003 - (TJG) - Bug fix and optimization **/ /** 09/25/2003 - (TJG) - Version for NeHe Basecode users **/ /** **/ /*************************************************************/ /* MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "stdafx.h" #include "math.h" // Needed for sqrtf #include "arcball.h" // ArcBall header //Arcball sphere constants: //Diameter is 2.0f //Radius is 1.0f //Radius squared is 1.0f void ArcBall::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const { Point2fT TempPt; GLfloat length; //Copy paramter into temp point TempPt = *NewPt; //Adjust point coords and scale down to range of [-1 ... 1] TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f; TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight); //Compute the square of the length of the vector to the point from the center length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y); //If the point is mapped outside of the sphere... (length > radius squared) if (length > 1.0f) { GLfloat norm; //Compute a normalizing factor (radius / sqrt(length)) norm = 1.0f / FuncSqrt(length); //Return the "normalized" vector, a point on the sphere NewVec->s.X = TempPt.s.X * norm; NewVec->s.Y = TempPt.s.Y * norm; NewVec->s.Z = 0.0f; } else //Else it's on the inside { //Return a vector to a point mapped inside the sphere sqrt(radius squared - length) NewVec->s.X = TempPt.s.X; NewVec->s.Y = TempPt.s.Y; NewVec->s.Z = FuncSqrt(1.0f - length); } } //Create/Destroy ArcBall::ArcBall(GLfloat NewWidth, GLfloat NewHeight) { //Clear initial values this->StVec.s.X = this->StVec.s.Y = this->StVec.s.Z = this->EnVec.s.X = this->EnVec.s.Y = this->EnVec.s.Z = 0.0f; //Set initial bounds this->setBounds(NewWidth, NewHeight); } //Mouse down void ArcBall::click(GLfloat x, GLfloat y, Matrix4fT *stTrans) { Point2fT NewPt; NewPt.T[0] = x; NewPt.T[1] = y; //Map the point to the sphere this->_mapToSphere(&NewPt, &this->StVec); Matrix4fSetRotationScaleFromMatrix4f(&this->StTransform, stTrans); } //Mouse drag, calculate rotation void ArcBall::drag(GLfloat x, GLfloat y, Quat4fT* NewRot) { Point2fT NewPt; NewPt.T[0] = x; NewPt.T[1] = y; //Map the point to the sphere this->_mapToSphere(&NewPt, &this->EnVec); //Return the quaternion equivalent to the rotation if (NewRot) { Vector3fT Perp; //Compute the vector perpendicular to the begin and end vectors Vector3fCross(&Perp, &this->StVec, &this->EnVec); //Compute the length of the perpendicular vector if (Vector3fLength(&Perp) > Epsilon) //if its non-zero { //We're ok, so return the perpendicular vector as the transform after all NewRot->s.X = Perp.s.X; NewRot->s.Y = Perp.s.Y; NewRot->s.Z = Perp.s.Z; //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle NewRot->s.W= Vector3fDot(&this->StVec, &this->EnVec); } else //if its zero { //The begin and end vectors coincide, so return an identity transform NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f; } } } void ArcBall::dragAccumulate(GLfloat x, GLfloat y, Matrix4fT *transform) { Quat4fT tmpQuat; Matrix3fT tmpRot; drag(x, y, &tmpQuat); // Set output to the initial transform Matrix4fSetRotationScaleFromMatrix4f(transform, &this->StTransform); // get current rotation matrix Matrix3fSetRotationFromQuat4f(&tmpRot, &tmpQuat); // Apply to initial transform Matrix4fMulRotationFromMatrix3f(transform, &tmpRot); } repsnapper-2.3.2a5/src/arcball.h000066400000000000000000000503411231531733200164660ustar00rootroot00000000000000/** KempoApi: The Turloc Toolkit *****************************/ /** * * **/ /** ** ** Filename: arcball.h **/ /** ** Version: Common **/ /** ** **/ /** **/ /** Arcball class for mouse manipulation. **/ /** **/ /** **/ /** **/ /** **/ /** (C) 1999-2003 Tatewake.com **/ /** History: **/ /** 08/17/2003 - (TJG) - Creation **/ /** 09/23/2003 - (TJG) - Bug fix and optimization **/ /** 09/25/2003 - (TJG) - Version for NeHe Basecode users **/ /** **/ /*************************************************************/ /* MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _ArcBall_h #define _ArcBall_h #ifdef _MSC_VER // Visual C++ compiler # pragma comment( lib, "opengl32.lib" ) // Search For OpenGL32.lib While Linking # pragma comment( lib, "glu32.lib" ) // Search For GLu32.lib While Linking #endif // 8<--Snip here if you have your own math types/funcs-->8 //Only support assertions in debug builds #ifdef _DEBUG # include "assert.h" #else #ifndef assert # define assert(x) { } #endif #endif //Math types derived from the KempoApi tMath library typedef union Tuple2f_t { struct { GLfloat X, Y; } s; GLfloat T[2]; } Tuple2fT; //A generic 2-element tuple that is represented by single-precision floating point x,y coordinates. typedef union Tuple3f_t { struct { GLfloat X, Y, Z; } s; GLfloat T[3]; } Tuple3fT; //A generic 3-element tuple that is represented by single precision-floating point x,y,z coordinates. typedef union Tuple4f_t { struct { GLfloat X, Y, Z, W; } s; GLfloat T[4]; } Tuple4fT; //A 4-element tuple represented by single-precision floating point x,y,z,w coordinates. typedef union Matrix3f_t { struct { //column major union { GLfloat M00; GLfloat XX; GLfloat SX; }; //XAxis.X and Scale X union { GLfloat M10; GLfloat XY; }; //XAxis.Y union { GLfloat M20; GLfloat XZ; }; //XAxis.Z union { GLfloat M01; GLfloat YX; }; //YAxis.X union { GLfloat M11; GLfloat YY; GLfloat SY; }; //YAxis.Y and Scale Y union { GLfloat M21; GLfloat YZ; }; //YAxis.Z union { GLfloat M02; GLfloat ZX; }; //ZAxis.X union { GLfloat M12; GLfloat ZY; }; //ZAxis.Y union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; //ZAxis.Z and Scale Z } s; GLfloat M[9]; } Matrix3fT; //A single precision floating point 3 by 3 matrix. typedef union Matrix4f_t { struct { //column major union { GLfloat M00; GLfloat XX; GLfloat SX; }; //XAxis.X and Scale X union { GLfloat M10; GLfloat XY; }; //XAxis.Y union { GLfloat M20; GLfloat XZ; }; //XAxis.Z union { GLfloat M30; GLfloat XW; }; //XAxis.W union { GLfloat M01; GLfloat YX; }; //YAxis.X union { GLfloat M11; GLfloat YY; GLfloat SY; }; //YAxis.Y and Scale Y union { GLfloat M21; GLfloat YZ; }; //YAxis.Z union { GLfloat M31; GLfloat YW; }; //YAxis.W union { GLfloat M02; GLfloat ZX; }; //ZAxis.X union { GLfloat M12; GLfloat ZY; }; //ZAxis.Y union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; //ZAxis.Z and Scale Z union { GLfloat M32; GLfloat ZW; }; //ZAxis.W union { GLfloat M03; GLfloat TX; }; //Trans.X union { GLfloat M13; GLfloat TY; }; //Trans.Y union { GLfloat M23; GLfloat TZ; }; //Trans.Z union { GLfloat M33; GLfloat TW; GLfloat SW; }; //Trans.W and Scale W } s; GLfloat M[16]; } Matrix4fT; //A single precision floating point 4 by 4 matrix. typedef union Matrix4d_t { struct { //column major union { GLdouble M00; GLdouble XX; GLdouble SX; }; //XAxis.X and Scale X union { GLdouble M10; GLdouble XY; }; //XAxis.Y union { GLdouble M20; GLdouble XZ; }; //XAxis.Z union { GLdouble M30; GLdouble XW; }; //XAxis.W union { GLdouble M01; GLdouble YX; }; //YAxis.X union { GLdouble M11; GLdouble YY; GLdouble SY; }; //YAxis.Y and Scale Y union { GLdouble M21; GLdouble YZ; }; //YAxis.Z union { GLdouble M31; GLdouble YW; }; //YAxis.W union { GLdouble M02; GLdouble ZX; }; //ZAxis.X union { GLdouble M12; GLdouble ZY; }; //ZAxis.Y union { GLdouble M22; GLdouble ZZ; GLdouble SZ; }; //ZAxis.Z and Scale Z union { GLdouble M32; GLdouble ZW; }; //ZAxis.W union { GLdouble M03; GLdouble TX; }; //Trans.X union { GLdouble M13; GLdouble TY; }; //Trans.Y union { GLdouble M23; GLdouble TZ; }; //Trans.Z union { GLdouble M33; GLdouble TW; GLdouble SW; }; //Trans.W and Scale W } s; GLdouble M[16]; } Matrix4dT; //A double precision floating point 4 by 4 matrix. //"Inherited" types #define Point2fT Tuple2fT //A 2 element point that is represented by single precision floating point x,y coordinates. #define Quat4fT Tuple4fT //A 4 element unit quaternion represented by single precision floating point x,y,z,w coordinates. #define Vector2fT Tuple2fT //A 2-element vector that is represented by single-precision floating point x,y coordinates. #define Vector3fT Tuple3fT //A 3-element vector that is represented by single-precision floating point x,y,z coordinates. //Custom math, or speed overrides #define FuncSqrt sqrtf //Math functions /** * Sets the value of this tuple to the vector sum of itself and tuple t1. * @param t1 the other tuple */ inline static void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1) { assert(NewObj && t1); NewObj->s.X += t1->s.X; NewObj->s.Y += t1->s.Y; } /** * Sets the value of this tuple to the vector difference of itself and tuple t1 (this = this - t1). * @param t1 the other tuple */ inline static void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1) { assert(NewObj && t1); NewObj->s.X -= t1->s.X; NewObj->s.Y -= t1->s.Y; } /** * Sets this vector to be the vector cross product of vectors v1 and v2. * @param v1 the first vector * @param v2 the second vector */ inline static void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2) { Vector3fT Result; //safe not to initialize assert(NewObj && v1 && v2); // store on stack once for aliasing-safty // i.e. safe when a.cross(a, b) Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y); Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z); Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X); //copy result back *NewObj = Result; } /** * Computes the dot product of the this vector and vector v1. * @param v1 the other vector */ inline static GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1) { assert(NewObj && v1); return (NewObj->s.X * v1->s.X) + (NewObj->s.Y * v1->s.Y) + (NewObj->s.Z * v1->s.Z); } /** * Returns the squared length of this vector. * @return the squared length of this vector */ inline static GLfloat Vector3fLengthSquared(const Vector3fT* NewObj) { assert(NewObj); return (NewObj->s.X * NewObj->s.X) + (NewObj->s.Y * NewObj->s.Y) + (NewObj->s.Z * NewObj->s.Z); } /** * Returns the length of this vector. * @return the length of this vector */ inline static GLfloat Vector3fLength(const Vector3fT* NewObj) { assert(NewObj); return FuncSqrt(Vector3fLengthSquared(NewObj)); } inline static void Matrix3fSetZero(Matrix3fT* NewObj) { NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f; } /** * Sets this Matrix3 to identity. */ inline static void Matrix3fSetIdentity(Matrix3fT* NewObj) { Matrix3fSetZero(NewObj); //then set diagonal as 1 NewObj->s.M00 = NewObj->s.M11 = NewObj->s.M22 = 1.0f; } /** * Sets the value of this matrix to the matrix conversion of the * quaternion argument. * @param q1 the quaternion to be converted */ //$hack this can be optimized some(if s == 0) inline static void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1) { GLfloat n, s; GLfloat xs, ys, zs; GLfloat wx, wy, wz; GLfloat xx, xy, xz; GLfloat yy, yz, zz; assert(NewObj && q1); n = (q1->s.X * q1->s.X) + (q1->s.Y * q1->s.Y) + (q1->s.Z * q1->s.Z) + (q1->s.W * q1->s.W); s = (n > 0.0f) ? (2.0f / n) : 0.0f; xs = q1->s.X * s; ys = q1->s.Y * s; zs = q1->s.Z * s; wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs; xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs; yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs; NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX = xy - wz; NewObj->s.ZX = xz + wy; NewObj->s.XY = xy + wz; NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY = yz - wx; NewObj->s.XZ = xz - wy; NewObj->s.YZ = yz + wx; NewObj->s.ZZ = 1.0f - (xx + yy); } inline static void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1) { assert(NewObj && m1); NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX; NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY; NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; } /** * Performs SVD on this matrix and gets scale and rotation. * Rotation is placed into rot3, and rot4. * @param rot3 the rotation factor(Matrix3d). if null, ignored * @param rot4 the rotation factor(Matrix4) only upper 3x3 elements are changed. if null, ignored * @return scale factor */ inline static GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4) { GLfloat s, n; assert(NewObj); // this is a simple svd. // Not complete but fast and reasonable. // See comment in Matrix3d. s = FuncSqrt( ( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) + (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) + (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ) / 3.0f ); if (rot3) //if pointer not null { //this->getRotationScale(rot3); rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ; rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ; rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ; // zero-div may occur. n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) ); rot3->s.XX *= n; rot3->s.XY *= n; rot3->s.XZ *= n; n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) ); rot3->s.YX *= n; rot3->s.YY *= n; rot3->s.YZ *= n; n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ); rot3->s.ZX *= n; rot3->s.ZY *= n; rot3->s.ZZ *= n; } if (rot4) //if pointer not null { if (rot4 != NewObj) { Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj); // private method } // zero-div may occur. n = 1.0f / FuncSqrt( (NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) ); rot4->s.XX *= n; rot4->s.XY *= n; rot4->s.XZ *= n; n = 1.0f / FuncSqrt( (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) ); rot4->s.YX *= n; rot4->s.YY *= n; rot4->s.YZ *= n; n = 1.0f / FuncSqrt( (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ) ); rot4->s.ZX *= n; rot4->s.ZY *= n; rot4->s.ZZ *= n; } return s; } inline static void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) { assert(NewObj && m1); NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX; NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY; NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; } inline static void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale) { assert(NewObj); NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale; NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale; NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale; } /** * Sets the rotational component (upper 3x3) of this matrix to the matrix * values in the T precision Matrix3d argument; the other elements of * this matrix are unchanged; a singular value decomposition is performed * on this object's upper 3x3 matrix to factor out the scale, then this * object's upper 3x3 matrix components are replaced by the passed rotation * components, and then the scale is reapplied to the rotational * components. * @param m1 T precision 3x3 matrix */ inline static void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) { GLfloat scale; assert(NewObj && m1); scale = Matrix4fSVD(NewObj, NULL, NULL); Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1); Matrix4fMulRotationScale(NewObj, scale); } inline static void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1) { Matrix3fT Result; //safe not to initialize assert(NewObj && m1); // alias-safe way. Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20); Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21); Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22); Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20); Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21); Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22); Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20); Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21); Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22); //copy result back to this *NewObj = Result; } /* Apply the Matrix3f rotation to the existing values in NewObj */ inline static void Matrix4fMulRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) { Matrix3fT tmp, tmp2; GLfloat scale; assert(NewObj && m1); scale = Matrix4fSVD(NewObj, &tmp, NULL); tmp2 = *m1; Matrix3fMulMatrix3f(&tmp2, &tmp); Matrix4fSetRotationScaleFromMatrix3f(NewObj, &tmp2); Matrix4fMulRotationScale(NewObj, scale); } // 8<--Snip here if you have your own math types/funcs-->8 class ArcBall { protected: inline void _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const; public: //Create/Destroy ArcBall(GLfloat NewWidth = 2.0, GLfloat NewHeight = 2.0); ~ArcBall() { /* nothing to do */ }; //Set new bounds inline void setBounds(GLfloat NewWidth, GLfloat NewHeight) { assert((NewWidth > 1.0f) && (NewHeight > 1.0f)); //Set adjustment factor for width/height this->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f); this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f); } //Mouse down void click(GLfloat x, GLfloat y, Matrix4fT *startTransform); //Mouse drag, calculate rotation void drag(GLfloat x, GLfloat y, Quat4fT* NewRot); void dragAccumulate(GLfloat x, GLfloat y, Matrix4fT *transform); protected: Vector3fT StVec; //Saved click vector Matrix4fT StTransform; //Reference start transform Vector3fT EnVec; //Saved drag vector GLfloat AdjustWidth; //Mouse bounds width GLfloat AdjustHeight; //Mouse bounds height }; #endif repsnapper-2.3.2a5/src/files.cpp000066400000000000000000000440561231531733200165310ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "files.h" #include static string numlocale = ""; static string colllocale = ""; static string ctypelocale = ""; void save_locales() { numlocale = string(setlocale(LC_NUMERIC, NULL)); colllocale = string(setlocale(LC_COLLATE, NULL)); ctypelocale = string(setlocale(LC_CTYPE, NULL)); } void set_locales(const char * loc) { setlocale(LC_NUMERIC, loc); setlocale(LC_COLLATE, loc); setlocale(LC_CTYPE, loc); } void reset_locales() { setlocale(LC_NUMERIC, numlocale.c_str()); setlocale(LC_COLLATE, colllocale.c_str()); setlocale(LC_CTYPE, ctypelocale.c_str()); } static float read_float(ifstream &file) { // Read platform independent 32 bit ieee 754 little-endian float. union ieee_union { char buffer[4]; struct ieee_struct { unsigned int mantissa:23; unsigned int exponent:8; unsigned int negative:1; } ieee; } ieee; file.read (ieee.buffer, 4); GFloatIEEE754 ret; ret.mpn.mantissa = ieee.ieee.mantissa; ret.mpn.biased_exponent = ieee.ieee.exponent; ret.mpn.sign = ieee.ieee.negative; return ret.v_float; } static double read_double(ifstream &file) { return double(read_float(file)); } File::File(Glib::RefPtr file) : _file(file) { _path = _file->get_path(); _type = getFileType(_path); } void File::loadTriangles(vector< vector > &triangles, vector &names, uint max_triangles) { Gio::FileType type = _file->query_file_type(); if (type != Gio::FILE_TYPE_REGULAR && type != Gio::FILE_TYPE_SYMBOLIC_LINK) return; ustring name_by_file = _file->get_basename(); size_t found = name_by_file.find_last_of("."); name_by_file = (ustring)name_by_file.substr(0,found); set_locales("C"); if(_type == ASCII_STL) { // multiple shapes per file load_asciiSTL(triangles, names, max_triangles); if (names.size() == 1) // if single shape name by file names[0] = name_by_file; if (triangles.size() == 0) {// if no success, try binary mode _type = BINARY_STL; loadTriangles(triangles, names, max_triangles); return; } } else if (_type == AMF) { // multiple shapes per file load_AMF(triangles, names, max_triangles); if (names.size() == 1) // if single shape name by file names[0] = name_by_file; } else { // single shape per file triangles.resize(1); names.resize(1); names[0] = name_by_file; if (_type == BINARY_STL) { load_binarySTL(triangles[0], max_triangles); } else if (_type == VRML) { load_VRML(triangles[0], max_triangles); } else { cerr << _("Unrecognized file - ") << _file->get_parse_name() << endl; cerr << _("Known extensions: ") << "STL, WRL, AMF." << endl; } } reset_locales(); } filetype_t File::getFileType(ustring filename) { // Extract file extension (i.e. "stl") ustring extension = filename.substr(filename.find_last_of(".")+1); if(extension == "wrl" || extension == "WRL") { return VRML; } if(extension == "amf" || extension == "AMF") { return AMF; } if(extension != "stl" && extension != "STL") { return NONE_STL; } ifstream file; file.open(filename.c_str()); if(file.fail()) { cerr << _("Error: Unable to open file - ") << filename << endl; return NONE_STL; } // ASCII files start with "solid [Name_of_file]" ustring first_word; try { file >> first_word; // Find bad Solid Works STL header // 'solid binary STL from Solid Edge, Unigraphics Solutions Inc.' ustring second_word; if(first_word == "solid") file >> second_word; file.close(); if(first_word == "solid" && second_word != "binary") { // ASCII return ASCII_STL; } else { return BINARY_STL; } } catch (Glib::ConvertError e) { return BINARY_STL; // no keyword -> binary } } bool File::load_binarySTL(vector &triangles, uint max_triangles, bool readnormals) { ifstream file; ustring filename = _file->get_path(); file.open(filename.c_str(), ifstream::in | ifstream::binary); if(file.fail()) { cerr << _("Error: Unable to open stl file - ") << filename << endl; return false; } // cerr << "loading bin " << filename << endl; /* Binary STL files have a meaningless 80 byte header * followed by the number of triangles */ file.seekg(80, ios_base::beg); unsigned int num_triangles; unsigned char buffer[4]; file.read(reinterpret_cast (buffer), 4); // Read platform independent 32-bit little-endian int. num_triangles = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24; uint step = 1; if (max_triangles > 0 && max_triangles < num_triangles) { step = ceil(num_triangles/max_triangles); triangles.reserve(max_triangles); } else triangles.reserve(num_triangles); uint i = 0; for(; i < num_triangles; i+=step) { if (step>1) file.seekg(84 + 50*i, ios_base::beg); double a,b,c; a = read_double (file); b = read_double (file); c = read_double (file); Vector3d N(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Ax(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Bx(a,b,c); a = read_double (file); b = read_double (file); c = read_double (file); Vector3d Cx(a,b,c); if (file.eof()) { cerr << _("Unexpected EOF reading STL file - ") << filename << endl; break; } /* attribute byte count - sometimes contains face color information but is useless for our purposes */ unsigned short byte_count; file.read(reinterpret_cast (buffer), 2); byte_count = buffer[0] | buffer[1] << 8; // Repress unused variable warning. (void)&byte_count; Triangle T = Triangle(Ax,Bx,Cx); if (readnormals) if (T.Normal.dot(N) < 0) T.invertNormal(); // cout << "bin triangle "<< N << ":\n\t" << Ax << "/\n\t"< > &triangles, vector &names, uint max_triangles, bool readnormals) { ustring filename = _file->get_path(); ifstream file; file.open(filename.c_str(), ifstream::in); if(file.fail()) { cerr << _("Error: Unable to open stl file - ") << filename << endl; return false; } // fileis.imbue(std::locale::classic()); // get as many shapes as found in file while (true) { vector tr; ustring name; if (!File::parseSTLtriangles_ascii(file, max_triangles, readnormals, tr, name)) break; triangles.push_back(tr); names.push_back(name); // go back to get "solid " keyword again streampos where = file.tellg(); where-=100; if (where < 0) break; file.seekg(where,ios::beg); } // if (ret < 0) {// cannot parse, try binary // cerr << _("Could not read file in ASCII mode, trying Binary: ")<< filename << endl; // file.close(); // return loadBinarySTL(filename, max_triangles, readnormals); // } file.close(); return true; } bool File::parseSTLtriangles_ascii (istream &text, uint max_triangles, bool readnormals, vector &triangles, ustring &shapename) { //cerr << "loading ascii " << endl; //cerr << " locale " << std::locale().name() << endl; shapename = _("Unnamed"); // uint step = 1; // if (max_triangles > 0 && max_triangles < num_triangles) { // step = ceil(num_triangles/max_triangles); streampos pos = text.tellg(); text.seekg(0, ios::end); streampos fsize = text.tellg(); text.seekg(pos, ios::beg); // a rough estimation uint num_triangles = (fsize-pos)/30; uint step = 1; if (max_triangles > 0 && max_triangles < num_triangles) step = ceil(num_triangles/max_triangles); //cerr << "step " << step << endl; /* ASCII files start with "solid [Name_of_file]" * so get rid of them to access the data */ string solid; //getline (text, solid); while(!text.eof()) { // Find next solid text >> solid; if (solid == "solid") { string name; getline(text,name); shapename = (ustring)name; break; } } if (solid != "solid") { return false; } // uint itr = 0; while(!text.eof()) { // Loop around all triangles string facet; text >> facet; //cerr << text.tellg() << " - " << fsize << " - " < 1) { for (uint s=0; s < step; s++) { if (text.eof()) break; facet = ""; while (facet != "facet" && facet != "endsolid"){ if (text.eof()) break; text >> facet; } if (facet == "endsolid") { break; } } } // Parse possible end of text - "endsolid" if(text.eof() || facet == "endsolid" ) { break; } if(facet != "facet") { cerr << _("Error: Facet keyword not found in STL text!") << endl; return false; } // Parse Face Normal - "normal %f %f %f" string normal; Vector3d normal_vec; text >> normal; if(readnormals && normal != "normal") { cerr << _("Error: normal keyword not found in STL text!") << endl; return false; } if (readnormals){ text >> normal_vec.x() >> normal_vec.y() >> normal_vec.z(); } // Parse "outer loop" line string outer, loop; while (outer!="outer" && !text.eof()) { text >> outer; } text >> loop; if(outer != "outer" || loop != "loop") { cerr << _("Error: Outer/Loop keywords not found!") << endl; return false; } // Grab the 3 vertices - each one of the form "vertex %f %f %f" Vector3d vertices[3]; for(int i=0; i<3; i++) { string vertex; text >> vertex >> vertices[i].x() >> vertices[i].y() >> vertices[i].z(); if(vertex != "vertex") { cerr << _("Error: Vertex keyword not found") << endl; return false; } } // Parse end of vertices loop - "endloop endfacet" string endloop, endfacet; text >> endloop >> endfacet; if(endloop != "endloop" || endfacet != "endfacet") { cerr << _("Error: Endloop or endfacet keyword not found") << endl; return false; } // Create triangle object and push onto the vector Triangle triangle(vertices[0], vertices[1], vertices[2]); if (readnormals){ //cerr << "reading normals from file" << endl; if (triangle.Normal.dot(normal_vec) < 0) triangle.invertNormal(); } triangles.push_back(triangle); } //cerr << "loaded " << filename << endl; return true; } bool File::load_VRML(vector &triangles, uint max_triangles) { triangles.clear(); ustring filename = _file->get_path(); ifstream file; file.open(filename.c_str()); if(file.fail()) { cerr << _("Error: Unable to open vrml file - ") << filename << endl; return false; } ustring word; std::vector vertices; std::vector indices; bool finished = false; while(!file.eof() && !finished) { // while (word!="Shape" && !file.eof()) // file >> word; // while (word!="Appearance" && !file.eof()) // file >> word; // while (word!="Coordinate" && !file.eof()) // file >> word; while (word!="point" && !file.eof()) file >> word; file >> word; if (word=="[") { float f; while (word!="]" && !file.eof()){ file >> word; if (word!="]") if (word.find("#")!=0) { std::istringstream iss(word); iss >> f; vertices.push_back(f); //cerr << f << ", "; } } //cerr << endl; } while (word!="coordIndex" && !file.eof()) file >> word; file >> word; if (word=="[") { int c; while (word!="]" && !file.eof()){ file >> word; if (word!="]") if (word.find("#")!=0) { std::istringstream iss(word); iss >> c; indices.push_back(c); //cerr << c << ", "; } } //cerr << endl; } } file.close(); if (indices.size()%4!=0) return false; if (vertices.size()%3!=0) return false; vector vert; for (uint i=0; i &triangles) { nObject* object = GetObject(onum); uint nmeshes = object->Meshes.size(); for (uint m = 0; m < nmeshes; m++) { const nMesh mesh = object->Meshes[m]; //cerr << "Units "<< GetUnitsString() << endl; switch (aUnit) { case UNIT_M: _scale = 1000.; break; case UNIT_IN: _scale = 25.4; break; case UNIT_FT: _scale = 304.8; break; case UNIT_UM: _scale = 0.001; break; case UNIT_MM: default: _scale = 1.; break; } uint nvolumes = mesh.Volumes.size(); for (uint v = 0; v < nvolumes; v++) { uint ntria = mesh.Volumes[v].Triangles.size(); for (uint t = 0; t < ntria; t++) { triangles.push_back( getTriangle(mesh, mesh.Volumes[v].Triangles[t]) ); } } } return true; } }; class AMFWriter : public AmfFile { public: AMFWriter() {}; ~AMFWriter() {}; nVertex vertex(const Vector3d &v) const { return nVertex(v.x(), v.y(), v.z()); } bool AddObject(const vector &triangles, const ustring name) { int num = AmfFile::AddObject(string(name)); if (num<0) return false; nObject* object = GetObject(num, true); if (!object) return false; nMesh mesh; for (uint t = 0; t < triangles.size(); t++) { nVertex A = vertex(triangles[t].A); mesh.AddVertex(A); nVertex B = vertex(triangles[t].B); mesh.AddVertex(B); nVertex C = vertex(triangles[t].C); mesh.AddVertex(C); } nVolume* vol = mesh.NewVolume(name); for (uint t = 0; t < triangles.size(); t++) { nTriangle tr(3*t, 3*t+1, 3*t+2); vol->AddTriangle(tr); } object->Meshes.push_back(mesh); return true; } }; #endif bool File::load_AMF(vector< vector > &triangles, vector &names, uint max_triangles) { #if ENABLE_AMF AMFLoader amf; if (!amf.open(_file->get_path())) return false; uint nobjs = amf.GetObjectCount(); //cerr << nobjs << " objs" << endl; for (uint o = 0; o < nobjs; o++) { vector otr; amf.getObjectTriangles(o,otr); triangles.push_back(otr); names.push_back(ustring(amf.GetObjectName(o))); } return true; #else return false; #endif } bool File::save_AMF (ustring filename, const vector< vector > &triangles, const vector &names, bool compressed) { #if ENABLE_AMF AMFWriter amf; amf.SetUnits(UNIT_MM); uint nobjs = triangles.size(); for (uint o = 0; o < nobjs; o++) { bool ok = amf.AddObject(triangles[o],names[o]); if (!ok) return false; } amf.Save(filename, compressed); return true; #else return false; #endif } bool File::saveBinarySTL(ustring filename, const vector &triangles, const Matrix4d &T) { FILE *file = fopen(filename.c_str(),"wb"); if (file==0) { cerr << _("Error: Unable to open stl file - ") << filename << endl; return false; } int num_tri = (int)triangles.size(); // Write Header string tmp = "solid binary by Repsnapper "; fwrite(tmp.c_str(), 80, 1, file); // write number of triangles fwrite(&num_tri, 1, sizeof(int), file); for(int i=0; i file); virtual ~File(){}; Glib::RefPtr _file; ustring _path; filetype_t _type; static filetype_t getFileType(ustring path); void loadTriangles(vector< vector > &triangles, vector &names, uint max_triangles=0); bool load_asciiSTL(vector< vector > &triangles, vector &names, uint max_triangles=0, bool readnormals=false); bool load_binarySTL(vector &triangles, uint max_triangles=0, bool readnormals=false); bool load_VRML(vector &triangles, uint max_triangles=0); bool load_AMF (vector< vector > &triangles, vector &names, uint max_triangles=0); static bool save_AMF (ustring filename, const vector< vector > &triangles, const vector &names, bool compressed = true); static bool parseSTLtriangles_ascii(istream &text, uint max_triangles, bool readnormals, vector &triangles, ustring &name); /* static bool loadVRMLtriangles(ustring filename, */ /* uint max_triangles, */ /* vector &triangles); */ static bool saveBinarySTL(ustring filename, const vector &triangles, const Matrix4d &T); }; repsnapper-2.3.2a5/src/flatshape.cpp000066400000000000000000000406211231531733200173700ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "flatshape.h" #include "ui/progress.h" // #include "settings.h" #include "clipping.h" #ifdef _OPENMP #include #endif FlatShape::FlatShape() { slow_drawing = false; Min.set(0,0,0); Max.set(200,200,0); CalcBBox(); } FlatShape::FlatShape(string filename) { slow_drawing = false; this->filename = filename; loadSVG(filename); } // FlatShape::FlatShape(const FlatShape &rhs) // { // slow_drawing = false; // polygons = rhs.polygons; // scale_factor_x = rhs.scale_factor_x; // scale_factor_y = rhs.scale_factor_y; // scale_factor = rhs.scale_factor; // Min = rhs.Min; // Max = rhs.Max; // Center = rhs.Center; // } vector REMatches(const Glib::RefPtr &RE, const string &input, const string &name) { Glib::MatchInfo match_info; vector matches; if (RE->match(input, match_info)) { matches.push_back(match_info.fetch_named(name).c_str()); while (match_info.next()){ matches.push_back(match_info.fetch_named(name).c_str()); } } return matches; } vector REMatches(const string ®ex, const string &input, const string &name) { Glib::RefPtr RE = Glib::Regex::create(regex); return REMatches(RE, input,name); } // int loadSVGold(string filename) // { // Min=Vector3d(1000000,1000000,0); // Max=Vector3d(-1000000,-1000000,0); // polygons.clear(); // ifstream file; // file.open(filename.c_str()); // string lines; // string line; // if (file.is_open()) { // while ( file.good() ) { // getline (file,line); // lines += line; // } // file.close(); // Glib::RefPtr polyregex = // Glib::Regex::create ("(?ims).*?(Z|\"/\\>))"); // Glib::RefPtr strokeregex = // Glib::Regex::create ("(?ims)fill\\:none.*?\\sd\\=\".*?\"/\\>)"); // Glib::RefPtr strwidthregex = // Glib::Regex::create ("stroke\\-width\\:(?[\\-\\.\\d]+)"); // Glib::RefPtr pointregex = // Glib::Regex::create ("(?[LM](\\s+[\\-\\.\\d]+){2})"); // Glib::RefPtr transregex = // Glib::Regex::create ("transform=\"(?.*?)\""); // Glib::RefPtr matrixregex = // Glib::Regex::create ("matrix\\((?([\\-\\.\\d]*?(\\,|\\))){6})"); // vector strokes = REMatches(strokeregex, lines, "STROKE"); // for (uint i = 0; i < strokes.size(); i++) { // cerr << i << ": "< strwidth = REMatches(strwidthregex,strokes[i],"STRWIDTH"); // for (uint j = 0; j < strwidth.size(); j++) { // cerr << "STRW " << strwidth[j] << endl; // } // vector points = REMatches(pointregex,strokes[i],"POINT"); // for (uint j = 0; j < points.size(); j++) { // cerr << j << ":: "< trans = REMatches(transregex,strokes[i],"TRANS"); // for (uint j = 0; j < trans.size(); j++) { // cerr << j << "trans: "< matrix = REMatches(matrixregex,trans[j],"MATR"); // for (uint k = 0; k < matrix.size(); k++) // cerr << k << " matr: "< polys = REMatches(polyregex, lines, "POLY"); // for (uint i = 0; i < polys.size(); i++) { // vector points = REMatches(pointregex, polys[i], "POINT"); // Poly poly; // //cout << i << ": "; // //cout << polys[i] << endl; // for (uint j = 0; j < points.size(); j++) { // //cout << j << " - " << points[j] << endl ; // istringstream is(points[j]); // string type; // is >> type; // //cerr << type<< endl; // if (type=="M" || type == "L") { // double x,y; // is >> x; // is >> y; // //cout << x << "," << y << endl; // poly.addVertex(x,y); // if (xMax.x()) Max.x() = x; // if (y>Max.y()) Max.y() = y; // } // } // if (poly.size()>0) { // poly.setZ(0); // //cerr << poly.info() << endl; // polygons.push_back(poly); // } // cout << endl; // } // } // else cerr << _("Error: Unable to open SVG file - ") << filename << endl; // Center = (Min+Max)/2; // } bool FlatShape::getPolygonsAtZ(const Matrix4d &T, double z, vector &polys, double &max_grad, vector &supportpolys, double max_supportangle, double thickness) const { max_grad = 0; polys = polygons; const Matrix4d trans = T * transform3D.transform; for (uint i = 0; i < polys.size(); i++) { polys[i].setZ(0); polys[i].transform(trans); } return true; } void FlatShape::clear() { polygons.clear(); } void FlatShape::draw_geometry(uint max_polygons) { const Matrix4d invT = transform3D.getInverse(); const Vector3d minT = invT*Min; const Vector3d maxT = invT*Max; const Vector2d min2d(minT.x(), minT.y()); const Vector2d max2d(maxT.x(), maxT.y()); glDrawPolySurfaceRastered(polygons, min2d, max2d, 0, 0.1); uint step = 1; if (max_polygons > 0) step = polygons.size()/max_polygons; for (uint i = 0; i < polygons.size(); i+=step) { polygons[i].draw(GL_LINE_LOOP,false); // Poly p; // p.vertices = simplified(polygons[i].vertices, 0.2); // cleandist(p.vertices, 0.2); // p.draw_as_surface(); //polygons[i].draw_as_surface(); } } void FlatShape::CalcBBox() { Min.set(INFTY,INFTY,0); Max.set(-INFTY,-INFTY,0); for(size_t i = 0; i < polygons.size(); i++) for(size_t j = 0; j < polygons[i].size(); j++){ if ( polygons[i][j].x() < Min.x() ) Min.x() = polygons[i][j].x(); if ( polygons[i][j].y() < Min.y() ) Min.y() = polygons[i][j].y(); if ( polygons[i][j].x() > Max.x() ) Max.x() = polygons[i][j].x(); if ( polygons[i][j].y() > Max.y() ) Max.y() = polygons[i][j].y(); } Min = transform3D.transform*Min; Max = transform3D.transform*Max; Center = (Max + Min )/2; } void FlatShape::invertNormals() { for (uint i = 0; i < polygons.size(); i++) polygons[i].reverse(); } void FlatShape::mirror() { for (uint i = 0; i < polygons.size(); i++) polygons[i].mirrorX(Center); } // Rotate and adjust for the user - not a pure rotation by any means void FlatShape::Rotate(const Vector3d & axis, const double & angle) { CalcBBox(); if (axis.z()==0) return; // try to only 2D-rotate Vector2d center(Center.x(),Center.y()); for (size_t i=0; i &shapes, ViewProgress *progress) { uint count = polygons.size(); if (progress) progress->start(_("Split Polygons"), count); int progress_steps = max(1,(int)(count/100)); for (uint i = 0; i < count; i++) { FlatShape *fs = new FlatShape(); fs->polygons.push_back(polygons[i]); if (progress && i%progress_steps==0 && !progress->update(count)) break; shapes.push_back(fs); } progress->stop("_(Done)"); } string FlatShape::info() const { ostringstream ostr; ostr <<"FlatShape with "<> x)) return -1; return x; } const Glib::RefPtr polyregex = Glib::Regex::create ("(?ims).*?(Z|\"/\\>))"); const Glib::RefPtr strokeregex = Glib::Regex::create ("(?ims)fill\\:none.*?\\sd\\=\".*?\"/\\>)"); const Glib::RefPtr strwidthregex = Glib::Regex::create ("stroke\\-width\\:(?[\\-\\.\\d]+)"); const Glib::RefPtr pointregex = Glib::Regex::create ("(?[LM](\\s+[\\-\\.\\d]+){2})"); const Glib::RefPtr transregex = Glib::Regex::create ("transform=\"(?.*?)\""); const Glib::RefPtr matrixregex = Glib::Regex::create ("matrix\\((?([\\-\\.\\d]*?(\\,|\\))){6})"); Matrix3d svg_trans(const string &line) { Matrix3d mat; vector val = REMatches(matrixregex, line, "MATR"); if (val.size()>0) { vector vals = Glib::Regex::split_simple("[\\,\\)]",val[0]); if (vals.size()>5) { mat.set_row(0,Vector3d(ToDouble(vals[0]),ToDouble(vals[2]),ToDouble(vals[4]))); mat.set_row(1,Vector3d(ToDouble(vals[1]),ToDouble(vals[3]),ToDouble(vals[5]))); mat.set_row(2,Vector3d(0,0,1)); } } return mat; } string get_attr(const string &line, const string &attrname) { vector parts = Glib::Regex::split_simple(";",line); for (uint p = 0; p < parts.size(); p++) { vector lr = Glib::Regex::split_simple(":",parts[p]); if (lr.size()==2){ if (lr[0] == attrname) return lr[1]; } else return ""; } return ""; } vector ToVertices(const string &line) { vector points = REMatches(pointregex, line, "POINT"); vector v; for (uint j = 0; j < points.size(); j++) { //cout << j << " - " << points[j] << endl ; istringstream is(points[j]); string type; is >> type; //cerr << type<< endl; if (type=="M" || type == "L") { double x,y; if (is >> x && is >> y) //cout << x << "," << y << endl; v.push_back(Vector2d(x,y)); } } return v; } int FlatShape::svg_addPolygon() { vector polys; if (svg_cur_style.find("stroke:none") != string::npos) { // polygon Poly poly; poly.vertices = ToVertices(svg_cur_path); poly.setZ(0); poly.reverse(); polys.push_back(poly); } else if (svg_cur_style.find("fill:none") != string::npos) { // stroke // cerr << "stroke " << svg_cur_path << endl; // cerr << "\t" << svg_cur_style << endl; string wstr = get_attr(svg_cur_style,"stroke-width"); double width = ToDouble(wstr); // cerr << "\t width " << wstr << " = " << width << endl; vector vertices = ToVertices(svg_cur_path); polys = thick_lines(vertices, width); // cerr <<"thick "<< polys.size()<<" of " << vertices.size() << endl; } else if (svg_cur_style!="") { cerr << "unknown " << svg_cur_path << " in " << svg_cur_name << endl; cerr << "\t style: " << svg_cur_style << endl; } if (polys.size()>0) { if (svg_cur_trans!="") { // cerr << svg_cur_trans << endl; Matrix3d mat = svg_trans(svg_cur_trans); // cerr << mat << endl; for (uint i=0; i < polys.size(); i++) { polys[i].setZ(0); polys[i].transform(mat); } } polygons.insert(polygons.begin(),polys.begin(),polys.end()); } return polys.size(); } void FlatShape::xml_handle_node(const xmlpp::Node* node) { //std::cout << std::endl; //Separate nodes by an empty line. const xmlpp::ContentNode* nodeContent = dynamic_cast(node); const xmlpp::TextNode* nodeText = dynamic_cast(node); const xmlpp::CommentNode* nodeComment = dynamic_cast(node); // if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this. // return; const Glib::ustring nodename = node->get_name(); if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text". { const Glib::ustring namespace_prefix = node->get_namespace_prefix(); if (svg_cur_name != "") svg_addPolygon(); svg_cur_name = nodename; svg_cur_path = ""; svg_cur_trans = ""; svg_cur_style = ""; // if(namespace_prefix.empty()) // std::cout << "Node name = " << nodename << std::endl; // else // std::cout << "Node name = " << namespace_prefix << ":" << nodename << std::endl; } // else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is. // { // std::cout << "Text Node " << nodename << nodeText->get_content()<< std::endl; // } //Treat the various node types differently: if(nodeText) { ; //std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl; } else if(nodeComment) { ; //std::cout << "comment = " << nodeComment->get_content() << std::endl; } else if(nodeContent) { ; //std::cout << "content = " << nodeContent->get_content() << std::endl; } else if (const xmlpp::Element* nodeElement = dynamic_cast(node)) { //A normal Element node: //line() works only for ElementNodes. // std::cout << " line = " << node->get_line() << std::endl; //attributes: const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes(); for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) { const xmlpp::Attribute* attribute = *iter; const Glib::ustring namespace_prefix = attribute->get_namespace_prefix(); string attr = attribute->get_name(); if (attr=="d") svg_cur_path = attribute->get_value(); else if (attr == "style") svg_cur_style = attribute->get_value(); else if (attr == "transform") svg_cur_trans = attribute->get_value(); else if (svg_cur_name == "svg" ){ if (attr == "width" || attr == "height") { string val = attribute->get_value(); if (val.find("pt") != string::npos) svg_prescale = 0.3527; } } else if (attr=="id") { } else cerr << "unknown Attribute in " << svg_cur_name << " : " << attr << " = " <get_value() << endl; // if(namespace_prefix.empty()) // std::cout << " Attribute " << attribute->get_name() << " = " << << std::endl; // else // std::cout << " Attribute " << namespace_prefix << ":" << attribute->get_name() << " = " << attribute->get_value() << std::endl; } const xmlpp::Attribute* attribute = nodeElement->get_attribute("title"); if(attribute) { std::cout << "title found: =" << attribute->get_value() << std::endl; } } if(!nodeContent) { //Recurse through child nodes: xmlpp::Node::NodeList list = node->get_children(); for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter) { xml_handle_node(*iter); //recursive } // get last bit (?) if (svg_cur_name!="") svg_addPolygon(); } } int FlatShape::loadSVG(string filename) { // Set the global C++ locale to the user-configured locale, // so we can use std::cout with UTF-8, via Glib::ustring, without exceptions. #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED try { #endif //LIBXMLCPP_EXCEPTIONS_ENABLED xmlpp::DomParser parser; //parser.set_validate(); parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically. parser.parse_file(filename); if(parser) { polygons.clear(); svg_cur_name = ""; svg_cur_path = ""; svg_cur_trans = ""; svg_cur_style = ""; svg_prescale = 1.; //Walk the tree: const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser. xml_handle_node(pNode); } if (svg_prescale!=1) for (uint i= 0; i // shape to represent a 2-dimensional Object (SVG file etc.) class FlatShape : public Shape { public: virtual short dimensions(){return 2;}; FlatShape(); FlatShape(string filename); ~FlatShape(){}; /* FlatShape(const FlatShape &rhs); */ int loadSVG(istream *text); bool getPolygonsAtZ(const Matrix4d &T, double z, vector &polys, double &max_grad, vector &supportpolys, double max_supportangle=-1, double thickness=-1) const; /* int load(std::string filename); */ void clear(); /* void displayInfillOld(const Settings &settings, CuttingPlane &plane, */ /* guint LayerNr, vector& altInfillLayers); */ /* void draw (const Model *model, const Settings &settings, */ /* bool highlight=false); */ void draw_geometry (uint max_triangles=0); /* void drawBBox() const; */ /*void CenterAroundXY();*/ /* vector getMostUsedNormals() const; */ // Auto-Rotate object to have the largest area surface down for printing: /* void OptimizeRotation(); */ void CalcBBox(); // Rotation for manual rotate and used by OptimizeRotation: void Rotate(const Vector3d & axis, const double &angle); /* void Scale(double scale_factor); */ /* void ScaleX(double scale_factor); */ /* void ScaleY(double scale_factor); */ /* void ScaleZ(double scale_factor){}; */ /* double getScaleFactor(){ return scale_factor; }; */ /* double getScaleFactorX(){ return scale_factor_x; }; */ /* double getScaleFactorY(){ return scale_factor_y; }; */ /* double getScaleFactorZ(){ return 1; }; */ void invertNormals(); void mirror(); double area() const; int loadSVG(std::string filename); void xml_handle_node(const xmlpp::Node* node); string svg_cur_style; string svg_cur_name; string svg_cur_trans; string svg_cur_path; double svg_prescale; int svg_addPolygon(); static filetype_t getFileType(std::string filename) {return SVG;}; void splitshapes(vector &shapes, ViewProgress *progress=NULL); string info() const; private: vector polygons; }; repsnapper-2.3.2a5/src/gcode/000077500000000000000000000000001231531733200157735ustar00rootroot00000000000000repsnapper-2.3.2a5/src/gcode/Makefile000066400000000000000000000002411231531733200174300ustar00rootroot00000000000000# Delegate everything to the toplevel makefile # this is only here so 'make' works in src/ all: @$(MAKE) -C ../.. $@ # Catch all rule %: @$(MAKE) -C ../.. $@ repsnapper-2.3.2a5/src/gcode/Makefile.am000066400000000000000000000007631231531733200200350ustar00rootroot00000000000000# # Combined Makefile for Linux and OS/X # # # Copyright 2009+ Joachim Glauche # Copyright 2011 Bas Wijnen # # This file is part of RepSnapper and is made available under # the terms of the GNU General Public License, version 2, or at your # option, any later version, incorporated herein by reference. SHARED_SRC += \ src/gcode/gcode.cpp \ src/gcode/gcodestate.cpp \ src/gcode/command.cpp SHARED_INC += \ src/gcode/gcode.h \ src/gcode/gcodestate.h \ src/gcode/command.h repsnapper-2.3.2a5/src/gcode/command.cpp000066400000000000000000000405611231531733200201230ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #include "math.h" #include "gcode.h" #include #include #include "model.h" #include "ui/progress.h" #include "geometry.h" #include "ctype.h" #include "slicer/poly.h" using namespace std; // String feeder class class Feed { public: Feed(std::string s) : str(s), pos(0) { } char get() { return (pos < str.size()) ? str[pos++] : 0; } void unget() { if (pos) --pos; } protected: std::string str; size_t pos; }; // Gcode string feeder, skips over spaces and comments class GcodeFeed : public Feed { public: GcodeFeed( std::string s) : Feed(s) {} char get() { while ( 1 ) { char ch = Feed::get(); if (isspace(ch)) continue ; if (ch == ';') {// ; COMMENT #EOL str=""; return 0; } if (ch == '(') // ( COMMENT ) { while (ch && ch != ')') ch = Feed::get(); continue; } return ch; } } }; inline std::string ParseNumber(GcodeFeed & f) { std::string str; for (char ch = f.get(); ch; ch = f.get()) { if (ch == ',') ch = '.'; // some program's wrong output with decimal comma in some language(s) if (!isdigit(ch) && ch != '.' && ch != '+' && ch != '-') { // Non-number part f.unget(); // We read something that doesn't belong to us break; } str += ch; } return str; } inline int ToInt(GcodeFeed &f) { std::istringstream i(ParseNumber(f)); int x; if (!(i >> x)) return -1; return x; } inline float ToFloat(GcodeFeed &f) { std::istringstream i(ParseNumber(f)); float x; if (!(i >> x)) return -1; return x; } inline double ToDouble(GcodeFeed &f) { std::istringstream i(ParseNumber(f)); double x; if (!(i >> x)) return -1; return x; } Command::Command() { Code = UNKNOWN; init(); } void Command::init() { where=Vector3d::ZERO; is_value = false; f = 0.0; e = 0.0; extruder_no = 0; explicit_arg = ""; comment = ""; not_layerchange = false; abs_extr = 0; travel_length = 0; } Command::Command(GCodes code, const string explicit_arg_) : Code(code) { init(); explicit_arg = explicit_arg_; } Command::Command(GCodes code, const Vector3d &position, double E, double F) : Code(code), where(position), is_value(false), f(F), e(E), extruder_no(0), abs_extr(0), travel_length(0), not_layerchange(false) { if (where.z() < 0) where.z() = 0; } Command::Command(GCodes code, double value_) : Code(code), where(0,0,0), is_value(true), value(value_), f(0), e(0), extruder_no(0), abs_extr(0), travel_length(0), not_layerchange(false) { // for letter-without-number codes like "T" // the value is not an "S" value, it belongs to the command if ( MCODES[code].length() == 1 ) is_value = false; } Command::Command(string comment_only) : Code(COMMENT), where(0,0,0), is_value(true), value(0), f(0), e(0), extruder_no(0), abs_extr(0), travel_length(0), not_layerchange(true), comment(comment_only) { } Command::Command(const Command &rhs) : Code(rhs.Code), where(rhs.where), arcIJK (rhs.arcIJK), is_value(rhs.is_value), value(rhs.value), f(rhs.f), e(rhs.e), extruder_no(rhs.extruder_no), abs_extr(rhs.abs_extr), travel_length(rhs.travel_length), not_layerchange(rhs.not_layerchange), explicit_arg(rhs.explicit_arg), comment(rhs.comment) { } /** * Parse GCodes from a delivered line. * Comments are from ; to end-of-line * Comments are from ( to ) * Spaces and case outside of comments are ignored completely, according to NIST standard * Multiple commands can appear on one line * Uninteresting commands are silently dropped. * * @param gcodeline the string containing a line of gcode * @param defaultpos * @param [OUT] gcodeline the unparsed portion of the string */ Command::Command(string gcodeline, const Vector3d &defaultpos, const vector &E_letters) : where(defaultpos), arcIJK(0,0,0), is_value(false), f(0), e(0), extruder_no(0), abs_extr(0), travel_length(0) { // Notes: // Spaces are not significant in GCode // Weird-ass syntax like "G1X + 0 . 2543" is the same as "G1 X0.2453" // "G02" is the same as "G2" // Multiple Gxx codes on a line are accepted, but results are undefined. GcodeFeed buffer(gcodeline) ; //default: Code = COMMENT; comment = gcodeline; for (char ch = buffer.get(); ch; ch = buffer.get()) { // GCode is always ch=toupper(ch); float num = ToFloat(buffer) ; stringstream commss; commss << ch << num; switch (ch) { case 'G': Code = getCode(commss.str()); comment = ""; break; case 'M': // M commands is_value = true; Code = getCode(commss.str()); comment = ""; break; case 'S': value = num; break; case 'F': f = num; break; case 'X': where.x() = num; break; case 'Y': where.y() = num; break; case 'Z': where.z() = num; break; case 'I': arcIJK.x() = num; break; case 'J': arcIJK.y() = num; break; case 'K': cerr << "cannot handle ARC K command (yet?)!" << endl; break; case 'R': cerr << "cannot handle ARC R command (yet?)!" << endl; break; case 'T': Code = getCode("T"); comment = ""; extruder_no = num; break; default: { bool foundExtr = false; for (uint ie = 0; ie < E_letters.size(); ie++) if (ch == E_letters[ie]) { extruder_no = ie; e = num; foundExtr = true; } if (!foundExtr) cerr << "cannot parse GCode line " << gcodeline << endl; break; } } } if (where.z() < 0) { where.z() = 0; //throw(Glib::OptionError(Glib::OptionError::BAD_VALUE, "Z < 0 at " + info())); } } GCodes Command::getCode(const string commstr) const { GCodes code = COMMENT; for (int i = 0; i < NUM_GCODES; i++){ if (MCODES[i] == commstr) { code = (GCodes)i; return code; } } return code; } bool Command::hasNoEffect(const Vector3d LastPos, const double lastE, const double lastF, const bool relativeEcode) const { return ((Code == COORDINATEDMOTION || Code == RAPIDMOTION) && where.squared_distance(LastPos) < 0.000001 && ((relativeEcode && abs(e) < 0.00001) || (!relativeEcode && abs(e-lastE) < 0.00001)) && abs(abs_extr) < 0.00001); } string Command::GetGCodeText(Vector3d &LastPos, double &lastE, double &lastF, bool relativeEcode, const char E_letter, bool speedAlways) const { ostringstream ostr; if (Code > NUM_GCODES || MCODES[Code]=="") { cerr << "Don't know GCode for Command type "<< Code < split xy and z movements Vector3d delta = where-LastPos; const double RETRACT_E = 2; //mm if ( (where.z() < 0 || delta.z() < 0) && (delta.x()!=0 || delta.y()!=0) ) { Command xycommand(*this); // copy xycommand.comment = comment + _(" xy part"); Command zcommand(*this); // copy zcommand.comment = comment + _(" z part"); if (where.z() < 0) { // z<0 cannot be absolute -> positions are relative xycommand.where.z() = 0.; zcommand.where.x() = zcommand.where.y() = 0.; // this command will be z-only } else { xycommand.where.z() = LastPos.z(); } if (relativeEcode) { xycommand.e = -RETRACT_E; // retract filament at xy move zcommand.e = 0; // all extrusion done in xy } else { xycommand.e = lastE - RETRACT_E; zcommand.e = lastE - RETRACT_E; } //cerr << "split xy and z commands delta=" << delta < 0.1)) { if (f>10) ostr.precision(0); ostr << " F" << f; ostr.precision(PREC); } lastF = f; break; case SELECTEXTRUDER: ostr.precision(0); ostr << value; ostr.precision(PREC); comm += _(" Select Extruder"); break; case RESET_E: ostr << " " << E_letter << "0" ; comm += _(" Reset Extrusion"); lastE = 0; break; case UNKNOWN: cerr << "unknown GCode " << info() << endl; break; default: //cerr << "unhandled GCode " << info() << endl; break; } if(explicit_arg.length() != 0) ostr << " " << explicit_arg; if(comm.length() != 0) { if (Code!=COMMENT) ostr << " ; " ; ostr << comm; } if(abs_extr != 0) { ostr << " ; AbsE " << abs_extr; if (travel_length != 0) { const double espeed = abs_extr / travel_length * f / 60; ostr.precision(2); ostr << " ("<< espeed; if (thisE != 0) { const double espeed_tot = (thisE + abs_extr) / travel_length * f / 60; ostr << "/" << espeed_tot ; } ostr << " mm/s) "; ostr.precision(PREC); } else { // cerr << ostr.str() << endl; } } // ostr << "; "<< info(); // show Command on line return ostr.str(); } void draw_arc(Vector3d &lastPos, Vector3d center, double angle, double dz, short ccw) { Vector3d arcpoint; Vector3d radiusv = lastPos-center; radiusv.z() = 0; double astep = angle/radiusv.length()/30.; if (angle/astep > 10000) astep = angle/10000; if (angle<0) ccw=!ccw; Vector3d axis(0.,0.,ccw?1.:-1.); double startZ = lastPos.z(); for (long double a = 0; abs(a) < abs(angle); a+=astep){ arcpoint = center + radiusv.rotate(a, axis); if (dz!=0 && angle!=0) arcpoint.z() = startZ + dz*a/angle; glVertex3dv(lastPos); glVertex3dv(arcpoint); lastPos = arcpoint; } } void Command::draw(Vector3d &lastPos, const Vector3d &offset, double extrwidth, bool arrows, bool debug_arcs) const { Vector3d off_where = where + offset; Vector3d off_lastPos = lastPos + offset; GLfloat ccol[4]; glGetFloatv(GL_CURRENT_COLOR,&ccol[0]); glBegin(GL_LINES); // arc: if (Code == ARC_CW || Code == ARC_CCW) { Vector3d center = off_lastPos + arcIJK; Vector3d P = -arcIJK, Q = off_where-center; // arc endpoints bool ccw = (Code == ARC_CCW); if (debug_arcs) { glColor4f(0.f,1.f,0.0f,0.2f); glVertex3dv(center); glVertex3dv(off_lastPos); glColor4f(1.f,0.f,0.0f,0.2f); glVertex3dv(center); glVertex3dv(off_where); glColor4fv(ccol); float lum = ccol[3]; if (off_where == off_lastPos) // full circle glColor4f(1.f,0.f,1.f,lum); else if (ccw) glColor4f(0.5f,0.5f,1.f,lum); else glColor4f(1.f,0.5f,0.0f,lum); } long double angle; if (P==Q) angle = 2*M_PI; else { #if 0 // marlin calculation (motion_control.cpp) angle = atan2(P.x()*Q.y()-P.y()*Q.x(), P.x()*Q.x()+P.y()*Q.y()); if (angle < 0) angle += 2*M_PI; if (!ccw) angle-=2*M_PI; // angle sign determines rotation #else angle = angleBetween(P,Q); // ccw angle if (!ccw) angle=-angle; if (angle < 0) angle += 2*M_PI; // alway positive, ccw determines rotation #endif } //if (abs(angle) < 0.00001) angle = 0; double dz = off_where.z()-(off_lastPos).z(); // z move with arc Vector3d arcstart = off_lastPos; draw_arc(off_lastPos, center, angle, dz, ccw); // extrusion boundary for arc: if (extrwidth > 0) { glEnd(); glLineWidth(1); glColor4f(ccol[0],ccol[1],ccol[2],ccol[3]/2); Vector3d normarcIJK(arcIJK); normarcIJK.normalize(); Vector3d dradius = normarcIJK*extrwidth/2; glBegin(GL_LINES); Vector3d offstart = arcstart+dradius; draw_arc(offstart, center, angle, dz, ccw); offstart = arcstart-dradius; draw_arc(offstart, center, angle, dz, ccw); //glEnd(); } } // end ARCs if (off_lastPos==off_where) { glEnd(); if (arrows) { glPointSize(10); glBegin(GL_POINTS); //glColor4f(1.,0.1,0.1,ccol[3]); glVertex3dv(off_where); glEnd(); } } else { glVertex3dv(off_lastPos); glVertex3dv(off_where); if (arrows) { glColor4f(ccol[0],ccol[1],ccol[2],0.7*ccol[3]); // 0.3mm long arrows if no boundary double alen = 0.3; if (extrwidth > 0) alen = 1.2*extrwidth ; Vector3d normdir = normalized(off_where-off_lastPos); if (normdir.x() != 0 || normdir.y() != 0 ) { Vector3d arrdir = normdir * alen; Vector3d arrdir2(-0.5*alen*normdir.y(), 0.5*alen*normdir.x(), arrdir.z()); glVertex3dv(off_where); Vector3d arr1 = off_where-arrdir+arrdir2; glVertex3dv(arr1); glVertex3dv(off_where); Vector3d arr2 = off_where-arrdir-arrdir2; glVertex3dv(arr2); } } glEnd(); // extrusion boundary for straight line: if (extrwidth > 0) { glLineWidth(1); glColor4f(ccol[0],ccol[1],ccol[2],ccol[3]/2); vector thickpoly; if (abs_extr != 0) { double fr_extr = extrwidth / (1+abs_extr); double to_extr = extrwidth * (1+abs_extr); thickpoly = dir_thick_line(Vector2d(off_lastPos.x(),off_lastPos.y()), Vector2d(off_where.x(),off_where.y()), fr_extr, to_extr); } else thickpoly = thick_line(Vector2d(off_lastPos.x(),off_lastPos.y()), Vector2d(off_where.x(),off_where.y()), extrwidth); for (uint i=0; i0) linewidth*=abs_extr; // else if (abs_extr<0) linewidth/=(-abs_extr); glLineWidth(linewidth); glColor4fv(&color[0]); draw(lastPos, offset, extrwidth, arrows, debug_arcs); } void Command::addToPosition(Vector3d &from, bool relative) { if (relative) from += where; else { if (where.x()!=0) from.x() = where.x(); if (where.y()!=0) from.y() = where.y(); if (where.z()!=0) from.z() = where.z(); } } string Command::info() const { ostringstream ostr; ostr << "Command"; if (comment!="") ostr << " '" << comment << "'"; ostr << ": Extr="< #include #include "stdafx.h" #include #include #include #include /* Movement Codes G0 Rapid Motion Implemented - supports X, Y, and Z axes. G1 Coordinated Motion Implemented - supports X, Y, and Z axes. G2 Arc – Clockwise Not used by Skienforge G3 Arc - Counter Clockwise Not used by Skienforge G4 Dwell Implemented. G20 Inches as units Implemented. G21 Millimetres as units Implemented. G28 Go Home Implemented. (X = -135mm, Y = 100mm, Z = 0mm) G90 Absolute Positioning Implemented. V1.0.5 G92 Set current as home Implemented V1.0.5 G1 Coordinated Motion G1 X-53.67 Y52.16 Z0.54 E54.394 F213.333 Go to X=-53.67, Y=52.16, Z=0.54 using SPEED=213.333 mm per minute (3.5mm/sec) E is distance and is still not implemented in RapMan firmware Note that if E values (E-code) exists for the G1 the RapMan firmware up to 1.0.5 will not parse it properly and will cause all different problems during print. You can disable E value generation in INSET tab by setting the "Extrusion Distance Format Choice" to "Do Not Add Extrusion Distance". Special functions (M Codes) M101 Turn extruder on Forward. M102 Turn extruder on Reverse. Still to add M103 Turn extruder off. M104 S145.0 Set target temperature to 145.0 C. M105 Custom code for temperature reading. Not used M106 Turn fan on. M107 Turn fan off. M108 S400 Set Extruder speed to S value/10 = 40rpm. Future functions (M Codes) M codes that may be introduced for the RepRap M120 Pgain PWM control values M121 Igain “ M122 Dgain “ M123 Imax “ M124 Imin “ Special BFB-only M Codes M220 Turn off AUX V1.0.5 M221 Turn on AUX V1.0.5 M222 Set speed of fast XY moves V1.0.5 M223 Set speed of fast Z moves V1.0.5 M224 Enable extruder motor during fast move M225 Disable extruder motor during fast move M226 Pause the printer until ESC key is pressed M227 S1000 P800 on extruder stop (M103) reverse the extruder stepper for S turns and on extruder start (M101) prepare (push) filament P steps (available from firmware 1.0.8) Typical File header produced by Skeinforge G21 millimeter system selection G90 absolute distance mode G28 Return to home position M222 S1024 Manually added to file M222 S500 Set speed of fast XY moves. Default value 500 -V1.0.5 M223 S768 Manually added to file M223 S500 Set speed of fast Z moves. Default value 500 -V1.0.5 M103 Turn extruder OFF. M105 Custom code for temperature reading – not used by RapMan M104 S247.0 Set temperature to 145.0 DegC. G1 X0.0 Y0.0 Z0.0 F480.0 linear interpolation M101 Turn extruder ON. Main code follows */ enum GCodes{GOTO, DRAWTO, DWELL, // 0 1 2 RAPIDMOTION, COORDINATEDMOTION, // 3 .. ARC_CW, ARC_CCW, // 5 .. EXTRUDERON, EXTRUDERONREVERSE, EXTRUDEROFF, // 7 .. MILLIMETERSASUNITS, INCHESASUNITS, // 10 .. GOHOME, GOHOMEVIAINTERMEDIATEPOINT, // 12 .. ABSOLUTEPOSITIONING, RELATIVEPOSITIONING, // 14 .. ABSOLUTE_ECODE, RELATIVE_ECODE, // 16 .. SETCURRENTPOS, SELECTEXTRUDER, ZMOVE, SETSPEED, // 18 .. FANON, FANOFF, // 22 .. ASKTEMP, // 24 EXTRUDERTEMP, BEDTEMP, RESET_E, COMMENT, LAYERCHANGE, UNKNOWN}; const int NUM_GCODES = 31; const string MCODES[] = {"G92", "", "", "G0", "G1", "G2", "G3", //arcs "M101", "M102", "M103", // eon erev eoff "G21", "G20", // mm in "G28", "", "G90", "G91", // abs. rel. pos "M82", "M83", // abs. E, relative E "G92", "T", "G1", "G1" , "M106", "M107", "M105", // temp? "M104", "M140", "G92", "; ", "; Layer", "; UNKNOWN"}; class Model; class ViewProgress; class Command { public: void init(); Command(); Command(GCodes code, const Vector3d &where=Vector3d::ZERO, double E=0, double F=0); Command(GCodes code, const string explicit_arg); // explicit string arguments to command Command(GCodes code, double value); // S value gcodes and letter/number codes Command(string gcodeline, const Vector3d &defaultpos, const vector &E_letters); Command(string comment); Command(const Command &rhs); GCodes Code; Vector3d where; Vector3d arcIJK; // I,J,K (dx, dy, dz) bool is_value; // M commands double value; // M commands S value code double f,e; // Feedrate f=speed, e=extrusion to perform while moving (Pythagoras) uint extruder_no; double abs_extr; // for debugging/painting double travel_length; // for debugging bool not_layerchange; // don't record as layerchange for lifted moves string explicit_arg; string comment; void draw(Vector3d &lastPos, const Vector3d &offset, guint linewidth, Vector4f color, double extrwidth, bool arrows=true, bool debug_arcs = false) const; void draw(Vector3d &lastPos, const Vector3d &offset, double extrwidth, bool arrows=true, bool debug_arcs = false) const; bool hasNoEffect(const Vector3d LastPos, const double lastE, const double lastF, const bool relativeEcode) const; string GetGCodeText(Vector3d &LastPos, double &lastE, double &lastF, bool relativeEcode, const char E_letter='E', bool speedAlways = false) const; GCodes getCode(const string commstr) const; void addToPosition(Vector3d &from, bool relative); string info() const; }; repsnapper-2.3.2a5/src/gcode/gcode.cpp000066400000000000000000000530211231531733200175610ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #include "math.h" #include "gcode.h" #include #include #include "model.h" #include "ui/progress.h" #include "geometry.h" #include "ctype.h" #include "settings.h" #include "render.h" GCode::GCode() : gl_List(-1) { Min.set(99999999.0,99999999.0,99999999.0); Max.set(-99999999.0,-99999999.0,-99999999.0); Center.set(0,0,0); buffer = Gtk::TextBuffer::create(); } void GCode::clear() { buffer->erase (buffer->begin(), buffer->end()); commands.clear(); layerchanges.clear(); buffer_zpos_lines.clear(); Min = Vector3d::ZERO; Max = Vector3d::ZERO; Center= Vector3d::ZERO; if (gl_List>=0) glDeleteLists(gl_List,1); gl_List = -1; } double GCode::GetTotalExtruded(bool relativeEcode) const { if (commands.size()==0) return 0; if (relativeEcode) { double E=0; for (uint i=0; i0; i--) if (commands[i].e>0) return commands[i].e; } return 0; } void GCode::translate(Vector3d trans) { for (uint i=0; i buffer, int lineno) { Gtk::TextBuffer::iterator from ,to; from = buffer->get_iter_at_line (lineno); to = buffer->get_iter_at_line (lineno+1); return buffer->get_text (from, to); } void GCode::updateWhereAtCursor(const vector &E_letters) { int line = buffer->get_insert()->get_iter().get_line(); // Glib::RefPtr buf = iter.get_buffer(); if (line == 0) return; string text = getLineAt(buffer, line-1); Command commandbefore(text, Vector3d::ZERO, E_letters); Vector3d where = commandbefore.where; // complete position of previous line int l = line; while (l>0 && where.x()==0) { l--; text = getLineAt(buffer, l); where.x() = Command(text, Vector3d::ZERO, E_letters).where.x(); } l = line; while (l>0 && where.y()==0) { l--; text = getLineAt(buffer, l); where.y() = Command(text, Vector3d::ZERO, E_letters).where.y(); } l = line; // find last z pos fast if (buffer_zpos_lines.size()>0) for (uint i = buffer_zpos_lines.size()-1; i>0 ;i--) { if (int(buffer_zpos_lines[i]) <= l) { text = getLineAt(buffer, buffer_zpos_lines[i]); //cerr << text << endl; Command c(text, Vector3d::ZERO, E_letters); where.z() = c.where.z(); if (where.z()!=0) break; } } while (l>0 && where.z()==0) { l--; text = getLineAt(buffer, l); Command c(text, Vector3d::ZERO, E_letters); where.z() = c.where.z(); } // current move: text = getLineAt(buffer, line); Command command(text, where, E_letters); Vector3d dwhere = command.where - where; where.z() -= 0.0000001; currentCursorWhere = where+dwhere; currentCursorCommand = command; currentCursorFrom = where; } void GCode::Read(Model *model, const vector E_letters, ViewProgress *progress, string filename) { clear(); ifstream file; file.open(filename.c_str()); //open a file file.seekg (0, ios::end); double filesize = double(file.tellg()); file.seekg (0); progress->start(_("Loading GCode"), filesize); int progress_steps=(int)(filesize/1000); if (progress_steps==0) progress_steps=1; buffer_zpos_lines.clear(); if(!file.good()) { // MessageBrowser->add(str(boost::format("Error opening file %s") % Filename).c_str()); return; } set_locales("C"); uint LineNr = 0; string s; bool relativePos = false; Vector3d globalPos(0,0,0); Min.set(99999999.0,99999999.0,99999999.0); Max.set(-99999999.0,-99999999.0,-99999999.0); std::vector loaded_commands; double lastZ=0.; double lastE=0.; double lastF=0.; layerchanges.clear(); stringstream alltext; int current_extruder = 0; while(getline(file,s)) { alltext << s << endl; LineNr++; unsigned long fpos = file.tellg(); if (fpos%progress_steps==0) if (!progress->update(fpos)) break; Command command; if (relativePos) command = Command(s, Vector3d::ZERO, E_letters); else command = Command(s, globalPos, E_letters); if (command.Code == COMMENT) { continue; } if (command.Code == UNKNOWN) { cerr << "Unknown GCode " << s << endl; continue; } if (command.Code == RELATIVEPOSITIONING) { relativePos = true; continue; } if (command.Code == ABSOLUTEPOSITIONING) { relativePos = false; continue; } if (command.Code == SELECTEXTRUDER) { current_extruder = command.extruder_no; continue; } command.extruder_no = current_extruder; // not used yet // if (command.Code == ABSOLUTE_ECODE) { // relativeE = false; // continue; // } // if (command.Code == RELATIVE_ECODE) { // relativeE = true; // continue; // } if (command.e == 0) command.e = lastE; else lastE = command.e; if (command.f != 0) lastF = command.f; else command.f = lastF; // cout << s << endl; //cerr << command.info()<< endl; // if(command.where.x() < -100) // continue; // if(command.where.y() < -100) // continue; if (command.Code == SETCURRENTPOS) { continue;//if (relativePos) globalPos = command.where; } else { command.addToPosition(globalPos, relativePos); } if (globalPos.z() < 0){ cerr << "GCode below zero!"<< endl; continue; } if ( command.Code == RAPIDMOTION || command.Code == COORDINATEDMOTION || command.Code == ARC_CW || command.Code == ARC_CCW || command.Code == GOHOME ) { if(globalPos.x() < Min.x()) Min.x() = globalPos.x(); if(globalPos.y() < Min.y()) Min.y() = globalPos.y(); if(globalPos.z() < Min.z()) Min.z() = globalPos.z(); if(globalPos.x() > Max.x()) Max.x() = globalPos.x(); if(globalPos.y() > Max.y()) Max.y() = globalPos.y(); if(globalPos.z() > Max.z()) Max.z() = globalPos.z(); if (globalPos.z() > lastZ) { // if (lastZ > 0){ // don't record first layer unsigned long num = loaded_commands.size(); layerchanges.push_back(num); loaded_commands.push_back(Command(LAYERCHANGE, layerchanges.size())); // } lastZ = globalPos.z(); buffer_zpos_lines.push_back(LineNr-1); } else if (globalPos.z() < lastZ) { lastZ = globalPos.z(); if (layerchanges.size()>0) layerchanges.erase(layerchanges.end()-1); } } loaded_commands.push_back(command); } file.close(); reset_locales(); commands = loaded_commands; buffer->set_text(alltext.str()); Center = (Max + Min)/2; model->m_signal_gcode_changed.emit(); double time = GetTimeEstimation(); int h = (int)time/3600; int min = ((int)time%3600)/60; int sec = ((int)time-3600*h-60*min); cerr << "GCode Time Estimation "<< h <<"h "<0) // have recorded layerchange indices -> draw whole layers for(uint i=0;i layerchanges[i]) { if (commands[layerchanges[i]].where.z() >= z) { //cerr << " _ " << i << endl; return i; } } } return -1; } int GCode::getLayerNo(const unsigned long commandno) const { if (commandno<0) return commandno; if (layerchanges.size()>0) {// have recorded layerchange indices -> draw whole layers if (commandno > layerchanges.back() && commandno < commands.size()) // last layer? return layerchanges.size()-1; for(uint i=0;i commandno) return (i-1); } return -1; } unsigned long GCode::getLayerStart(const uint layerno) const { if (layerchanges.size() > layerno) return layerchanges[layerno]; return 0; } unsigned long GCode::getLayerEnd(const uint layerno) const { if (layerchanges.size()>layerno+1) return layerchanges[layerno+1]-1; return commands.size()-1; } void GCode::draw(const Settings &settings, int layer, bool liveprinting, int linewidth) { /*--------------- Drawing -----------------*/ //cerr << "gc draw "<0) { // have recorded layerchange indices -> draw whole layers if (layer>-1) { if (layer != 0) start = layerchanges[layer]; if (layer < (int)layerchanges.size()-1) end = layerchanges[layer+1]; else end = commands.size(); } else { int n_changes = layerchanges.size(); int sind = 0; int eind = 0; if (n_changes > 0) { sind = (uint)ceil(settings.get_double("Display","GCodeDrawStart")*(n_changes-1)/Max.z()); eind = (uint)ceil(settings.get_double("Display","GCodeDrawEnd") *(n_changes-1)/Max.z()); } if (sind>=eind) { eind = MIN(sind+1, n_changes-1); } else arrows = false; // arrows only for single layers sind = CLAMP(sind, 0, n_changes-1); eind = CLAMP(eind, 0, n_changes-1); if (sind == 0) start = 0; else start = layerchanges[sind]; //if (start>0) start-=1; // get one command before layer end = layerchanges[eind]; if (sind == n_changes-1) end = commands.size(); // get last layer if (eind == n_changes-1) end = commands.size(); // get last layer } } else { if (n_cmds > 0) { start = (uint)(settings.get_double("Display","GCodeDrawStart")*(n_cmds)/Max.z()); end = (uint)(settings.get_double("Display","GCodeDrawEnd") *(n_cmds)/Max.z()); } } drawCommands(settings, start, end, liveprinting, linewidth, arrows && settings.get_boolean("Display","DisplayGCodeArrows"), !liveprinting && settings.get_boolean("Display","DisplayGCodeBorders"), settings.get_boolean("Display","DebugGCodeOnlyZChange")); if (currentCursorWhere!=Vector3d::ZERO) { glDisable(GL_DEPTH_TEST); // glPointSize(10); // glLineWidth(5); // glColor4f(1.f,0.f,1.f,1.f); // glBegin(GL_POINTS); // glVertex3dv(currentCursorWhere); // glEnd(); // glBegin(GL_LINES); // glVertex3dv(currentCursorFrom); // glVertex3dv(currentCursorWhere); // glEnd(); const Vector3d offset = settings.get_extruder_offset(currentCursorCommand.extruder_no); currentCursorCommand.draw(currentCursorFrom, offset, 7, Vector4f(1.f,0.f,1.f,1.f), 0., true, false); } } void GCode::drawCommands(const Settings &settings, uint start, uint end, bool liveprinting, int linewidth, bool arrows, bool boundary, bool onlyZChange) { // if (gl_List < 0) { // gl_List = glGenLists(1); // glNewList(gl_List, GL_COMPILE); // cerr << "list " << gl_List << endl; double LastE=0.0; bool extruderon = false; // Vector4f LastColor = Vector4f(0.0f,0.0f,0.0f,1.0f); Vector4f Color = Vector4f(0.0f,0.0f,0.0f,1.0f); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); uint n_cmds = commands.size(); if (n_cmds==0) return; Vector3d defaultpos(0,0,0); Vector3d pos(0,0,0); bool relativeE = settings.get_boolean("Slicing","RelativeEcode"); bool debug_arcs = settings.get_boolean("Display","DisplayDebugArcs"); double extrusionwidth = 0; if (boundary) extrusionwidth = settings.GetExtrudedMaterialWidth(settings.get_double("Slicing","LayerThickness")); start = CLAMP (start, 0, n_cmds-1); end = CLAMP (end, 0, n_cmds-1); if (end<=start) return; // get starting point if (start>0) { uint i = start; while ((commands[i].is_value || commands[i].where == defaultpos) && i < end) i++; pos = commands[i].where; } // draw begin glPointSize(20); glBegin(GL_POINTS); //glColor4f(1.,0.1,0.1,ccol[3]); glVertex3dv((GLdouble*)&pos); glEnd(); Vector3d last_extruder_offset = Vector3d::ZERO; (void) extruderon; // calm warnings double maxmove_xy = settings.get_double("Hardware","MaxMoveSpeedXY"); bool debuggcodeoffset = settings.get_boolean("Display","DebugGCodeOffset"); bool displaygcodemoves = settings.get_boolean("Display","DisplayGCodeMoves"); bool debuggcodeextruders = settings.get_boolean("Display","DebugGCodeExtruders"); bool luminanceshowsspeed = settings.get_boolean("Display","LuminanceShowsSpeed"); Vector4f gcodemovecolour = settings.get_colour("Display","GCodeMoveColour"); Vector4f gcodeprintingcolour = settings.get_colour("Display","GCodePrintingColour"); for(uint i=start; i <= end; i++) { Vector3d extruder_offset = Vector3d::ZERO; //Vector3d next_extruder_offset = Vector3d::ZERO; string extrudername = settings.numberedExtruder("Extruder", commands[i].extruder_no); // TO BE FIXED: if (!debuggcodeoffset) { // show all together extruder_offset = settings.get_extruder_offset(commands[i].extruder_no); pos -= extruder_offset - last_extruder_offset; last_extruder_offset = extruder_offset; } double extrwidth = extrusionwidth; if (commands[i].is_value) continue; if (onlyZChange && commands[i].where.z() == pos.z()) { pos = commands[i].where; LastE=commands[i].e; continue; } switch(commands[i].Code) { case SETSPEED: case ZMOVE: case EXTRUDERON: extruderon = true; break; case EXTRUDEROFF: extruderon = false; break; // case COORDINATEDMOTION3D: // old 3D gcode // if (extruderon) { // if (liveprinting) { // Color = settings.Display.GCodePrintingColour; // } else // Color = settings.Display.GCodeExtrudeColour; // } // else { // Color = settings.Display.GCodeMoveColour; // extrwidth = 0; // } // commands[i].draw(pos, linewidth, Color, extrwidth, // arrows, debug_arcs); // LastE=commands[i].e; // break; case ARC_CW: case ARC_CCW: if (i==start) { break; // don't draw arcs at beginning (wrong startpoint) } case COORDINATEDMOTION: { double speed = commands[i].f; double luma = 1.; if( (!relativeE && commands[i].e == LastE) || (relativeE && commands[i].e == 0) ) // move only { if (displaygcodemoves) { luma = 0.3 + 0.7 * speed / maxmove_xy / 60; Color = gcodemovecolour; extrwidth = 0; } else { pos = commands[i].where; break; } } else { luma = 0.3 + 0.7 * speed / settings.get_double(extrudername,"MaxLineSpeed") / 60; if (liveprinting) { Color = gcodeprintingcolour; } else { Color = settings.get_colour(extrudername,"DisplayColour"); } if (debuggcodeextruders) { ostringstream o; o << commands[i].extruder_no+1; Render::draw_string( (pos + commands[i].where) / 2. + extruder_offset, o.str()); } } if (luminanceshowsspeed) Color *= luma; commands[i].draw(pos, extruder_offset, linewidth, Color, extrwidth, arrows, debug_arcs); LastE=commands[i].e; break; } case RAPIDMOTION: { Color = gcodemovecolour; commands[i].draw(pos, extruder_offset, 1, Color, extrwidth, arrows, debug_arcs); break; } default: break; // ignored GCodes } //if(commands[i].Code != EXTRUDERON && commands[i].Code != EXTRUDEROFF) //pos = commands[i].where; } glLineWidth(1); // glEndList(); // } // glCallList(gl_List); } // bool add_text_filter_nan(string str, string &GcodeTxt) // { // if (int(str.find("nan"))<0) // GcodeTxt += str; // else { // cerr << "not appending " << str << endl; // //cerr << "find: " << str.find("nan") << endl; // return false; // } // return true; // } void GCode::MakeText(string &GcodeTxt, const Settings &settings, ViewProgress * progress) { string GcodeStart = settings.get_string("GCode","Start"); string GcodeLayer = settings.get_string("GCode","Layer"); string GcodeEnd = settings.get_string("GCode","End"); double lastE = -10; double lastF = 0; // last Feedrate (can be omitted when same) Vector3d pos(0,0,0); Vector3d LastPos(-10,-10,-10); std::stringstream oss; Glib::Date date; date.set_time_current(); Glib::TimeVal time; time.assign_current_time(); GcodeTxt += "; GCode by Repsnapper, "+ date.format_string("%a, %x") + //time.as_iso8601() + "\n"; GcodeTxt += "\n; Startcode\n"+GcodeStart + "; End Startcode\n\n"; layerchanges.clear(); if (progress) progress->restart(_("Collecting GCode"), commands.size()); int progress_steps=(int)(commands.size()/100); if (progress_steps==0) progress_steps=1; double speedalways = settings.get_boolean("Hardware","SpeedAlways"); bool useTcommand = settings.get_boolean("Slicing","UseTCommand"); const bool relativeecode = settings.get_boolean("Slicing","RelativeEcode"); uint currextruder = 0; const uint numExt = settings.getNumExtruders(); string extLetters=""; for (uint i = 0;iupdate(i)) break; if ( commands[i].Code == LAYERCHANGE ) { layerchanges.push_back(i); if (GcodeLayer.length()>0) GcodeTxt += "\n; Layerchange GCode\n" + GcodeLayer + "; End Layerchange GCode\n\n"; } if ( commands[i].where.z() < 0 ) { cerr << i << " Z < 0 " << commands[i].info() << endl; } else { GcodeTxt += commands[i].GetGCodeText(LastPos, lastE, lastF, relativeecode, E_letter, speedalways) + "\n"; } } GcodeTxt += "\n; End GCode\n" + GcodeEnd + "\n"; buffer->set_text (GcodeTxt); // save zpos line numbers for faster finding buffer_zpos_lines.clear(); uint blines = buffer->get_line_count(); for (uint i = 0; i < blines; i++) { const string line = getLineAt(buffer, i); if (line.find("Z") != string::npos || line.find("z") != string::npos) buffer_zpos_lines.push_back(i); } if (progress) progress->stop(); } // void GCode::Write (Model *model, string filename) // { // FILE *file; // file = fopen (filename.c_str(), "w+"); // if (!file) // model->alert (_("failed to open file")); // else { // fprintf (file, "%s", buffer->get_text().c_str()); // fclose (file); // } // } // bool GCode::append_text (const std::string &line) // { // if (int(line.find("nan"))<0{) // buffer->insert (buffer->end(), line); // return true; // } // else { // cerr << "not appending line \"" << line << "\"" << endl; // return false; // } // } std::string GCode::get_text () const { return buffer->get_text(); } /////////////////////////////////////////////////////////////////////////////////// GCodeIter::GCodeIter (Glib::RefPtr buffer) : m_buffer (buffer), m_it (buffer->begin()), m_line_count (buffer->get_line_count()), m_cur_line (1) { } void GCodeIter::set_to_lineno(long lineno) { m_cur_line = max((long)0,lineno); m_it = m_buffer->get_iter_at_line (m_cur_line); } std::string GCodeIter::next_line() { Gtk::TextBuffer::iterator last = m_it; m_it = m_buffer->get_iter_at_line (m_cur_line++); return m_buffer->get_text (last, m_it); } std::string GCodeIter::next_line_stripped() { string line = next_line(); size_t pos = line.find(";"); if (pos!=string::npos){ line = line.substr(0,pos); } size_t newline = line.find("\n"); if (newline==string::npos) line += "\n"; return line; } bool GCodeIter::finished() { return m_cur_line > m_line_count; } GCodeIter *GCode::get_iter () { GCodeIter *iter = new GCodeIter (buffer); iter->time_estimation = GetTimeEstimation(); return iter; } Command GCodeIter::getCurrentCommand(Vector3d defaultwhere, const vector &E_letters) { Gtk::TextBuffer::iterator from ,to; // cerr <<"currline" << defaultwhere << endl; // cerr <<"currline" << (int) m_cur_line << endl; from = m_buffer->get_iter_at_line (m_cur_line); to = m_buffer->get_iter_at_line (m_cur_line+1); Command command(m_buffer->get_text (from, to), defaultwhere, E_letters); return command; } repsnapper-2.3.2a5/src/gcode/gcode.h000066400000000000000000000056221231531733200172320ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #include #include #include #include #include "command.h" class GCodeIter { Glib::RefPtr m_buffer; Gtk::TextBuffer::iterator m_it; public: unsigned long m_line_count, m_cur_line; GCodeIter (Glib::RefPtr buffer); std::string next_line (); std::string next_line_stripped(); bool finished(); double time_used; time_t time_started; double time_estimation; Command getCurrentCommand(Vector3d defaultwhere, const vector &E_letters); void set_to_lineno(long lineno); }; class GCode { int gl_List; public: GCode(); void Read (Model *model, const vector E_letters, ViewProgress *progress, string filename); //void Write (Model *model, string filename); void draw (const Settings &settings, int layer=-1, bool liveprinting=false, int linewidth=3); void drawCommands(const Settings &settings, uint start, uint end, bool liveprinting, int linewidth, bool arrows, bool boundary=false, bool onlyZChange = false); void MakeText(string &GcodeTxt, const Settings &settings, ViewProgress * progress); //bool append_text (const std::string &line); std::string get_text() const; void clear(); std::vector commands; uint size() { return commands.size(); }; Vector3d Min, Max, Center; void translate(Vector3d trans); Glib::RefPtr buffer; GCodeIter *get_iter (); double GetTotalExtruded(bool relativeEcode) const; double GetTimeEstimation() const; void updateWhereAtCursor(const vector &E_letters); Vector3d currentCursorWhere; Vector3d currentCursorFrom; Command currentCursorCommand; vector buffer_zpos_lines; // line numbers where a z position is set vector layerchanges; int getLayerNo(const double z) const; int getLayerNo(const unsigned long commandno) const; unsigned long getLayerStart(const uint layerno) const; unsigned long getLayerEnd(const uint layerno) const; private: unsigned long unconfirmed_blocks; }; repsnapper-2.3.2a5/src/gcode/gcodestate.cpp000066400000000000000000000155001231531733200206220ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "shape.h" #include "gcodestate.h" #include "printlines.h" struct GCodeStateImpl { GCode &code; Vector3d LastPosition; Command lastCommand; GCodeStateImpl(GCode &_code) : code(_code), LastPosition(0,0,0) {} }; GCodeState::GCodeState(GCode &code) { pImpl = new GCodeStateImpl(code); timeused = 0; } GCodeState::~GCodeState() { delete pImpl; } // void GCodeState::SetZ(double z) // { // if (!isnan(z)) // pImpl->LastPosition.z = z; // } const Vector3d &GCodeState::LastPosition() { return pImpl->LastPosition; } void GCodeState::SetLastPosition(const Vector3d &v) { pImpl->LastPosition = v; } void GCodeState::AppendCommand(Command &command, bool relativeE) { if (!command.is_value) { if (!relativeE) command.e += pImpl->lastCommand.e; if (command.f!=0) { timeused += (command.where - pImpl->lastCommand.where).length()/command.f*60; } pImpl->lastCommand = command; pImpl->LastPosition = command.where; } pImpl->code.commands.push_back(command); if (command.where.z() > pImpl->code.Max.z()) pImpl->code.Max.z() = command.where.z(); } void GCodeState::AppendCommand(GCodes code, bool relativeE, string comment) { Command comm(code); comm.comment = comment; AppendCommand(comm, relativeE); } void GCodeState::AppendCommands(vector commands, bool relativeE) { for (uint i = 0; i < commands.size(); i++) { AppendCommand(commands[i], relativeE); } } // double GCodeState::GetLastLayerZ(double curZ) // { // if (pImpl->lastLayerZ <= 0) // pImpl->lastLayerZ = curZ; // return pImpl->lastLayerZ; // } // void GCodeState::SetLastLayerZ(double z) // { // if (!isnan(z)) // pImpl->lastLayerZ = z; // } void GCodeState::ResetLastWhere(Vector3d to) { pImpl->lastCommand.where = to; } double GCodeState::DistanceFromLastTo(Vector3d here) { return (pImpl->lastCommand.where - here).length(); } double GCodeState::LastCommandF() { return pImpl->lastCommand.f; } // // dont use -- commands are generated in PLine3 printlines.cpp // void GCodeState::AddLines (vector plines, // double extrusionfactor, // double offsetZ, // const Settings::SlicingSettings &slicing, // const Settings::HardwareSettings &hardware) // { // for (uint i=0; i < plines.size(); i++) // MakeGCodeLine (plines[i], extrusionfactor, offsetZ, slicing, hardware); // } void GCodeState::AddLines (vector linespoints, double extrusionFactor, double maxspeed, double maxmovespeed, double offsetZ, const Settings &settings) { bool relEcode = settings.get_boolean("Slicing","RelativeEcode"); double minmovespeed = settings.get_double("Hardware","MinMoveSpeedXY") * 60; for (uint i=0; i < linespoints.size(); i+=2) { // MOVE to start of next line if(LastPosition() != linespoints[i]) { MakeGCodeLine (LastPosition(), linespoints[i], Vector3d(0,0,0),0, 0, 0, minmovespeed, maxmovespeed, offsetZ, relEcode); SetLastPosition (linespoints[i]); } // PLOT to endpoint of line MakeGCodeLine (LastPosition(), linespoints[i+1], Vector3d(0,0,0),0, extrusionFactor, 0, minmovespeed, maxspeed, offsetZ, relEcode); SetLastPosition(linespoints[i+1]); } //SetLastLayerZ(z); } // // dont use -- commands are generated in PLine3 printlines.cpp // // (speeds are in mm/min which is obsolete) // void GCodeState::MakeGCodeLine (PLine3 pline, // double extrusionfactor, // double offsetZ, // const Settings::SlicingSettings &slicing, // const Settings::HardwareSettings &hardware) // { // bool relativeE = slicing.RelativeEcode; // double minspeed = hardware.MinPrintSpeedXY; // double maxspeed = hardware.MaxPrintSpeedXY; // cerr << "dont use GCodeState::MakeGCodeLine (PLine3 pline..." << endl; // if(LastPosition() != pline.from) { // then first move to pline.from // maxspeed = max(minspeed, (double)hardware.MoveSpeed); // in case maxspeed is too low // Command command(COORDINATEDMOTION, pline.from, 0, maxspeed); // AppendCommand(command,relativeE); // //SetLastPosition(pline.from); // } // if (pline.arc == 0) { // make line // maxspeed = max(minspeed, pline.speed); // in case maxspeed is too low // double extrudedMaterial = DistanceFromLastTo(pline.to) * extrusionfactor; // Command command(COORDINATEDMOTION, pline.to, extrudedMaterial, maxspeed); // if (pline.from==pline.to) command.comment = _("Extrusion only "); // } else { // make arc // cerr << "no arc in GCodeState::MakeGCodeLine (PLine3 pline..." // << " dont use this function" << endl; // } // MakeGCodeLine(pline.from, pline.to, pline.arcIJK, pline.arc, // pline.extrusionfactor * extrusionfactor, // pline.absolute_extrusion, // pline.speed, // offsetZ, slicing, hardware); // //SetLastPosition(pline.to); // } void GCodeState::MakeGCodeLine (Vector3d start, Vector3d end, Vector3d arcIJK, short arc, double extrusionFactor, double absolute_extrusion, double minspeed, double maxspeed, double offsetZ, bool relativeE) { // if ((end-start).length() < 0.05) // ignore micro moves // return; Command command; command.is_value = false; maxspeed = max(minspeed,maxspeed); // in case maxspeed is too low ResetLastWhere (start); command.where = end; if (start==end) { // pure extrusions command.comment = _("Extrusion only "); } double extrudedMaterial = DistanceFromLastTo(command.where)*extrusionFactor; if (absolute_extrusion!=0) { command.comment += _("Absolute Extrusion"); } extrudedMaterial += absolute_extrusion; command.e = extrudedMaterial; command.f = maxspeed; if (arc == 0) { // make line command.Code = COORDINATEDMOTION; } else { // make arc if (arc==1) { command.Code = ARC_CW; command.comment = "cw arc"; } else if (arc==-1) { command.Code = ARC_CCW; command.comment = "ccw arc"; } else cerr << "Undefined arc direction! "<< arc << endl; command.arcIJK = arcIJK; } AppendCommand(command,relativeE); } repsnapper-2.3.2a5/src/gcode/gcodestate.h000066400000000000000000000046241231531733200202740ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "settings.h" #include "gcode.h" //#include "printlines.h" struct printline; class GCode; class Command; struct GCodeStateImpl; class GCodeState { GCodeStateImpl *pImpl; public: GCodeState(GCode &code); ~GCodeState(); /* void SetZ (double z); */ void AppendCommand(Command &command, bool incrementalE); void AppendCommand(GCodes code, bool incrementalE=false, string comment=""); void AppendCommands(vector commands, bool relativeE); /* void AddLines (vector lines, */ /* double extrusionfactor, */ /* double offsetZ, */ /* const Settings::SlicingSettings &slicing, */ /* const Settings::HardwareSettings &hardware); */ void AddLines (vector lines, double extrusionFactor, double maxspeed, double movespeed, double offsetZ, const Settings &settings); /* void MakeGCodeLine (PLine3 line, */ /* double extrusionfactor, */ /* double offsetZ, */ /* const Settings::SlicingSettings &slicing, */ /* const Settings::HardwareSettings &hardware); */ void MakeGCodeLine (Vector3d start, Vector3d end, Vector3d arcIJK, short arc, double extrusionFactor, double absolute_extrusion, double minspeed, double maxspeed, double offsetZ, bool relativeE); /* double GetLastLayerZ(double curZ); */ /* void SetLastLayerZ(double z); */ const Vector3d &LastPosition(); void SetLastPosition(const Vector3d &v); void ResetLastWhere(Vector3d to); double DistanceFromLastTo(Vector3d here); double LastCommandF(); double timeused; }; repsnapper-2.3.2a5/src/gllight.cpp000066400000000000000000000031571231531733200170560ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Evan Clinton (Palomides) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #include "gllight.h" gllight::gllight() { Init(GL_LIGHT0); } gllight::~gllight() { } void gllight::Init(int position) { offset = position; } void gllight::Enable(bool on) { if (on) glEnable(offset); else glDisable(offset); } void gllight::SetAmbient(float r, float g, float b, float a) { float ambient[] = {r,g,b,a}; glLightfv(offset, GL_AMBIENT, ambient); } void gllight::SetDiffuse(float r, float g, float b, float a) { float diffuse[] = {r,g,b,a}; glLightfv(offset, GL_DIFFUSE, diffuse); } void gllight::SetLocation(float x, float y, float z, float w) { float position[] = {x,y,z,w}; glLightfv(offset, GL_POSITION, position); } void gllight::SetSpecular(float r, float g, float b, float a) { float specular[] = {r,g,b,a}; glLightfv ( offset, GL_SPECULAR, specular ); } repsnapper-2.3.2a5/src/gllight.h000066400000000000000000000023371231531733200165220ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Evan Clinton (Palomides) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef GL_LIGHT_H #define GL_LIGHT_H class gllight { public: gllight(); ~gllight(); void Init (int position); void Enable(bool on); void SetAmbient(float r, float g, float b, float a); void SetDiffuse(float r, float g, float b, float a); void SetLocation(float x, float y, float z, float w); void SetSpecular(float r, float g, float b, float a); private: int offset; }; #endif // GL_LIGHT_H repsnapper-2.3.2a5/src/miniball.h000066400000000000000000000256571231531733200166710ustar00rootroot00000000000000// Copright (C) 1999-2006, Bernd Gaertner // $Revision: 1.3 $ // $Date: 2006/11/16 08:01:52 $ // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, // or download the License terms from prep.ai.mit.edu/pub/gnu/COPYING-2.0. // // Contact: // -------- // Bernd Gaertner // Institute of Theoretical Computer Science // ETH Zuerich // CAB G32.2 // CH-8092 Zuerich, Switzerland // http://www.inf.ethz.ch/personal/gaertner #include #include #include #include #include // Functions // ========= inline double mb_sqr (double r) {return r*r;} // Class Declarations // ================== // smallest enclosing ball of a set of n points in dimension d template class Miniball; // smallest ball with a set of n <= d+1 points *on the boundary* template class Miniball_b; // point in dimension d template class Point; // Class Definitions // ================= // Miniball // -------- template class Miniball { public: // types typedef typename std::list >::iterator It; typedef typename std::list >::const_iterator Cit; private: // data members std::list > L; // internal point set Miniball_b B; // the current ball It support_end; // past-the-end iterator of support set // private methods void mtf_mb (It k); void pivot_mb (It k); void move_to_front (It j); double max_excess (It t, It i, It& pivot) const; public: // creates an empty ball Miniball() {} // copies p to the internal point set void check_in (const Point& p); // builds the smallest enclosing ball of the internal point set void build (); // returns center of the ball (undefined if ball is empty) Point center() const; // returns squared_radius of the ball (-1 if ball is empty) double squared_radius () const; // returns size of internal point set int nr_points () const; // returns begin- and past-the-end iterators for internal point set Cit points_begin () const; Cit points_end () const; // returns size of support point set; this set has the following properties: // - there are at most d+1 support points, // - all support points are on the boundary of the computed ball, and // - the smallest enclosing ball of the support point set equals the // smallest enclosing ball of the internal point set int nr_support_points () const; // returns begin- and past-the-end iterators for internal point set Cit support_points_begin () const; Cit support_points_end () const; // assesses the quality of the computed ball. The return value is the // maximum squared distance of any support point or point outside the // ball to the boundary of the ball, divided by the squared radius of // the ball. If everything went fine, this will be less than e-15 and // says that the computed ball approximately contains all the internal // points and has all the support points on the boundary. // // The slack parameter that is set by the method says something about // whether the computed ball is really the *smallest* enclosing ball // of the support points; if everything went fine, this value will be 0; // a positive value may indicate that the ball is not smallest possible, // with the deviation from optimality growing with the slack double accuracy (double& slack) const; // returns true if the accuracy is below the given tolerance and the // slack is 0 bool is_valid (double tolerance = 1e-15) const; }; // Miniball_b // ---------- template class Miniball_b { private: // data members int m, s; // size and number of support points double q0[d]; double z[d+1]; double f[d+1]; double v[d+1][d]; double a[d+1][d]; double c[d+1][d]; double sqr_r[d+1]; double* current_c; // refers to some c[j] double current_sqr_r; public: Miniball_b() {reset();} // access const double* center() const; double squared_radius() const; int size() const; int support_size() const; double excess (const Point& p) const; // modification void reset(); // generates empty sphere with m=s=0 bool push (const Point& p); void pop (); // checking double slack() const; }; // Point (inline) // ------------- template class Point { private: double coord [d]; public: // default Point() {} // copy from Point Point (const Point& p) { for (int i=0; i void Miniball::check_in (const Point& p) { L.push_back(p); } template void Miniball::build () { B.reset(); support_end = L.begin(); pivot_mb (L.end()); } template void Miniball::mtf_mb (It i) { support_end = L.begin(); if ((B.size())==d+1) return; for (It k=L.begin(); k!=i;) { It j=k++; if (B.excess(*j) > 0) { if (B.push(*j)) { mtf_mb (j); B.pop(); move_to_front(j); } } } } template void Miniball::move_to_front (It j) { if (support_end == j) support_end++; L.splice (L.begin(), L, j); } template void Miniball::pivot_mb (It i) { It t = ++L.begin(); mtf_mb (t); double max_e, old_sqr_r = -1; do { It pivot; max_e = max_excess (t, i, pivot); if (max_e > 0) { t = support_end; if (t==pivot) ++t; old_sqr_r = B.squared_radius(); B.push (*pivot); mtf_mb (support_end); B.pop(); move_to_front (pivot); } } while ((max_e > 0) && (B.squared_radius() > old_sqr_r)); } template double Miniball::max_excess (It t, It i, It& pivot) const { const double *c = B.center(), sqr_r = B.squared_radius(); double e, max_e = 0; for (It k=t; k!=i; ++k) { const double *p = (*k).begin(); e = -sqr_r; for (int j=0; j max_e) { max_e = e; pivot = k; } } return max_e; } template Point Miniball::center () const { return Point(B.center()); } template double Miniball::squared_radius () const { return B.squared_radius(); } template int Miniball::nr_points () const { return L.size(); } template typename Miniball::Cit Miniball::points_begin () const { return L.begin(); } template typename Miniball::Cit Miniball::points_end () const { return L.end(); } template int Miniball::nr_support_points () const { return B.support_size(); } template typename Miniball::Cit Miniball::support_points_begin () const { return L.begin(); } template typename Miniball::Cit Miniball::support_points_end () const { return support_end; } template double Miniball::accuracy (double& slack) const { double e, max_e = 0; int n_supp=0; Cit i; for (i=L.begin(); i!=support_end; ++i,++n_supp) if ((e = std::abs (B.excess (*i))) > max_e) max_e = e; // you've found a non-numerical problem if the following ever fails assert (n_supp == nr_support_points()); for (i=support_end; i!=L.end(); ++i) if ((e = B.excess (*i)) > max_e) max_e = e; slack = B.slack(); return (max_e/squared_radius()); } template bool Miniball::is_valid (double tolerance) const { double slack; return ( (accuracy (slack) < tolerance) && (slack == 0) ); } // Miniball_b // ---------- template const double* Miniball_b::center () const { return current_c; } template double Miniball_b::squared_radius() const { return current_sqr_r; } template int Miniball_b::size() const { return m; } template int Miniball_b::support_size() const { return s; } template double Miniball_b::excess (const Point& p) const { double e = -current_sqr_r; for (int k=0; k void Miniball_b::reset () { m = s = 0; // we misuse c[0] for the center of the empty sphere for (int j=0; j void Miniball_b::pop () { --m; } template bool Miniball_b::push (const Point& p) { int i, j; double eps = 1e-32; if (m==0) { for (i=0; i double Miniball_b::slack () const { double l[d+1], min_l=0; l[0] = 1; for (int i=s-1; i>0; --i) { l[i] = f[i]; for (int k=s-1; k>i; --k) l[i]-=a[k][i]*l[k]; if (l[i] < min_l) min_l = l[i]; l[0] -= l[i]; } if (l[0] < min_l) min_l = l[0]; return ( (min_l < 0) ? -min_l : 0); } // Point // ----- // Output template std::ostream& operator << (std::ostream& os, const Point& p) { os << "("; for (int i=0; i #include #include #include #include #include "stdafx.h" #include "model.h" #include "objtree.h" #include "settings.h" #include "layer.h" #include "infill.h" #include "ui/progress.h" #include "shape.h" #include "flatshape.h" #include "render.h" Model::Model() : m_previewLayer(NULL), //m_previewGCodeLayer(NULL), currentprintingline(0), settings(), Min(), Max(), m_inhibit_modelchange(false), errlog (Gtk::TextBuffer::create()), echolog (Gtk::TextBuffer::create()), is_calculating(false), is_printing(false) { // Variable defaults Center.set(100.,100.,0.); preview_shapes.clear(); } Model::~Model() { ClearLayers(); ClearGCode(); delete m_previewLayer; preview_shapes.clear(); } void Model::alert (const char *message) { signal_alert.emit (Gtk::MESSAGE_INFO, message, NULL); } void Model::error (const char *message, const char *secondary) { signal_alert.emit (Gtk::MESSAGE_ERROR, message, secondary); } void Model::SaveConfig(Glib::RefPtr file) { settings.save_settings(file); } void Model::LoadConfig(Glib::RefPtr file) { settings.load_settings(file); ModelChanged(); } void Model::SimpleAdvancedToggle() { cout << _("not yet implemented\n"); } void Model::SetViewProgress (ViewProgress *progress) { m_progress = progress; } void Model::ClearGCode() { m_previewGCode.clear(); m_previewGCode_z = -100000; gcode.clear(); } void Model::ClearLayers() { for(vector::iterator i=layers.begin(); i != layers.end(); i++) { if ((*i)) (*i)->Clear(); delete *i; } layers.clear(); Infill::clearPatterns(); ClearPreview(); } void Model::ClearPreview() { if (m_previewLayer) delete m_previewLayer; m_previewLayer = NULL; m_previewGCode.clear(); m_previewGCode_z = -100000; } Glib::RefPtr Model::GetGCodeBuffer() { return gcode.buffer; } void Model::GlDrawGCode(int layerno) { if (settings.get_boolean("Display","DisplayGCode")) { gcode.draw (settings, layerno, false); } // assume that the real printing line is the one at the start of the buffer if (currentprintingline > 0) { int currentlayer = gcode.getLayerNo(currentprintingline); if (currentlayer>=0) { int start = gcode.getLayerStart(currentlayer); int end = gcode.getLayerEnd(currentlayer); //gcode.draw (settings, currentlayer, true, 1); bool displaygcodeborders = settings.get_boolean("Display","DisplayGCodeBorders"); gcode.drawCommands(settings, start, currentprintingline, true, 4, false, displaygcodeborders); gcode.drawCommands(settings, currentprintingline, end, true, 1, false, displaygcodeborders); } // gcode.drawCommands(settings, currentprintingline-currentbufferedlines, // currentprintingline, false, 3, true, // settings.Display.DisplayGCodeBorders); } } void Model::GlDrawGCode(double layerz) { if (!settings.get_boolean("Display","DisplayGCode")) return; int layer = gcode.getLayerNo(layerz); if (layer>=0) GlDrawGCode(layer); } void Model::init() {} void Model::WriteGCode(Glib::RefPtr file) { Glib::ustring contents = gcode.get_text(); Glib::file_set_contents (file->get_path(), contents); settings.GCodePath = file->get_parent()->get_path(); } void Model::ReadSVG(Glib::RefPtr file) { if (is_calculating) return; if (is_printing) return; bool autoplace = settings.get_boolean("Misc","ShapeAutoplace"); string path = file->get_path(); FlatShape * svgshape = new FlatShape(path); cerr << svgshape->info() << endl; AddShape(NULL, svgshape, path, autoplace); ClearLayers(); } vector Model::ReadShapes(Glib::RefPtr file, uint max_triangles) { vector shapes; if (file==0) return shapes; File sfile(file); vector< vector > triangles; vector shapenames; sfile.loadTriangles(triangles, shapenames, max_triangles); for (uint i = 0; i < triangles.size(); i++) { if (triangles[i].size() > 0) { Shape *shape = new Shape(); shape->setTriangles(triangles[i]); shape->filename = shapenames[i]; shape->FitToVolume(settings.getPrintVolume() - 2.*settings.getPrintMargin()); shapes.push_back(shape); } } return shapes; } void Model::ReadStl(Glib::RefPtr file) { bool autoplace = settings.get_boolean("Misc","ShapeAutoplace"); vector shapes = ReadShapes(file, 0); // do not autoplace in multishape files if (shapes.size() > 1) autoplace = false; for (uint i = 0; i < shapes.size(); i++){ AddShape(NULL, shapes[i], shapes[i]->filename, autoplace); } shapes.clear(); ModelChanged(); } void Model::SaveStl(Glib::RefPtr file) { vector shapes; vector transforms; objtree.get_all_shapes(shapes,transforms); if(shapes.size() == 1) { shapes[0]->saveBinarySTL(file->get_path()); } else { if (settings.get_boolean("Misc","SaveSingleShapeSTL")) { Shape single = GetCombinedShape(); single.saveBinarySTL(file->get_path()); } else { set_locales("C"); stringstream sstr; for(uint s=0; s < shapes.size(); s++) { sstr << shapes[s]->getSTLsolid() << endl; } Glib::file_set_contents (file->get_path(), sstr.str()); reset_locales(); } } settings.STLPath = file->get_parent()->get_path(); } // everything in one shape Shape Model::GetCombinedShape() const { Shape shape; for (uint o = 0; oshapes.size(); s++) { vector tr = objtree.Objects[o]->shapes[s]->getTriangles(objtree.Objects[o]->transform3D.transform); shape.addTriangles(tr); } } return shape; } void Model::SaveAMF(Glib::RefPtr file) { vector shapes; vector transforms; objtree.get_all_shapes(shapes,transforms); vector< vector > triangles; vector names; for(uint s = 0; s < shapes.size(); s++) { triangles.push_back(shapes[s]->getTriangles(transforms[s])); names.push_back(shapes[s]->filename); } File::save_AMF(file->get_path(), triangles, names); } void Model::Read(Glib::RefPtr file) { std::string basename = file->get_basename(); size_t pos = basename.rfind('.'); cerr << "reading " << basename<< endl; string directory_path = file->get_parent()->get_path(); if (pos != std::string::npos) { std::string extn = basename.substr(pos); if (extn == ".conf") { LoadConfig (file); settings.SettingsPath = directory_path; return; } else if (extn == ".gcode") { ReadGCode (file); settings.GCodePath = directory_path; return; } else if (extn == ".svg") { ReadSVG (file); settings.STLPath = directory_path; return; } else if (extn == ".rfo") { // ReadRFO (file); settings.STLPath = directory_path; return; } } ReadStl (file); settings.STLPath = directory_path; } void Model::ReadGCode(Glib::RefPtr file) { if (is_calculating) return; if (is_printing) return; is_calculating=true; settings.set_boolean("Display","DisplayGCode",true); m_progress->start (_("Reading GCode"), 100.0); gcode.Read (this, settings.get_extruder_letters(), m_progress, file->get_path()); m_progress->stop (_("Done")); is_calculating=false; Max = gcode.Max; Min = gcode.Min; Center = (Max + Min) / 2.0; m_signal_zoom.emit(); } void Model::translateGCode(Vector3d trans) { if (is_calculating) return; if (is_printing) return; is_calculating=true; gcode.translate(trans); string GcodeTxt; gcode.MakeText (GcodeTxt, settings, m_progress); Max = gcode.Max; Min = gcode.Min; Center = (Max + Min) / 2.0; is_calculating=false; } void Model::ModelChanged() { if (m_inhibit_modelchange) return; if (objtree.empty()) return; //printer.update_temp_poll_interval(); // necessary? if (!is_printing) { CalcBoundingBoxAndCenter(); Infill::clearPatterns(); if ( layers.size()>0 || m_previewGCode.size()>0 || m_previewLayer ) { ClearGCode(); ClearLayers(); } setCurrentPrintingLine(0); m_model_changed.emit(); } } static bool ClosestToOrigin (Vector3d a, Vector3d b) { return (a.squared_length()) < (b.squared_length()); } // rearrange unselected shapes in random sequence bool Model::AutoArrange(vector &path) { // all shapes vector allshapes; vector transforms; objtree.get_all_shapes(allshapes, transforms); // selected shapes vector selshapes; vector seltransforms; objtree.get_selected_shapes(path, selshapes, seltransforms); // get unselected shapes vector unselshapes; vector unseltransforms; for(uint s=0; s < allshapes.size(); s++) { bool issel = false; for(uint ss=0; ss < selshapes.size(); ss++) if (selshapes[ss] == allshapes[s]) { issel = true; break; } if (!issel) { unselshapes. push_back(allshapes[s]); unseltransforms.push_back(transforms[s]); } } // find place for unselected shapes int num = unselshapes.size(); vector rand_seq(num,1); // 1,1,1... partial_sum(rand_seq.begin(), rand_seq.end(), rand_seq.begin()); // 1,2,3,...,N Glib::TimeVal timeval; timeval.assign_current_time(); srandom((unsigned long)(timeval.as_double())); random_shuffle(rand_seq.begin(), rand_seq.end()); // shuffle for(int s=0; s < num; s++) { int index = rand_seq[s]-1; // use selshapes as vector to fill up Vector3d trans = FindEmptyLocation(selshapes, seltransforms, unselshapes[index]); selshapes.push_back(unselshapes[index]); seltransforms.push_back(unseltransforms[index]); // basic transform, not shape selshapes.back()->transform3D.move(trans); CalcBoundingBoxAndCenter(); } ModelChanged(); return true; } Vector3d Model::FindEmptyLocation(const vector &shapes, const vector &transforms, const Shape *shape) { // Get all object positions std::vector maxpos; std::vector minpos; for(uint s=0; sMin; Vector3d max = strans * shapes[s]->Max; minpos.push_back(Vector3d(min.x(), min.y(), 0)); maxpos.push_back(Vector3d(max.x(), max.y(), 0)); } double d = 5.0; // 5mm spacing between objects Vector3d StlDelta = (shape->Max - shape->Min); vector candidates; candidates.push_back(Vector3d(0.0, 0.0, 0.0)); for (uint j=0; j (settings.getPrintVolume().x() - 2*settings.getPrintMargin().x()) || candidates[c].y()+StlDelta.y() > (settings.getPrintVolume().y() - 2*settings.getPrintMargin().y())) { ok = false; break; } } if (ok) { result.x() = candidates[c].x(); result.y() = candidates[c].y(); result.z() = candidates[c].z(); // keep z result.x() -= shape->Min.x(); result.y() -= shape->Min.y(); return result; } } // no empty spots return Vector3d(100,100,0); } bool Model::FindEmptyLocation(Vector3d &result, const Shape *shape) { // Get all object positions std::vector maxpos; std::vector minpos; vector allshapes; vector transforms; objtree.get_all_shapes(allshapes, transforms); result = FindEmptyLocation(allshapes, transforms, shape); return true; } int Model::AddShape(TreeObject *parent, Shape *shape, string filename, bool autoplace) { //Shape *retshape; bool found_location=false; FlatShape* flatshape = dynamic_cast(shape); if (flatshape != NULL) shape = flatshape; if (!parent) { if (objtree.Objects.size() <= 0) objtree.newObject(); parent = objtree.Objects.back(); } g_assert (parent != NULL); // Decide where it's going Vector3d trans = Vector3d(0,0,0); if (autoplace) found_location = FindEmptyLocation(trans, shape); // Add it to the set size_t found = filename.find_last_of("/\\"); Gtk::TreePath path = objtree.addShape(parent, shape, filename.substr(found+1)); Shape *retshape = parent->shapes.back(); // Move it, if we found a suitable place if (found_location) { retshape->transform3D.move(trans); } //if (autoplace) retshape->PlaceOnPlatform(); // Update the view to include the new object ModelChanged(); // Tell everyone m_signal_stl_added.emit (path); return 0; } int Model::SplitShape(TreeObject *parent, Shape *shape, string filename) { vector splitshapes; shape->splitshapes(splitshapes, m_progress); if (splitshapes.size()<2) return splitshapes.size(); for (uint s = 0; s < splitshapes.size(); s++) { ostringstream sfn; sfn << filename << "_" << (s+1) ; AddShape(parent, splitshapes[s], sfn.str(), false); } return splitshapes.size(); } int Model::MergeShapes(TreeObject *parent, const vector shapes) { Shape * shape = new Shape(); for (uint s = 0; s < shapes.size(); s++) { vector str = shapes[s]->getTriangles(); shape->addTriangles(str); } AddShape(parent, shape, "merged", true); return 1; } int Model::DivideShape(TreeObject *parent, Shape *shape, string filename) { Shape *upper = new Shape(); Shape *lower = new Shape(); Matrix4d T = Matrix4d::IDENTITY;;//FIXME! objtree.GetSTLTransformationMatrix(parent); int num = shape->divideAtZ(0, upper, lower, T); if (num<2) return num; else if (num==2) { AddShape(parent, upper, filename+_("_upper") ,false); AddShape(parent, lower, filename+_("_lower") ,false); } return num; } void Model::newObject() { objtree.newObject(); } /* Scales the object on changes of the scale slider */ void Model::ScaleObject(Shape *shape, TreeObject *object, double scale) { if (shape) shape->Scale(scale); else if(object) // for (uint s = 0;sshapes.size(); s++) { //double fact = object->shapes[s].getScaleFactor(); object->transform3D.scale(scale); //} else return; ModelChanged(); } void Model::ScaleObjectX(Shape *shape, TreeObject *object, double scale) { if (shape) shape->ScaleX(scale); else if(object) for (uint s = 0;sshapes.size(); s++) { //double fact = object->shapes[s].getScaleFactor(); object->shapes[s]->ScaleX(scale); } else return; ModelChanged(); } void Model::ScaleObjectY(Shape *shape, TreeObject *object, double scale) { if (shape) shape->ScaleY(scale); else if(object) for (uint s = 0;sshapes.size(); s++) { //double fact = object->shapes[s].getScaleFactor(); object->shapes[s]->ScaleY(scale); } else return; ModelChanged(); } void Model::ScaleObjectZ(Shape *shape, TreeObject *object, double scale) { if (shape) shape->ScaleZ(scale); else if(object) for (uint s = 0;sshapes.size(); s++) { // double fact = object->shapes[s].getScaleFactorZ(); object->shapes[s]->ScaleZ(scale); } else return; ModelChanged(); } void Model::RotateObject(Shape* shape, TreeObject* object, Vector4d rotate) { if (!shape) return; Vector3d rot(rotate.x(), rotate.y(), rotate.z()); shape->Rotate(rot, rotate.w()); ModelChanged(); } void Model::TwistObject(Shape *shape, TreeObject *object, double angle) { if (!shape) return; shape->Twist(angle); ModelChanged(); } void Model::OptimizeRotation(Shape *shape, TreeObject *object) { if (!shape) return; // FIXME: rotate entire Objects ... shape->OptimizeRotation(); ModelChanged(); } void Model::InvertNormals(Shape *shape, TreeObject *object) { if (shape) shape->invertNormals(); else // if (object) object->invertNormals(); return; ModelChanged(); } void Model::Mirror(Shape *shape, TreeObject *object) { if (shape) shape->mirror(); else // if (object) object->mirror(); return; ModelChanged(); } void Model::PlaceOnPlatform(Shape *shape, TreeObject *object) { if (shape) shape->PlaceOnPlatform(); else if(object) { Transform3D * transf = &object->transform3D; transf->move(Vector3f(0, 0, -transf->getTranslation().z())); for (uint s = 0;sshapes.size(); s++) { object->shapes[s]->PlaceOnPlatform(); } } else return; ModelChanged(); } void Model::DeleteObjTree(vector &iter) { objtree.DeleteSelected (iter); ClearGCode(); ClearLayers(); ModelChanged(); } void Model::ClearLogs() { errlog->set_text(""); echolog->set_text(""); } void Model::CalcBoundingBoxAndCenter(bool selected_only) { Vector3d newMax = Vector3d(G_MINDOUBLE, G_MINDOUBLE, G_MINDOUBLE); Vector3d newMin = Vector3d(G_MAXDOUBLE, G_MAXDOUBLE, G_MAXDOUBLE); vector shapes; vector transforms; if (selected_only) objtree.get_selected_shapes(m_current_selectionpath, shapes, transforms); else objtree.get_all_shapes(shapes, transforms); for (uint s = 0 ; s < shapes.size(); s++) { shapes[s]->CalcBBox(); Vector3d stlMin = transforms[s] * shapes[s]->Min; Vector3d stlMax = transforms[s] * shapes[s]->Max; for (uint k = 0; k < 3; k++) { newMin[k] = MIN(stlMin[k], newMin[k]); newMax[k] = MAX(stlMax[k], newMax[k]); } } // for (uint i = 0 ; i < objtree.Objects.size(); i++) { // Matrix4d M = objtree.getTransformationMatrix (i); // for (uint j = 0; j < objtree.Objects[i]->shapes.size(); j++) { // objtree.Objects[i]->shapes[j]->CalcBBox(); // Vector3d stlMin = M * objtree.Objects[i]->shapes[j]->Min; // Vector3d stlMax = M * objtree.Objects[i]->shapes[j]->Max; // for (uint k = 0; k < 3; k++) { // newMin[k] = MIN(stlMin[k], newMin[k]); // newMax[k] = MAX(stlMax[k], newMax[k]); // } // } // } if (newMin.x() > newMax.x()) { // Show the whole platform if there's no objects Min = Vector3d(0,0,0); Vector3d pM = settings.getPrintMargin(); Max = settings.getPrintVolume() - pM - pM; Max.z() = 0; } else { Max = newMax; Min = newMin; } Center = (Max + Min) / 2.0; m_signal_zoom.emit(); } Vector3d Model::GetViewCenter() { Vector3d printOffset = settings.getPrintMargin(); if(settings.get_boolean("Raft","Enable")){ const double rsize = settings.get_double("Raft","Size"); printOffset += Vector3d(rsize, rsize, 0); } return printOffset + Center; } // called from View::Draw int Model::draw (vector &iter) { vector sel_shapes; vector transforms; objtree.get_selected_shapes(iter, sel_shapes, transforms); gint index = 1; // pick/select index. matches computation in update_model() Vector3d printOffset = settings.getPrintMargin(); if(settings.get_boolean("Raft","Enable")) { const double rsize = settings.get_double("Raft","Size"); printOffset += Vector3d(rsize, rsize, 0); } Vector3d translation = objtree.transform3D.getTranslation(); Vector3d offset = printOffset + translation; // Add the print offset to the drawing location of the STL objects. glTranslated(offset.x(),offset.y(),offset.z()); glPushMatrix(); glMultMatrixd (&objtree.transform3D.transform.array[0]); // draw preview shapes and nothing else if (settings.get_boolean("Display","PreviewLoad")) if (preview_shapes.size() > 0) { Vector3d v_center = GetViewCenter() - offset; glTranslated( v_center.x(), v_center.y(), v_center.z()); for (uint i = 0; i < preview_shapes.size(); i++) { offset = preview_shapes[i]->t_Center(); glTranslated(offset.x(), offset.y(), offset.z()); // glPushMatrix(); // glMultMatrixd (&preview_shapes[i]->transform3D.transform.array[0]); preview_shapes[i]->draw (settings, false, 20000); preview_shapes[i]->drawBBox (); // glPopMatrix(); } glPopMatrix(); glPopMatrix(); return 0; } bool support = settings.get_boolean("Slicing","Support"); double supportangle = settings.get_double("Slicing","SupportAngle"); bool displaypolygons = settings.get_boolean("Display","DisplayPolygons"); bool displaybbox = settings.get_boolean("Display","DisplayBBox"); for (uint i = 0; i < objtree.Objects.size(); i++) { TreeObject *object = objtree.Objects[i]; index++; glPushMatrix(); glMultMatrixd (&object->transform3D.transform.array[0]); for (uint j = 0; j < object->shapes.size(); j++) { Shape *shape = object->shapes[j]; glLoadName(index); // Load select/pick index index++; glPushMatrix(); glMultMatrixd (&shape->transform3D.transform.array[0]); bool is_selected = false; for (uint s = 0; s < sel_shapes.size(); s++) if (sel_shapes[s] == shape) is_selected = true; // this is slow for big shapes if (is_selected) { if (!shape->slow_drawing && shape->dimensions()>2) { // Enable stencil buffer when we draw the selected object. glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); shape->draw (settings); if (!displaypolygons) { // If not drawing polygons, need to draw the geometry // manually, but invisible, to set up the stencil buffer glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); // Set to not draw anything, and not update depth buffer glDepthMask(GL_FALSE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); shape->draw_geometry(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); } // draw highlight around selected object glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glLineWidth(3.0); glEnable (GL_POLYGON_OFFSET_LINE); glDisable (GL_CULL_FACE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_NOTEQUAL, 1, 1); glEnable(GL_DEPTH_TEST); shape->draw_geometry(); glEnable (GL_CULL_FACE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_STENCIL_TEST); glDisable(GL_POLYGON_OFFSET_LINE); } else shape->draw (settings, true); } else { shape->draw (settings, false); } // draw support triangles if (support) { glColor4f(0.8f,0.f,0.f,0.5f); vector suppTr = shape->trianglesSteeperThan(supportangle*M_PI/180.); for (uint i=0; i < suppTr.size(); i++) suppTr[i].draw(GL_TRIANGLES); } glPopMatrix(); if(displaybbox) shape->drawBBox(); } glPopMatrix(); } glPopMatrix(); glLoadName(0); // Clear selection name to avoid selecting last object with later rendering. // draw total bounding box if(displaybbox) { const double minz = max(0., Min.z()); // above xy plane only // Draw bbox glDisable(GL_DEPTH_TEST); glLineWidth(1); glColor3f(1,0,0); glBegin(GL_LINE_LOOP); glVertex3f(Min.x(), Min.y(), minz); glVertex3f(Min.x(), Max.y(), minz); glVertex3f(Max.x(), Max.y(), minz); glVertex3f(Max.x(), Min.y(), minz); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(Min.x(), Min.y(), Max.z()); glVertex3f(Min.x(), Max.y(), Max.z()); glVertex3f(Max.x(), Max.y(), Max.z()); glVertex3f(Max.x(), Min.y(), Max.z()); glEnd(); glBegin(GL_LINES); glVertex3f(Min.x(), Min.y(), minz); glVertex3f(Min.x(), Min.y(), Max.z()); glVertex3f(Min.x(), Max.y(), minz); glVertex3f(Min.x(), Max.y(), Max.z()); glVertex3f(Max.x(), Max.y(), minz); glVertex3f(Max.x(), Max.y(), Max.z()); glVertex3f(Max.x(), Min.y(), minz); glVertex3f(Max.x(), Min.y(), Max.z()); glEnd(); glColor3f(1,0.6,0.6); ostringstream val; val.precision(1); Vector3d pos; val << fixed << (Max.x()-Min.x()); pos = Vector3d((Max.x()+Min.x())/2.,Min.y(),Max.z()); Render::draw_string(pos,val.str()); val.str(""); val << fixed << (Max.y()-Min.y()); pos = Vector3d(Min.x(),(Max.y()+Min.y())/2.,Max.z()); Render::draw_string(pos,val.str()); val.str(""); val << fixed << (Max.z()-minz); pos = Vector3d(Min.x(),Min.y(),(Max.z()+minz)/2.); Render::draw_string(pos,val.str()); } int drawnlayer = -1; if(settings.get_boolean("Display","DisplayLayer")) { drawnlayer = drawLayers(settings.get_double("Display","LayerValue"), offset, false); } if(settings.get_boolean("Display","DisplayGCode") && gcode.size() == 0) { // preview gcode if not calculated yet if ( m_previewGCode.size() != 0 || ( layers.size() == 0 && gcode.commands.size() == 0 ) ) { Vector3d start(0,0,0); const double thickness = settings.get_double("Slicing","LayerThickness"); const double gcodedrawstart = settings.get_double("Display","GCodeDrawStart"); const double z = gcodedrawstart + thickness/2; const int LayerCount = (int)ceil(Max.z()/thickness)-1; const uint LayerNo = (uint)ceil(gcodedrawstart*(LayerCount-1)); if (z != m_previewGCode_z) { //uint prevext = settings.selectedExtruder; Layer * previewGCodeLayer = calcSingleLayer(z, LayerNo, thickness, true, true); if (previewGCodeLayer) { m_previewGCode.clear(); vector commands; GCodeState state(m_previewGCode); previewGCodeLayer->MakeGCode(start, state, 0, settings); // state.AppendCommands(commands, settings.Slicing.RelativeEcode); m_previewGCode_z = z; } //settings.SelectExtruder(prevext); } glDisable(GL_DEPTH_TEST); m_previewGCode.drawCommands(settings, 1, m_previewGCode.commands.size(), true, 2, settings.get_boolean("Display","DisplayGCodeArrows"), settings.get_boolean("Display","DisplayGCodeBorders")); } } return drawnlayer; } // if single layer returns layerno of drawn layer // else returns -1 int Model::drawLayers(double height, const Vector3d &offset, bool calconly) { if (is_calculating) return -1; // infill calculation (saved patterns) would be disturbed glDisable(GL_DEPTH_TEST); int drawn = -1; int LayerNr; ; bool have_layers = (layers.size() > 0); // have sliced already bool fillAreas = settings.get_boolean("Display","DisplayFilledAreas"); double minZ = 0;//max(0.0, Min.z()); double z; double zStep = settings.get_double("Slicing","LayerThickness"); double zSize = (Max.z() - minZ - zStep*0.5); int LayerCount = (int)ceil((zSize - zStep*0.5)/zStep)-1; double sel_Z = height; //*zSize; uint sel_Layer; if (have_layers) sel_Layer = (uint)floor(height*(layers.size())/zSize); else sel_Layer = (uint)ceil(LayerCount*sel_Z/zSize); LayerCount = sel_Layer+1; if(have_layers && settings.get_boolean("Display","DisplayAllLayers")) { LayerNr = 0; z=minZ; // don't fill areas if multiple layers settings.set_boolean("Display","DisplayFilledAreas",false); } else { LayerNr = sel_Layer; z= minZ + sel_Z; } if (have_layers) { LayerNr = CLAMP(LayerNr, 0, (int)layers.size() - 1); LayerCount = CLAMP(LayerCount, 0, (int)layers.size()); } z = CLAMP(z, 0, Max.z()); z += 0.5*zStep; // always cut in middle of layer //cerr << zStep << ";"<getZ(); drawn = layer->LayerNo; } else { if (!m_previewLayer || m_previewLayer->getZ() != z) { m_previewLayer = calcSingleLayer(z, LayerNr, lthickness, displayinfill, false); layer = m_previewLayer; Layer * previous = NULL; if (LayerNr>0 && z >= lthickness) previous = calcSingleLayer(z-lthickness, LayerNr-1, lthickness, false, false); layer->setPrevious(previous); } layer = m_previewLayer; } if (!calconly) { layer->Draw(settings); if (drawrulers) layer->DrawRulers(measuresPoint); } // if (!have_layers) // { // // need to delete the temporary layer // delete layer; // } LayerNr++; z+=zStep; }// while settings.set_boolean("Display","DisplayFilledAreas", fillAreas); // set to value before return drawn; } Layer * Model::calcSingleLayer(double z, uint LayerNr, double thickness, bool calcinfill, bool for_gcode) const { if (is_calculating) return NULL; // infill calculation (saved patterns) would be disturbed if (!for_gcode) { if (m_previewLayer && m_previewLayer->getZ() == z && m_previewLayer->thickness == thickness) return m_previewLayer; } vector shapes; vector transforms; if (settings.get_boolean("Slicing","SelectedOnly")) objtree.get_selected_shapes(m_current_selectionpath, shapes, transforms); else objtree.get_all_shapes(shapes, transforms); double max_grad = 0; double supportangle = settings.get_double("Slicing","SupportAngle")*M_PI/180.; if (!settings.get_boolean("Slicing","Support")) supportangle = -1; Layer * layer = new Layer(NULL, LayerNr, thickness, settings.get_integer("Slicing","Skins")); layer->setZ(z); for(size_t f = 0; f < shapes.size(); f++) { layer->addShape(transforms[f], *shapes[f], z, max_grad, supportangle); } // vector polys = layer->GetPolygons(); // for (guint i=0; i tri; // polys[i].getTriangulation(tri); // for (guint j=0; jMakeShells(settings); if (settings.get_boolean("Slicing","Skirt")) { if (layer->getZ() - layer->thickness <= settings.get_double("Slicing","SkirtHeight")) layer->MakeSkirt(settings.get_double("Slicing","SkirtDistance"), settings.get_boolean("Slicing","SingleSkirt") && !settings.get_boolean("Slicing","Support")); } if (calcinfill) layer->CalcInfill(settings); #define DEBUGPOLYS 0 #if DEBUGPOLYS // write out polygons for gnuplot vector polys = layer->GetPolygons(); vector< vector > offs = layer->GetShellPolygons(); cout << "# polygons "<< endl; for (guint i=0; igetZ(); return 0; } void Model::setMeasuresPoint(const Vector3d &point) { measuresPoint = Vector2d(point.x(), point.y()) ; } repsnapper-2.3.2a5/src/model.h000066400000000000000000000137221231531733200161700ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef MODEL_H #define MODEL_H #include #include #include "stdafx.h" #include "files.h" #include "objtree.h" #include "gcode/gcode.h" /* #include "gcodestate.h" */ #include "settings.h" /* #include "progress.h" */ /* #include "slicer/poly.h" */ #ifdef _MSC_VER // Visual C++ compiler # pragma warning( disable : 4244 4267) #endif class Model { sigc::signal< void > m_signal_zoom; ViewProgress *m_progress; public: Gtk::Statusbar *statusbar; // Something in the rfo changed sigc::signal< void > signal_zoom() { return m_signal_zoom; } sigc::signal< void > m_signal_gcode_changed; Model(); ~Model(); void SimpleAdvancedToggle(); void SaveConfig(Glib::RefPtr file); void LoadConfig() { LoadConfig(Gio::File::create_for_path("repsnapper.conf")); } void LoadConfig(Glib::RefPtr file); // STL Functions void ReadStl(Glib::RefPtr file); vector ReadShapes(Glib::RefPtr file, uint max_triangles = 0); void SaveStl(Glib::RefPtr file); void SaveAMF(Glib::RefPtr file); int AddShape(TreeObject *parent, Shape * shape, string filename, bool autoplace = true); int SplitShape(TreeObject *parent, Shape *shape, string filename); int MergeShapes(TreeObject *parent, const vector shapes); int DivideShape(TreeObject *parent, Shape *shape, string filename); Shape GetCombinedShape() const; sigc::signal< void, Gtk::TreePath & > m_signal_stl_added; void Read(Glib::RefPtr file); void SetViewProgress (ViewProgress *progress); void DeleteObjTree(vector &iter); vector m_current_selectionpath; void OptimizeRotation(Shape *shape, TreeObject *object); void ScaleObject(Shape *shape, TreeObject *object, double scale); void ScaleObjectX(Shape *shape, TreeObject *object, double scale); void ScaleObjectY(Shape *shape, TreeObject *object, double scale); void ScaleObjectZ(Shape *shape, TreeObject *object, double scale); void RotateObject(Shape *shape, TreeObject *object, Vector4d rotate); void TwistObject(Shape *shape, TreeObject *object, double angle); void PlaceOnPlatform(Shape *shape, TreeObject *object); bool updateStatusBar(GdkEventCrossing *event, Glib::ustring = ""); void InvertNormals(Shape *shape, TreeObject *object); void Mirror(Shape *shape, TreeObject *object); vector layers; Layer * m_previewLayer; double get_preview_Z(); //Layer * m_previewGCodeLayer; GCode m_previewGCode; double m_previewGCode_z; vector preview_shapes; // Slicing void SliceToSVG(Glib::RefPtr file, bool single_layer=false); // GCode Functions void init(); void ReadGCode(Glib::RefPtr file); void translateGCode(Vector3d trans); void ConvertToGCode(); void MakeRaft(GCodeState &state, double &z); void WriteGCode(Glib::RefPtr file); void ClearGCode(); void ClearLayers(); void ClearPreview(); Glib::RefPtr GetGCodeBuffer(); void GlDrawGCode(int layer=-1); // should be in the view void GlDrawGCode(double Z); void setCurrentPrintingLine(long line){ currentprintingline = line; } unsigned long currentprintingline; Matrix4f &SelectedNodeMatrix(guint objectNr = 1); void SelectedNodeMatrices(vector &result ); void newObject(); Settings settings; // Model derived: Bounding box info Vector3d Center; Vector3d Min; Vector3d Max; void CalcBoundingBoxAndCenter(bool selected_only = false); Vector3d GetViewCenter(); bool AutoArrange(vector &iter); Vector3d FindEmptyLocation(const vector &shapes, const vector &transforms, const Shape *shape); bool FindEmptyLocation(Vector3d &result, const Shape *stl); sigc::signal< void > m_model_changed; void ModelChanged(); bool m_inhibit_modelchange; // Truly the model ObjectsTree objtree; Glib::RefPtr errlog, echolog; int draw(vector &selected); int drawLayers(double height, const Vector3d &offset, bool calconly = false); void setMeasuresPoint(const Vector3d &point); Vector2d measuresPoint; Layer * calcSingleLayer(double z, uint LayerNr, double thickness, bool calcinfill, bool for_gcode=false) const ; sigc::signal< void, Gtk::MessageType, const char *, const char * > signal_alert; void alert (const char *message); void error (const char *message, const char *secondary); void ClearLogs(); GCode gcode; void SetIsPrinting(bool printing) { is_printing = printing; }; string getSVG(int single_layer_no = -1) const; void ReadSVG(Glib::RefPtr file); private: bool is_calculating; bool is_printing; //GCodeIter *m_iter; Layer * lastlayer; // Slicing/GCode conversion functions void Slice(); void CleanupLayers(); void CalcInfill(); void MakeShells(); void MakeUncoveredPolygons(bool make_decor, bool make_bridges=true); vector GetUncoveredPolygons(const Layer *subjlayer, const Layer *cliplayer); void MakeFullSkins(); void MultiplyUncoveredPolygons(); void MakeSupportPolygons(Layer * subjlayer, const Layer * cliplayer, double widen=0); void MakeSupportPolygons(double widen=0); void MakeSkirt(); }; #endif // MODEL_H repsnapper-2.3.2a5/src/model_slice.cpp000066400000000000000000000766341231531733200177150ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011 Michael Meeks Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define MODEL_IMPLEMENTATION #include #include #include #include //#include // should move to platform.h with com port fun. #include #include #ifdef _OPENMP #include #endif #include "stdafx.h" #include "model.h" #include "objtree.h" #include "settings.h" #include "ui/progress.h" #include "slicer/layer.h" #include "slicer/infill.h" #include "slicer/clipping.h" void Model::MakeRaft(GCodeState &state, double &z) { if (layers.size() == 0) return; vector raftpolys = Clipping::getOffset(layers[0]->GetHullPolygon(), settings.get_double("Raft","Size"), jround); double layerthickness =settings.get_double("Slicing","LayerThickness"); for (uint i = 0; i< raftpolys.size(); i++) raftpolys[i].cleanup(layerthickness/4); vector raft_layers; double rotation = settings.get_double("Raft","Base.Rotation"); double basethickness = layerthickness * settings.get_double("Raft","Base.Thickness"); double interthickness = layerthickness * settings.get_double("Raft","Interface.Thickness"); double totalthickness = settings.get_integer("Raft","Base.LayerCount") * basethickness + settings.get_double("Raft","Interface.LayerCount") * interthickness; double raft_z = -totalthickness + basethickness * settings.get_double("Slicing","FirstLayerHeight"); for (int i = 0; i < settings.get_integer("Raft","Base.LayerCount"); i++) { Layer * layer = new Layer(lastlayer, -settings.get_integer("Raft","Interface.LayerCount") -settings.get_integer("Raft","Base.LayerCount") + i, basethickness, 1); layer->setZ(raft_z); layer->CalcRaftInfill(raftpolys, settings.get_double("Raft","Base.MaterialDistanceRatio"), settings.get_double("Raft","Base.Distance"), rotation); raft_layers.push_back(layer); lastlayer = layer; rotation += settings.get_double("Raft","Base.RotationPrLayer")*M_PI/180; raft_z += basethickness; } rotation = settings.get_double("Raft","Interface.Rotation"); int if_layers = settings.get_integer("Raft","Interface.LayerCount"); for (int i = 0; i < if_layers; i++) { Layer * layer = new Layer(lastlayer, -settings.get_integer("Raft","Base.LayerCount") + i, interthickness, 1); layer->setZ(raft_z); layer->CalcRaftInfill(raftpolys, settings.get_double("Raft","Interface.MaterialDistanceRatio"), settings.get_double("Raft","Interface.Distance"), rotation); raft_layers.push_back(layer); lastlayer = layer; rotation += settings.get_double("Raft","Interface.RotationPrLayer")*M_PI/180; raft_z += interthickness; } layers.insert(layers.begin(),raft_layers.begin(),raft_layers.end()); z += totalthickness; } #if 0 // old raft void Model::MakeRaft(GCodeState &state, double &z) { vector HitsBuffer; double raftSize = settings.Raft.Size; Vector3d raftMin = settings.Hardware.PrintMargin + Min; Vector3d raftMax = settings.Hardware.PrintMargin + Max + 2 * raftSize; Vector2d Center = Vector2d((raftMin.x + raftMax.x) / 2, (raftMin.y + raftMax.y) / 2); // bbox of object double Length = (std::max(raftMax.x,raftMax.y) - std::min(raftMin.x, raftMin.y))/sqrt(2.0); double rot; uint LayerNr = 0; uint layerCount = settings.Raft.Phase[0].LayerCount + settings.Raft.Phase[1].LayerCount; Settings::RaftSettings::PhasePropertiesType *props = &settings.Raft.Phase[0]; double thickness = props->Thickness * settings.Hardware.LayerThickness; double extrusionfactor = settings.Hardware.GetExtrudeFactor(thickness) * props->MaterialDistanceRatio; while(LayerNr < layerCount) { // If we finished phase 0, start phase 1 of the raft... if (LayerNr >= settings.Raft.Phase[0].LayerCount) props = &settings.Raft.Phase[1]; rot = (props->Rotation+(double)LayerNr * props->RotationPrLayer)/180.0*M_PI; Vector2d InfillDirX(cosf(rot), sinf(rot)); Vector2d InfillDirY(-InfillDirX.y, InfillDirX.x); Vector3d LastPosition; bool reverseLines = false; Vector2d P1, P2; double maxerr = 0.1*props->Distance; for(double x = -Length ; x < Length ; x+=props->Distance) { P1 = (InfillDirX * Length)+(InfillDirY*x) + Center; P2 = (InfillDirX * -Length)+(InfillDirY*x) + Center; if(reverseLines) { Vector2d tmp = P1; P1 = P2; P2 = tmp; } // glBegin(GL_LINES); // glVertex2fv(&P1.x); // glVertex2fv(&P2.x); // Crop lines to bbox*size Vector3d point; Intersection hit; HitsBuffer.clear(); Vector2d P3(raftMin.x, raftMin.y); Vector2d P4(raftMin.x, raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) //Intersect edges of bbox HitsBuffer.push_back(hit); P3 = Vector2d(raftMax.x,raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); P4 = Vector2d(raftMax.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); P3 = Vector2d(raftMin.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); // glEnd(); if(HitsBuffer.size() == 0) // it can only be 2 or zero continue; if(HitsBuffer.size() != 2) continue; std::sort(HitsBuffer.begin(), HitsBuffer.end()); P1 = HitsBuffer[0].p; P2 = HitsBuffer[1].p; state.MakeGCodeLine (Vector3d(P1.x,P1.y,z), Vector3d(P2.x,P2.y,z), Vector3d(0,0,0), 0, settings.Hardware.MaxPrintSpeedXY * 60, extrusionfactor, 0, z, settings.Slicing, settings.Hardware); reverseLines = !reverseLines; } // Set startspeed for Z-move Command g; g.Code = SETSPEED; g.where = Vector3d(P2.x, P2.y, z); g.f=settings.Hardware.MinPrintSpeedZ * 60; g.comment = "Move Z"; g.e = 0; gcode.commands.push_back(g); z += thickness; // Move Z g.Code = ZMOVE; g.where = Vector3d(P2.x, P2.y, z); g.f = settings.Hardware.MinPrintSpeedZ * 60; g.comment = "Move Z"; g.e = 0; gcode.commands.push_back(g); LayerNr++; } // restore the E state // Command gotoE; // gotoE.Code = GOTO; // gotoE.e = 0; // gotoE.comment = _("Reset E for the remaining print"); // gcode.commands.push_back(gotoE); } #endif // 0 // this is of not much use, too fast void Model::CleanupLayers() { int count = (int)layers.size(); if (count == 0) return; if(!m_progress->restart (_("Cleanup"), count)) return; int progress_steps=(int)(count/100); if (progress_steps==0) progress_steps=1; bool cont = true; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i=0; i < count; i++) { #ifdef _OPENMP #pragma omp flush (cont) if (!cont) continue; #else if (!cont) break; #endif if (i%progress_steps==0) { #ifdef _OPENMP #pragma omp critical(updateProgress) { cont = m_progress->update(i); #pragma omp flush (cont) } #else cont = m_progress->update(i); #endif } layers[i]->cleanupPolygons(); } } bool layersort(const Layer * l1, const Layer * l2){ return (l1->Z < l2->Z); } void Model::Slice() { vector shapes; vector transforms; if (settings.get_boolean("Slicing","SelectedOnly")) objtree.get_selected_shapes(m_current_selectionpath, shapes, transforms); else objtree.get_all_shapes(shapes,transforms); if (shapes.size() == 0) return; assert(shapes.size() == transforms.size()); CalcBoundingBoxAndCenter(settings.get_boolean("Slicing","SelectedOnly")); for (uint i = 0; iset_terminal_output(settings.get_boolean("Display","TerminalProgress")); m_progress->start (_("Slicing"), maxZ); // for (vector::iterator pIt = layers.begin(); // pIt != layers. end(); pIt++) // delete *pIt; ClearLayers(); bool flatshapes = shapes.front()->dimensions() == 2; if (flatshapes) { layers.resize(1); layers[0] = new Layer(lastlayer, 0, thickness , 1); lastlayer = layers[0]; layers[0]->setZ(0); // set to real z for (uint nshape= 0; nshape < shapes.size(); nshape++) { layers[0]->addShape(transforms[nshape], *shapes[nshape], 0, max_gradient, -1); } return; } int progress_steps=(int)(maxZ/thickness/100); if (progress_steps==0) progress_steps=1; if ((varSlicing && skins > 1) || (settings.get_boolean("Slicing","BuildSerial") && shapes.size() > 1)) { // have skins and/or serial build, so can't parallelise uint currentshape = 0; double serialheight = maxZ; // settings.Slicing.SerialBuildHeight; double z = minZ; double shape_z = z; double max_shape_z = z + serialheight; Layer * layer = new Layer(lastlayer, LayerNr, thickness, 1); // first layer no skins layer->setZ(shape_z); LayerNr = 1; int new_polys=0; bool cont = true; while(cont && z < maxZ) { shape_z = z; max_shape_z = min(shape_z + serialheight, maxZ); while ( cont && currentshape < shapes.size() && shape_z <= max_shape_z ) { if (LayerNr%progress_steps==0) cont = m_progress->update(shape_z); layer->setZ(shape_z); // set to real z if (shape_z == minZ) { // the layer is on the platform layer->LayerNo = 0; layer->setSkins(1); LayerNr = 1; } new_polys = layer->addShape(transforms[currentshape], *shapes[currentshape], shape_z, max_gradient, supportangle); // cerr << "Z="<= max_shape_z) { // next shape, reset z currentshape++; shape_z = z; } else { // next z, same shape if (varSlicing && LayerNr!=0) { // higher gradient -> slice thinner with fewer skin divisions skins = max_skins-(uint)(max_skins* max_gradient); thickness = skin_thickness*skins; } shape_z += thickness; max_gradient = 0; if (new_polys > -1){ layers.push_back(layer); lastlayer = layer; layer = new Layer(lastlayer, LayerNr++, thickness, skins); } } } //thickness = max_thickness-(max_thickness-min_thickness)*max_gradient; if (currentshape < shapes.size()-1) { // reached max_shape_z, next shape currentshape++; } else { // end of shapes if (new_polys > -1){ if (varSlicing) { skins = max_skins-(uint)(max_skins* max_gradient); thickness = skin_thickness*skins; } layers.push_back(layer); lastlayer = layer; layer = new Layer(lastlayer, LayerNr++, thickness, skins); } z = max_shape_z + thickness; currentshape = 0; // all shapes again } max_gradient=0; //cerr << " Z="<restart (_("Skins"), layers.size())) return; int progress_steps=(int)(layers.size()/100); if (progress_steps==0) progress_steps=1; int count = (int)layers.size(); #ifdef _OPENMP omp_lock_t progress_lock; omp_init_lock(&progress_lock); #pragma omp parallel for schedule(dynamic) //ordered #endif for (int i=1; i < count; i++) { #ifdef _OPENMP omp_set_lock(&progress_lock); #endif if (i%progress_steps==0 && !m_progress->update(i)) #ifndef _OPENMP break; #else continue; omp_unset_lock(&progress_lock); #endif layers[i]->makeSkinPolygons(); } //m_progress->stop (_("Done")); } void Model::MakeUncoveredPolygons(bool make_decor, bool make_bridges) { int count = (int)layers.size(); if (count == 0 ) return; if (!m_progress->restart (_("Find Uncovered"), 2*count+2)) return; int progress_steps=(int)((2*count+2)/100); if (progress_steps==0) progress_steps=1; // bottom to top: uncovered from above -> top polys for (int i = 0; i < count-1; i++) { if (i%progress_steps==0) if(!m_progress->update(i)) return ; layers[i]->addFullPolygons(GetUncoveredPolygons(layers[i],layers[i+1]), make_decor); } // top to bottom: uncovered from below -> bridge polys for (uint i = count-1; i > 0; i--) { //cerr << "layer " << i << endl; if (i%progress_steps==0) if(!m_progress->update(count + count - i)) return; //make_bridges = false; // no bridge on marked layers (serial build) bool mbridge = make_bridges && (layers[i]->LayerNo != 0); if (mbridge) { vector uncovered = GetUncoveredPolygons(layers[i],layers[i-1]); layers[i]->addBridgePolygons(Clipping::getExPolys(uncovered)); layers[i]->calcBridgeAngles(layers[i-1]); } else { const vector &uncovered = GetUncoveredPolygons(layers[i],layers[i-1]); layers[i]->addFullPolygons(uncovered,make_decor); } } m_progress->update(2*count+1); layers.front()->addFullPolygons(layers.front()->GetFillPolygons(), make_decor); m_progress->update(2*count+2); layers.back()->addFullPolygons(layers.back()->GetFillPolygons(), make_decor); //m_progress->stop (_("Done")); } // find polys in subjlayer that are not covered by shell of cliplayer vector Model::GetUncoveredPolygons(const Layer * subjlayer, const Layer * cliplayer) { Clipping clipp; clipp.clear(); clipp.addPolys(subjlayer->GetFillPolygons(), subject); clipp.addPolys(subjlayer->GetFullFillPolygons(), subject); clipp.addPolys(subjlayer->GetBridgePolygons(), subject); clipp.addPolys(subjlayer->GetDecorPolygons(), subject); //clipp.addPolys(cliplayer->GetOuterShell(), clip); // have some overlap clipp.addPolys(*(cliplayer->GetInnerShell()), clip); // have some more overlap vector uncovered = clipp.subtractMerged(); return uncovered; } void Model::MultiplyUncoveredPolygons() { if (!settings.get_boolean("Slicing","DoInfill") && settings.get_double("Slicing","SolidThickness") == 0.0) return; if (settings.get_boolean("Slicing","NoTopAndBottom")) return; int shells = (int)ceil(settings.get_double("Slicing","SolidThickness")/settings.get_double("Slicing","LayerThickness")); shells = max(shells, (int)settings.get_integer("Slicing","ShellCount")); if (shells<1) return; int count = (int)layers.size(); int numdecor = 0; // add another full layer if making decor if (settings.get_boolean("Slicing","MakeDecor")) numdecor = settings.get_integer("Slicing","DecorLayers"); shells += numdecor; if (!m_progress->restart (_("Uncovered Shells"), count*3)) return; int progress_steps=(int)(count*3/100); if (progress_steps==0) progress_steps=1; // bottom-up: mulitply downwards int i,s; for (i=0; i < count; i++) { if (i%progress_steps==0) if(!m_progress->update(i)) return; // (brigdepolys are not multiplied downwards) const vector &fullpolys = layers[i]->GetFullFillPolygons(); const vector &skinfullpolys = layers[i]->GetSkinFullPolygons(); const vector &decorpolys = layers[i]->GetDecorPolygons(); for (s=1; s < shells; s++) if (i-s > 1) { layers[i-s]->addFullPolygons (fullpolys, false); layers[i-s]->addFullPolygons (skinfullpolys, false); layers[i-s]->addFullPolygons (decorpolys, s < numdecor); } } // top-down: mulitply upwards for (int i=count-1; i>=0; i--) { if (i%progress_steps==0) if (!m_progress->update(count + count -i)) return; const vector &fullpolys = layers[i]->GetFullFillPolygons(); const vector &bridgepolys = layers[i]->GetBridgePolygons(); const vector &skinfullpolys = layers[i]->GetSkinFullPolygons(); const vector &decorpolys = layers[i]->GetDecorPolygons(); for (int s=1; s < shells; s++) if (i+s < count){ layers[i+s]->addFullPolygons (fullpolys, false); layers[i+s]->addFullPolygons (bridgepolys, false); layers[i+s]->addFullPolygons (skinfullpolys, false); layers[i+s]->addFullPolygons (decorpolys, s < numdecor); } } m_progress->set_label(_("Merging Full Polygons")); // merge results bool cont = true; #ifdef _OPENMP omp_lock_t progress_lock; omp_init_lock(&progress_lock); #pragma omp parallel for schedule(dynamic) #endif for (i=0; i < count; i++) { if (i%progress_steps==0) { #ifdef _OPENMP omp_set_lock(&progress_lock); #endif cont = (m_progress->update(count + count +i)); #ifdef _OPENMP omp_unset_lock(&progress_lock); #endif } if (!cont) continue; layers[i]->mergeFullPolygons(false); } #ifdef _OPENMP omp_destroy_lock(&progress_lock); #endif //m_progress->stop (_("Done")); } void Model::MakeSupportPolygons(Layer * layer, // lower -> will change const Layer * layerabove, // upper double widen) { const double distance = settings.GetExtrudedMaterialWidth(layer->thickness); // vector tosupport = Clipping::getOffset(layerabove->GetToSupportPolygons(), // distance/2.); //vector tosupport = Clipping::getMerged(layerabove->GetToSupportPolygons(), // distance); vector tosupport = layerabove->GetToSupportPolygons(); Clipping clipp; clipp.addPolys(layerabove->GetSupportPolygons(), subject); clipp.addPolys(tosupport, subject); clipp.addPolys(layer->GetPolygons(), clip); clipp.setZ(layer->getZ()); vector spolys = clipp.subtract(CL::pftNonZero,CL::pftEvenOdd); if (widen != 0) // widen from layer to layer spolys = clipp.getOffset(spolys, widen * layer->thickness); spolys = clipp.getMerged(spolys,distance); layer->setSupportPolygons(spolys); } void Model::MakeSupportPolygons(double widen) { int count = layers.size(); if (!m_progress->restart (_("Support"), count*2)) return; int progress_steps=(int)(count*2/100); if (progress_steps==0) progress_steps=1; for (int i=count-1; i>0; i--) { if (i%progress_steps==0) if(! m_progress->update(count-i)) return; if (layers[i]->LayerNo == 0) continue; MakeSupportPolygons(layers[i-1], layers[i], widen); } // // shrink a bit // Clipping clipp; // for (int i=0; ithickness); // if (i%progress_steps==0) if(!m_progress->update(i+count)) return; // vector offset = // Clipping::getOffset(layers[i]->GetSupportPolygons(), -distance); // layers[i]->setSupportPolygons(offset); // } // m_progress->stop (_("Done")); } void Model::MakeSkirt() { if (!settings.get_boolean("Slicing","Skirt")) return; double skirtdistance = settings.get_double("Slicing","SkirtDistance"); Clipping clipp; guint count = layers.size(); guint endindex = 0; // find maximum of all calculated skirts clipp.clear(); double skirtheight = settings.get_double("Slicing","SkirtHeight"); bool singleskirt = settings.get_boolean("Slicing","SingleSkirt"); bool support = settings.get_boolean("Slicing","Support"); for (guint i=0; i < count; i++) { if (layers[i]->getZ() > skirtheight) break; layers[i]->MakeSkirt(skirtdistance, singleskirt && !support); vector sp = layers[i]->GetSkirtPolygons(); clipp.addPolys(sp,subject); endindex = i; } vector skirts = clipp.unite(CL::pftPositive,CL::pftPositive); // set this skirt for all skirted layers if (skirts.size()>0) for (guint i=0; i<=endindex; i++) { layers[i]->setSkirtPolygons(skirts); } } void Model::MakeShells() { int count = (int)layers.size(); if (count == 0) return; if (!m_progress->restart (_("Shells"), count)) return; int progress_steps=(int)(count/100); if (progress_steps==0) progress_steps=1; bool cont = true; #ifdef _OPENMP omp_lock_t progress_lock; omp_init_lock(&progress_lock); #pragma omp parallel for schedule(dynamic) #endif for (int i=0; i < count; i++) { if (i%progress_steps==0) { #ifdef _OPENMP omp_set_lock(&progress_lock); #endif cont = (m_progress->update(i)); #ifdef _OPENMP omp_unset_lock(&progress_lock); #endif } if (!cont) continue; layers[i]->MakeShells(settings); } #ifdef _OPENMP omp_destroy_lock(&progress_lock); #endif m_progress->update(count); //m_progress->stop (_("Done")); } void Model::CalcInfill() { if (!settings.get_boolean("Slicing","DoInfill") && settings.get_double("Slicing","SolidThickness") == 0.0) return; int count = (int)layers.size(); m_progress->start (_("Infill"), count); int progress_steps=(count/100); if (progress_steps==0) progress_steps=1; bool cont = true; //cerr << "make infill"<< endl; #ifdef _OPENMP omp_lock_t progress_lock; omp_init_lock(&progress_lock); #pragma omp parallel for schedule(dynamic) #endif for (int i=0; i < count ; i++) { //cerr << "thread " << omp_get_thread_num() << endl; if (i%progress_steps==0){ #ifdef _OPENMP omp_set_lock(&progress_lock); #endif cont = (m_progress->update(i)); #ifdef _OPENMP omp_unset_lock(&progress_lock); #endif } if (!cont) continue; layers[i]->CalcInfill(settings); } #ifdef _OPENMP omp_destroy_lock(&progress_lock); #endif //m_progress->stop (_("Done")); } void Model::ConvertToGCode() { if (is_calculating) { return; } is_calculating=true; // default: settings.SelectExtruder(0); Glib::TimeVal start_time; start_time.assign_current_time(); gcode.clear(); GCodeState state(gcode); Infill::clearPatterns(); Vector3d printOffset = settings.getPrintMargin(); double printOffsetZ = printOffset.z(); // Make Layers lastlayer = NULL; Slice(); //CleanupLayers(); MakeShells(); if (settings.get_boolean("Slicing","DoInfill") && !settings.get_boolean("Slicing","NoTopAndBottom") && (settings.get_double("Slicing","SolidThickness") > 0 || settings.get_integer("Slicing","ShellCount") > 0)) // not bridging when support MakeUncoveredPolygons( settings.get_boolean("Slicing","MakeDecor"), !settings.get_boolean("Slicing","NoBridges") && !settings.get_boolean("Slicing","Support") ); if (settings.get_boolean("Slicing","Support")) // easier before having multiplied uncovered bottoms MakeSupportPolygons(settings.get_double("Slicing","SupportWiden")); MakeFullSkins(); // must before multiplied uncovered bottoms MultiplyUncoveredPolygons(); if (settings.get_boolean("Slicing","Skirt")) MakeSkirt(); CalcInfill(); if (settings.get_boolean("Raft","Enable")) { printOffset += Vector3d (settings.get_double("Raft","Size"), 0); MakeRaft (state, printOffsetZ); // printOffsetZ will have height of raft added } state.ResetLastWhere(Vector3d(0,0,0)); uint count = layers.size(); m_progress->start (_("Making Lines"), count+1); state.AppendCommand(MILLIMETERSASUNITS, false, _("Millimeters")); state.AppendCommand(ABSOLUTEPOSITIONING, false, _("Absolute Pos")); if (settings.get_boolean("Slicing","RelativeEcode")) state.AppendCommand(RELATIVE_ECODE, false, _("Relative E Code")); else state.AppendCommand(ABSOLUTE_ECODE, false, _("Absolute E Code")); bool cont = true; vector plines; bool farthestStart = settings.get_boolean("Slicing","FarthestLayerStart"); Vector3d start = state.LastPosition(); for (uint p=0; pupdate(p)) ; if (!cont) break; // cerr << "GCode layer " << (p+1) << " of " << count // << " offset " << printOffsetZ // << " have commands: " <getRandomPolygonPoint(); // start.set(randstart.x(), randstart.y()); const Vector2d fartheststart = layers[p]->getFarthestPolygonPoint(start); start.set(fartheststart.x(), fartheststart.y()); } layers[p]->MakePrintlines(start, plines, printOffsetZ, settings); // } catch (Glib::Error e) { // error("GCode Error:", (e.what()).c_str()); // } // if (layers[p]->getPrevious() != NULL) // cerr << p << ": " <LayerNo << " prev: " // << layers[p]->getPrevious()->LayerNo << endl; } // do antiooze retract for all lines: Printlines::makeAntioozeRetract(plines, settings, m_progress); vector commands; //Printlines::getCommands(plines, settings, commands, m_progress); Printlines::getCommands(plines, settings, state, m_progress); //state.AppendCommands(commands, settings.Slicing.RelativeEcode); string GcodeTxt; if (cont) gcode.MakeText (GcodeTxt, settings, m_progress); else { ClearLayers(); ClearGCode(); ClearPreview(); } // display whole layer if flat shapes // if (shapes.back()->dimensions() == 2) // gcode.layerchanges.push_back(0); m_progress->stop (_("Done")); int h = (int)state.timeused/3600; int m = ((int)state.timeused%3600)/60; int s = ((int)state.timeused-3600*h-60*m); std::ostringstream ostr; ostr << _("Time Estimation: ") ; if (h>0) ostr << h <<_("h") ; ostr < 10) { h = (int)(gctime/3600); m = ((int)gctime)%3600/60; s = (int)(gctime)-3600*h-60*m; ostr << _(" / GCode Estimation: "); if (h>0) ostr << h <<_("h"); ostr<< m <<_("m") << s <<_("s") ; } double totlength = gcode.GetTotalExtruded(settings.get_boolean("Slicing","RelativeEcode")); ostr << _(" - total extruded: ") << totlength << "mm"; // TODO: ths assumes all extruders use the same filament diameter const double diam = settings.get_double("Extruder","FilamentDiameter"); const double ccm = totlength * diam * diam / 4. * M_PI / 1000 ; ostr << " = " << ccm << "cm^3 "; ostr << "(ABS~" << ccm*1.08 << "g, PLA~" << ccm*1.25 << "g)"; if (statusbar) statusbar->push(ostr.str()); else cout << ostr.str() << endl; { Glib::TimeVal now; now.assign_current_time(); const int time_used = (int) round((now - start_time).as_double()); // seconds cerr << "GCode generated in " << time_used << " seconds. " << GcodeTxt.size() << " bytes" << endl; } is_calculating=false; m_signal_gcode_changed.emit(); } string Model::getSVG(int single_layer_no) const { Vector3d printOffset = settings.getPrintMargin(); ostringstream ostr; ostr << "" <" << endl << "" << endl << "" << endl; if (single_layer_no<0) { ostr << "" << endl; for (uint i = 0; i < layers.size(); i++) { ostr << "\t\t" << layers[i]->SVGpath() << endl; } } else { ostr << "" << endl; ostr << "\t\t" << layers[single_layer_no]->SVGpath() << endl; } ostr << "" << endl; ostr << "" << endl; return ostr.str(); } void Model::SliceToSVG(Glib::RefPtr file, bool single_layer) { if (is_calculating) return; is_calculating=true; lastlayer = NULL; Slice(); m_progress->stop (_("Done")); if (!single_layer) { Glib::file_set_contents (file->get_path(), getSVG()); } else { uint n_layers = layers.size(); m_progress->start (_("Saving Files"),n_layers); uint digits = log10(n_layers)+1; string base = file->get_path(); ostringstream ostr; for (uint i = 0; i < n_layers; i++) { ostr.str(""); ostr << base; uint nzero = (uint)(digits - log10(i+1)); if (i==0) nzero = digits-1; for (uint d = 0; d < nzero; d++) ostr << "0"; ostr << i << ".svg"; if (!m_progress->update(i)) break; Glib::file_set_contents (ostr.str(), getSVG(i)); } m_progress->stop (_("Done")); } string directory_path = file->get_parent()->get_path(); settings.STLPath = directory_path; is_calculating = false; } repsnapper-2.3.2a5/src/objtree.cpp000066400000000000000000000220231231531733200170470ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "stdafx.h" #include "objtree.h" #include "model.h" TreeObject::~TreeObject() { for (uint i = 0; i0) { for (uint i = 0; iCenter; } center /= shapes.size(); } return center; } Gtk::TreePath TreeObject::addShape(Shape *shape, std::string location) { Gtk::TreePath path; path.push_back (0); // root path.push_back (idx); shape->filename = location; if (shapes.size() > 0) if (dimensions != shape->dimensions()) { Gtk::MessageDialog dialog (_("Cannot add a 3-dimensional Shape to a 2-dimensional Model and vice versa"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.run(); path.push_back (shapes.size() - 1); return path; } dimensions = shape->dimensions(); shapes.push_back(shape); path.push_back (shapes.size() - 1); return path; } void ObjectsTree::clear() { for (vector::iterator i = Objects.begin(); i != Objects.end(); i++) delete *i; Objects.clear(); version = 0.0f; m_filename = ""; transform3D.identity(); update_model(); } void ObjectsTree::newObject() { Objects.push_back(new TreeObject()); update_model(); } Gtk::TreePath ObjectsTree::addShape(TreeObject *parent, Shape *shape, std::string location) { Gtk::TreePath path = parent->addShape(shape, location); update_model(); return path; } ObjectsTree::ObjectsTree() { version=0.1f; m_cols = new ModelColumns(); m_model = Gtk::TreeStore::create (*m_cols); update_model(); m_model->signal_row_changed().connect(sigc::mem_fun(*this, &ObjectsTree::on_row_changed)); } ObjectsTree::~ObjectsTree() { for (vector::iterator i = Objects.begin(); i != Objects.end(); i++) delete *i; Objects.clear(); delete m_cols; } void ObjectsTree::on_row_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter){ if (!inhibit_row_changed) update_shapenames(m_model->children()); } void ObjectsTree::update_model() { inhibit_row_changed = true; // re-build the model each time for ease ... m_model->clear(); size_t psep; std::string root_label = m_filename; if (!root_label.length()) root_label = _("Unsaved file"); else if ((psep = m_filename.find_last_of("/\\")) != string::npos) root_label = m_filename.substr(psep + 1); Gtk::TreeModel::iterator root; root = m_model->append(); Gtk::TreeModel::Row row = *root; row[m_cols->m_name] = root_label; row[m_cols->m_object] = -1; row[m_cols->m_shape] = -1; row[m_cols->m_pickindex] = 0; row[m_cols->m_material] = 0; gint index = 1; // pick/select index. matches computation in draw() for (guint i = 0; i < Objects.size(); i++) { Objects[i]->idx = i; Gtk::TreeModel::iterator obj = m_model->append(row.children()); Gtk::TreeModel::Row orow = *obj; orow[m_cols->m_name] = Objects[i]->name; orow[m_cols->m_object] = i; orow[m_cols->m_shape] = -1; orow[m_cols->m_pickindex] = index++; orow[m_cols->m_material] = 0; for (guint j = 0; j < Objects[i]->shapes.size(); j++) { Objects[i]->shapes[j]->idx = j; Gtk::TreeModel::iterator iter = m_model->append(orow.children()); row = *iter; row[m_cols->m_name] = Objects[i]->shapes[j]->filename; row[m_cols->m_object] = i; row[m_cols->m_shape] = j; row[m_cols->m_pickindex] = index++; row[m_cols->m_material] = 0; } } inhibit_row_changed = false; } void ObjectsTree::update_shapenames(Gtk::TreeModel::Children children) { Gtk::TreeModel::iterator iter = children.begin(); for (;iter; iter++) { int nobj = (*iter)[m_cols->m_object]; int nshape = (*iter)[m_cols->m_shape]; if (nobj >= 0 && nshape >= 0) { ustring name = (*iter)[m_cols->m_name]; if ((int)Objects.size() > nobj && (int)Objects[nobj]->shapes.size() > nshape) Objects[nobj]->shapes[nshape]->filename = name; } else update_shapenames((*iter).children()); } } Matrix4d ObjectsTree::getTransformationMatrix(int object, int shape) const { Matrix4d result = transform3D.transform; // Vector3f translation = result.getTranslation(); // result.setTranslation(translation+PrintMargin); if(object >= 0) result *= Objects[object]->transform3D.transform; if(shape >= 0) result *= Objects[object]->shapes[shape]->transform3D.transform; return result; } void ObjectsTree::get_selected_objects(const vector &path, vector &objects, vector &shapes) const { objects.clear(); shapes.clear(); if (path.size()==0) return; for (uint p = 0; p < path.size(); p++) { // cerr << "sel " << p << " -> "<< path[p].to_string () // << " - "<< path[p].size() << endl; int num = path[p].size(); if (num == 1) for (uint i=0; ishapes[path[p][2]]); } } } void ObjectsTree::get_selected_shapes(const vector &path, vector &allshapes, vector &transforms) const { allshapes.clear(); transforms.clear(); vector sel_shapes; vector sel_objects; get_selected_objects(path, sel_objects, sel_shapes); // add shapes if their parent object not selected for (uint s = 0; s < sel_shapes.size(); s++) { bool parent_obj_selected = false; for (uint o = 0; o < sel_objects.size(); o++) { if (getParent(sel_shapes[s]) == Objects[o]) parent_obj_selected = true; } if (!parent_obj_selected){ allshapes.push_back(sel_shapes[s]); transforms.push_back(transform3D.transform * getParent(sel_shapes[s])->transform3D.transform); } } // add all shapes of selected objects for (uint o = 0; o < sel_objects.size(); o++) { Matrix4d otrans = transform3D.transform * sel_objects[o]->transform3D.transform; allshapes.insert(allshapes.begin(), sel_objects[o]->shapes.begin(), sel_objects[o]->shapes.end()); for (uint s = 0; s < sel_objects[o]->shapes.size(); s++) { transforms.push_back(otrans); } } } void ObjectsTree::get_all_shapes(vector &allshapes, vector &transforms) const { allshapes.clear(); transforms.clear(); for (uint o = 0; o < Objects.size(); o++) { Matrix4d otrans = transform3D.transform * Objects[o]->transform3D.transform; allshapes.insert(allshapes.begin(), Objects[o]->shapes.begin(), Objects[o]->shapes.end()); for (uint s = 0; s < Objects[o]->shapes.size(); s++) { transforms.push_back(otrans); } } } void ObjectsTree::DeleteSelected(vector &path) { if (path.size()==0) return; for (int p = path.size()-1; p>=0; p--) { int num = path[p].size(); if (num == 1) Objects.clear(); else if (num == 2) Objects.erase (Objects.begin() + path[p][1]); else if (num == 3) { // have shapes Objects[path[p][1]]->deleteShape(path[p][2]); } update_model(); } } TreeObject * ObjectsTree::getParent(const Shape *shape) const { for (uint i=0; ishapes.size(); j++) { if (Objects[i]->shapes[j] == shape) return Objects[i]; } } return NULL; } Gtk::TreeModel::iterator ObjectsTree::find_stl_in_children(Gtk::TreeModel::Children children, guint pickindex) { Gtk::TreeModel::iterator iter = children.begin(); for (;iter; iter++) { guint curindex = (*iter)[m_cols->m_pickindex]; if (curindex == pickindex) return iter; Gtk::TreeModel::iterator child_iter = find_stl_in_children((*iter).children(), pickindex); if (child_iter) return child_iter; } Gtk::TreeModel::iterator invalid; return invalid; } Gtk::TreeModel::iterator ObjectsTree::find_stl_by_index(guint pickindex) { return find_stl_in_children(m_model->children(), pickindex); } repsnapper-2.3.2a5/src/objtree.h000066400000000000000000000065641231531733200165300ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "shape.h" /* class RFO_File */ /* { */ /* public: */ /* RFO_File(){} */ /* void Draw(); */ /* RFO_Transform3D transform3D; */ /* string location; */ /* string filetype; */ /* string material; */ /* Shape stl; */ /* Shape getSTL() const {return stl;}; */ /* int idx; */ /* }; */ class TreeObject { public: TreeObject(){name = _("Unnamed object");}; ~TreeObject(); string name; Transform3D transform3D; vector shapes; bool deleteShape(uint i); short dimensions; uint size(){return shapes.size();}; int idx; Gtk::TreePath addShape(Shape *shape, std::string location); void move(const Vector3d &delta){ transform3D.move(delta); }; Vector3d center() const; }; class ObjectsTree { void update_model(); bool inhibit_row_changed; void update_shapenames(Gtk::TreeModel::Children children); void on_row_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter); public: class ModelColumns : public Gtk::TreeModelColumnRecord { public: ModelColumns() { add (m_name); add (m_object); add (m_shape); add(m_pickindex); add (m_material); //add (m_extruder); } Gtk::TreeModelColumn m_name; Gtk::TreeModelColumn m_object; Gtk::TreeModelColumn m_shape; Gtk::TreeModelColumn m_pickindex; Gtk::TreeModelColumn m_material; //Gtk::TreeModelColumn m_extruder; }; ObjectsTree(); ~ObjectsTree(); void clear(); bool empty() const {return Objects.size()==0; } void DeleteSelected(vector &iter); //void draw(Settings &settings, Gtk::TreeModel::iterator &iter); void newObject(); Gtk::TreePath addShape(TreeObject *parent, Shape *shape, std::string location); void get_selected_objects(const vector &iter, vector &object, vector &shape) const; void get_selected_shapes(const vector &iter, vector &shape, vector &transforms) const; void get_all_shapes(vector &shapes, vector &transforms) const; Gtk::TreeModel::iterator find_stl_by_index(guint pickindex); Matrix4d getTransformationMatrix(int object, int shape=-1) const; TreeObject * getParent(const Shape *shape) const; vector Objects; Transform3D transform3D; float version; string m_filename; Glib::RefPtr m_model; ModelColumns *m_cols; private: Gtk::TreeModel::iterator find_stl_in_children(Gtk::TreeModel::Children children, guint pickindex); }; repsnapper-2.3.2a5/src/platform.cpp000066400000000000000000000053571231531733200172540ustar00rootroot00000000000000/* Provide some simple platform abstraction, and the right headers for GL stuff depending on OS This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "stdafx.h" #include "platform.h" #ifndef WIN32 # include #endif #include unsigned long Platform::getTickCount() { #ifdef WIN32 return GetTickCount(); #else struct timeval now; gettimeofday (&now, NULL); return now.tv_sec * 1000 + now.tv_usec / 1000; #endif } static char *binary_path = NULL; void Platform::setBinaryPath (const char *apparg) { const char *p; if (!(p = strrchr (apparg, G_DIR_SEPARATOR))) return; binary_path = g_strndup (apparg, p - apparg); } bool Platform::has_extension(const std::string &fname, const char *extn) { if (fname.find_last_of(".") == std::string::npos) return false; std::string this_extn = fname.substr(fname.find_last_of(".") + 1); return this_extn == extn; } std::vector Platform::getConfigPaths() { const gchar * const *datadirs = g_get_system_data_dirs(); std::vector dirs; /* Always prefer config files in the current directory */ dirs.push_back(std::string("src") + G_DIR_SEPARATOR); /* Otherwise prefer the app's current directory */ if (binary_path) { dirs.push_back(std::string(binary_path) + G_DIR_SEPARATOR); /* Finally prefer an etc/xdg path in app's current directory */ #ifdef WIN32 dirs.push_back(std::string(binary_path) + G_DIR_SEPARATOR + ".." + G_DIR_SEPARATOR + "etc" + G_DIR_SEPARATOR + "xdg" + G_DIR_SEPARATOR + "repsnapper"); #endif } dirs.push_back(std::string(G_STRINGIFY(RSDATADIR)) + G_DIR_SEPARATOR); dirs.push_back(std::string(G_STRINGIFY(SYSCONFDIR)) + G_DIR_SEPARATOR); for(gsize i = 0; datadirs[i] != NULL; ++i) dirs.push_back(std::string(datadirs[i]) + G_DIR_SEPARATOR + "repsnapper" + G_DIR_SEPARATOR); return dirs; } std::string str(double r, int prec) { ostringstream o; if (prec>=0) o.precision(prec); o< #include /** * OSX uses a different setup for opengl, we compile with carbon */ #ifdef __APPLE__ #include #include // #include #else #include // Header File For The OpenGL32 Library #include // Header File For The GLu32 Library //#ifndef WIN32 // #include // Header GLUT Library //#endif #endif class Platform { public: static unsigned long getTickCount(); static void setBinaryPath(const char *apparg); static std::vector getConfigPaths(); static bool has_extension(const std::string &fname, const char *extn); }; std::string str(double r, int prec = -1); #endif // PLATFORM_H repsnapper-2.3.2a5/src/printer/000077500000000000000000000000001231531733200163755ustar00rootroot00000000000000repsnapper-2.3.2a5/src/printer/Makefile000066400000000000000000000002411231531733200200320ustar00rootroot00000000000000# Delegate everything to the toplevel makefile # this is only here so 'make' works in src/ all: @$(MAKE) -C ../.. $@ # Catch all rule %: @$(MAKE) -C ../.. $@ repsnapper-2.3.2a5/src/printer/Makefile.am000066400000000000000000000012031231531733200204250ustar00rootroot00000000000000# # Combined Makefile for Linux and OS/X # # # Copyright 2009+ Joachim Glauche # Copyright 2011 Bas Wijnen # # This file is part of RepSnapper and is made available under # the terms of the GNU General Public License, version 2, or at your # option, any later version, incorporated herein by reference. SHARED_SRC += \ src/printer/printer_serial.cpp \ src/printer/thread_buffer.cpp \ src/printer/threaded_printer_serial.cpp \ src/printer/printer.cpp SHARED_INC += \ src/printer/printer_serial.h \ src/printer/thread.h \ src/printer/thread_buffer.h \ src/printer/threaded_printer_serial.h \ src/printer/printer.h repsnapper-2.3.2a5/src/printer/printer.cpp000066400000000000000000000225251231531733200205720ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #include "printer.h" #include "model.h" #include "../ui/view.h" Printer::Printer( View *view ) { m_view = view; m_model = NULL; was_connected = false; was_printing = false; prev_line = 0; waiting_temp = false; temp_countdown = 100; temps[ TEMP_NOZZLE ] = 0; temps[ TEMP_BED ] = 0; idle_timeout = Glib::signal_timeout().connect ( sigc::mem_fun(*this, &Printer::Idle), 100 ); print_timeout = Glib::signal_timeout().connect ( sigc::mem_fun(*this, &Printer::CheckPrintingProgress), 700 ); } Printer::~Printer() { idle_timeout.disconnect(); print_timeout.disconnect(); if ( temp_timeout.connected() ) temp_timeout.disconnect(); } void Printer::setModel( Model *model ) { m_model = model; UpdateTemperatureMonitor(); } bool Printer::Connect( bool connect ) { if ( ! connect ) { Disconnect(); return true; } if ( m_model == NULL ) return false; return Connect( m_model->settings.get_string("Hardware","PortName"), m_model->settings.get_integer("Hardware","SerialSpeed") ); } bool Printer::Connect( string device, int baudrate ) { signal_serial_state_changed.emit( SERIAL_CONNECTING ); bool ret = ThreadedPrinterSerial::Connect( device, baudrate ); signal_serial_state_changed.emit( ret ? SERIAL_CONNECTED : SERIAL_DISCONNECTED ); UpdateTemperatureMonitor(); return ret; } void Printer::Disconnect( void ) { signal_serial_state_changed.emit( SERIAL_DISCONNECTING ); ThreadedPrinterSerial::Disconnect(); signal_serial_state_changed.emit( SERIAL_DISCONNECTED ); } bool Printer::Reset( void ) { bool ret = ThreadedPrinterSerial::Reset(); if ( ret && was_printing ) { was_printing = false; signal_printing_changed.emit(); } if ( !ret ) alert( _("Error: Unable to reset printer") ); return ret; } bool Printer::StartPrinting( unsigned long start_line, unsigned long stop_line ) { string commands = m_model->GetGCodeBuffer()->get_text(); return Printer::StartPrinting( commands, start_line, stop_line ); } bool Printer::StartPrinting( string commands, unsigned long start_line, unsigned long stop_line ) { bool ret = ThreadedPrinterSerial::StartPrinting( commands, start_line, stop_line ); if ( ret ) { prev_line = start_line; was_printing = IsPrinting(); signal_printing_changed.emit(); if ( start_line > 0 ) signal_now_printing.emit( start_line ); } return ret; } bool Printer::StopPrinting( bool wait ) { bool ret = ThreadedPrinterSerial::StopPrinting( wait ); if ( ret && wait ) { prev_line = 0; was_printing = IsPrinting(); signal_printing_changed.emit(); } return ret; } bool Printer::ContinuePrinting( bool wait ) { bool ret = ThreadedPrinterSerial::ContinuePrinting( wait ); if ( ret && wait ) { prev_line = GetPrintingProgress(); signal_printing_changed.emit(); if ( prev_line > 0 ) signal_now_printing.emit( prev_line ); } return ret; } void Printer::Inhibit( bool value ) { ThreadedPrinterSerial::Inhibit( value ); signal_inhibit_changed.emit(); } bool Printer::SwitchPower( bool on ) { if ( IsPrinting() ) { alert(_("Can't switch power while printing")); return false; } string resp; if ( on ) return Send( "M80" ); return Send( "M81" ); } bool Printer::Home( string axis ) { if( IsPrinting() ) { alert(_("Can't go home while printing")); return false; } if ( axis == "X" || axis == "Y" || axis == "Z" ) { return Send("G28 "+axis+"0"); } else if ( axis == "ALL" ) { return Send("G28"); } alert(_("Home called with unknown axis")); return false; } bool Printer::Move(string axis, double distance, bool relative ) { if ( m_model == NULL ) return false; if ( IsPrinting() ) { alert(_("Can't move while printing")); return false; } Settings *settings = &m_model->settings; float speed = 0.0; if ( axis == "X" || axis == "Y" ) speed = settings->get_double("Hardware","MaxMoveSpeedXY") * 60; else if(axis == "Z") speed = settings->get_double("Hardware","MaxMoveSpeedZ") * 60; else alert (_("Move called with unknown axis")); ostringstream os; if ( relative ) os << "G91\n"; os << "G1 " << axis << distance << " F" << speed; if ( relative ) os << "\nG90"; return Send( os.str() ); } bool Printer::Goto( string axis, double position ) { return Move( axis, position, false ); } bool Printer::SelectExtruder( int extruder_no ) { if (extruder_no < 0) return true; ostringstream os; os << "T" << extruder_no; return Send( os.str() ); } bool Printer::SetTemp( TempType type, float value, int extruder_no ) { ostringstream os; switch (type) { case TEMP_NOZZLE: os << "M104 S"; break; case TEMP_BED: os << "M140 S"; break; default: ostringstream ose; ose << "No such Temptype: " << type; alert( ose.str().c_str() ); return false; } os << value << endl; if ( extruder_no >= 0 ) if ( !SelectExtruder( extruder_no ) ) return false; return Send( os.str() ); } bool Printer::RunExtruder( double extruder_speed, double extruder_length, bool reverse, int extruder_no ) { if ( IsPrinting() ) { alert(_("Can't manually extrude while printing")); return false; } if ( extruder_no >= 0 ) if ( !SelectExtruder(extruder_no ) ) return false; ostringstream os; os << "M83\n"; os << "G1 E" << ( reverse ? -extruder_length : extruder_length ) << " F" << extruder_speed << "\n"; os << "M82\n"; os << "G1 F1500"; return Send( os.str() ); } void Printer::alert( const char *message ) { if ( m_view ) m_view->err_log( string(message) + "\n" ); signal_alert.emit( Gtk::MESSAGE_INFO, message, NULL ); } void Printer::error( const char *message, const char *secondary ) { if ( m_view ) m_view->err_log( string(message) + " - " + string(secondary) + "\n" ); signal_alert.emit( Gtk::MESSAGE_ERROR, message, secondary ); } void Printer::UpdateTemperatureMonitor( void ) { if ( temp_timeout.connected() ) temp_timeout.disconnect(); if ( IsConnected() && m_model && m_model->settings.get_boolean("Misc","TempReadingEnabled") ) { const unsigned int timeout = m_model->settings.get_double("Display","TempUpdateSpeed"); temp_timeout = Glib::signal_timeout().connect_seconds ( sigc::mem_fun(*this, &Printer::QueryTemp), timeout ); } } bool Printer::Idle( void ) { string str; bool is_connected; while ( ( str = ReadResponse() ) != "" ) ParseResponse( str ); if ( m_view ) { while ( ( str = ReadLog() ) != "" ) m_view->comm_log( str ); while ( ( str = ReadErrorLog() ) != "" ) { alert( str.c_str() ); } } if ( ( is_connected = IsConnected() ) != was_connected ) { was_connected = is_connected; signal_serial_state_changed.emit( is_connected ? SERIAL_CONNECTED : SERIAL_DISCONNECTED ); } if ( waiting_temp && --temp_countdown == 0 && m_model && m_model->settings.get_boolean("Misc","TempReadingEnabled") ) { UpdateTemperatureMonitor(); temp_countdown = 100; waiting_temp = false; } return true; } bool Printer::CheckPrintingProgress( void ) { bool is_printing = IsPrinting(); unsigned long line = GetPrintingProgress(); if ( is_printing != was_printing ) { prev_line = line; signal_printing_changed.emit(); was_printing = is_printing; } else if ( is_printing && line != prev_line ) { prev_line = line; if ( line > 0 ) signal_now_printing.emit( line ); } return true; } bool Printer::QueryTemp( void ) { if ( temp_timeout.connected() ) temp_timeout.disconnect(); if ( IsConnected() && m_model && m_model->settings.get_boolean("Misc","TempReadingEnabled") ) { Send( "M105" ); waiting_temp = true; } return true; } const Glib::RefPtr templineRE_T = Glib::Regex::create("(?ims)T\\:(?[\\-\\.\\d]+?)\\s+?"); const Glib::RefPtr templineRE_B = Glib::Regex::create("(?ims)B\\:(?[\\-\\.\\d]+?)\\s+?"); void Printer::ParseResponse( string line ) { if (line.find("T:") != string::npos) { Glib::MatchInfo match_info; vector matches; string name; if (templineRE_T->match(line, match_info)) { std::istringstream iss(match_info.fetch_named("temp").c_str()); double temp; iss >> temp; temps[TEMP_NOZZLE] = temp; } if (templineRE_B->match(line, match_info)) { std::istringstream iss(match_info.fetch_named("temp").c_str()); double temp; iss >> temp; temps[TEMP_BED] = temp; } waiting_temp = false; UpdateTemperatureMonitor(); signal_temp_changed.emit(); } } repsnapper-2.3.2a5/src/printer/printer.h000066400000000000000000000065451231531733200202430ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // everything taken from model.h #pragma once #include "stdafx.h" #include "threaded_printer_serial.h" enum RR_logtype { LOG_COMM, LOG_ERROR, LOG_ECHO }; enum TempType { TEMP_NOZZLE, TEMP_BED, TEMP_LAST }; class Printer : public ThreadedPrinterSerial { private: double temps[ TEMP_LAST ]; View *m_view; Model *m_model; bool was_connected; bool was_printing; unsigned long prev_line; bool waiting_temp; int temp_countdown; sigc::connection idle_timeout; sigc::connection print_timeout; sigc::connection temp_timeout; bool Idle( void ); bool QueryTemp( void ); bool CheckPrintingProgress( void ); void ParseResponse( string line ); public: Printer( View *view ); ~Printer(); void setModel( Model *model ); bool Connect( bool connect = true ); bool Connect( string device, int baudrate ); void Disconnect( void ); bool Reset( void ); bool StartPrinting( unsigned long start_line = 1, unsigned long stop_line = ULONG_MAX ); bool StartPrinting( string commands, unsigned long start_line = 1, unsigned long stop_line = ULONG_MAX ); bool StopPrinting( bool wait = true ); bool ContinuePrinting( bool wait = true ); void Inhibit( bool value = true ); void UpdateTemperatureMonitor( void ); double get_temp( TempType t ) { return temps[(int)t]; } void Pause( void ) { StopPrinting(); } bool SwitchPower( bool on ); bool SelectExtruder( int extruder_no=-1 ); bool SetTemp( TempType type, float value, int extruder_no=-1 ); bool RunExtruder(double extruder_speed, double extruder_length, bool reverse, int extruder_no=-1 ); bool Home( string axis ); bool Move( string axis, double distance, bool relative = true ); bool Goto( string axis, double position ); void alert( const char *message ); void error( const char *message, const char *secondary = NULL ); sigc::signal< void > signal_printing_changed; sigc::signal< void, unsigned long > signal_now_printing; sigc::signal< void > signal_inhibit_changed; sigc::signal< void > signal_temp_changed; //sigc::signal< void, string, RR_logtype > signal_logmessage; sigc::signal< void, Gtk::MessageType, const char *, const char * > signal_alert; sigc::signal< void, SerialState > signal_serial_state_changed; }; // Exception safe guard to stop people printing // GCode while loading it / converting etc. class PrintInhibitor { Printer *printer; public: PrintInhibitor( Printer *p ) : printer ( p ) { printer->Inhibit(); } ~PrintInhibitor() { printer->Inhibit( false ); } }; repsnapper-2.3.2a5/src/printer/printer_serial.cpp000066400000000000000000000446061231531733200221350ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "stdafx.h" #else #define _( t ) t #endif #include #include #include #include #include #ifdef WIN32 #include #else #include #include #include #include #include #include #include #include #include #endif #include "printer_serial.h" PrinterSerial::PrinterSerial( unsigned long max_recv_block_ms ) : max_recv_block_ms( max_recv_block_ms ) { full_command_scratch = new char[ max_command_size + max_command_prefix + max_command_postfix + 10 ]; command_scratch = full_command_scratch + max_command_prefix; full_recv_buffer = new char[ max_command_size + max_command_prefix + 10 ]; recv_buffer = full_recv_buffer + max_command_prefix; #ifdef WIN32 device_handle = INVALID_HANDLE_VALUE; raw_recv = new char[ max_command_size + max_command_prefix + 10 ]; *raw_recv = '\0'; #else device_fd = -1; #endif prev_cmd_line_number = 0; } PrinterSerial::~PrinterSerial() { #ifdef WIN32 if ( device_handle != INVALID_HANDLE_VALUE ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; } #else if ( device_fd >= 0 ) { close( device_fd ); device_fd = -1; } #endif delete [] full_command_scratch; delete [] full_recv_buffer; #ifdef WIN32 delete [] raw_recv; #endif } bool PrinterSerial::TestPort( const string device ) { #ifdef WIN32 HANDLE h; h = CreateFile( device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( h == INVALID_HANDLE_VALUE ) return false; CloseHandle( h ); return true; #else int fd; if ( ( fd = open( device.c_str(), O_RDWR | O_NOCTTY ) ) < 0 ) return false; close( fd ); return true; #endif } vector PrinterSerial::FindPorts() { vector ports; #ifdef WIN32 char name[5]; strncpy( name, "COMx", 5 ); for ( int i = 0; i <= 9; i++ ) { name[3] = i + '0'; if ( TestPort( name ) ) ports.push_back( name ); } return ports; #else DIR *dir; struct dirent *de; if ( ( dir = opendir( "/dev" ) ) == NULL ) return ports; while ( ( de = readdir( dir ) ) ) { if ( strncmp( de->d_name, "ttyUSB", 6 ) == 0 ) ports.push_back( string( "/dev/" ) + de->d_name ); else if ( strncmp( de->d_name, "ttyACM", 6 ) == 0 ) ports.push_back( string( "/dev/" ) + de->d_name ); else if ( strncmp( de->d_name, "cuaU", 4 ) == 0 ) ports.push_back( string( "/dev/" ) + de->d_name ); } closedir( dir ); return ports; #endif } bool PrinterSerial::RawConnect( string device, int baudrate ) { #ifdef WIN32 if ( IsConnected() || device_handle != INVALID_HANDLE_VALUE ) { Disconnect(); if ( device_handle != INVALID_HANDLE_VALUE ) return false; } device_handle = CreateFile( device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( device_handle == INVALID_HANDLE_VALUE ) { char err_str[ 256 ]; snprintf( err_str, 256, _("Error opening port %s"), device.c_str() ); err_str[ 256 ] = '\0'; ostringstream os; os << err_str << " (" << GetLastError() << ")"<< endl; LogError( os.str().c_str() ); return false; } DCB dcb = { 0 }; dcb.DCBlength = sizeof( dcb ); if ( ! GetCommState( device_handle, &dcb ) ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; char err_str[ 256 ]; snprintf( err_str, 256, _("Error getting port %s state"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << " (" << GetLastError() << ")"<< endl; LogError( os.str().c_str() ); return false; } dcb.BaudRate = baudrate; dcb.fBinary = 1; dcb.fParity = 0; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = 0; dcb.fOutX = 0; dcb.fInX = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; if ( ! SetCommState( device_handle, &dcb ) ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; char err_str[ 256 ]; snprintf( err_str, 256, _("Error setting port %s state"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << " (" << GetLastError() << ")"<< endl; LogError( os.str().c_str() ); return false; } COMMTIMEOUTS ct; if ( ! GetCommTimeouts( device_handle, &ct ) ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; char err_str[ 256 ]; snprintf( err_str, 256, _("Error getting port %s timeouts"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << " (" << GetLastError() << ")"<< endl; LogError( os.str().c_str() ); return false; } ct.ReadIntervalTimeout = 5; ct.ReadTotalTimeoutConstant = max_recv_block_ms; ct.ReadTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = max_recv_block_ms; ct.WriteTotalTimeoutMultiplier= 0; if ( ! SetCommTimeouts( device_handle, &ct ) ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; char err_str[ 256 ]; snprintf( err_str, 256, _("Error setting port %s timeouts"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << " (" << GetLastError() << ")"<< endl; LogError( os.str().c_str() ); return false; } *raw_recv = '\0'; #else // Verify speed is valid and convert to posix value speed_t speed = B0; switch ( baudrate ) { case 50: speed = B50; break; case 75: speed = B75; break; case 110: speed = B110; break; case 134: speed = B134; break; case 150: speed = B150; break; case 200: speed = B200; break; case 300: speed = B300; break; case 600: speed = B600; break; case 1200: speed = B1200; break; case 1800: speed = B1800; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; case 230400: speed = B230400; break; default: ostringstream ostr; ostr << "Nonstandard baudrate " << baudrate << endl; LogLine( ostr.str().c_str() ); speed = baudrate; // char err_str[ 256 ]; // snprintf( err_str, 256, _( %d\n"), baudrate ); // if ( err_str[ 254 ] != '\0' ) // err_str[ 254 ] = '\n'; // err_str[ 255 ] = '\0'; //LogError( err_str ); // return false; } if ( IsConnected() || device_fd >= 0 ) { Disconnect(); if ( device_fd >= 0 ) return false; } // Open file if ( ( device_fd = open( device.c_str(), O_RDWR | O_NOCTTY ) ) < 0 ) { int err = errno; char err_str[ 256 ]; snprintf( err_str, 256, _("Error opening port %s"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << ": " << strerror( err ) << endl; LogError( os.str().c_str() ); return false; } // Configure port struct termios attribs; if ( tcgetattr( device_fd, &attribs ) < 0 ) { int err = errno; close( device_fd ); device_fd = -1; char err_str[ 256 ]; snprintf( err_str, 256, _("Error getting port %s state"), device.c_str() ); err_str[ 255 ] = '\0'; ostringstream os; os << err_str << ": " << strerror( err ) << endl; LogError( os.str().c_str() ); return false; } // Use RAW settings, except add ICANON. ICANON makes the port line buffered // and read will return immediately when a newline is received. // HUPCL lowers the modem control lines (hang up) when the port is closed cfmakeraw( &attribs ); attribs.c_lflag |= ICANON; attribs.c_cflag |= HUPCL; if( tcsetattr(device_fd, TCSANOW, &attribs ) < 0 ) { close( device_fd ); device_fd = -1; char err_str[ 256 ]; snprintf( err_str, 256, _("Error enabling port %s raw mode\n"), device.c_str() ); if ( err_str[ 254 ] != '\0' ) err_str[ 254 ] = '\n'; err_str[ 255 ] = '\0'; LogError( err_str ); return false; } // Set port speed if ( cfsetispeed( &attribs, speed ) < 0 || cfsetospeed( &attribs, speed ) < 0 ) { close( device_fd ); device_fd = -1; char err_str[ 256 ]; snprintf( err_str, 256, _("Error setting port %s baudrate to %d\n"), device.c_str(), baudrate ); if ( err_str[ 254 ] != '\0' ) err_str[ 254 ] = '\n'; err_str[ 255 ] = '\0'; LogError( err_str ); return false; } if( tcsetattr(device_fd, TCSANOW, &attribs ) < 0) { close( device_fd ); device_fd = -1; char err_str[ 256 ]; snprintf( err_str, 256, _("Error setting port %s baudrate to %d\n"), device.c_str(), baudrate ); if ( err_str[ 254 ] != '\0' ) err_str[ 254 ] = '\n'; err_str[ 255 ] = '\0'; LogError( err_str ); return false; } #endif char msg[ 256 ]; memcpy( msg, "--- ", 4 ); snprintf( msg + 4, 256 - 4, _("Connected to port %s at %d baud\n"), device.c_str(), baudrate ); if ( msg[ 254 ] != '\0' ) msg[ 254 ] = '\n'; msg[ 255 ] = '\0'; LogLine( msg ); // Reset line number prev_cmd_line_number = 0; return true; } bool PrinterSerial::Connect( string device, int baudrate ) { if ( ! RawConnect( device, baudrate ) ) return false; // Read start line before returning // The printer seems to lock up if it recvs a command before the start // line has been sent RecvLine(); return true; } void PrinterSerial::Disconnect( void ) { #ifdef WIN32 if ( device_handle != INVALID_HANDLE_VALUE ) { CloseHandle( device_handle ); device_handle = INVALID_HANDLE_VALUE; } #else if ( device_fd >= 0 ) { close( device_fd ); device_fd = -1; } #endif } bool PrinterSerial::IsConnected( void ) { #ifdef WIN32 return device_handle != INVALID_HANDLE_VALUE; #else return device_fd >= 0; #endif } bool PrinterSerial::RawReset( void ) { #ifdef WIN32 if ( device_handle == INVALID_HANDLE_VALUE ) return false; if ( ! EscapeCommFunction( device_handle, CLRDTR ) ) return false; if ( ! EscapeCommFunction( device_handle, SETDTR ) ) return false; #else if ( device_fd < 0 ) return false; // First try clear/set DTR if ( ioctl( device_fd, TIOCMBIC, TIOCM_DTR ) || ioctl( device_fd, TIOCMBIS, TIOCM_DTR ) ) { // Finally try setting baud rate to zero struct termios attribs; if ( tcgetattr( device_fd, &attribs ) != 0 ) return false; speed_t orig_speed = cfgetispeed( &attribs ); cfsetispeed( &attribs, B0 ); cfsetospeed( &attribs, B0 ); if ( tcsetattr( device_fd, TCSANOW, &attribs ) != 0 ) return false; cfsetispeed( &attribs, orig_speed ); cfsetospeed( &attribs, orig_speed ); if ( tcsetattr( device_fd, TCSANOW, &attribs ) != 0 ) return false; } #endif // Reset line number prev_cmd_line_number = 0; return true; } bool PrinterSerial::Reset( void ) { if ( ! RawReset() ) return false; // Read start line before returning // The printer seems to lock up if it recvs a command before the start // line has been sent RecvLine(); return true; } char *PrinterSerial::Send( const char *command ) { strncpy( command_scratch, command, max_command_size ); return SendCommand(); } // Sends gcode command. Performs formating and waits for reply. The line starts at command_scratch + max_command_prefix. If buffer_response, the reply is entered into the response_buffer. char *PrinterSerial::SendCommand( void ) { char *formated; char *recvd; bool send_text = true; if ( ( formated = FormatLine() ) == NULL ) { // Printer can't handle blank lines // Don't send them, just return an "ok" response // They won't show up in the log, since no data was actually sent char *loc = recv_buffer; *loc++ = 'o'; *loc++ = 'k'; *loc++ = '\n'; *loc++ = '\0'; return recv_buffer; } while ( true ) { if ( send_text ) { if ( ! SendText( formated ) ) return NULL; } if ( ( recvd = RecvLine() ) == NULL ) return NULL; if ( strncasecmp( recvd, "ok", 2 ) == 0 || strncasecmp( recvd, "!!", 2 ) == 0 ) { return recvd; } if ( strncasecmp( recvd, "rs", 2 ) == 0 || strncasecmp( recvd, "resend:", 7 ) == 0 ) { // Checksum error, resend the line send_text = true; } else { send_text = false; } } } // Formats line of gcode in command_scratch and returns a pointer to the starting character char *PrinterSerial::FormatLine( void ) { char *start = command_scratch; // Add prefix start--; *start = ' '; unsigned long this_line = prev_cmd_line_number + 1; if ( this_line == 0 ) { start--; *start = '0'; } else { unsigned long count; for ( count = this_line; count > 0; count /= 10 ) { start--; *start = ( count % 10 ) + '0'; } } start--; *start = 'N'; // Calculate checksum unsigned char cksum = 0; char *loc; for ( loc = start; *loc != '\n' && *loc != ';' && *loc != '\0' && *loc != '*'; loc++ ) { cksum ^= *loc; } while ( loc[-1] == ' ' || loc[-1] == '\t' ) { loc--; cksum ^= *loc; } if ( loc <= command_scratch ) { // Line was all whitespace and/or comment, nothing to send return NULL; } // Write checksum *loc++ = '*'; if ( cksum >= 100 ) { *loc++ = cksum / 100 + '0'; } if ( cksum >= 10 ) { *loc++ = ( cksum / 10 ) % 10 + '0'; } *loc++ = cksum % 10 + '0'; // Terminate line *loc++ = '\n'; *loc++ = '\0'; prev_cmd_line_number++; return start; } // Sends indicated text exactly. Does not wait for reply. Performs logging. // Text must point mutable memory with 4 bytes available before it bool PrinterSerial::SendText( char *text ) { memcpy( text - 4, "<-- ", 4 ); LogLine( text - 4 ); size_t len = strlen( text ); #ifdef WIN32 DWORD num; while ( len > 0 ) { if ( ! WriteFile( device_handle, text, len, &num, NULL ) ) { LogLine( _("*** Error Writing to port ***\n") ); LogError( _("*** Error Writing to port ***\n") ); return false; } len -= num; text += num; } #else ssize_t num; while ( len > 0 ) { if ( ( num = write( device_fd, text, len ) ) == -1 ) { int err = errno; char msg[ 256 ]; LogLine( _("*** Error Writing to port ***\n") ); snprintf( msg, 250, _("*** Error Writing to port: %s ***\n"), strerror( err ) ); if ( msg[ 248 ] != '\0' ) msg[ 248 ] = '\n'; msg[ 249 ] = '\0'; LogError( msg ); return false; } len -= num; text += num; } #endif return true; } // Waits for a complete line from the port and receives that line into recv_buffer (but not at the start of recv_buffer to make logging easier). Returns pointer to start of recv'd data. Performs logging. char *PrinterSerial::RecvLine( void ) { size_t tot_size = 0; #ifdef WIN32 char *raw_loc = raw_recv; DWORD num; while ( true ) { while ( *raw_loc != '\0' && *raw_loc != '\n' ) raw_loc++; tot_size = raw_loc - raw_recv; if ( *raw_loc == '\n' ) { raw_loc++; tot_size++; break; } if ( tot_size + 20 >= max_command_size ) { LogLine( _("*** Error: Received line too long ***\n") ); LogError( _("*** Error: Received line too long ***\n") ); *raw_loc++ = '\n'; break; } if ( ! ReadFile( device_handle, raw_loc, max_command_size - tot_size - 20, &num, NULL ) ) { LogLine( _("*** Error Reading from port ***\n") ); LogError( _("*** Error Reading from port ***\n") ); return NULL; } raw_loc[ num ] = '\0'; if ( num == 0 ) RecvTimeout(); } memcpy( recv_buffer, raw_recv, tot_size ); recv_buffer[ tot_size ] = '\0'; memmove( raw_recv, raw_recv + tot_size, strlen( raw_recv + tot_size ) + 1 ); #else char *buf = recv_buffer; bool done = false; ssize_t num; struct timeval timeout; fd_set set; // Read the data while ( ! done ) { // Make sure line is not too long if ( tot_size + 20 >= max_command_size ) { LogLine( _("*** Error: Received line too long ***\n") ); LogError( _("*** Error: Received line too long ***\n") ); *buf++ = '\n'; break; } // Use select to allow a read timeout. // If the timeout is reached, call RecvTimeout timeout.tv_sec = 0; timeout.tv_usec = max_recv_block_ms * 1000; FD_ZERO( &set ); FD_SET( device_fd, &set ); select( device_fd + 1, &set, NULL, NULL, max_recv_block_ms == 0 ? NULL : &timeout ); if ( FD_ISSET( device_fd, &set ) ) { // Read the data. Use a loop since Posix does not guarentee that an // entire line will be read at once. //cout << "Reading" << endl; if ( ( num = read( device_fd, buf, max_command_size - tot_size - 20 ) ) == -1 ) { int err = errno; char msg[ 256 ]; LogLine( _("*** Error reading from port ***\n") ); snprintf( msg, 250, _("*** Error reading from port: %s ***\n"), strerror( err ) ); if ( msg[ 248 ] != '\0' ) msg[ 248 ] = '\n'; msg[ 249 ] = '\0'; LogError( msg ); return NULL; } tot_size += num; buf += num; if ( num > 0 && ( buf[-1] == '\n' || buf[-1] == '\r' ) ) { done = true; } } else { RecvTimeout(); } } *buf = '\0'; #endif char *recvd = recv_buffer; // Ignore inital whitespace while ( isspace( *recvd ) ) { recvd++; } // Log the line memcpy( recvd - 4, "--> ", 4 ); LogLine( recvd - 4 ); return recvd; } void PrinterSerial::RecvTimeout( void ) { } void PrinterSerial::LogLine( const char *line ) { cout << line; } void PrinterSerial::LogError( const char *error_line ) { cerr << error_line; } repsnapper-2.3.2a5/src/printer/printer_serial.h000066400000000000000000000063011231531733200215700ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #ifdef WIN32 #include #endif using namespace std; class PrinterSerial { protected: static const unsigned long max_command_size = 1024; static const unsigned long max_command_prefix = 32; static const unsigned long max_command_postfix = 32; const unsigned long max_recv_block_ms; #ifdef WIN32 HANDLE device_handle; #else int device_fd; #endif unsigned long prev_cmd_line_number; char *full_command_scratch; char *command_scratch; char *full_recv_buffer; char *recv_buffer; #ifdef WIN32 char *raw_recv; #endif char *SendCommand( void ); // Sends gcode command. Performs formating and waits for reply. The line starts at command_scratch + max_command_prefix. If buffer_response, the reply is entered into the response_buffer. char *FormatLine( void ); // Formats line of gcode in command_scratch and returns a pointer to the starting character bool SendText( char *text ); // Sends indicated text exactly. Does not wait for reply. Performs logging. char *RecvLine( void ); // Waits for a complete line from the port and receives that line into recv_buffer (but not at the start of recv_buffer to make logging easier). Returns pointer to start of recv'd data. Performs logging. virtual void RecvTimeout( void ); virtual void LogLine( const char *line ); virtual void LogError( const char *error_line ); // Gcodes return: // ok // ok T:xx.x Bxx.x // ok C: X:xx.x Y:xx.x Z:xx.x E:xx.x // rs line_num <- resend this line number // !! <- fatal error, printer is shutting down, disconnect // // comments // The following commands connect and reset without // caling RecvLine() at the end. Calling RecvLine() // is necessary. The ONLY reason to use these functions // is in a derived class that will call RecvLine later // after performing other initalization tasks. bool RawConnect( string device, int baudrate ); bool RawReset( void ); public: PrinterSerial( unsigned long max_recv_block_ms ); virtual ~PrinterSerial(); static bool TestPort( const string device ); static vector FindPorts( void ); virtual bool Connect( string device, int baudrate ); virtual void Disconnect( void ); virtual bool IsConnected( void ); virtual bool Reset( void ); virtual char *Send( const char *command ); }; repsnapper-2.3.2a5/src/printer/printer_serial_test.cpp000066400000000000000000000035141231531733200231650ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "printer_serial.h" #include #include using namespace std; int main( int argc, char *argv[] ) { PrinterSerial ps( 100 ); char command[ 1024 ]; vector ports = PrinterSerial::FindPorts(); for ( unsigned int ind = 0; ind < ports.size(); ind++ ) { cout << "Found port: " << ports[ind] << endl; cout << "Testing: " << PrinterSerial::TestPort( ports[ind] ) << endl; } if ( argc >= 3 ) ps.Connect( argv[1], strtol( argv[2], NULL, 10 ) ); if ( argc >= 2 ) ps.Connect( argv[1], 115200 ); else ps.Connect( ports[0], 115200 ); cout << "Connected" << endl; cout << ps.Send( "M115" ); while ( 1 ) { cin.getline( command, 1024 ); if ( strncasecmp( command, "reset", 1024 ) == 0 ) { if ( ps.Reset() ) cout << "Success" << endl; else cout << "Failure" << endl; continue; } else if ( strncasecmp( command, "quit", 1024 ) == 0 ) break; cout << ps.Send( command ); } ps.Disconnect(); } repsnapper-2.3.2a5/src/printer/test.gcode000066400000000000000000000003501231531733200203550ustar00rootroot00000000000000G28 G1 Z0.5 F100 G1 X100 F1000 G1 Y100 F1000 G1 X10 Y10 F1000 G1 Y50 X10 F1000 G1 X10 Y10 F1000 G1 X20 Y10 F1000 G1 X20 Y20 F1000 G1 X30 Y20 F1000 G1 X30 Y30 F1000 G1 X40 Y40 F1000 G1 X50 Y40 F1000 G1 X50 Y50 F1000 G1 X60 Y50 F1000 repsnapper-2.3.2a5/src/printer/thread.h000066400000000000000000000101521231531733200200140ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_POSIX_THREADS #include typedef pthread_t thread_t; typedef pthread_mutex_t mutex_t; typedef pthread_cond_t cond_t; #define thread_create( thread, start_func, arg ) pthread_create( thread, NULL, start_func, arg ) #define thread_join( thread ) pthread_join( thread, NULL ) #define thread_exit() pthread_exit( NULL ) #define HAS_THREAD_CANCEL #define thread_cancel pthread_cancel #define mutex_init( m ) pthread_mutex_init( m, NULL ) #define mutex_destroy pthread_mutex_destroy #define mutex_lock pthread_mutex_lock #define mutex_unlock pthread_mutex_unlock #define cond_init( c ) pthread_cond_init( c, NULL ) #define cond_destroy pthread_cond_destroy #define cond_wait pthread_cond_wait #define cond_signal pthread_cond_signal #define cond_broadcast pthread_cond_broadcast #else // USE_GLIB_THREADS #include #include #if GLIB_CHECK_VERSION( 2, 32, 0 ) // Glib thread implementation changed 2.32. Use the newer version // if it is available. typedef GThread *thread_t; typedef GMutex mutex_t; typedef GCond cond_t; inline int thread_create( thread_t *thread, void *(*start_func)( void *), void *arg ) { *thread = g_thread_new( "PrinterThread", start_func, arg ); return 0; }; inline int thread_join( thread_t thd ) { g_thread_join( thd ); return 0; }; #define thread_exit() g_thread_exit( NULL ) #define mutex_init g_mutex_init #define mutex_destroy g_mutex_clear inline int mutex_lock( mutex_t *m ) { g_mutex_lock( m ); return 0; }; inline int mutex_unlock( mutex_t *m ) { g_mutex_unlock( m ); return 0; }; #define cond_init g_cond_init #define cond_destroy g_cond_clear inline int cond_wait( cond_t *c, mutex_t *m ) { g_cond_wait( c, m ); return 0; }; inline int cond_signal( cond_t *c ) { g_cond_signal( c ); return 0; }; inline int cond_broadcast( cond_t *c ) { g_cond_broadcast( c ); return 0; }; #else // Glib older than 2.32. Use 2.24 version of pthreads, which was // deprecated in 2.32. typedef GThread *thread_t; typedef GMutex *mutex_t; typedef GCond *cond_t; inline int thread_create( thread_t *thread, void *(*start_func)( void *), void *arg ) { *thread = g_thread_create( start_func, arg, TRUE, NULL ); return 0; }; inline int thread_join( thread_t thd ) { g_thread_join( thd ); return 0; }; #define thread_exit() g_thread_exit( NULL ) inline void mutex_init( mutex_t *m ) { *m = g_mutex_new(); }; #define mutex_destroy( m ) g_mutex_free( *(m) ) inline int mutex_lock( mutex_t *m ) { g_mutex_lock( *m ); return 0; }; inline int mutex_unlock( mutex_t *m ) { g_mutex_unlock( *m ); return 0; }; inline void cond_init( cond_t *c ) { *c = g_cond_new(); }; #define cond_destroy( m ) g_cond_free( *(m) ) inline int cond_wait( cond_t *c, mutex_t *m ) { g_cond_wait( *c, *m ); return 0; }; inline int cond_signal( cond_t *c ) { g_cond_signal( *c ); return 0; }; inline int cond_broadcast( cond_t *c ) { g_cond_broadcast( *c ); return 0; }; #endif #endif #ifdef WIN32 #include typedef struct { unsigned long tv_sec; long tv_nsec; } ntime_t; inline int nsleep( const ntime_t *req ) { Sleep( req->tv_sec * 1000 + ( req->tv_nsec + 999999 ) / 1000000 ); return 0; }; #else #include typedef struct timespec ntime_t; inline int nsleep( const ntime_t *req ) { return nanosleep( req, NULL ); }; #endif repsnapper-2.3.2a5/src/printer/thread_buffer.cpp000066400000000000000000000335101231531733200217030ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "thread_buffer.h" ThreadBuffer::ThreadBuffer( size_t buffer_size, bool is_line_buffered, const ntime_t &nsleep_time, string overflow_indicator, bool use_read_mutex, bool use_write_mutex, unsigned long min_line_len ) : size( buffer_size + 10 + overflow_indicator.length() ), use_write_mutex( use_write_mutex ), overflow( overflow_indicator ), line_buffered( is_line_buffered ), min_line_len( min_line_len ) { read_ptr = write_ptr = buff = new char[ size + 10 ]; mutex_init( &mutex ); if ( use_write_mutex ) mutex_init( &write_mutex ); sleep_time = nsleep_time; last_write_overflowed = false; } ThreadBuffer::~ThreadBuffer() { delete [] buff; mutex_destroy( &mutex ); if ( use_write_mutex ) mutex_destroy( &write_mutex ); } ssize_t ThreadBuffer::SpaceAvailable( void ) { // Determine space remaining in buffer, being sure to always leave room // for the overflow string // 10 is a padding factor to ensure than a simple off by one errors // never cause the write pointer to advance pass the read pointer return size - ( ( write_ptr - read_ptr ) % size ) - 10 - overflow.length(); } bool ThreadBuffer::Write( const char *data, bool wait, ssize_t datalen ) { // Length check if ( datalen < 0 ) datalen = strlen( data ); if ( (size_t)datalen > size - 10 - overflow.length() - 5 ) { return false; } // Lock mutex(es) if ( use_write_mutex ) if ( mutex_lock( &write_mutex ) != 0 ) return false; if ( mutex_lock( &mutex ) != 0 ) { if ( use_write_mutex ) mutex_unlock( &write_mutex ); return false; } // Determine if enough space is available // If the buffer is line buffered and the data to write does not // end in a newline, one will be added. // datalen is the length of provided data // fulldatalen is the length including the appended newline ssize_t fulldatalen = datalen; if ( line_buffered && data[ datalen - 1 ] != '\n' ) fulldatalen++; if ( fulldatalen > SpaceAvailable() ) { if ( wait ) { // Wait until enough space is available while ( fulldatalen > SpaceAvailable() ) { mutex_unlock( &mutex ); nsleep( &sleep_time ); mutex_lock( &mutex ); } } else if ( last_write_overflowed || overflow.length() == 0 ) { // Wrote overflow string last time, don't write it again, just give up mutex_unlock( &mutex ); if ( use_write_mutex ) mutex_unlock( &write_mutex ); return false; } else { // Write the overflow string fulldatalen = datalen = overflow.length(); data = overflow.c_str(); if ( line_buffered && data[ datalen - 1 ] != '\n' ) fulldatalen++; last_write_overflowed = true; } } // Determine if the new data "wraps around" at the end of the buffer memory // space. The variable split contains the number of bytes to write before // the end of the memory space. size_t split = datalen; char *new_write_ptr = write_ptr + fulldatalen; char *old_write_ptr = write_ptr; if ( new_write_ptr >= buff + size ) { new_write_ptr -= size; } if ( write_ptr + datalen >= buff + size ) { split = buff - write_ptr + size; } // First change the data memcpy( write_ptr, data, split ); memcpy( buff, &data[split], datalen - split ); // If a newline needs appended, add it now if ( fulldatalen > datalen ) { if ( new_write_ptr == buff ) buff[ size - 1 ] = '\n'; else new_write_ptr[ -1 ] = '\n'; } // Next atomically change the write pointer write_ptr = new_write_ptr; // Determine if the buffer was possibly empty somewhere in the process // Since reading happens async to writing, data could have been read out // immediately before the write pointer update. char *final_read_ptr = read_ptr; bool was_empty = false; if ( write_ptr < old_write_ptr ) was_empty = final_read_ptr >= old_write_ptr || final_read_ptr <= write_ptr; else was_empty = final_read_ptr >= old_write_ptr && final_read_ptr <= write_ptr; if ( was_empty ) WroteToEmpty(); // Unlock mutex(es) mutex_unlock( &mutex ); if ( use_write_mutex ) mutex_unlock( &write_mutex ); return true; } bool ThreadBuffer::DataAvailable( void ) { if ( min_line_len == 0 ) return read_ptr != write_ptr; ptrdiff_t avail = ( write_ptr - read_ptr ) % size; return avail >= (ptrdiff_t) min_line_len; } char *ThreadBuffer::ReadRawData( string *str, char *data, char *read_start, unsigned long length, bool null_terminate ) { // Determine if the new data "wraps around" at the end of the buffer memory // space. The variable split contains the number of bytes to write before // the end of the memory space. size_t split = length; char *read_end = read_start + length; if ( read_end >= buff + size ) { read_end -= size; split = buff + size - read_start; } // Read the data if ( str == NULL ) { memcpy( data, read_start, split ); memcpy( &data[split], buff, length - split ); if ( null_terminate ) data[ length ] = '\0'; } else { try { str->assign( read_start, split ); str->append( buff, length - split ); } catch (...) { mutex_unlock( &mutex ); throw; } } return read_end; } size_t ThreadBuffer::Read( string *str, char *data, size_t max_len, bool wait, char *line_start ) { // Lock mutex if ( mutex_lock( &mutex ) != 0 ) return false; // Determine if data is available if ( ! DataAvailable() ) { if ( wait ) { WaitOnRead(); } else { mutex_unlock( &mutex ); return 0; } } // Atomically grab the write pointer for use in the rest of the function // Any data written after this grab will not be read during this call char *init_write_ptr = write_ptr; // Determine the number of bytes to read ptrdiff_t bytes_to_read; char *new_read_ptr; char *read_start = read_ptr; if ( line_buffered ) { // Find first newline, accounting for wrap around bytes_to_read = min_line_len; char *loc = read_ptr + min_line_len; if ( loc >= buff + size ) loc -= size; while ( loc != init_write_ptr ) { bytes_to_read++; if ( *loc == '\n' ) break; if ( ++loc >= buff + size ) loc = buff; } } else { bytes_to_read = init_write_ptr - read_ptr; while ( bytes_to_read < 0 ) bytes_to_read += size; } new_read_ptr = read_ptr + bytes_to_read; if ( new_read_ptr >= buff + size ) new_read_ptr -= size; // Read min_line_len bytes to line_start, if requested if ( min_line_len > 0 && line_start != NULL ) { read_start = ReadRawData( NULL, line_start, read_start, min_line_len, false ); bytes_to_read -= min_line_len; } // Truncate read to max length if ( str == NULL && (size_t) bytes_to_read > max_len ) { bytes_to_read = max_len; if ( ! line_buffered ) { new_read_ptr = read_start + bytes_to_read; if ( new_read_ptr >= buff + size ) new_read_ptr -= size; } } // Read the data ReadRawData( str, data, read_start, bytes_to_read ); // Atomically update the read pointer read_ptr = new_read_ptr; if ( last_write_overflowed && SpaceAvailable() > 0 ) { // Turn overflow message back on last_write_overflowed = false; } // Unlock mutex mutex_unlock( &mutex ); return bytes_to_read; } size_t ThreadBuffer::Read( char *data, size_t max_len, bool wait ) { return Read( NULL, data, max_len, wait ); } string ThreadBuffer::Read( bool wait ) { string str; Read( &str, NULL, 0, wait ); return str; } void ThreadBuffer::WaitOnRead( void ) { while ( read_ptr == write_ptr ) { mutex_unlock( &mutex ); nsleep( &sleep_time ); mutex_lock( &mutex ); } } void ThreadBuffer::WroteToEmpty( void ) { } void ThreadBuffer::Flush( void ) { mutex_lock( &mutex ); read_ptr = write_ptr; mutex_unlock( &mutex ); } SignalingThreadBuffer::SignalingThreadBuffer( size_t buffer_size, bool is_line_buffered, const ntime_t &nsleep_time, string overflow_indicator, bool use_read_mutex, bool use_write_mutex, unsigned long min_line_length ) : ThreadBuffer( buffer_size, is_line_buffered, nsleep_time, overflow_indicator, use_read_mutex, use_write_mutex, min_line_length ) { cond_init( &signal_cond ); } SignalingThreadBuffer::~SignalingThreadBuffer() { cond_destroy( &signal_cond ); } void SignalingThreadBuffer::WaitOnRead( void ) { while ( read_ptr == write_ptr ) { cond_wait( &signal_cond, &mutex ); } } void SignalingThreadBuffer::WroteToEmpty( void ) { cond_broadcast( &signal_cond ); } ThreadBufferReturnData::ThreadBufferReturnData( size_t buffer_size, const ntime_t &nsleep_time, string overflow_indicator, bool use_read_mutex, bool use_write_mutex ) : ThreadBuffer( buffer_size, true, nsleep_time, overflow_indicator, use_read_mutex, use_write_mutex, sizeof( ReturnData * ) ) { mutex_init( &return_mutex ); cond_init( &return_cond ); } ThreadBufferReturnData::~ThreadBufferReturnData() { mutex_destroy( &return_mutex ); cond_destroy( &return_cond ); } bool ThreadBufferReturnData::Write( const char *data, bool wait, ssize_t datalen, ReturnData **return_data ) { unsigned long num_lines = 0; const char *loc, *line_start; string extended_data; ReturnData *ret_data = NULL; if ( return_data != NULL ) { ret_data = new ReturnData( &return_cond, &return_mutex ); } if ( datalen < 0 ) datalen = strlen( data ); for ( line_start = loc = data; loc - data < datalen; loc++ ) { if ( *loc == '\n' ) { extended_data.append( ( char * ) &ret_data, min_line_len ); extended_data.append( line_start, loc - line_start + 1 ); line_start = loc + 1; num_lines++; } } if ( loc == data || loc[ -1 ] != '\n' ) { extended_data.append( ( char * ) &ret_data, min_line_len ); extended_data.append( line_start, loc - line_start ); extended_data.append( 1, '\n' ); num_lines++; } if ( ret_data != NULL ) { ret_data->SetLineCount( num_lines ); *return_data = ret_data; } bool ret = ThreadBuffer::Write( extended_data.c_str(), wait, extended_data.length() ); if ( ! ret && ret_data != NULL ) { *return_data = NULL; } return ret; } size_t ThreadBufferReturnData::Read( char *data, size_t max_len, bool wait, ReturnData **return_data ) { ReturnData *ret_data = NULL; ssize_t ret = ThreadBuffer::Read( NULL, data, max_len, wait, (char *) &ret_data ); if ( return_data != NULL ) *return_data = ret_data; return ret; } string ThreadBufferReturnData::Read( bool wait, ReturnData **return_data ) { ReturnData *ret_data; string str; ThreadBuffer::Read( &str, NULL, 0, wait, (char *) &ret_data ); if ( return_data != NULL ) *return_data = ret_data; return str; } void ThreadBufferReturnData::Flush( void ) { // Need to all the ReturnData elements in the buffer by returning blank lines mutex_lock( &mutex ); char *init_write_ptr = write_ptr; char *read_start = read_ptr; ReturnData *ret_data; bool at_line_start = true; if ( read_start > init_write_ptr ) { while ( read_start < buff + size ) { if ( at_line_start ) { ReadRawData( NULL, (char*) &ret_data, read_start, min_line_len, false ); if ( ret_data != NULL ) ret_data->AddLine( "\n" ); read_start += min_line_len; at_line_start = false; } else { at_line_start = *read_start == '\n'; read_start++; } } read_start -= size; } while ( read_start < init_write_ptr ) { if ( at_line_start ) { ReadRawData( NULL, (char*) &ret_data, read_start, min_line_len, false ); if ( ret_data != NULL ) ret_data->AddLine( "\n" ); read_start += min_line_len; at_line_start = false; } else { at_line_start = *read_start == '\n'; read_start++; } } read_ptr = init_write_ptr; mutex_unlock( &mutex ); } bool ThreadBufferReturnData::WaitForReturnData( ReturnData &return_data ) { if ( mutex_lock( &return_mutex ) != 0 ) return false; while ( return_data.LinesRemaining() > 0 ) { cond_wait( &return_cond, &return_mutex ); } mutex_unlock( &return_mutex ); return true; } ThreadBufferReturnData::ReturnData::ReturnData( cond_t *return_cond, mutex_t *return_mutex, bool use_write_mutex ) : return_cond( return_cond ), return_mutex( return_mutex ) { mutex_init( &write_mutex ); } ThreadBufferReturnData::ReturnData::~ReturnData() { mutex_destroy( &write_mutex ); } void ThreadBufferReturnData::ReturnData::SetLineCount( unsigned long line_count ) { lines_remaining = line_count; } unsigned long ThreadBufferReturnData::ReturnData::LinesRemaining( void ) { return lines_remaining; } void ThreadBufferReturnData::ReturnData::AddLine( const char *line ) { mutex_lock( &write_mutex ); try { data.append( line ); } catch (...) { mutex_unlock( &write_mutex ); throw; } mutex_lock( return_mutex ); lines_remaining--; if ( lines_remaining == 0 ) cond_broadcast( return_cond ); mutex_unlock( return_mutex ); mutex_unlock( &write_mutex ); } string ThreadBufferReturnData::ReturnData::GetData( void ) { return data; } repsnapper-2.3.2a5/src/printer/thread_buffer.h000066400000000000000000000103731231531733200213520ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include "thread.h" using namespace std; // These classes buffer string data between threads. One or more threads write // to the buffer and one or more threads can read from the buffer. // Options exist to drop write data if buffer is full or to read the // empty string if no data is available. // The additional write mutex is usefull if multple threads are writting // to the buffer continuiously because it tends to make the write operations // more fair. The code is fully thread-safe without this parameter. class ThreadBuffer { protected: const size_t size; const bool use_write_mutex; char *buff; char *read_ptr; char *write_ptr; mutex_t mutex; mutex_t write_mutex; const string overflow; bool last_write_overflowed; ntime_t sleep_time; const bool line_buffered; const unsigned long min_line_len; ssize_t SpaceAvailable( void ); virtual void WaitOnRead( void ); virtual void WroteToEmpty( void ); char *ReadRawData( string *str, char *data, char *read_start, unsigned long length, bool null_terminate = true ); // Copys data from circular buffer, wrapping when necessary. size_t Read( string *str, char *data, size_t max_len, bool wait, char *line_start = NULL ); // Generic function, returns value in str, unless it is NULL, then returns value into data. // max_len applies only to data, if used. str can return unlimited length. public: ThreadBuffer( size_t buffer_size, bool is_line_buffered, const ntime_t &nsleep_time, string overflow_indicator = "", bool use_read_mutex = true, bool use_write_mutex = true, unsigned long min_line_len = 0 ); virtual ~ThreadBuffer(); virtual bool Write( const char *data, bool wait, ssize_t datalen = -1 ); virtual size_t Read( char *data, size_t max_len, bool wait ); virtual string Read( bool wait ); virtual bool DataAvailable( void ); virtual void Flush( void ); }; class SignalingThreadBuffer : public ThreadBuffer { protected: cond_t signal_cond; virtual void WaitOnRead( void ); virtual void WroteToEmpty( void ); public: SignalingThreadBuffer( size_t buffer_size, bool is_line_buffered, const ntime_t &nsleep_time, string overflow_indicator = "", bool use_read_mutex = true, bool use_write_mutex = true, unsigned long min_line_len = 0 ); virtual ~SignalingThreadBuffer(); }; class ThreadBufferReturnData : public ThreadBuffer { public: class ReturnData { private: mutex_t write_mutex; cond_t *return_cond; mutex_t *return_mutex; unsigned long lines_remaining; string data; public: ReturnData( cond_t *return_cond, mutex_t *return_mutex, bool use_write_mutex = true ); ~ReturnData(); void SetLineCount( unsigned long line_count ); unsigned long LinesRemaining( void ); void AddLine( const char *line ); string GetData( void ); }; protected: cond_t return_cond; mutex_t return_mutex; public: ThreadBufferReturnData( size_t buffer_size, const ntime_t &nsleep_time, string overflow_indicator = "", bool use_read_mutex = true, bool use_write_mutex = true ); virtual ~ThreadBufferReturnData(); virtual bool Write( const char *data, bool wait, ssize_t datalen = -1, ReturnData **return_data = NULL ); virtual size_t Read( char *data, size_t max_len, bool wait, ReturnData **return_data = NULL ); virtual string Read( bool wait, ReturnData **return_data = NULL ); virtual void Flush( void ); virtual bool WaitForReturnData( ReturnData &return_data ); }; repsnapper-2.3.2a5/src/printer/thread_buffer_test.cpp000066400000000000000000000053071231531733200227450ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "thread_buffer.h" #include #include //#define USE_RET_DATA const ntime_t ns = { 10, 100 * 1000 * 1000 }; #ifndef USE_RET_DATA //ThreadBuffer tb( 50, 1, ns, "*overflow*", false, false ); //ThreadBuffer tb( 20, false, ns, "\n*** Log overflow ***\n\n", true, false ); SignalingThreadBuffer tb( 50, 1, ns, "*overflow*", false, false ); #else ThreadBufferReturnData tb( 50, ns, "*overflow*", true, true ); #endif void *Reader( void * ) { string str; #ifdef USE_RET_DATA char ret[1024]; int count = 0; ThreadBufferReturnData::ReturnData *ret_data; #endif cout << "Type commands seperated by newlines" << endl; cout << "Reponses start 10 seconds after first entry" << endl; cout << "with 3 seconds between sucessive reads" << endl; #ifdef USE_RET_DATA cout << "Use a semicolon to seperate reply bundles" << endl; #endif while ( 1 ) { #ifndef USE_RET_DATA str = tb.Read( true ); #else str = tb.Read( true, &ret_data ); #endif cout << "Read: \"" << str << "\"" << endl; #ifdef USE_RET_DATA if ( ret_data == NULL ) { cout << "Read has null ret_data" << endl; } else { snprintf( ret, 1000, "*ret: %d*\n", count++ ); ret_data->AddLine( ret ); } #endif ntime_t nt = { 1, 0 }; nsleep( &nt ); } return NULL; } int main( void ) { char line[ 1024 + 10 ]; thread_t thread; #ifdef USE_RET_DATA ThreadBufferReturnData::ReturnData *ret_data; #endif thread_create( &thread, Reader, NULL ); while ( 1 ) { #ifndef USE_RET_DATA cin.getline( line, 1024 ); tb.Write( line, false ); #else cin.getline( line, 1024, ';' ); tb.Write( line, false, -1, &ret_data ); if ( ret_data == NULL ) { cout << "Write has null ret_data" << endl; } else { tb.WaitForReturnData( *ret_data ); cout << "Return: " << ret_data->GetData() << endl; } #endif } return 0; } repsnapper-2.3.2a5/src/printer/threaded_printer_serial.cpp000066400000000000000000000404711231531733200237710ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "stdafx.h" #else #define _( t ) t #endif #include #include #include #include #include "threaded_printer_serial.h" const ntime_t ThreadedPrinterSerial::command_buffer_sleep = { 0, 100 * 1000 * 1000 }; const ntime_t ThreadedPrinterSerial::response_buffer_sleep = { 0, 10 * 1000 * 1000 }; const ntime_t ThreadedPrinterSerial::log_buffer_sleep = { 0, 10 * 1000 * 1000 }; const ntime_t ThreadedPrinterSerial::helper_thread_sleep = { 0, 100 * 1000 * 1000 }; ThreadedPrinterSerial::ThreadedPrinterSerial() : PrinterSerial( helper_thread_sleep.tv_nsec / 1000 / 1000 ), command_buffer( command_buffer_size, command_buffer_sleep, "", false, true ), response_buffer( response_buffer_size, true, response_buffer_sleep, "", true, false ), log_buffer( log_buffer_size, false, log_buffer_sleep, _("\n*** Log overflow ***\n\n"), true, false ), error_buffer( log_buffer_size, true, log_buffer_sleep, _("\n*** Error Log overflow ***\n\n"), true, false ) { request_print = is_printing = printing_complete = false; printer_commands = NULL; pc_lines_printed = 0; pc_bytes_printed = 0; pc_stop_line = 0; inhibit_count = 0; mutex_init( &pc_mutex ); mutex_init( &pc_cond_mutex ); cond_init( &pc_cond ); helper_active = false; helper_cancel = false; return_data = NULL; } ThreadedPrinterSerial::~ThreadedPrinterSerial() { if ( helper_active ) { mutex_lock( &pc_cond_mutex ); helper_cancel = true; mutex_unlock( &pc_cond_mutex ); thread_join( helper_thread ); helper_active = false; } mutex_destroy( &pc_mutex ); mutex_destroy( &pc_cond_mutex ); cond_destroy( &pc_cond ); if ( printer_commands != NULL ) delete [] printer_commands; } bool ThreadedPrinterSerial::Connect( string device, int baudrate ) { // Open Serial Port if ( ! PrinterSerial::RawConnect( device, baudrate ) ) return false; // Clear printer_commands if ( printer_commands != NULL ) { delete [] printer_commands; printer_commands = NULL; } // Clear/Flush buffers command_buffer.Flush(); response_buffer.Flush(); helper_cancel = false; // Start thread int rc; if ( ( rc = thread_create( &helper_thread, HelperMainStatic, this ) ) != 0 ) { PrinterSerial::Disconnect(); ostringstream os; os << _("Error connecting to printer") << ": "; os << _("Error creating serial helper thread") << ": "; os << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } helper_active = true; return true; } void ThreadedPrinterSerial::Disconnect( void ) { StopPrinting( true ); if ( helper_active ) { mutex_lock( &pc_cond_mutex ); helper_cancel = true; mutex_unlock( &pc_cond_mutex ); thread_join( helper_thread ); helper_active = false; } command_buffer.Flush(); PrinterSerial::Disconnect(); } bool ThreadedPrinterSerial::IsConnected( void ) { return helper_active && PrinterSerial::IsConnected(); } bool ThreadedPrinterSerial::Reset( void ) { StopPrinting( true ); if ( ! IsConnected() ) return false; if ( helper_active ) { mutex_lock( &pc_cond_mutex ); helper_cancel = true; mutex_unlock( &pc_cond_mutex ); thread_join( helper_thread ); helper_active = false; } command_buffer.Flush(); response_buffer.Flush(); bool ret = PrinterSerial::RawReset(); helper_cancel = false; // Start thread int rc; if ( ( rc = thread_create( &helper_thread, HelperMainStatic, this ) ) != 0 ) { PrinterSerial::Disconnect(); ostringstream os; os << _("Error reseting printer") << ": "; os << _("Error creating serial helper thread") << ": "; os << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } helper_active = true; return ret; } bool ThreadedPrinterSerial::StartPrinting( string commands, unsigned long start_line, unsigned long stop_line ) { char *commands_copy; int rc; size_t pos; unsigned long count; unsigned long lines_printed; unsigned long bytes_printed; for ( pos = -1, count = 1; count < start_line; count++ ) { if ( ( pos = commands.find( '\n', pos + 1 ) ) == string::npos ) { char err_buf[ 1024 ]; snprintf( err_buf, 1024, _("Error: Cannot start print at line %lu since Gcode only contains %lu lines\n"), start_line, count ); if ( err_buf[ 1022 ] != '\0' ) err_buf[ 1022 ] = '\n'; err_buf[ 1023 ] = '\0'; LogError( err_buf ); return false; } } bytes_printed = pos + 1; lines_printed = start_line > 0 ? start_line - 1 : 0; while ( count < stop_line ) { if ( ( pos = commands.find( '\n', pos + 1 ) ) == string::npos ) { if ( commands[ commands.length() - 1 ] != '\n' ) count++; break; } count++; } stop_line = count; // Allocate memory for commands size_t len; len = commands.length(); commands_copy = new char[ len + 10 ]; memcpy( commands_copy, commands.c_str(), len + 1 ); // Make sure we are connected to a printer if ( ! IsConnected() ) { delete [] commands_copy; ostringstream os; os << _("Error starting print") << ": " << _("Printer connection not established") << endl; LogError( os.str().c_str() ); return false; } // Lock pc_mutex if ( ( rc = mutex_lock( &pc_mutex ) ) != 0 ) { delete [] commands_copy; ostringstream os; os << _("Error starting print") << ": pc_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } // Lock the cond mutex if ( ( rc = mutex_lock( &pc_cond_mutex ) ) != 0 ) { delete [] commands_copy; mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error starting print") << ": pc_cond_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } if ( inhibit_count > 0 ) { delete [] commands_copy; mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); return false; } // Make sure we are not already printing if ( is_printing ) { request_print = false; if ( ( rc = cond_wait( &pc_cond, &pc_cond_mutex ) ) !=0 ) { delete [] commands_copy; mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error starting print") << ": cond_wait: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } } // Ready to start printing, set the variables if ( printer_commands != NULL ) delete [] printer_commands; printer_commands = commands_copy; pc_lines_printed = lines_printed; pc_bytes_printed = bytes_printed; pc_stop_line = stop_line; // Request printing request_print = true; if ( ( rc = cond_wait( &pc_cond, &pc_cond_mutex ) ) !=0 ) { delete [] commands_copy; mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error starting print") << ": cond_wait: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } // Unlock mutexes mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); return true; } bool ThreadedPrinterSerial::IsPrinting() { return is_printing && ! printing_complete; } bool ThreadedPrinterSerial::StopPrinting( bool wait ) { int rc; if ( ! IsConnected() ) { return true; } if ( ( rc = mutex_lock( &pc_mutex ) ) != 0 ) { ostringstream os; os << _("Error stopping print") << ": pc_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } if ( ( rc = mutex_lock( &pc_cond_mutex ) ) != 0 ) { mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error stopping print") << ": pc_cond_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } request_print = false; if ( wait && is_printing ) { if ( ( rc = cond_wait( &pc_cond, &pc_cond_mutex ) ) !=0 ) { mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error stopping print") << ": cond_wait: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } } mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); return true; } bool ThreadedPrinterSerial::ContinuePrinting( bool wait ) { int rc; if ( printer_commands == NULL ) { ostringstream os; os << _("Error continuing print") << ": "; os << _("No stopped print to continue") << endl; LogError( os.str().c_str() ); return false; } if ( ( rc = mutex_lock( &pc_mutex ) ) != 0 ) { ostringstream os; os << _("Error continuing print") << ": pc_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } if ( ! IsConnected() ) { mutex_unlock( &pc_mutex ); return false; } if ( ( rc = mutex_lock( &pc_cond_mutex ) ) != 0 ) { mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error continuing print") << ": pc_cond_mutex: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } if ( inhibit_count > 0 ) { mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); return false; } request_print = true; if ( wait && ! is_printing ) { if ( ( rc = cond_wait( &pc_cond, &pc_cond_mutex ) ) !=0 ) { mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); ostringstream os; os << _("Error continuing print") << ": cond_wait: " << strerror( rc ) << endl; LogError( os.str().c_str() ); return false; } } mutex_unlock( &pc_cond_mutex ); mutex_unlock( &pc_mutex ); return true; } void ThreadedPrinterSerial::Inhibit( bool value ) { mutex_lock( &pc_cond_mutex ); if ( value ) inhibit_count++; else if ( inhibit_count > 0 ) inhibit_count--; mutex_unlock( &pc_cond_mutex ); } bool ThreadedPrinterSerial::IsInhibited( void ) { mutex_lock( &pc_cond_mutex ); bool inhib = inhibit_count > 0; mutex_unlock( &pc_cond_mutex ); return inhib; } unsigned long ThreadedPrinterSerial::GetPrintingProgress( unsigned long *bytes_printed ) { unsigned long lines; unsigned long bytes; mutex_lock( &pc_cond_mutex ); lines = pc_lines_printed; bytes = pc_bytes_printed; mutex_unlock( &pc_cond_mutex ); if ( bytes_printed != NULL ) *bytes_printed = bytes; return lines; } unsigned long ThreadedPrinterSerial::GetTotalPrintingLines( void ) { unsigned long lines; mutex_lock( &pc_cond_mutex ); lines = pc_stop_line; mutex_unlock( &pc_cond_mutex ); return lines; } bool ThreadedPrinterSerial::Send( string command ) { return command_buffer.Write( command.c_str(), true ); } string ThreadedPrinterSerial::SendAndWaitResponse( string command ) { ThreadBufferReturnData::ReturnData *ret_data = NULL; if ( ! command_buffer.Write( command.c_str(), true, -1, &ret_data ) ) return ""; if ( ret_data == NULL ) return ""; if ( ! command_buffer.WaitForReturnData( *ret_data ) ) { delete return_data; return ""; } string str = ret_data->GetData(); delete ret_data; return str; } string ThreadedPrinterSerial::ReadResponse( bool wait ) { return response_buffer.Read( wait ); } string ThreadedPrinterSerial::ReadLog( bool wait ) { return log_buffer.Read( wait ); } string ThreadedPrinterSerial::ReadErrorLog( bool wait ) { return error_buffer.Read( wait ); } //////////////////////////////////////////////////////////////////////////// // Helper Thread Funcitons //////////////////////////////////////////////////////////////////////////// void *ThreadedPrinterSerial::HelperMainStatic( void *arg ) { ThreadedPrinterSerial *serial = ( ThreadedPrinterSerial * ) arg; return serial->HelperMain(); } void *ThreadedPrinterSerial::HelperMain( void ) { // Read start line before continuing // The printer seems to lock up if it recvs a command before the start // line has been sent RecvLine(); // Sleep for 10 ms ntime_t nts = { 0, 10 * 1000 * 1000 }; nsleep( &nts ); // Send version request command strncpy( command_scratch, "M115\n", 6 ); SendCommand( false ); while ( true ) { if ( return_data != NULL ) return_data->AddLine( _("**Internal Error\n") ); return_data = NULL; CheckPrintingState(); if ( command_buffer.Read( command_scratch, max_command_size, false, &return_data ) > 0 ) { SendCommand( true ); } else if ( IsPrinting() ) { SendNextPrinterCommand(); } else { nsleep( &helper_thread_sleep ); } } return NULL; } void ThreadedPrinterSerial::CheckPrintingState( void ) { mutex_lock( &pc_cond_mutex ); if ( helper_cancel ) { helper_cancel = false; mutex_unlock( &pc_cond_mutex ); if ( return_data != NULL ) return_data->AddLine( _("**Connection closed\n") ); return_data = NULL; thread_exit(); } if ( request_print != is_printing ) { is_printing = request_print; printing_complete = false; cond_broadcast( &pc_cond ); } mutex_unlock( &pc_cond_mutex ); } void ThreadedPrinterSerial::SendNextPrinterCommand( void ) { unsigned long datalen; bool truncated = false; mutex_lock( &pc_cond_mutex ); // Find the bounds of the next command const char *start = printer_commands + pc_bytes_printed; const char *stop; for ( stop = start; *stop != '\n' && *stop != '\0'; stop++ ) ; datalen = stop - start; if ( datalen > max_command_size - 2 ) { datalen = max_command_size - 2; truncated = true; } // Copy command to scratch buffer. Always add a newline. memcpy( command_scratch, start, datalen ); char *loc = command_scratch + datalen; *loc++ = '\n'; *loc++ = '\0'; // Update status pc_lines_printed++; pc_bytes_printed = stop - printer_commands + ( ( *stop == '\n' ) ? 1 : 0 ); // Update printing complete if ( *stop == '\0' || pc_lines_printed >= pc_stop_line ) printing_complete = true; mutex_unlock( &pc_cond_mutex ); if ( truncated ) { char warn[ 100 ]; snprintf( warn, 99, _("*** Warning: Truncated long printer command at line %lu\n"), pc_lines_printed ); if ( warn[ 98 ] != '\0' ) warn[ 98 ] = '\n'; warn[ 99 ] = '\0'; LogLine( warn ); LogError( warn ); } // Send the command and wait for response SendCommand( false ); } void ThreadedPrinterSerial::SendCommand( bool buffer_response ) { // Don't send blank lines char *recvd = PrinterSerial::SendCommand(); if ( recvd == NULL ) { if ( return_data != NULL ) return_data->AddLine( _("**Error sending line\n") ); return_data = NULL; return; } if ( strncasecmp( recvd, "!!", 2 ) == 0 ) { // !! Fatal Error response_buffer.Write( recvd, true ); if ( return_data != NULL ) return_data->AddLine( _("**Fatal Error\n") ); return_data = NULL; helper_active = false; Disconnect(); // This is safe. With helper active false, no mutexes are needed and no threads are killed. thread_exit(); } if ( return_data != NULL ) { return_data->AddLine( recvd ); return_data = NULL; } else if ( buffer_response ) { // buffer resposne if it is "interesting", that is if it is more than // just the two letter "ok" reply followed by white space. char *loc; for ( loc = recvd + 2; *loc != ' '; loc++ ) ; if ( *loc != '\n' ) response_buffer.Write( recvd, false ); } } void ThreadedPrinterSerial::RecvTimeout( void ) { CheckPrintingState(); } // Log the line. The provided line should end in a newline character. void ThreadedPrinterSerial::LogLine( const char *line ) { log_buffer.Write( line, false ); } // Log error the line. The provided line should end in a newline character. void ThreadedPrinterSerial::LogError( const char *error_line ) { error_buffer.Write( error_line, false ); } repsnapper-2.3.2a5/src/printer/threaded_printer_serial.h000066400000000000000000000140341231531733200234320ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include "thread.h" #include "thread_buffer.h" #include "printer_serial.h" using namespace std; class ThreadedPrinterSerial : protected PrinterSerial { static const unsigned long command_buffer_size = 8192; static const unsigned long response_buffer_size = 4096; static const unsigned long log_buffer_size = 8192; static const ntime_t command_buffer_sleep; static const ntime_t response_buffer_sleep; static const ntime_t log_buffer_sleep; static const ntime_t helper_thread_sleep; // Rules: // request_print, is_printing, and printer_commands are initialized to NULL // To stop printing, thread must lock the mutex, set request_print to false // and wait for the helper to signal on pc_cond. Finally, release the // mutex. // To start printing, lock the mutex, if is_printing is true, stop printing // per the above steps. Next, set printer commands to the desired commands // and clear ps_status. Then, set request_print to true and wait for // the helper to signal on pc_cond. Finally, release the mutex. // For the purpose of status bars and status lights, // the values of is_printing and pc_status can be examined without needing // to lock the mutex. // // Helper: // if request_print is different than is_printing, aquire the mutex, // set is_printing to match request_print, signal on pc_cond, and relase // the mutex. // < // if is_printing, send the next command from printer_commands. Do NOT // need to lock the mutex. mutex_t pc_mutex; bool request_print; // set by main thread(s), pc_mutex required bool is_printing; // set by helper, pc_cond_mutex required bool printing_complete; // set by helper, no mutex required cond_t pc_cond; // signaled by helper, pc_mutex and pc_cond_mutex required mutex_t pc_cond_mutex; const char *printer_commands; // set by main thread(s), pc_mutex required unsigned long pc_lines_printed; // when is_printing is false, set by main thread(s), pc_mutex required. When is_printing is true, set by helper, pc_mutex requried unsigned long pc_bytes_printed; // when is_printing is false, set by main thread(s), pc_mutex required. When is_printing is true, set by helper, pc_mutex required unsigned long pc_stop_line; // set by main thread(s), pc_mutex required int inhibit_count; // set by main thread(s), pc_cond_mutex required ThreadBufferReturnData command_buffer; SignalingThreadBuffer response_buffer; ThreadBuffer log_buffer; ThreadBuffer error_buffer; bool helper_active; thread_t helper_thread; bool helper_cancel; ThreadBufferReturnData::ReturnData *return_data; void CheckPrintingState( void ); // Check if main thread is requesting printing and set helper thread switches accordingly void SendNextPrinterCommand( void ); void SendCommand( bool buffer_response ); void RecvTimeout( void ); void LogLine( const char *line ); // Log the line. The provided line should end in a newline character. void LogError( const char *error_line ); // Log the error. The provided line should end in a newline character. static void *HelperMainStatic( void *arg ); void *HelperMain( void ); public: ThreadedPrinterSerial(); virtual ~ThreadedPrinterSerial(); // Connect to or disconnect from a printer virtual bool Connect( string device, int baudrate ); virtual void Disconnect( void ); virtual bool IsConnected( void ); virtual bool Reset( void ); // Start printing gcode // Commands are sent one at a time in the background // Send and SendAndWaitResponse can safely be sent // while printing. virtual bool StartPrinting( string commands, unsigned long start_line = 1, unsigned long stop_line = ULONG_MAX ); virtual bool IsPrinting( void ); virtual bool StopPrinting( bool wait = true ); virtual bool ContinuePrinting( bool wait = true ); virtual void Inhibit( bool value = true ); virtual bool IsInhibited( void ); unsigned long GetPrintingProgress( unsigned long *bytes_printed = NULL ); // Returns last line number ok'd by the printer // If printing is stopped, returns last line number of previous print // If bytes_printed is non-null, sets that value as well. unsigned long GetTotalPrintingLines( void ); // Return the ending line of the current print using PrinterSerial::Send; bool Send( string command ); // Command may be multiple commands separated by newlines (\n). // Such commands are queued atomically. // Commands may be sent when printing is active. // Commands sent with this interface have higher priority than commands // sent from StartPrinting. string ReadResponse( bool wait = false ); // returns "" if wait is false and no response is ready // only returns responses from Send() and StartPeriodic() and NOT from // SendAndWaitResponse() or StartingPrinting() string SendAndWaitResponse( string command ); // Send the string and wait for the response // May take up to several seconds if the printer is already processing // a long command string ReadLog( bool wait = false ); // returns "" if wait is false and no log entries are ready string ReadErrorLog( bool wait = false ); // returns "" if wait is false and no log entries are ready }; repsnapper-2.3.2a5/src/printer/threaded_printer_serial_test.cpp000066400000000000000000000074411231531733200250300ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "threaded_printer_serial.h" #include #include #include #include #include using namespace std; void *LogReader( void *arg ) { ThreadedPrinterSerial *tps = (ThreadedPrinterSerial *) arg; string str; while ( 1 ) { str = tps->ReadLog( true ); if ( str.length() > 0 ) { //if ( ! tps->IsPrinting() ) cerr << str; // Use cerr instead of cerr. Wine seams to have a concurancy issue with // This thread and the main thread both using cout. } } return NULL; } void *ErrorReader( void *arg ) { ThreadedPrinterSerial *tps = (ThreadedPrinterSerial *) arg; string str; while ( 1 ) { str = tps->ReadErrorLog( true ); if ( str.length() > 0 ) { cerr << str; // Use cerr instead of cerr. Wine seams to have a concurancy issue with // This thread and the main thread both using cout. } } return NULL; } int main( int argc, char *argv[] ) { ThreadedPrinterSerial tps; char command[ 1024 + 10 ]; thread_t log_reader; thread_t error_reader; bool is_printing; vector ports = PrinterSerial::FindPorts(); for ( unsigned int ind = 0; ind < ports.size(); ind++ ) { cout << "Found port: " << ports[ind] << endl; cout << "Testing: " << PrinterSerial::TestPort( ports[ind] ) << endl; } thread_create( &log_reader, LogReader, &tps ); thread_create( &error_reader, ErrorReader, &tps ); if ( argc >= 3 ) tps.Connect( argv[1], strtol( argv[2], NULL, 10 ) ); else if ( argc >= 2 ) tps.Connect( argv[1], 115200 ); else tps.Connect( ports[0], 115200 ); while ( 1 ) { cin.getline( command, 1024 ); if ( strncasecmp( command, "send ", 5 ) == 0 ) { string resp( "Resp: " ); resp.append( tps.SendAndWaitResponse( command + 5 ) ); resp.append( 1, '\n' ); cout << resp; } else if ( strncasecmp( command, "file ", 5 ) == 0 ) { ifstream file( command + 5, ifstream::in ); string str( "" ); char block[ 1024 + 10 ]; while ( file.good() ) { file.read( block, 1024 ); str.append( block, file.gcount() ); } file.close(); tps.StartPrinting( str ); } else if ( strncasecmp( command, "stop", 4 ) == 0 ) { tps.StopPrinting( true ); } else if ( strncasecmp( command, "cont", 4 ) == 0 ) { tps.ContinuePrinting( true ); } else if ( strncasecmp( command, "reset", 5 ) == 0 ) { tps.Reset(); } else if ( strncasecmp( command, "quit", 1024 ) == 0 ) break; is_printing = tps.IsPrinting(); cout << "Is printing: " << is_printing << endl; if ( is_printing ) { cout << "At line: " << tps.GetPrintingProgress() << endl; } } tps.Disconnect(); cout << "Disconnected" << endl; #ifdef HAS_THREAD_CANCEL #ifndef WIN32 thread_cancel( log_reader ); thread_cancel( error_reader ); thread_join( log_reader ); thread_join( error_reader ); #endif #endif exit( 0 ); } repsnapper-2.3.2a5/src/render.cpp000066400000000000000000000454601231531733200167060ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include "stdafx.h" #include "render.h" #include "arcball.h" #include "gllight.h" #include "settings.h" #include "ui/view.h" #include "model.h" #include "slicer/geometry.h" #define N_LIGHTS (sizeof (m_lights) / sizeof(m_lights[0])) #define TRYFONTS "helvetica,arial,dejavu sans,sans,courier" #define FONTSIZE 8 GLuint Render::fontlistbase = 0; int Render::fontheight = 0; inline GtkWidget *Render::get_widget() { return GTK_WIDGET (gobj()); } inline Model *Render::get_model() const { return m_view->get_model(); } Render::Render (View *view, Glib::RefPtr selection) : m_arcBall(new ArcBall()), m_view (view), m_selection(selection) { set_events (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON2_MOTION_MASK | Gdk::BUTTON3_MOTION_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK ); Glib::RefPtr glconfig; glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGBA | Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_ALPHA | Gdk::GL::MODE_STENCIL | Gdk::GL::MODE_DOUBLE); if (!glconfig) { // try single buffered std::cerr << "*** Cannot find the double-buffered visual." << " Trying single-buffered visual.\n"; glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGBA | Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_ALPHA | Gdk::GL::MODE_STENCIL ); } if (!glconfig) { g_error (_("failed to init gl area\n")); } set_gl_capability(glconfig); set_can_focus (true); memset (&m_transform.M, 0, sizeof (m_transform.M)); Matrix3fT identity; Matrix3fSetIdentity(&identity); // set initial rotation 30 degrees around Y axis identity.s.M11 = identity.s.M22 = 0.5253; // cos -45 identity.s.M12 = 0.851; // -sin -45 identity.s.M21 = -0.851; // sin -45 Matrix4fSetRotationScaleFromMatrix3f(&m_transform, &identity); m_transform.s.SW = 1.0; m_zoom = 120.0; for (uint i = 0; i < N_LIGHTS; i++) m_lights[i] = NULL; m_selection->signal_changed().connect (sigc::mem_fun(*this, &Render::selection_changed)); } Render::~Render() { delete m_arcBall; for (uint i = 0; i < N_LIGHTS; i++) delete (m_lights[i]); } void Render::set_model(Model *model) { model->signal_zoom().connect (sigc::mem_fun(*this, &Render::zoom_to_model)); zoom_to_model(); } void Render::selection_changed() { queue_draw(); } void Render::zoom_to_model() { Model *model = get_model(); if (!model) return; // reset the zoom to cover the entire model m_zoom = (model->Max - model->Min).find_max(); // reset the pan to center setArcballTrans(m_transform, Vector3d::ZERO); // zoom to platform if model has zero size if (m_zoom == 0) { m_zoom = model->settings.getPrintVolume().find_max(); setArcballTrans(m_transform, model->settings.getPrintMargin() ); //model->settings.getPrintVolume()/2.); } queue_draw(); } void Render::draw_string(const Vector3d &pos, const string s) { if (fontheight == 0) return; glRasterPos3dv(pos); glListBase(fontlistbase); glCallLists(s.length(), GL_UNSIGNED_BYTE, s.c_str()); } void Render::on_realize() { Gtk::GL::DrawingArea::on_realize(); fontlistbase = glGenLists (128); Glib::RefPtr pcontext = get_pango_context(); Pango::FontDescription font_desc; vector < Glib::RefPtr< Pango::FontFamily > > families = pcontext->list_families(); bool found_font = false; vector fonts = Glib::Regex::split_simple(",", TRYFONTS); for (uint i = 0; !found_font && i < families.size(); i++) { Glib::ustring famname = families[i]->get_name().lowercase(); // cerr <<"Family: " << famname << endl; for (uint k = 0; !found_font && k < fonts.size(); k++) { if ((int)famname.find(fonts[k])!=-1) { // found_font family, now get normal style and weight vector< Glib::RefPtr< Pango::FontFace > > faces = families[i]->list_faces(); for (uint j = 0; !found_font && j < faces.size(); j++) { font_desc = faces[j]->describe(); if (font_desc.get_style() == Pango::STYLE_NORMAL && font_desc.get_weight() == Pango::WEIGHT_NORMAL ) { font_desc.set_size(Pango::SCALE * FONTSIZE); //cerr <<"Trying " << font_desc.to_string() << endl; Glib::RefPtr font = Gdk::GL::Font::use_pango_font(font_desc, 0, 128, fontlistbase); if (font) { //cerr <<"Using " << font_desc.to_string() << endl; found_font = true; Pango::FontMetrics font_metrics = font->get_metrics(); fontheight = font_metrics.get_ascent() + font_metrics.get_descent(); fontheight = PANGO_PIXELS(fontheight); } else { std::cerr << "*** Can't load font \"" << font_desc.to_string() << "\"" << std::endl; found_font = false; } } } } } } if (!found_font) { cerr << "Did not find any working font matching \"" << TRYFONTS << "\"" << " on your system!" << endl << "Cannot display any numbers" << endl; fontheight = 0; } } bool Render::on_configure_event(GdkEventConfigure* event) { Glib::RefPtr gldrawable = get_gl_drawable(); if (!gldrawable->gl_begin(get_gl_context())) return false; const int w = get_width(), h = get_height(); glLoadIdentity(); glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (45.0f, (float)get_width()/(float)get_height(),1.0f, 1000000.0f); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); if (w > 1 && h > 1) // Limit arcball minimum size or it asserts m_arcBall->setBounds(w, h); glEnable(GL_LIGHTING); struct { GLfloat x; GLfloat y; GLfloat z; } light_locations[] = { { -100, 100, 200 }, { 100, 100, 200 }, { 100, -100, 200 }, { 100, -100, 200 } }; for (uint i = 0; i < N_LIGHTS; i++) { delete (m_lights[i]); m_lights[i] = new gllight(); m_lights[i]->Init((GLenum)(GL_LIGHT0+i)); m_lights[i]->SetAmbient(0.2f, 0.2f, 0.2f, 1.0f); m_lights[i]->SetDiffuse(1.0f, 1.0f, 1.0f, 1.0f); m_lights[i]->SetSpecular(1.0f, 1.0f, 1.0f, 1.0f); m_lights[i]->Enable(false); m_lights[i]->SetLocation(light_locations[i].x, light_locations[i].y, light_locations[i].z, 0); } m_lights[0]->Enable(true); m_lights[3]->Enable(true); glDisable ( GL_LIGHTING); glDepthFunc (GL_LEQUAL); glEnable (GL_DEPTH_TEST); glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); gldrawable->gl_end(); return true; } bool Render::on_expose_event(GdkEventExpose* event) { Glib::RefPtr gldrawable = get_gl_drawable(); if (!gldrawable || !gldrawable->gl_begin(get_gl_context())) return false; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glLoadIdentity(); glTranslatef (0.0, 0.0, -2.0 * m_zoom); glMultMatrixf (m_transform.M); CenterView(); glPushMatrix(); glColor3f(0.75f,0.75f,1.0f); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); // Gtk::TreeModel::iterator iter = m_selection->get_selected(); vector selpath = m_selection->get_selected_rows(); m_view->Draw (selpath); glPopMatrix(); if (gldrawable->is_double_buffered()) { gldrawable->swap_buffers(); } else { glFlush(); } gldrawable->gl_end(); return true; } bool Render::on_key_press_event(GdkEventKey* event) { // cerr << "key " << event->keyval << endl; bool moveZ = (event->state & GDK_SHIFT_MASK); bool rotate = (event->state & GDK_CONTROL_MASK); double tendeg = M_PI/18.; bool ret = false; switch (event->keyval) { case GDK_Up: case GDK_KP_Up: if (rotate) ret = m_view->rotate_selection(Vector3d(1.,0.,0.), tendeg); else if (moveZ) ret = m_view->move_selection( 0.0, 0.0, 1.0 ); else ret = m_view->move_selection( 0.0, 1.0 ); break; case GDK_Down: case GDK_KP_Down: if (rotate) ret = m_view->rotate_selection(Vector3d(1.,0.,0.), -tendeg); else if (moveZ) ret = m_view->move_selection( 0.0, 0.0, -1.0 ); else ret = m_view->move_selection( 0.0, -1.0 ); break; case GDK_Left: case GDK_KP_Left: if (rotate) ret = m_view->rotate_selection(Vector3d(0.,0.,1.), tendeg); else ret = m_view->move_selection( -1.0, 0.0 ); break; case GDK_Right: case GDK_KP_Right: if (rotate) ret = m_view->rotate_selection(Vector3d(0.,0.,1.), -tendeg); else ret = m_view->move_selection( 1.0, 0.0 ); break; } if (ret) { m_view->get_model()->ModelChanged(); queue_draw(); } grab_focus(); return ret; } bool Render::on_key_release_event(GdkEventKey* event) { switch (event->keyval) { case GDK_Up: case GDK_KP_Up: case GDK_Down: case GDK_KP_Down: case GDK_Left: case GDK_KP_Left: case GDK_Right: case GDK_KP_Right: //m_view->get_model()->ModelChanged(); // interrupts key_press_event actions! return false; } return true; } bool Render::on_button_press_event(GdkEventButton* event) { grab_focus(); // real mouse-down: m_downPoint = Vector2f(event->x, event->y); // "moving" mouse-down, updated with dragpoint on mouse move: m_dragStart = Vector2f(event->x, event->y); m_arcBall->click (event->x, event->y, &m_transform); // on button 1 with shift/ctrl, if there is an object, select it (for dragging) if ( event->button == 1 && (event->state & GDK_SHIFT_MASK || event->state & GDK_CONTROL_MASK) ) { guint index = find_object_at(event->x, event->y); if (index) { Gtk::TreeModel::iterator iter = get_model()->objtree.find_stl_by_index(index); if (!m_selection->is_selected(iter)) { // if (!(event->state & GDK_CONTROL_MASK)) // add to selection by CONTROL m_selection->unselect_all(); m_selection->select(iter); } // else // if ((event->state & GDK_CONTROL_MASK)) // remove from selection by CONTROL // m_selection->unselect(iter); } } return true; } bool Render::on_button_release_event(GdkEventButton* event) { //dragging = false; if (event->state & GDK_SHIFT_MASK || event->state & GDK_CONTROL_MASK) { // move/rotate object get_model()->ModelChanged(); queue_draw(); } else { if (m_downPoint.x() == event->x && m_downPoint.y() == event->y) {// click only if (event-> button == 3) { // right button -> popup menu? //cerr << "menu" << endl; } else { guint index = find_object_at(event->x, event->y); if (index) { Gtk::TreeModel::iterator iter = get_model()->objtree.find_stl_by_index(index); if (iter) { if (event->button == 1) { m_selection->unselect_all(); } if (m_selection->is_selected(iter)) m_selection->unselect(iter); else m_selection->select(iter); } } // click on no object -> clear the selection: else if (event->button == 1) { //if (m_downPoint.x() == event->x && m_downPoint.y() == event->y) // click only m_selection->unselect_all(); } } } } return true; } bool Render::on_scroll_event(GdkEventScroll* event) { double factor = 110.0/100.0; if (event->direction == GDK_SCROLL_UP) m_zoom /= factor; else m_zoom *= factor; queue_draw(); return true; } const double drag_factor = 0.3; bool Render::on_motion_notify_event(GdkEventMotion* event) { bool redraw=true; const Vector2f dragp(event->x, event->y); const Vector2f delta = dragp - m_dragStart; const Vector3d delta3f(delta.x()*drag_factor, -delta.y()*drag_factor, 0); const Vector3d mouse_preview = mouse_on_plane(event->x, event->y, get_model()->get_preview_Z()); get_model()->setMeasuresPoint(mouse_preview); if (event->state & GDK_BUTTON1_MASK) { // move or rotate if (event->state & GDK_SHIFT_MASK) { // move object XY vector shapes; vectorobjects; if (!m_view->get_selected_objects(objects, shapes)) return true; const Vector3d mouse_down_plat = mouse_on_plane(m_dragStart.x(), m_dragStart.y()); const Vector3d mousePlat = mouse_on_plane(event->x, event->y); const Vector2d mouse_xy = Vector2d(mousePlat.x(), mousePlat.y()); const Vector2d deltamouse = mouse_xy - Vector2d(mouse_down_plat.x(), mouse_down_plat.y()); const Vector3d movevec(deltamouse.x(), deltamouse.y(), 0.); if (shapes.size()>0) for (uint s=0; stransform3D.move(movevec); } else for (uint o=0; otransform3D.move(movevec); } m_dragStart = dragp; } else if (event->state & GDK_CONTROL_MASK) { // move object Z wise const Vector3d delta3fz(0, 0, -delta.y()*drag_factor); vector shapes; vectorobjects; if (!m_view->get_selected_objects(objects, shapes)) return true; if (shapes.size()>0) for (uint s=0; stransform3D; double scale = transf.transform[3][3]; Vector3d movevec = delta3fz*scale; transf.move(movevec); } else for (uint o=0; otransform3D; const double scale = transf.transform[3][3]; const Vector3d movevec = delta3fz*scale; transf.move(movevec); } m_dragStart = dragp; } else { // rotate view //Vector3d axis(delta.y(), delta.x(), 0); //rotArcballTrans(m_transform, axis, -delta.length()/100.); m_arcBall->dragAccumulate(event->x, event->y, &m_transform); } if (redraw) queue_draw(); return true; } // BUTTON 1 else { if (event->state & GDK_BUTTON2_MASK) { // zoom const double factor = 1.0 + 0.01 * (delta.y() - delta.x()); if (event->state & GDK_SHIFT_MASK) { // scale shape vector shapes; vectorobjects; if (!m_view->get_selected_objects(objects, shapes)) return true; if (shapes.size()>0) { for (uint s=0; sScale(shapes[s]->getScaleFactor()/factor, false); } m_view->update_scale_value(); } } else { // zoom view m_zoom *= factor; } m_dragStart = dragp; } // BUTTON 2 else if (event->state & GDK_BUTTON3_MASK) { if (event->state & GDK_SHIFT_MASK || event->state & GDK_CONTROL_MASK ) { // rotate shape vector shapes; vectorobjects; Vector3d axis; if (event->state & GDK_CONTROL_MASK) // rotate z wise axis = Vector3d(0,0,delta.x()); else axis = Vector3d(delta.y(), delta.x(), 0); // rotate strange ... m_view->rotate_selection(axis, delta.length()/100.); m_dragStart = dragp; } else { // move view XY / pan moveArcballTrans(m_transform, delta3f); m_dragStart = dragp; //setArcballTrans(m_transform, delta3f); } } // BUTTON 3 if (redraw) queue_draw(); return true; } if (redraw) queue_draw(); return Gtk::DrawingArea::on_motion_notify_event (event); } void Render::SetEnableLight(unsigned int i, bool on) { assert (i < N_LIGHTS); m_lights[i]->Enable(on); queue_draw(); } void Render::CenterView() { Vector3d c = get_model()->GetViewCenter(); glTranslatef (-c.x(), -c.y(), -c.z()); } guint Render::find_object_at(gdouble x, gdouble y) { // Render everything in selection mode Glib::RefPtr gldrawable = get_gl_drawable(); if (!gldrawable->gl_begin(get_gl_context())) return false; const GLsizei BUFSIZE = 256; GLuint select_buffer[BUFSIZE]; glSelectBuffer(BUFSIZE, select_buffer); (void)glRenderMode(GL_SELECT); GLint viewport[4]; glMatrixMode (GL_PROJECTION); glPushMatrix(); glLoadIdentity (); glGetIntegerv(GL_VIEWPORT,viewport); gluPickMatrix(x,viewport[3]-y,2,2,viewport); // 2x2 pixels around the cursor gluPerspective (45.0f, (float)get_width()/(float)get_height(),1.0f, 1000000.0f); glMatrixMode (GL_MODELVIEW); glInitNames(); glPushName(0); glLoadIdentity (); glTranslatef (0.0, 0.0, -2.0 * m_zoom); glMultMatrixf (m_transform.M); CenterView(); glPushMatrix(); glColor3f(0.75f,0.75f,1.0f); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); vector no_object; m_view->Draw (no_object, true); // restor projection and model matrices glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); // restore rendering mode GLint hits = glRenderMode(GL_RENDER); if (gldrawable->is_double_buffered()) gldrawable->swap_buffers(); else glFlush(); gldrawable->gl_end(); // Process the selection hits GLuint *ptr = select_buffer; GLuint name = 0; GLuint minZ = G_MAXUINT; for (GLint i = 0; i < hits; i++) { /* for each hit */ GLuint n = *ptr++; // number of hits in this record GLuint z1 = *ptr++; // Minimum Z in the hit record ptr++; // Skip Maximum Z coord if (n > 0 && z1 < minZ) { // Found an object further forward. name = *ptr; minZ = z1; } ptr += n; // Skip n name records; } return name; } // http://www.3dkingdoms.com/selection.html Vector3d Render::mouse_on_plane(double x, double y, double plane_z) const { Vector3d margin; Model *m = get_model(); if (m!=NULL) margin = m->settings.getPrintMargin(); // This function will find 2 points in world space that are on the line into the screen defined by screen-space( ie. window-space ) point (x,y) double mvmatrix[16]; double projmatrix[16]; int viewport[4]; double dX, dY, dZ, dClickY; // glUnProject uses doubles, glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); dClickY = double ((double)get_height() - y); // OpenGL renders with (0,0) on bottom, mouse reports with (0,0) on top gluUnProject ((double) x, dClickY, 0.0, mvmatrix, projmatrix, viewport, &dX, &dY, &dZ); Vector3d rayP1( dX, dY, dZ ); gluUnProject ((double) x, dClickY, 1.0, mvmatrix, projmatrix, viewport, &dX, &dY, &dZ); Vector3d rayP2( dX, dY, dZ ); // intersect with z=plane_z; if (rayP2.z() != rayP1.z()) { double t = (plane_z-rayP1.z())/(rayP2.z()-rayP1.z()); Vector3d downP = rayP1 + (rayP2-rayP1) * t; return downP - margin; } else return rayP1 - margin; } repsnapper-2.3.2a5/src/render.h000066400000000000000000000045771231531733200163570ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef RENDER_H #define RENDER_H #include "arcball.h" #include class View; class Model; class gllight; class Settings; class Render : public Gtk::GL::DrawingArea { ArcBall *m_arcBall; Matrix4fT m_transform; Vector2f m_downPoint; Vector2f m_dragStart; View *m_view; Model *get_model() const; Glib::RefPtr m_selection; // font rendering: static GLuint fontlistbase; static int fontheight; float m_zoom; gllight *m_lights[4]; void SetEnableLight(unsigned int lightNr, bool on); void CenterView(); void selection_changed(); guint find_object_at(gdouble x, gdouble y); Vector3d mouse_on_plane(double x, double y, double plane_z=0) const; public: Render (View *view, Glib::RefPtr selection); ~Render(); GtkWidget *get_widget(); void set_model (Model *model); void set_zoom (float zoom) {m_zoom=zoom;}; void zoom_to_model(); void set_transform(const Matrix4fT &transform) {m_transform=transform;}; static void draw_string(const Vector3d &pos, const string s); virtual void on_realize(); virtual bool on_configure_event(GdkEventConfigure* event); virtual bool on_expose_event(GdkEventExpose* event); virtual bool on_motion_notify_event(GdkEventMotion* event); virtual bool on_button_press_event(GdkEventButton* event); virtual bool on_button_release_event(GdkEventButton* event); virtual bool on_scroll_event(GdkEventScroll* event); virtual bool on_key_press_event(GdkEventKey* event); virtual bool on_key_release_event(GdkEventKey* event); }; #endif // RENDER_H repsnapper-2.3.2a5/src/repsnapper-osx.sh000077500000000000000000000005251231531733200202410ustar00rootroot00000000000000#!/bin/bash # get actual path to .app script_dir_link=$(dirname "$(readlink "$0")") if [[ $script_dir_link == "." ]]; then APP_PATH=$(dirname "$0") else APP_PATH=$script_dir_link fi # set place to load dylibs from export DYLD_FALLBACK_LIBRARY_PATH=${DYLD_FALLBACK_LIBRARY_PATH}:$APP_PATH/lib # run the program itself $APP_PATH/repsnapper repsnapper-2.3.2a5/src/repsnapper.conf000066400000000000000000000220631231531733200177430ustar00rootroot00000000000000[Global] SettingsName=Default Settings SettingsImage= Version=2.3.0 [Raft] Enable=false Size=1.3300000429153442 Base.LayerCount=1 Base.MaterialDistanceRatio=1.7999999523162842 Base.Rotation=0 Base.RotationPrLayer=90 Base.Distance=2 Base.Thickness=1 Base.Temperature=1.1000000238418579 Interface.LayerCount=2 Interface.MaterialDistanceRatio=1 Interface.Rotation=90 Interface.RotationPrLayer=90 Interface.Distance=2 Interface.Thickness=1 Interface.Temperature=1 [Hardware] MinMoveSpeedXY=20 MaxMoveSpeedXY=180 MinMoveSpeedZ=1 MaxMoveSpeedZ=3 Volume.X=200 Volume.Y=200 Volume.Z=140 PrintMargin.X=10 PrintMargin.Y=10 PrintMargin.Z=0 PortName=/dev/ttyUSB0 SerialSpeed=115200 KeepLines=1000 SpeedAlways=false [Printer] ExtrudeAmount=2 ExtrudeSpeed=1.5 FanVoltage=200 Logging=false ClearLogOnPrintStart=false NozzleTemp=210 BedTemp=60 [Slicing] RelativeEcode=false UseTCommand=true LayerThickness=0.25999999046325684 MoveNearest=true InfillPercent=30 InfillRotation=90 InfillRotationPrLayer=60 AltInfillPercent=80 InfillOverlap=0.20000000298023224 AltInfillLayers=0 NormalFilltype=0 NormalFillExtrusion=1 FullFilltype=0 FullFillExtrusion=1 SupportFilltype=0 SupportExtrusion=0.64999997615814209 SupportInfillDistance=3 MakeDecor=false DecorFilltype=0 DecorLayers=0 DecorInfillRotation=0 DecorInfillDistance=2 SolidThickness=0.40000000596046448 NoTopAndBottom=false Support=false SupportAngle=0 SupportWiden=0 Skirt=false SingleSkirt=true SkirtHeight=0.40000000596046448 SkirtDistance=3 FillSkirt=false Skins=1 Varslicing=false DoInfill=true ShellCount=2 MinShelltime=2 MinLayertime=5 FanControl=true MinFanSpeed=150 MaxFanSpeed=255 MaxOverhangSpeed=20 BuildSerial=false SelectedOnly=false ShellOffset=-0 FirstLayersNum=1 FirstLayersSpeed=0.5 FirstLayersInfillDist=0.80000001192092896 FirstLayerHeight=0.69999998807907104 UseArcs=false ArcsMaxAngle=20 MinArcLength=1 RoundCorners=true CornerRadius=1 NoBridges=false BridgeExtrusion=1 GCodePostprocess=false GCodePostprocessor= RandomizeLayerStart=false FarthestLayerStart=true [Milling] ToolDiameter=2 [Misc] SpeedsAreMMperSec=true ShapeAutoplace=true TempReadingEnabled=true ExpandLayerDisplay=true ExpandModelDisplay=true ExpandPAxisDisplay=true [Display] DisplayGCode=true GCodeDrawStart=1.4900000095367432 GCodeDrawEnd=0 DisplayGCodeBorders=false DisplayGCodeMoves=true DisplayGCodeArrows=true DisplayEndpoints=false DisplayNormals=false DisplayBBox=true DisplayWireframe=false DisplayWireframeShaded=true DisplayPolygons=true DisplayAllLayers=false DisplayinFill=true DisplayDebuginFill=false DisplayDebug=false DisplayDebugArcs=true DebugGCodeExtruders=false DebugGCodeOffset=true DebugGCodeOnlyZChange=false DisplayFilledAreas=true ShowLayerOverhang=false CommsDebug=false TerminalProgress=false DisplayLayer=true RandomizedLines=false DrawVertexNumbers=false DrawLineNumbers=false DrawOutlineNumbers=false DrawCPVertexNumbers=false DrawCPLineNumbers=false DrawCPOutlineNumbers=false DrawRulers=true LayerValue=5.4800000190734863 LuminanceShowsSpeed=false Highlight=0.69999998807907104 NormalsLength=10 EndPointSize=8 TempUpdateSpeed=3 PreviewLoad=true PolygonColour=0.69770354032516479;1;1;0.49999237060546875; WireframeColour=1;0.47999998927116394;0;0.5; NormalsColour=0.62000000476837158;1;0;1; GCodeMoveColour=1;0.049988556653261185;1;1; GCodePrintingColour=0.96568244695663452;0.98207062482833862;0.96159303188323975;1; [GCode] Start=; GCode generated by RepSnapper:\n; http://reprap.org/wiki/RepSnapper_Manual:Introduction\nG21 ; metric is good!\nG90 ; absolute positioning\nT0 ; select new extruder\nG28 ; go home\nG92 E0 ; set extruder home\nM104 S200.0 ; set temperature to 200.0\nG1 X20 Y20 F500 ; move away from 0.0, to use the same reset for each layer\n\n Layer= End=G1 X0 Y0 F2000.0 ; feed for start of next move\nM104 S0.0 ; heater off\n [UserButtons] Labels=HomeZ; GCodes=G28 Z0; [Extruder0] UseForSupport=true CalibrateInput=true ExtrusionFactor=1 FilamentDiameter=3 ExtrudedMaterialWidthRatio=1.7999999523162842 MinimumLineWidth=0.40000000596046448 MaximumLineWidth=0.69999998807907104 MaxLineSpeed=180 EMaxSpeed=1.5 MaxShellSpeed=150 GCLetter=E name=Extruder EnableAntiooze=false AntioozeDistance=4.5 AntioozeAmount=1 AntioozeSpeed=20 AntioozeZlift=0 ZliftAlways=false DisplayColour=1;1;0;1; OffsetX=0 OffsetY=0 [Ranges] Raft.Size=0;50;1;3; Raft.Base.LayerCount=0;8;1;2; Raft.Interface.LayerCount=0;8;1;2; Raft.Base.MaterialDistanceRatio=0.10000000149011612;4;0.10000000149011612;1; Raft.Interface.MaterialDistanceRatio=0.10000000149011612;4;0.10000000149011612;1; Raft.Base.Rotation=-360;360;45;90; Raft.Interface.Rotation=-360;360;45;90; Raft.Base.RotationPrLayer=-360;360;45;90; Raft.Interface.RotationPrLayer=-360;360;45;90; Raft.Base.Distance=0.10000000149011612;8;0.10000000149011612;1; Raft.Interface.Distance=0.10000000149011612;8;0.10000000149011612;1; Raft.Base.Thickness=0.10000000149011612;4;0.10000000149011612;1; Raft.Interface.Thickness=0.10000000149011612;4;0.10000000149011612;1; Raft.Base.Temperature=0.89999997615814209;1.2000000476837158;0.0099999997764825821;0.10000000149011612; Raft.Interface.Temperature=0.89999997615814209;1.2000000476837158;0.0099999997764825821;0.10000000149011612; Slicing.LayerThickness=0.0099999997764825821;3;0.0099999997764825821;0.20000000298023224; Slicing.ShellCount=0;100;1;5; Slicing.SolidThickness=0;10;0.0099999997764825821;0.10000000149011612; Slicing.InfillRotation=-360;360;5;45; Slicing.InfillRotationPrLayer=-360;360;5;90; Slicing.InfillPercent=0;100;1;10; Slicing.AltInfillPercent=0;100;1;10; Slicing.AltInfillLayers=0;10000;10;100; Slicing.DecorLayers=1;100;1;5; Slicing.DecorInfillDistance=0;10;0.10000000149011612;1; Slicing.DecorInfillRotation=-360;360;5;45; Slicing.InfillOverlap=0;1;0.0099999997764825821;0.10000000149011612; Slicing.NormalFillExtrusion=0.0099999997764825821;3;0.0099999997764825821;0.10000000149011612; Slicing.FullFillExtrusion=0.0099999997764825821;3;0.0099999997764825821;0.10000000149011612; Slicing.BridgeExtrusion=0.0099999997764825821;3;0.0099999997764825821;0.10000000149011612; Slicing.SupportExtrusion=0.0099999997764825821;3;0.0099999997764825821;0.10000000149011612; Slicing.SupportInfillDistance=0;10;0.10000000149011612;1; Slicing.SupportWiden=-5;5;0.0099999997764825821;0.10000000149011612; Slicing.SupportAngle=0;90;1;10; Slicing.SkirtHeight=0;1000;0.10000000149011612;1; Slicing.SkirtDistance=0;100;0.10000000149011612;1; Slicing.Skins=1;5;1;1; Slicing.MinShelltime=0;100;0.10000000149011612;1; Slicing.MinLayertime=0;100;0.10000000149011612;1; Slicing.MinFanSpeed=0;255;5;25; Slicing.MaxFanSpeed=0;255;5;25; Slicing.MaxOverhangSpeed=0;1000;1;10; Slicing.ShellOffset=-10;10;0.0099999997764825821;0.10000000149011612; Slicing.FirstLayersNum=0;1000;1;10; Slicing.FirstLayersSpeed=0.0099999997764825821;3;0.0099999997764825821;0.10000000149011612; Slicing.FirstLayersInfillDist=0;100;0.0099999997764825821;0.10000000149011612; Slicing.FirstLayerHeight=0;100;0.0099999997764825821;0.10000000149011612; Slicing.ArcsMaxAngle=0;180;1;10; Slicing.MinArcLength=0;10;0.0099999997764825821;0.10000000149011612; Slicing.CornerRadius=0;5;0.0099999997764825821;0.10000000149011612; Milling.ToolDiameter=0;5;0.0099999997764825821;0.10000000149011612; Hardware.Volume.X=0;1000;5;25; Hardware.Volume.Y=0;1000;5;25; Hardware.Volume.Z=0;1000;5;25; Hardware.PrintMargin.X=0;100;1;5; Hardware.PrintMargin.Y=0;100;1;5; Hardware.PrintMargin.Z=0;100;1;5; Hardware.MinMoveSpeedXY=0.10000000149011612;2000;1;10; Hardware.MaxMoveSpeedXY=0.10000000149011612;2000;1;10; Hardware.MinMoveSpeedZ=0.10000000149011612;250;1;10; Hardware.MaxMoveSpeedZ=0.10000000149011612;250;1;10; Hardware.KeepLines=100;100000;1;500; Extruder.OffsetX=-5000;5000;0.10000000149011612;1; Extruder.OffsetY=-5000;5000;0.10000000149011612;1; Extruder.ExtrudedMaterialWidthRatio=0;10;0.0099999997764825821;0.10000000149011612; Extruder.MinimumLineWidth=0;10;0.0099999997764825821;0.10000000149011612; Extruder.MaximumLineWidth=0;10;0.0099999997764825821;0.10000000149011612; Extruder.ExtrusionFactor=0;10;0.10000000149011612;0.5; Extruder.FilamentDiameter=0.5;5;0.0099999997764825821;0.05000000074505806; Extruder.MaxLineSpeed=0.10000000149011612;2000;1;10; Extruder.MaxShellSpeed=0.10000000149011612;2000;1;10; Extruder.EMaxSpeed=0.0099999997764825821;2000;0.10000000149011612;1; Extruder.AntioozeDistance=0;25;0.10000000149011612;1; Extruder.AntioozeAmount=0;25;0.10000000149011612;1; Extruder.AntioozeSpeed=0;1000;1;5; Extruder.AntioozeZlift=0;10;0.0099999997764825821;0.10000000149011612; Display.TempUpdateSpeed=1;1000;1;5; m_scale_value=9.9999997473787516e-05;1000;0.0099999997764825821;0.10000000149011612; scale_x=9.9999997473787516e-05;1000;0.0099999997764825821;0.10000000149011612; scale_y=9.9999997473787516e-05;1000;0.0099999997764825821;0.10000000149011612; scale_z=9.9999997473787516e-05;1000;0.0099999997764825821;0.10000000149011612; translate_x=-5000;5000;1;10; translate_y=-5000;5000;1;10; translate_z=-5000;5000;0.10000000149011612;1; rot_x=-360;360;1;10; rot_y=-360;360;1;10; rot_z=-360;360;1;10; Display.LayerValue=0;1000;0;0.0099999997764825821; Display.GCodeDrawStart=0;1000;0;0.10000000149011612; Display.GCodeDrawEnd=0;1000;0;0.10000000149011612; repsnapper-2.3.2a5/src/repsnapper.cpp000066400000000000000000000223671231531733200176070ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include "stdafx.h" #include #include #include #include #include "ui/view.h" #include "ui/progress.h" #include "gcode/gcode.h" #include "model.h" using namespace std; GUI *gui; struct CommandLineOptions { public: bool use_gui; string stl_input_path; string binary_output_path; string gcode_output_path; string settings_path; string printerdevice_path; string svg_output_path; bool svg_single_output; std::vector files; private: void init () { // specify defaults here or in the block below use_gui = true; } void version () { printf(_("Version: %s\n"), VERSION); exit (1); } void usage () { fprintf (stderr, _("Version: %s\n"), VERSION); fprintf (stderr, _("Usage: repsnapper [OPTION]... [FILE]...\n" "Start reprap control software and load [FILES]\n" "Options:\n" " -t, --no-gui act as a head-less renderer\n" " -i, --input [file] read input Model [file]\n" " -b, --binary [file] batch convert input file to binary STL\n" " -o, --output [file] if not head-less (-t),\n" " enter non-printing GUI mode\n" " only able to output gcode to [file]\n" " --svg [file] slice to SVG file\n" " --ssvg [file] slice to single layer SVG files [file]NNNN.svg\n" " -s, --settings [file] read render settings [file]\n" " -h, --help show this help\n" "\n" "Report bugs to #repsnapper, irc.freenode.net\n\n")); exit (1); } public: CommandLineOptions(int argc, char **argv) { init (); for (int i = 1; i < argc; i++) { const char *arg = argv[i]; bool param = i < argc - 1; /**/ if (param && (!strcmp (arg, "-i") || !strcmp (arg, "--input"))) stl_input_path = argv[++i]; else if (param && (!strcmp (arg, "-b") || !strcmp (arg, "--binary"))) { binary_output_path = argv[++i]; use_gui = false; } else if (param && (!strcmp (arg, "-p") || !strcmp (arg, "--printnow"))) printerdevice_path = argv[++i]; else if (param && (!strcmp (arg, "-o") || !strcmp (arg, "--output"))) gcode_output_path = argv[++i]; else if (param && (!strcmp (arg, "-s") || !strcmp (arg, "--settings"))) settings_path = argv[++i]; else if (!strcmp (arg, "-t") || !strcmp (arg, "--no-gui")) use_gui = false; else if (!strcmp (arg, "--help") || !strcmp (arg, "-h") || !strcmp (arg, "/?")) usage(); else if (!strcmp (arg, "--svg")) { svg_output_path = argv[++i]; svg_single_output = false; } else if (!strcmp (arg, "--ssvg")) { svg_output_path = argv[++i]; svg_single_output = true; } else if (!strcmp (arg, "--version") || !strcmp (arg, "-v")) version(); else files.push_back (std::string (argv[i])); } } // add more options above }; Glib::RefPtr find_global_config(const std::string filename) { std::vector dirs = Platform::getConfigPaths(); Glib::RefPtr f; for (std::vector::const_iterator i = dirs.begin(); i != dirs.end(); ++i) { std::string f_name = Glib::build_filename (*i, filename); f = Gio::File::create_for_path(f_name); if(f->query_exists()) { return f; } } return Glib::RefPtr(); } int main(int argc, char **argv) { Glib::thread_init(); // gdk_threads_init(); // gdk_threads_enter(); Gtk::Main tk(argc, argv); // gdk_threads_leave(); gchar *locale_dir; #ifdef G_OS_WIN32 char *inst_dir; inst_dir = g_win32_get_package_installation_directory_of_module (NULL); locale_dir = g_build_filename (inst_dir, "share", "locale", NULL); g_free (inst_dir); #else locale_dir = g_strdup (LOCALEDIR); #endif bindtextdomain (GETTEXT_PACKAGE, locale_dir); textdomain (GETTEXT_PACKAGE); //cerr << locale_dir<< endl; g_free(locale_dir); locale_dir = NULL; save_locales(); CommandLineOptions opts (argc, argv); Platform::setBinaryPath (argv[0]); try { std::string user_config_dir = Glib::build_filename (Glib::get_user_config_dir(), "repsnapper"); Gio::File::create_for_path(user_config_dir)->make_directory_with_parents(); } catch(Gio::Error e) { switch(e.code()) { case Gio::Error::EXISTS: // Directory has already been created. Normal. break; default: Gtk::MessageDialog dialog (_("Couldn't create user config directory!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text(e.what()); dialog.run(); return 1; } } std::vector user_config_bits(3); user_config_bits[0] = Glib::get_user_config_dir(); user_config_bits[1] = "repsnapper"; user_config_bits[2] = "repsnapper.conf"; std::string user_config_file = Glib::build_filename (user_config_bits); Glib::RefPtr conf = Gio::File::create_for_path(user_config_file); Glib::RefPtr global_conf = find_global_config("repsnapper.conf"); if(!global_conf) { Gtk::MessageDialog dialog (_("Couldn't find global configuration!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text (_("It is likely that repsnapper is not correctly installed.")); dialog.run(); return 1; } try { // try to copy to user config, if it doesn't exist ... global_conf->copy(conf); } catch(Gio::Error e) { switch(e.code()) { case Gio::Error::EXISTS: // Forget about it, the user already has a config. This is the normal case. break; case Gio::Error::PERMISSION_DENIED: { // Fall back to global config Gtk::MessageDialog dialog (_("Unable to create user config"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text(e.what() + _("\nFalling back to global config. Settings will not be saved.")); dialog.run(); break; } default: { Gtk::MessageDialog dialog (_("Failed to locate config"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text(e.what()); dialog.run(); return 1; } } } Model *model = new Model(); if (opts.settings_path.size() > 0) conf = Gio::File::create_for_path(opts.settings_path); // first load global config to make sure all settings exist if (global_conf->query_exists()) model->LoadConfig(global_conf); if (conf->query_exists()) model->LoadConfig(conf); bool nonprintingmode = false; if (opts.gcode_output_path.size() > 0) { nonprintingmode = true; } if (opts.printerdevice_path.size() > 0) { model->settings.set_string("Hardware","PortName",opts.printerdevice_path); } if (!opts.use_gui) { if (opts.settings_path.size() > 0) model->LoadConfig(Gio::File::create_for_path(opts.settings_path)); ViewProgress vprog(new Gtk::HBox(),new Gtk::ProgressBar(),new Gtk::Label()); vprog.set_terminal_output(true); model->SetViewProgress(&vprog); model->statusbar=NULL; if (opts.stl_input_path.size() > 0) { model->Read(Gio::File::create_for_path(opts.stl_input_path)); } if (opts.printerdevice_path.size() > 0) { Printer printer(NULL); printer.setModel(model); printer.Connect(); printer.StartPrinting(); printer.Disconnect(); return 0; } if (opts.gcode_output_path.size() > 0) { model->ConvertToGCode(); model->WriteGCode(Gio::File::create_for_path(opts.gcode_output_path)); } else if (opts.svg_output_path.size() > 0) { model->SliceToSVG(Gio::File::create_for_path(opts.svg_output_path), opts.svg_single_output); } else if (opts.binary_output_path.size() > 0) { model->SaveStl(Gio::File::create_for_path(opts.binary_output_path)); } else cerr << _("No output file given") << endl; delete model; return 0; } Gdk::GL::init(argc, argv); View* mainwin = View::create(model); mainwin->setNonPrintingMode(nonprintingmode, opts.gcode_output_path); Glib::RefPtr iconfile = find_global_config("repsnapper.svg"); mainwin->set_icon_file(iconfile); mainwin->set_title("Repsnapper"); if (opts.stl_input_path.size() > 0) { model->Read(Gio::File::create_for_path(opts.stl_input_path)); } for (uint i = 0; i < opts.files.size(); i++) model->Read(Gio::File::create_for_path(opts.files[i])); model->ModelChanged(); tk.run(); delete mainwin; delete model; return 0; } repsnapper-2.3.2a5/src/repsnapper.svg000066400000000000000000000117471231531733200176240ustar00rootroot00000000000000 image/svg+xml Miroslav Hrončok <miro@hroncok.cz> repsnapper-2.3.2a5/src/repsnapper.ui000066400000000000000000022761761231531733200174550ustar00rootroot00000000000000 _About About Help about the application gtk-about _Calibrate Calibrate An interactive calibration routine Load _GCode Load GCode Load a file of control codes gtk-open Load _STL Load STL Load an STL file gtk-open _Preferences Preferences Open the Preferences Dialog gtk-preferences _Quit Quit Exit Repsnapper gtk-quit Save Settings Save Settings Save application settings profile Save Settings As Save Settings As Save settings in a custom file 1 0.10000000000000001 0.25 30 10 0.10000000000000001 10 1 0.10000000000000001 0.25 20 8 0.10000000000000001 10 Fullscreen Fullscreen Toggle Fullscreen Load Settings Load Settings Load application settings profile False 200 200 True False 50 50 True False 6 7 True True True True True False Y +0.1 mm up 3 4 2 3 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False Y +1 mm up 2 5 1 2 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True Y +10 mm True False up 1 6 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X -0.1 mm left 2 3 2 4 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X -1 mm left 1 2 1 5 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X -10 mm left 6 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X +0.1 mm 4 5 2 4 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X +1 mm 5 6 1 5 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False X +10 mm 6 7 6 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False Y -0.1 mm down 3 4 3 4 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False Y -1 mm down 2 5 4 5 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True True True False Y -10 mm down 1 6 5 6 GTK_EXPAND | GTK_SHRINK | GTK_FILL GTK_EXPAND | GTK_SHRINK | GTK_FILL True True 0 True False True center True True True True False Z +10 mm up False False 0 True True True True False Z +1 mm up False False 1 True True True True False Z +0.1 mm up False False 2 True False True True False False True True True True 0 True False Z False False 1 1 False False 3 True True True True False Z -0.1 mm down False False 4 True True True True False Z -1 mm down False False 5 True True True True False Z -10 mm down False False 6 False False 1 False 5 normal RepSnapper (C) 2008-2013 its contributors http://reprap.org/wiki/RepSnapper_Manual:Introduction Website LGPLv2+, GPLv2+, and other licenses, see licenses.txt Michael Meeks <michael@gnome.org> Kulitorum <repsnapper@kulitorum.com> Palomides <nave.notnilc@gmail.com> Joachim Glauche <info@gli-concept.de> Timothy Schmidt <timschmidt@gmail.com> Rick Kimball <rick@kimballsoftware.com> Jan Schmidt <thaytan@noraisin.net> Harry Eakins <harry.eakins@googlemail.com> Martin Dieringer <martin.dieringer@gmx.de> and others I forgot... (needs updating) True True False 2 True False end False True end 0 False 5 Custom Button True dialog True False 2 True False end gtk-cancel True True True True False False 0 gtk-ok True True True True False False 1 False True end 0 True False 2 2 3 5 True False GCode 1 2 True True 1 2 1 2 True True True False False True True 1 2 True False Name True True 5 1 BT_EXIT BT_OK 400 300 False 5 dialog True False 2 True False end False True end 0 True True True False False True True True 1 False True False True False True False True False _File True True False OpenStl True False True True imagemenuitem OpenGCode True False True True True False gtk-open LoadSettings True False True True gtk-save SaveSettings True False True True gtk-save-as SaveSettingsAs True False True True True False gtk-quit Quit True False True True True False _Edit True True False gtk-preferences PreferencesDialog True False True True Fullscreen False Fullscreen True Calibrate True False True True True False _Help True True False About True False True True False True 0 True False True True 1 True False Infill True True False True True True 0 _Support True True False True True True True 1 No Covers True True False True True True 2 Decor True True False True True True 3 Selected Only True True False True True True 4 Serial _Build True True False True True True True 5 False True 2 False True 0 True False True False False True 0 False False 1 True True 450 True False False Save GCode and Close True True True True True 0 True False label True True 1 False True 0 True False True True 1 False True True False Progress False True 4 0 True False 0.20000000000000001 True True 1 X True True True False False 2 False True end 2 True True 250 True False Generate _GCode True True True True True True 1 True True True True False ? True True True False True 5 0 True False True True 1 False Preview True True False True True True 0 True False False True 1 False Single Layer SVGs True True False True True True 0 Save STL as Single Object True True False Multiple Objects are combined and saved binary.. Otherwise the STL will contain separate Objects and it will be in ASCII mode (some programs won't be able to read them) True True True 1 False True 2 False True 2 True False Files False True False True False True True False Load Model True True True True True 0 True True False True True False False 1 _Autoplace True True True True False True 2 False False 0 False True 0 True True True True False True True 1 True False Save as STL/AMF True True True True True 0 Slice to S_VG True True True True False True 1 False True 2 True False 0 none True False 12 True False True False Delete True True True True True 0 D_uplicate True True True True True True 1 Split True True True True True 2 Merge True True True True True 3 Divide True True True True True 4 True True 0 True False 4 5 True False 0 Rotate: 1 2 True False 0 Translate: 2 3 True False 0 Scale: 3 4 True True True True False False True True 0.10000000000000001 2 True 1 2 3 4 GTK_FILL GTK_FILL True True True False False True True 2 4 5 2 3 GTK_FILL GTK_FILL True True True False False True True 2 3 4 2 3 GTK_FILL GTK_FILL True True True False False True True 2 2 3 2 3 GTK_FILL GTK_FILL True True True False False True True 2 4 5 3 4 GTK_FILL GTK_FILL True True True False False True True 2 3 4 3 4 GTK_FILL GTK_FILL True True True False False True True 2 2 3 3 4 GTK_FILL GTK_FILL Auto True True True 1 2 1 2 True False X 2 3 3 True False Y 3 4 3 True False Z 4 5 3 True True True False False True True 2 2 3 1 2 GTK_FILL GTK_FILL True True True False False True True 2 3 4 1 2 GTK_FILL GTK_FILL True True True False False True True 2 4 5 1 2 GTK_FILL GTK_FILL False True 3 1 True False On Platform True True True True True 0 Mirror True True True True True 1 Hollow True True True True True 2 False True 2 True False Invert Normals True True True True True 0 True False Twist: False True 4 1 - True True True False False 2 + True True True False False 3 True True 3 True False <b>Object</b> True False True 3 True True True False 2 3 Wireframe True True False 0 True 1 2 Surface Normals True True False 0 True 2 3 Endpoints True True False 0 True 1 2 Bounding Boxes True True False 0 True 1 3 1 2 Surface True True False 0 True True False Display False True 4 1 True False Model 1 False True False True False True False 0 none True False 12 True False True False 3 5 True False 0.40000000596046448 Layer Height: 1 2 True True True False False True True 2 2 3 GTK_FILL GTK_FILL True True True False False True True 1 True 2 3 1 2 GTK_FILL GTK_FILL True False Shells: 1 2 1 2 True True True False False True True 4 5 GTK_FILL GTK_FILL True False Skins: 3 4 1 2 True True True 1 False False True True 4 5 1 2 GTK_FILL GTK_FILL True False Infill % 3 4 True True 0 True False <b>Parameters</b> True True True 0 False True 0 True False _Load GCode True True True True True True 0 To Platform True True True True True 1 _Save GCode True True True True True True 2 False True 1 True False False True 2 True False False True 4 True True True True True True textbuffer1 True False Start False True True True True textbuffer2 1 True False Next Layer 1 False True True True True textbuffer3 2 True False End 3 False True True True True textbuffer1 3 True False Result 3 False True True 5 2 True False GCode 2 False True False True False 0 none True False 12 True False True False False True 0 True False icons False 5 True False Print Print True gtk-execute False True True False Pause Pause True gtk-media-pause False True True False Home All Home All True gtk-home False True True False Reset Printer Reset True gtk-refresh False True True False Power On Power On True gtk-connect False True False True 1 True False <b>Printer</b> True False True 2 True True True False False True icons True False True False X: False True True False X- X- True gtk-go-back False True True False X+ X+ True gtk-go-forward False True True False True False Y: False True True False Y- Y- True gtk-go-down False True True False Y+ Y+ True gtk-go-up False True True False True False Z: False True True False Z Down Z- True gtk-go-down False True True False Z Up Z+ True gtk-go-up False True True False True False False True True False True False Amount (mm) False True False True 3 True False Axis Control False False 3 True False True False Use Extruder: False True 5 0 True False False True 1 False True 4 True False 0 none True False 12 True False True False False True 0 True False True False 2 4 True False 1 3 2 True True 1 False True 1 True False 2 3 True False 1 10 Update Interval (sec) 1 2 True True True False False True True True 2 3 Monitor Temperature True True False True True Fan Enabled True True False True 1 2 True False 1 10 Fan Level 1 2 1 2 True True 3 True True 1 False False True True True 2 3 1 2 False True 2 True False <b>Temperature</b> True False True 5 True False True False Length (mm) True True 0 True True True False False True True 1 True True 1 True False Speed (mm/s) True True 2 True True True False False True True 1 True True 3 Purge True True True True True 4 False True 6 True False 0 none True False 12 True False True False True False False text True True 0 True True 0 True False New True True True True True 0 Edit True True True True True 1 Remove True True True True True 2 True True 1 True False <b>Custom Actions</b> True False True 7 True False True True True False False True True True True 0 Send GCode True True True False True 1 False True 8 3 True False Printer 3 False True False True False True True True False True True True True immediate False False True True 0 True False 15 Logging True True False True True True True 0 Clear on Print Start True True False True True True True 1 Clear Now True True True True True 2 False True 1 True False Communication False True True True True immediate False 1 True False Errors/Warnings False 1 False True True True True immediate False False 2 True False Echo 2 False True True 0 True True 1 4 True False Logs 4 False True True 2 True False True True 2 True True True False True False Draw Layers True True False 0 True False False 10 0 Infill True True False 0 True False False 10 1 All True True False 0 True False False 10 2 Dimensions True True False 0 True False False 3 True False Height: False False 10 4 True True 2 2 left True True 1 5 True False False False 6 False True 0 True False Draw GCode True True False 0 True False False 10 0 Moves True True False True False True 1 Arrows True True False 0 True False False 2 Borders True True False 0 True False False 3 True False 2 2 True False From/Single: 5 True True 2 2 left 1 2 True False To: 1 2 5 True True 2 2 left 1 2 1 2 True True 4 False True 1 True False Layer Preview False True 3 True False False True 4 False 5 repsnapper Preferences normal True False 2 True False end gtk-close True True True True False False 1 False True end 0 True False True False True False Settings set False True 6 0 True True never True True 1 True True 0 True True True True False True False Summary of Hardware Settings True True 0 True False True False Change image True True True True True 0 Save Settings True True True True True 1 Clone Settings True True True True True 2 True True 1 True False gtk-missing-image True True 2 True True 2 True False Summary False True False 6 6 6 6 True False 12 True False 0 none True False 6 12 True False 2 8 6 6 True True False False True True 2 3 GTK_FILL True False 0 Border right 1 2 GTK_FILL True False 0 Build Volume GTK_FILL True True False False True True 6 7 True True False False True True 4 5 True False X center 1 2 GTK_FILL True False mm center 7 8 GTK_FILL True False mm center 7 8 1 2 GTK_FILL True True False False True True 6 7 1 2 True True False False True True 4 5 1 2 True True False False True True 2 3 1 2 True False X center 1 2 1 2 GTK_FILL True False 6 True False Z center 5 6 1 2 GTK_FILL True False 6 True False Z center 5 6 GTK_FILL True False 6 True False Y center 3 4 GTK_FILL True False 6 True False Y center 3 4 1 2 GTK_FILL True False 0 <b>Geometry</b> True False True 0 True False 0 none True False 6 12 True False 2 5 6 6 True False 0 X/Y Axes: GTK_FILL True False 0 Z Axis: 1 2 GTK_FILL True True False False True True 1 4 5 1 2 True True False False True True 1 2 3 True True False False True True 1 2 3 1 2 True True False False True True 1 4 5 True False Max 3 4 GTK_FILL True False Max 3 4 1 2 True False Min 1 2 True False Min 1 2 1 2 True False <b>Axis Moving Speeds (mm/sec)</b> True False True 1 True False 0 none True False 6 12 True False 4 3 6 6 True False 0 Serial Link Speed GTK_FILL True True Number of lines of output to retain for each scrollback buffer False False True True 1 2 2 3 True False 0 Scrollback 2 3 GTK_FILL True False 0 lines 2 3 2 3 GTK_FILL True False True 0 1 3 True False <b>Serial Communications</b> True False True 2 Send Speed on Every GCode Command True True False True False True 3 1 True False Hardware Settings 1 False True False True False 0 none True False 12 True False 2 3 Relative Ecode True True False half True True Use T Command to Change Extruder True True False Otherwise use different GCode Letters True 1 3 True False <b>General</b> True False False 0 True False True False Copy True True True False False 0 True True True True 1 Remove True True True False False 2 True True 0 True False True False 0 none True False 6 12 True False True False True False X Offset (mm) True True 0 True True False False True True 1 True True 1 True False Y Offset (mm) True True 2 True True False False True True 1 True True 3 True True 0 True False Use this Extruder for Support True True False True True True 0 True True 1 True False 8 3 6 1 True False 0 Extrusion Multiplier 5 6 GTK_FILL True True True False False True True 2 1 2 5 6 True False mm center 2 3 1 2 GTK_FILL True False center 2 3 2 3 GTK_FILL True False 0 Minimum Line Width (~Nozzle Diameter) 3 4 True True True False False True True 2 1 2 3 4 True True True False False True True 2 1 2 4 5 True False 0 Maximum Line Width (~Nozzle Diameter) 4 5 True False mm center 2 3 3 4 GTK_FILL True False 0 GCode Letter 6 7 True True 1 True False False True True 1 2 6 7 True True True False False True True 2 1 2 2 3 GTK_FILL GTK_FILL True False 0 Desired Line Width/Height Ratio 2 3 GTK_FILL True False 0 Display Colour 7 8 True True True #e33be764245b 1 2 7 8 Calibrate mm as input True True False True True False mm 2 3 4 5 True False 0 Filament Diameter 1 2 GTK_FILL True True True False False True True 2 1 2 1 2 True True 2 True False <b>Extruder Settings</b> True False True 5 0 True False 0 none True False 12 True False 2 6 True False Extruded Lines True True True False False True True 1 1 2 True False Shells 2 3 True True True False False True True 1 3 4 True False E max 4 5 True True True False False True True 2 5 6 True False <b>Speeds (mm/sec)</b> True False True 5 1 True False 0 none True False 12 True False True False 3 4 Enable Antiooze Retract True True False True 2 True False 1 Minimum Distance (mm): 2 3 True True True False False True True 2 3 4 True False Speed (mm/sec): 1 2 True True True False False True True 1 1 2 1 2 True False Amount (mm): 2 3 1 2 True True True False False True True 2 3 4 1 2 True False Z lift on move (mm): 2 3 True True True False False True True 2 1 2 2 3 Lift Z on all moves True True False True 2 4 2 3 False True 0 True False <b>Antiooze Retract</b> True False True 5 2 False True 1 True True 1 2 True False Extruders 2 False True False True False 0 none True False 12 True False True False 15 6 True False Rotation per Layer (°): True True True False False True True 1 2 GTK_FILL True False Normal Fill: 2 3 True False Solid Fill: 4 5 True False 1 2 2 3 True False 1 2 4 5 True False Extrusion Factor: 2 3 2 3 True False Extrusion Factor: 2 3 4 5 True True False False True True 2 3 4 2 3 GTK_FILL True True False False True True 2 3 4 4 5 GTK_FILL True False Support: 6 7 True False 1 2 6 7 True False Extrusion Factor: 2 3 6 7 True True True False False True True 2 3 4 6 7 True False Widen: 4 5 6 7 True True True False False True True 2 5 6 6 7 True False Base Rotation (°): 2 3 True True True False False True True 3 4 GTK_FILL True False Decoration: 9 10 True False 1 2 9 10 True False Infill Distance: 2 3 9 10 True True True False False True True 2 3 4 9 10 True False Rotation: 4 5 9 10 True True True False False True True 5 6 9 10 True False Alternate Infill every 12 13 True True True False False True True 1 2 12 13 True False 0 th Layer 2 3 12 13 GTK_FILL True False Alternate Infill Percent: 3 5 12 13 True True True False False True True 5 6 12 13 True False Bridges Extrusion Factor: 1 3 14 15 True True True False False True True 2 3 4 14 15 True False Infill Overlap: 4 5 True True True False False True True 2 5 6 GTK_FILL Disable Bridges True True False True 14 15 True False Make enough solid layers to reach minimum thickness (mm) Solid Thickness: 4 5 4 5 True True False False True True 2 5 6 4 5 True False Decor Layers: 4 5 10 11 True True False False True True 5 6 10 11 True False Min. Angle: 4 5 7 8 True True True False False True True 5 6 7 8 True False 6 1 2 True False 6 3 4 True False 6 5 6 True False 6 8 9 True False 6 11 12 True True False False True True 2 3 4 7 8 True False Infill Distance: 2 3 7 8 False True 0 True False <b>Infill</b> True False True 5 0 3 True False Infill 3 False True False True False 0 none True False 12 True False True False 8 5 True False Offset Outer Shells by (mm): 2 True True True False False True True 2 2 3 Variable Slicing True True False True 3 4 True False Height (mm): 1 2 1 2 True True True False False True True 1 2 3 1 2 True False Distance (mm): 3 4 1 2 True True True False False True True 1 4 5 1 2 Arcs GCode (G2,G3) True True False True 4 5 True False Max. Angles: 1 2 4 5 True True True False False True True 2 3 4 5 Round Corners True True False True 5 6 True True True False False True True 2 2 3 5 6 True False Distance 1 2 5 6 True True True False False True True 2 4 5 4 5 True False Min. Arc Length (mm): 3 4 4 5 Move between nearest points of polygons True True False True 3 6 7 True False Skirt True True False True True True 0 1 2 Fill Skirt Area True True False True 3 5 2 3 Around All Objects True True False Always done when using Support True 1 3 2 3 False True 0 True False <b>General</b> True False True 5 0 True False 0 none True False 12 True False True False 5 5 True False Minimum Time per Layer (s): 2 True True True False False True True 1 2 3 GTK_FILL Fan Control True True False True 4 5 GTK_EXPAND True False Min. Speed: 1 2 4 5 True True True False False True True 2 3 4 5 GTK_FILL True False Max. Speed: 3 4 4 5 True True True False False True True 4 5 4 5 GTK_FILL True False Max. Overhang Speed (mm/sec): 2 2 3 True True True False False True True 1 2 3 2 3 True False Minimum Shell Time (s): 2 1 2 True True True False False True True 1 2 3 1 2 Move to Farthest Point on Layer Start True True False True 4 3 4 False True 0 True False <b>Cooling</b> True False True 5 1 True False 0 none True False 12 True False True False True False Number of first Layers: True True 0 True True True False False True True False True 1 True False Speed Ratio: True True 2 True True True False False True True 2 False True 3 True True 0 True False True False Minimum Infill Distance (line widths) True True 0 True True True False False True True 2 False True 1 True True 1 True False True False Very First Layer Height Ratio True True 0 True True True False False True True 2 False True 1 True True 2 True False <b>First Layer(s)</b> True False True 5 2 False 0 none True False 12 True False Enable Acceleration True True False True True True True 0 True False 1 Acceleration Distance: True True 5 1 True True True False False True True 1 False True 2 True False <b>Acceleration</b> True False True 5 3 True False False 0 none True False 12 True False True True False True False True 0 True True True False False True True True True 1 True False <b>GCode Postprocessor</b> True False True 4 4 True False Optimization Optimization 4 False True False True False 0 none True False 12 True False True False Enable Raft True True False True False True 5 0 True False Larger Than Object (mm) True True 1 True True True False False True True True True 2 False True 0 True False 8 3 True True True False False True True 1 2 4 5 True False Rotation per Layer 4 5 True True True False False True True 2 1 2 7 8 True True True False False True True 2 1 2 6 7 True True True False False True True 2 1 2 5 6 True True True False False True True 1 2 3 4 True True True False False True True 2 1 2 2 3 True True True False False True True 1 2 1 2 True False Temperature Ratio 7 8 True False Thickness Ratio 6 7 True False Distance Between Lines 5 6 True False Rotation 3 4 True False Extrusion Ratio 2 3 True False Number of Layers 1 2 True True True False False True True 2 3 1 2 True True True False False True True 2 2 3 2 3 True True True False False True True 2 3 3 4 True True True False False True True 2 3 4 5 True True True False False True True 2 2 3 5 6 True True True False False True True 2 2 3 6 7 True True True False False True True 2 2 3 7 8 True False <b>Base</b> True 1 2 True False <b>Interface</b> True 2 3 False True 1 True False <b>Raft</b> True True True 0 5 True False Raft 5 False True False True False 0 none True False 12 True False False 3 4 True False Tool Diameter GTK_FILL GTK_FILL True True False False True True 2 1 2 GTK_FILL GTK_FILL True False <b></b> True False True 0 6 True False Milling Settings 6 False True False 6 6 6 6 True False 12 True False 0 none True False 6 12 True False 4 3 6 6 True False 6 True False 0 Colour False False 0 True True True Choose Wireframe Colour #000000000000 False False 1 1 2 1 2 GTK_FILL GTK_FILL True False 6 True False 0 Colour False False 0 True True True Choose Normals Colour #000000000000 False False 1 1 2 2 3 GTK_FILL GTK_FILL True False 6 True False 0 Colour False False 0 True True True Choose Endpoints Colour #000000000000 False False 1 1 2 3 4 GTK_FILL True False 6 True False 0 Colour False False 0 True True True Choose Polygon Colour #000000000000 False False 1 1 2 GTK_FILL GTK_FILL True False 6 True False 0 Highlight Strength False True 0 True True False False True True Display.HighlightAdjustment 2 False False 1 2 3 GTK_FILL GTK_FILL True False 6 True False 0 0.49000000953674316 Length False True 0 True True False False True True Display.NormalsLengthAdjustment 2 False False 1 2 3 2 3 GTK_FILL GTK_FILL True False 6 True False 0 0.49000000953674316 Size False True 0 True True False False True True DisplayEndPointSizeAdjustment 2 False False 1 2 3 3 4 GTK_FILL GTK_FILL Shade Wireframe True True False True 2 3 1 2 GTK_FILL GTK_FILL True False True False Polygons GTK_FILL GTK_FILL True False Wireframe 1 2 GTK_FILL GTK_FILL True False Normals 2 3 True False Endpoints 3 4 True False <b>STL Rendering Colors</b> True False True 0 True False 0 none True False 6 12 True False 4 3 6 6 True False 6 GTK_FILL GTK_FILL Adjust Luminance to Indicate Speed True True False True 3 1 2 GTK_FILL GTK_FILL True False 6 True False 0 Move Head Colour False True 0 True True True Choose Head Movement Colour #000000000000 False False 1 1 2 GTK_FILL GTK_FILL True False True False GCode when Printing Preview/Live Extrude Color False False 0 True True True Choose Extrusion Colour #000000000000 False False 3 1 2 3 True False 0.4699999988079071 <b>GCode Rendering</b> True False True 1 True False 0 none True False 6 12 True False 6 True False 0 Enable Lights False True 0 1 True True False True False True 1 2 True True False True False True 2 3 True True False True False True 3 4 True True False True False True 4 True False <b>Lighting</b> True False True 2 7 True False Display Settings 7 False True False 6 6 6 6 True False 12 True False 0 none True False 6 12 True False Enable Debug True True False True False True 0 Speeds are handled as mm/sec True False False False True True True 1 True False <b>Debugging</b> True False True 0 True False 0 none True False 6 12 True False True False Draw Polygon Numbers True True False True False True 0 Draw Line Numbers True True False True False True 1 Draw Vertex Numbers True True False True False True 2 True True 0 True False Show Layer Overhang Areas True True False True True True 0 Randomize Lines True True False True True True 1 Fill Layer Areas True True False True True True 2 True True 1 True False <b>Layer Debug</b> True False True 1 True False 0 none True False 6 12 True False True False Debug Infill True True False True False True 0 Draw Polygon Numbers True True False True False True 1 True True 0 True False Draw Line Numbers True True False True False True 0 Draw Vertex Numbers True True False True False True 1 True True 1 True False <b>Infill Debug</b> True False True 2 True False 0 none True False 12 True False Debug Arcs True True False True False True 0 Show Extruder Number on GCode True True False True True True 1 Show GCode with Extruder Offset True False True False True True True 2 Show only GCode with Z Change True True False True True True 3 True False <b>Debug GCode</b> True False True 3 True False 0 none True False 12 True False Serial comms debug True True False True False False 0 True False <b>Comms Debug</b> True False False 4 True False 0 none True False 12 Output Progress to Terminal True True False True True False <b>Output</b> True False False 5 8 True False Debug 8 False True True 1 True True 1 Close repsnapper-2.3.2a5/src/settings.cpp000066400000000000000000000667231231531733200172740ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks Copyright (C) 2013 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "settings.h" #include #include "infill.h" /* * How settings are intended to work: * * Settings is a subclass of Glib::KeyFile. * * Glade Builder Widgets are named as ., so automatically * converted to KeyFile settings. This works for most settings, but * there are exceptions... * * All default setting values have to be at least in the default .conf file * * A redraw is done on every change made by the GUI. */ #ifdef WIN32 # define DEFAULT_COM_PORT "COM0" #else # define DEFAULT_COM_PORT "/dev/ttyUSB0" #endif const string serialspeeds[] = { "9600", "19200", "38400", "57600", "115200", "230400", "250000" }; // convert GUI name to group/key bool splitpoint(const string &glade_name, string &group, string &key) { int pos = glade_name.find("."); if (pos==(int)std::string::npos) return false; group = glade_name.substr(0,pos); key = glade_name.substr(pos+1); return true; } void set_up_combobox(Gtk::ComboBox *combo, vector values) { if (combo->get_model()) return; Gtk::TreeModelColumn column; Gtk::TreeModelColumnRecord record; record.add(column); Glib::RefPtr store = Gtk::ListStore::create(record); combo->pack_start (column); combo->set_model(store); for (uint i=0; iappend()->set_value(0, Glib::ustring(values[i].c_str())); } #if GTK_VERSION_GE(2, 24) if (!combo->get_has_entry()) #endif combo->set_active(0); //cerr << "ok" << endl; } string combobox_get_active_value(Gtk::ComboBox *combo){ #if GTK_VERSION_GE(2, 24) if (combo->get_has_entry()) { Gtk::Entry *entry = combo->get_entry(); if (entry) return string(entry->get_text()); } else #endif { uint c = combo->get_active_row_number(); Glib::ustring rval; combo->get_model()->children()[c].get_value(0,rval); return string(rval); } cerr << "could not get combobox active value" << endl; return ""; } bool combobox_set_to(Gtk::ComboBox *combo, string value) { Glib::ustring val(value); Glib::RefPtr model = combo->get_model(); uint nch = model->children().size(); Glib::ustring rval; Glib::ustring gvalue(value.c_str()); #if GTK_VERSION_GE(2, 24) if (combo->get_has_entry()) { Gtk::Entry *entry = combo->get_entry(); if (entry) { entry->set_text(value); return true; } } else #endif { for (uint c=0; c < nch; c++) { Gtk::TreeRow row = model->children()[c]; row.get_value(0,rval); if (rval== gvalue) { combo->set_active(c); return true; } } } cerr << "value " << value << " not found in combobox" << endl; return false; } ///////////////////////////////////////////////////////////////// Settings::Settings () { set_defaults(); m_user_changed = false; inhibit_callback = false; } Settings::~Settings() { } // merge into current settings void Settings::merge (const Glib::KeyFile &keyfile) { vector< Glib::ustring > groups = keyfile.get_groups(); for (uint g = 0; g < groups.size(); g++) { vector< Glib::ustring > keys = keyfile.get_keys(groups[g]); for (uint k = 0; k < keys.size(); k++) { set_value(groups[g], keys[k], keyfile.get_value(groups[g], keys[k])); } } } // always merge when loading settings bool Settings::load_from_file (string file) { Glib::KeyFile k; if (!k.load_from_file(file)) return false; merge(k); return true; } bool Settings::load_from_data (string data) { Glib::KeyFile k; if (!k.load_from_file(data)) return false; merge(k); return true; } // make "ExtruderN" group, if i<0 (not given), use current selected Extruder number string Settings::numberedExtruder(const string &group, int num) const { if (group == "Extruder") { ostringstream oss; oss << "Extruder" << num; //cerr << "call for " << oss.str() << endl; return oss.str(); } return group; } Vector4f Settings::get_colour(const string &group, const string &name) const { vector s = get_double_list(group, name); return Vector4f(s[0],s[1],s[2],s[3]); } void Settings::set_colour (const string &group, const string &name, const Vector4f &value) { Glib::KeyFile::set_double_list(group, name, value); } void Settings::assign_from(Settings *pSettings) { this->load_from_data(pSettings->to_data()); m_user_changed = false; m_signal_visual_settings_changed.emit(); m_signal_update_settings_gui.emit(); } void Settings::set_defaults () { filename = ""; set_string("Global","SettingsName","Default Settings"); set_string("Global","SettingsImage",""); set_string("Global","Version",VERSION); set_string("GCode","Start", "; This code is sent to the printer at the beginning.\n" "; Adjust it to your needs.\n" "; \n" "; GCode generated by RepSnapper:\n" "; http://reprap.org/wiki/RepSnapper_Manual:Introduction\n" "G21 ; metric coordinates\n" "G90 ; absolute positioning\n" "T0 ; select new extruder\n" "G28 ; go home\n" "G92 E0 ; set extruder home\n" "G1 X5 Y5 F500 ; move away 5 mm from 0.0, to use the same reset for each layer\n\n"); set_string("GCode","Layer",""); set_string("GCode","End", "; This code is sent to the printer after the print.\n" "; Adjust it to your needs.\n" "G1 X0 Y0 F2000.0 ; feed for start of next move\n" "M104 S0.0 ; heater off\n"); // Extruders.clear(); // Extruders.push_back(Extruder); // The vectors map each to 3 spin boxes, one per dimension set_double("Hardware","Volume.X", 200); set_double("Hardware","Volume.Y", 200); set_double("Hardware","Volume.Z", 140); set_double("Hardware","PrintMargin.X", 10); set_double("Hardware","PrintMargin.Y", 10); set_double("Hardware","PrintMargin.Z", 0); set_boolean("Misc","SpeedsAreMMperSec",true); } // make old single coordinate colours to lists void Settings::convert_old_colour (const string &group, const string &key) { try { cerr << "converting "<< group << "." < file) { inhibit_callback = true; filename = file->get_path(); // set_defaults(); if (has_group("Extruder")) remove_group("Extruder"); // avoid converting old if merging new file try { if (!load_from_file (filename)) { std::cout << _("Failed to load settings from file '") << filename << "\n"; return; } } catch (const Glib::KeyFileError &err) { std::cout << _("Exception ") << err.what() << _(" loading settings from file '") << filename << "\n"; return; } std::cerr << _("Parsing config from '") << filename << "\n"; // convert old colour handling: vector< Glib::ustring > groups = get_groups(); for (uint g = 0; g < groups.size(); g++) { //cerr << "["< keys = get_keys(groups[g]); for (uint k = 0; k < keys.size(); k++) { int n = keys[k].length(); int c = keys[k].find("Colour"); if (c >= 0 && c < n-6 && keys[k].substr(c+6,1) == "R") convert_old_colour(groups[g],keys[k].substr(0,c+6)); } } // convert old user buttons: std::vector CustomButtonLabels; std::vector CustomButtonGCodes; if (has_group("UserButtons")) { CustomButtonLabels = get_string_list("UserButtons","Labels"); CustomButtonGCodes = get_string_list("UserButtons","GCodes"); } try { vector< Glib::ustring > keys = get_keys("CustomButtons"); for (uint k = 0; k < keys.size(); k++) { bool havekey = false; for (uint o = 0; o < CustomButtonLabels.size(); o++) { if (CustomButtonLabels[o] == keys[k]) { CustomButtonGCodes[o] = get_string("CustomButtons",keys[k]); havekey = true; break; } } if (!havekey) { CustomButtonLabels.push_back(keys[k]); CustomButtonGCodes.push_back(get_string("CustomButtons",keys[k])); } } remove_group("CustomButtons"); } catch (Glib::KeyFileError &err) {} if (!has_group("UserButtons")) { set_string_list("UserButtons","Labels",CustomButtonLabels); set_string_list("UserButtons","GCodes",CustomButtonGCodes); } // convert old extruders, now we count "Extruder0", "Extruder1" ... // instead of "Extruder", "Extruder2" ... if (has_group("Extruder")) { // have old Extruders uint ne = getNumExtruders() + 1; // +1 because "Extruder" is not counted if (has_group("Extruder0")) ne--; // already have "new" Extruders copyGroup("Extruder","Extruder0"); if (ne > 1) { for (uint k = 2; k < ne+1; k++) // copy 2,3,4,... to 1,2,3,... copyGroup(numberedExtruder("Extruder",k), numberedExtruder("Extruder",k-1)); remove_group(numberedExtruder("Extruder",ne)); } remove_group("Extruder"); } uint ne = getNumExtruders(); for (uint k = 0; k < ne; k++) { if (!has_key(numberedExtruder("Extruder",k), "OffsetX")) set_double(numberedExtruder("Extruder",k), "OffsetX", 0); if (!has_key(numberedExtruder("Extruder",k), "OffsetY")) set_double(numberedExtruder("Extruder",k), "OffsetY", 0); } SelectExtruder(0); if ( ( has_group("Misc") && !has_key("Misc","SpeedsAreMMperSec") ) || !get_boolean("Misc","SpeedsAreMMperSec") ) cout << "!!!" << endl << _("\tThe config file has old speed settings (mm/min).\n\t Adjust them to mm/sec\n\t or use RepSnapper from 2.0 to 2.2 to convert them automatically.") << "!!!" << endl; set_boolean("Misc","SpeedsAreMMperSec",true); inhibit_callback = false; m_user_changed = false; m_signal_visual_settings_changed.emit(); m_signal_update_settings_gui.emit(); } void Settings::save_settings(Glib::RefPtr file) { inhibit_callback = true; set_string("Global","Version",VERSION); remove_group("Extruder"); // is only temporary Glib::ustring contents = to_data(); // cerr << contents << endl; Glib::file_set_contents (file->get_path(), contents); SelectExtruder(selectedExtruder); // reload default extruder inhibit_callback = false; // all changes safely saved m_user_changed = false; } void Settings::set_to_gui (Builder &builder, const string &group, const string &key) { inhibit_callback = true; Glib::ustring glade_name = group + "." + key; // inhibit warning for settings not defined in glade UI: if (!builder->get_object (glade_name)) { //cerr << glade_name << _(" not defined in GUI!")<< endl; return; } Gtk::Widget *w = NULL; builder->get_widget (glade_name, w); if (!w) { std::cerr << _("Missing user interface item ") << glade_name << "\n"; return; } Gtk::CheckButton *check = dynamic_cast(w); if (check) { check->set_active (get_boolean(group,key)); return; } Gtk::SpinButton *spin = dynamic_cast(w); if (spin) { spin->set_value (get_double(group,key)); return; } Gtk::Range *range = dynamic_cast(w); if (range) { range->set_value (get_double(group,key)); return; } Gtk::ComboBox *combo = dynamic_cast(w); if (combo) { if (glade_name == "Hardware.SerialSpeed") // has real value combobox_set_to(combo, get_string(group,key)); else // has index combo->set_active(get_integer(group,key)); return; } Gtk::Entry *entry = dynamic_cast(w); if (entry) { entry->set_text (get_string(group,key)); return; } Gtk::Expander *exp = dynamic_cast(w); if (exp) { exp->set_expanded (get_boolean(group,key)); return; } Gtk::ColorButton *col = dynamic_cast(w); if(col) { vector c = get_double_list(group,key); Gdk::Color co; co.set_rgb_p(c[0],c[1],c[2]); col->set_use_alpha(true); col->set_color(co); col->set_alpha(c[3] * 65535.0); return; } Gtk::TextView *tv = dynamic_cast(w); if (tv) { tv->get_buffer()->set_text(get_string(group,key)); return; } cerr << "set_to_gui of "<< glade_name << " not done!" << endl; } void Settings::get_from_gui (Builder &builder, const string &glade_name) { if (inhibit_callback) return; if (!builder->get_object (glade_name)) { cerr << "no such object " << glade_name << endl; return; } Gtk::Widget *w = NULL; builder->get_widget (glade_name, w); while (w) { // for using break ... string group, key; if (!splitpoint(glade_name, group, key)) return; //cerr << "get " << group << "." << key << " from gui"<< endl; m_user_changed = true; // is_changed; Gtk::CheckButton *check = dynamic_cast(w); if (check) { set_boolean(group, key, check->get_active()); break; } Gtk::SpinButton *spin = dynamic_cast(w); if (spin) { set_double(group, key, spin->get_value()); break; } Gtk::Range *range = dynamic_cast(w); if (range) { set_double(group, key, range->get_value()); break; } Gtk::ComboBox *combo = dynamic_cast(w); if (combo) { if (glade_name == "Hardware.SerialSpeed") // has real value set_string(group,key,combobox_get_active_value(combo)); else set_integer(group,key,combo->get_active_row_number ()); break; } Gtk::Entry *e = dynamic_cast(w); if (e) { set_string(group,key,e->get_text()); break; } Gtk::Expander *exp = dynamic_cast(w); if (exp) { set_boolean(group,key,exp->get_expanded()); break; } Gtk::ColorButton *cb = dynamic_cast(w); if (cb) { get_colour_from_gui(builder, glade_name); break; } Gtk::TextView *tv = dynamic_cast(w); if (tv) { set_string(group,key,tv->get_buffer()->get_text()); break; } cerr << _("Did not get setting from ") << glade_name << endl; m_user_changed = false; break; } if (m_user_changed) { // update currently edited extruder if (glade_name.substr(0,8) == "Extruder") { copyGroup("Extruder",numberedExtruder("Extruder", selectedExtruder)); } m_signal_visual_settings_changed.emit(); } } void Settings::get_colour_from_gui (Builder &builder, const string &glade_name) { string group,key; if (!splitpoint(glade_name, group,key)) return; Gdk::Color c; Gtk::ColorButton *w = NULL; builder->get_widget (glade_name, w); if (!w) return; c = w->get_color(); // FIXME: detect 'changed' etc. vector d(4); d[0] = c.get_red_p(); d[1] = c.get_green_p(); d[2] = c.get_blue_p(); d[3] = (float) (w->get_alpha()) / 65535.0; set_double_list(group, key, d); m_signal_visual_settings_changed.emit(); } // whole group or all groups void Settings::set_to_gui (Builder &builder, const string filter) { inhibit_callback = true; vector< Glib::ustring > groups = get_groups(); for (uint g = 0; g < groups.size(); g++) { vector< Glib::ustring > keys = get_keys(groups[g]); for (uint k = 0; k < keys.size(); k++) { set_to_gui(builder, groups[g], keys[k]); } } //set_filltypes_to_gui (builder); if (filter == "" || filter == "Misc") { Gtk::Window *pWindow = NULL; builder->get_widget("main_window", pWindow); try { int w = get_integer("Misc","WindowWidth"); int h = get_integer("Misc","WindowHeight"); if (pWindow && w > 0 && h > 0) pWindow->resize(w,h); int x = get_integer("Misc","WindowPosX"); int y = get_integer("Misc","WindowPosY"); if (pWindow && x > 0 && y > 0) pWindow->move(x,y); } catch (const Glib::KeyFileError &err) { std::cout << _("Exception ") << err.what() << _(" loading setting\n"); } } // Set serial speed. Find the row that holds this value if (filter == "" || filter == "Hardware") { Gtk::ComboBox *portspeed = NULL; builder->get_widget ("Hardware.SerialSpeed", portspeed); if (portspeed) { std::ostringstream ostr; ostr << get_integer("Hardware","SerialSpeed"); //cerr << "portspeed " << get_integer("Hardware","SerialSpeed") << endl; combobox_set_to(portspeed, ostr.str()); } } inhibit_callback = false; } void Settings::connect_to_ui (Builder &builder) { if (has_group("Ranges")) { vector ranges = get_keys("Ranges"); for (uint i = 0; i < ranges.size(); i++) { // get min, max, increment, page-incr. vector vals = get_double_list("Ranges", ranges[i]); Gtk::Widget *w = NULL; try { builder->get_widget (ranges[i], w); if (!w) { std::cerr << "Missing user interface item " << ranges[i] << "\n"; continue; } Gtk::SpinButton *spin = dynamic_cast(w); if (spin) { spin->set_range (vals[0],vals[1]); spin->set_increments (vals[2],vals[3]); continue; } Gtk::Range *range = dynamic_cast(w); // sliders etc. if (range) { range->set_range (vals[0],vals[1]); range->set_increments (vals[2],vals[3]); continue; } } catch (Glib::Exception &ex) { } } } // add signal callbacks to GUI elements vector< Glib::ustring > groups = get_groups(); for (uint g = 0; g < groups.size(); g++) { if (groups[g] == "Ranges") continue; // done that above vector< Glib::ustring > keys = get_keys(groups[g]); for (uint k = 0; k < keys.size(); k++) { string glade_name = groups[g] + "." + keys[k]; if (!builder->get_object (glade_name)) continue; Gtk::Widget *w = NULL; try { builder->get_widget (glade_name, w); if (!w) { std::cerr << "Missing user interface item " << glade_name << "\n"; continue; } Gtk::CheckButton *check = dynamic_cast(w); if (check) { check->signal_toggled().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::SpinButton *spin = dynamic_cast(w); if (spin) { spin->signal_value_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)) ; continue; } Gtk::Range *range = dynamic_cast(w); if (range) { range->signal_value_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::ComboBox *combo = dynamic_cast(w); if (combo) { if (glade_name == "Hardware.SerialSpeed") { // Serial port speed vector speeds(serialspeeds, serialspeeds+sizeof(serialspeeds)/sizeof(string)); set_up_combobox(combo, speeds); } else if (glade_name.find("Filltype")!=std::string::npos) { // Infill types uint nfills = sizeof(InfillNames)/sizeof(string); vector infills(InfillNames,InfillNames+nfills); set_up_combobox(combo,infills); } combo->signal_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::Entry *e = dynamic_cast(w); if (e) { e->signal_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::Expander *exp = dynamic_cast(w); if (exp) { exp->property_expanded().signal_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::ColorButton *cb = dynamic_cast(w); if (cb) { cb->signal_color_set().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } Gtk::TextView *tv = dynamic_cast(w); if (tv) { tv->get_buffer()->signal_changed().connect (sigc::bind(sigc::bind(sigc::mem_fun(*this, &Settings::get_from_gui), glade_name), builder)); continue; } } catch (Glib::Exception &ex) { } } } /* Update UI with defaults */ m_signal_update_settings_gui.emit(); } // extrusion ratio for round-edge lines double Settings::RoundedLinewidthCorrection(double extr_width, double layerheight) { double factor = 1 + (M_PI/4.-1) * layerheight/extr_width; // assume 2 half circles at edges // /-------------------\ // // | | // // \-------------------/ // //cerr << "round factor " << factor << endl; return factor; } double Settings::GetExtrudedMaterialWidth(double layerheight) const { // ExtrudedMaterialWidthRatio is preset by user return min(max(get_double("Extruder","MinimumLineWidth"), get_double("Extruder","ExtrudedMaterialWidthRatio") * layerheight), get_double("Extruder","MaximumLineWidth")); } // TODO This depends whether lines are packed or not - ellipsis/rectangle // how much mm filament material per extruded line length mm -> E gcode double Settings::GetExtrusionPerMM(double layerheight) const { double f = get_double("Extruder","ExtrusionFactor"); // overall factor if (get_boolean("Extruder","CalibrateInput")) { // means we use input filament diameter const double matWidth = GetExtrudedMaterialWidth(layerheight); // this is the goal // otherwise we just work back from the extruded diameter for now. const double filamentdiameter = get_double("Extruder","FilamentDiameter"); f *= (matWidth * matWidth) / (filamentdiameter * filamentdiameter); } // else: we work in terms of output anyway; return f; } // return infill distance in mm double Settings::GetInfillDistance(double layerthickness, float percent) const { double fullInfillDistance = GetExtrudedMaterialWidth(layerthickness); if (percent == 0) return 10000000; return fullInfillDistance * (100./percent); } uint Settings::getNumExtruders() const { vector< Glib::ustring > groups = get_groups(); uint num=0; for (uint g = 0; g < groups.size(); g++) if (groups[g].substr(0,8) == "Extruder" && groups[g].length() > 8 ) // count only numbered num++; return num; } std::vector Settings::get_extruder_letters() const { uint num = getNumExtruders(); std::vector letters(num); for (uint i = 0; i < num; i++) letters[i] = get_string(numberedExtruder("Extruder",i),"GCLetter")[0]; return letters; } uint Settings::GetSupportExtruder() const { uint num = getNumExtruders(); for (uint i = 0; i < num; i++) if (get_boolean(numberedExtruder("Extruder",i),"UseForSupport")) return i; return 0; } Vector3d Settings::get_extruder_offset(uint num) const { string ext = numberedExtruder("Extruder",num); return Vector3d(get_double(ext, "OffsetX"), get_double(ext, "OffsetY"), 0.); } void Settings::copyGroup(const string &from, const string &to) { vector keys = get_keys(from); for (uint i = 0; i < keys.size(); i++) set_value(to, keys[i], get_value(from, keys[i])); } // create new void Settings::CopyExtruder(uint num) { uint total = getNumExtruders(); string from = numberedExtruder("Extruder",num); string to = numberedExtruder("Extruder",total); copyGroup(from, to); } void Settings::RemoveExtruder(uint num) { ostringstream oss; oss << "Extruder"<= getNumExtruders()) return; selectedExtruder = num; copyGroup(numberedExtruder("Extruder",num),"Extruder"); // show Extruder settings on gui if (builder) { set_to_gui(*builder, "Extruder"); } } Matrix4d Settings::getBasicTransformation(Matrix4d T) const { Vector3d t; T.get_translation(t); const Vector3d margin = getPrintMargin(); double rsize = get_double("Raft","Size") * (get_boolean("Raft","Enable")?1:0); t+= Vector3d(margin.x() + rsize, margin.y() + rsize, 0); T.set_translation(t); return T; } Vector3d Settings::getPrintVolume() const { return Vector3d (get_double("Hardware","Volume.X"), get_double("Hardware","Volume.Y"), get_double("Hardware","Volume.Z")); } Vector3d Settings::getPrintMargin() const { Vector3d margin(get_double("Hardware","PrintMargin.X"), get_double("Hardware","PrintMargin.Y"), get_double("Hardware","PrintMargin.Z")); Vector3d maxoff = Vector3d::ZERO; uint num = getNumExtruders(); for (uint i = 0; i < num ; i++) { string ext = numberedExtruder("Extruder",i); double offx = 0, offy = 0; try { offx = abs(get_double(ext, "OffsetX")); offy = abs(get_double(ext, "OffsetY")); } catch (const Glib::KeyFileError &err) { } if (offx > abs(maxoff.x())) maxoff.x() = offx; if (offy > abs(maxoff.y())) maxoff.y() = offy; } if (get_boolean("Slicing","Skirt")) { double distance = get_double("Slicing","SkirtDistance"); maxoff += Vector3d(distance, distance, 0); } return margin + maxoff; } // Locate it in relation to ourselves ... std::string Settings::get_image_path() { std::string basename = Glib::path_get_dirname(filename); return Glib::build_filename (basename, get_string("Global","Image")); } bool Settings::set_user_button(const string &name, const string &gcode) { try { vector buttonlabels = get_string_list("UserButtons","Labels"); vector buttongcodes = get_string_list("UserButtons","GCodes"); for (uint i = 0; i < buttonlabels.size(); i++){ if (buttonlabels[i] == name) { // change button buttongcodes[i] = gcode; set_string_list("UserButtons","GCodes",buttongcodes); } else { // add button buttonlabels.push_back(name); buttongcodes.push_back(gcode); set_string_list("UserButtons","Labels",buttonlabels); set_string_list("UserButtons","GCodes",buttongcodes); } } } catch (const Glib::KeyFileError &err) { } return true; } string Settings::get_user_gcode(const string &name) { try { vector buttonlabels = get_string_list("UserButtons","Labels"); vector buttongcodes = get_string_list("UserButtons","GCodes"); for (uint i = 0; i < buttonlabels.size(); i++){ if (buttonlabels[i] == name) return buttongcodes[i]; } } catch (const Glib::KeyFileError &err) { } return ""; } bool Settings::del_user_button(const string &name) { try { vector buttonlabels = get_string_list("UserButtons","Labels"); vector buttongcodes = get_string_list("UserButtons","GCodes"); for (uint i = 0; i < buttonlabels.size(); i++){ if (buttonlabels[i] == name) { buttonlabels.erase(buttonlabels.begin()+i); buttongcodes.erase(buttongcodes.begin()+i); return true; } } } catch (const Glib::KeyFileError &err) { } return false; } repsnapper-2.3.2a5/src/settings.h000066400000000000000000000127011231531733200167240ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks Copyright (C) 2013 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #include #include "stdafx.h" // Allow passing as a pointer to something to // avoid including glibmm in every header. typedef Glib::RefPtr Builder; class Settings : public Glib::KeyFile { Glib::ustring filename; // where it's loaded from bool m_user_changed; bool inhibit_callback; // don't update settings from gui while setting to gui public: void copyGroup(const string &from, const string &to); // overwrite to get the chance to make multiple extruder manipulations /* int get_integer (const string &group, const string &name) const; */ /* double get_double (const string &group, const string &name) const; */ /* bool get_boolean (const string &group, const string &name) const; */ /* string get_string (const string &group, const string &name) const; */ Vector4f get_colour (const string &group, const string &name) const; /* void set_integer (const string &group, const string &name, const int value); */ /* void set_double (const string &group, const string &name, const double value); */ /* void set_boolean (const string &group, const string &name, const bool value); */ /* void set_string (const string &group, const string &name, const string &value); */ void set_colour (const string &group, const string &name, const Vector4f &value); string numberedExtruder(const string &group, int num=-1) const; vmml::vec3d getPrintVolume() const; vmml::vec3d getPrintMargin() const; static double RoundedLinewidthCorrection(double extr_width, double layerheight); double GetExtrudedMaterialWidth(const double layerheight) const; double GetExtrusionPerMM(double layerheight) const; std::vector get_extruder_letters() const; Vector3d get_extruder_offset(uint num) const; uint GetSupportExtruder() const; void CopyExtruder(uint num); void RemoveExtruder(uint num); void SelectExtruder(uint num, Builder *builder=NULL); uint selectedExtruder; uint getNumExtruders() const; /* class GCodeImpl; */ /* enum GCodeTextType { */ /* GCODE_TEXT_START, */ /* GCODE_TEXT_LAYER, */ /* GCODE_TEXT_END, */ /* GCODE_TEXT_TYPE_COUNT */ /* }; */ /* struct GCodeType { */ /* GCodeImpl *m_impl; */ /* std::string getText(GCodeTextType t) const ; */ /* std::string getStartText() const { return getText (GCODE_TEXT_START); } */ /* std::string getLayerText() const { return getText (GCODE_TEXT_LAYER); } */ /* std::string getEndText() const { return getText (GCODE_TEXT_END); } */ /* }; */ /* GCodeType GCode; */ // Paths we loaded / saved things to last time std::string STLPath; std::string RFOPath; std::string GCodePath; std::string SettingsPath; private: void set_to_gui (Builder &builder, int i); void set_to_gui (Builder &builder, const string &group, const string &key); void get_from_gui_old (Builder &builder, int i); void get_from_gui (Builder &builder, const string &glade_name); bool get_group_and_key (int i, Glib::ustring &group, Glib::ustring &key); void get_colour_from_gui (Builder &builder, const string &glade_name); void convert_old_colour (const string &group, const string &key); void set_defaults (); public: Settings(); ~Settings(); bool has_user_changed() const { return m_user_changed; } void assign_from(Settings *pSettings); bool set_user_button(const string &name, const string &gcode); bool del_user_button(const string &name); string get_user_gcode(const string &name); Matrix4d getBasicTransformation(Matrix4d T) const; // return real mm depending on hardware extrusion width setting double GetInfillDistance(double layerthickness, float percent) const; // sync changed settings with the GUI eg. used post load void set_to_gui (Builder &builder, const string filter=""); // connect settings to relevant GUI widgets void connect_to_ui (Builder &builder); void merge (const Glib::KeyFile &keyfile); bool load_from_file (string file); bool load_from_data (string data); void load_settings (Glib::RefPtr file); void load_settings_as (const Glib::ustring onlygroup = "", const Glib::ustring as_group = ""); void save_settings (Glib::RefPtr file); void save_settings_as (const Glib::ustring onlygroup = "", const Glib::ustring as_group = ""); std::string get_image_path(); sigc::signal< void > m_signal_visual_settings_changed; sigc::signal< void > m_signal_update_settings_gui; sigc::signal< void > m_signal_core_settings_changed; }; repsnapper-2.3.2a5/src/settings/000077500000000000000000000000001231531733200165525ustar00rootroot00000000000000repsnapper-2.3.2a5/src/settings/ed-sells-mendel.conf000066400000000000000000000001101231531733200223630ustar00rootroot00000000000000[Global] SettingsName=Ed-Sells Mendel SettingsImage=ed-sells-mendel.jpg repsnapper-2.3.2a5/src/settings/ed-sells-mendel.jpg000066400000000000000000000174231231531733200222350ustar00rootroot00000000000000JFIFHHC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((x"H !1"AQ2aqB#R$34Sbr&6CDc3 !1AQa"2qBR ?t\˄n\$Dif)H 'jh;94fUI%LccWAHZ<OG (+u!+<['%ef*Jmˈ #Ci+G^?WC@ip!Gtr gs `5(#o4wcm炕3_F\֏>#Z$ It4vum?k Ul+8+$g(k*َE }nN>~FDIysןeħy+nlBE4zEBeBP8xvV!Xgv\n`Hpm%* iwK~r Ze%R-4^);%dƝݿnt{"eMEo>di:mW'WOJԗ$_-&AņS]h ]ÃuI9."-u%{(hie iHSw$|*^4򕟣.,V~gXDp\gQ3P gȒ8Ĝj:Վ?lG:= {-8b=#>K!Aҵա햦X)@%YI/6 !9F^UO49Dۚ>'jݝSh=?Ɠ|^!,TLLVnD$U'o}aRA;h.mmĴRGq׮ K6q3 qINr02GA4R${><V=I?-R8J--1$+$S(Aw:R7**TaJ ~\VX7 0K ZVRT0A9V;|i %譱ũ@n 9>up,٭6;T 3zVԸRٚUH]٥Cx#hH=xceM\r0$8I e(NHMBw_3gG{ߐEF+-+|R5;rTLhP8w+_#__ !4s"*Fi{>RD2mꮲFp*7Yw' #򮷄ZS,ee8.;2"%MXYN:Ԛnh~HS%;~NW_tROѲ&ޒuKݝ*if,cJ[ְ6\%3g{)n RKa{a# ALJJzef4; +BO#N*]WlŽQ![LVqKt8fzmmhq[$]+ =s喇QIo:pѩO%GۃF-{v_QJP$ ;{8Χ=.rRñSƒ %xPӎ5}$ZTv L+Pbg]9'3 *qj;7ޅIQdoeJj8 bLش~e’X@:A)P#)Ljkqm*Ŏ/+$1sZQVNEvLs9<dtÃHUd hnzHLyJCeԡḧ=<@5u=h}`+Mq Օ? I[m7gm}VN<",S̛蕹ː/z^{8ǚfaՒKn- ))<(9'$%(;&b\k P)*ܒD}M[Z4.\6I4Y-R2Lu I~r Od kkozXj)iH{ +ycL3A(dNG~UE)Se Ⱥ&׭JPwI:5?[~4ň m⯴PoRR9%D.ICGFpWOZ{#F褺KJa`WOvu1uɋ2 w¢Cc*G*pWʭ-.ei)!CD᳌k.PH%ŒE;윺p8vnPNxo)|i'JU,DvdvSO8Tj\niTiim+@F@TuY]%].8IV/2D#SMј{i&JZ2 Q|[h⛋!jr9H(RĔq皢O/ϣ$6eK!J8NԌ{ d()Rˊh9Q#+Ẽ6=BvamZX\̆P]((Q[@8u^q~ ֕9-KY^wg9I֍7NиJ% w$zd4;s)CZ\ӥF m-%,nmׁ )* ~ɗq%w'=Ď|qʼn oiZPwzxWDunXDHŴi2绞gJtܞ}UZjUw{}mc>”NB*qCbR@###9ҳ*T5A6\[A\[-Ziz9![^ 0AϺR|xgRZsmv/zV=xVqݘ*Jni")L-H ҰnrYI ڷ8pNARIǶI5:}x”Àژ!EpY$ gޙʱ^vњmGgnA>-܍(#2RJmdjN3BF-i]EOu'R%hnz3nd{V $vais0OҀj+W5F$M)Z`Qy*hur9wBk$ߢܤ[ߜi]B'bQcW_V\cXH0^٥+N {%:*TS6/qsɽcuJd٥ Qv$0x8k^7/VDdʝQ8)NI*$' =+([CZܛ!#%KyKSmyUe[vׇ}JGF[e*ͪȓ!2ܒ#V~U).$) JzA;XҨ=BvqYC n8U Π6D֐Hi'Î*:@(#Rwϴz˩eh(dI S}9}* 6N,nugj?~9>\uKV .-JF| *:]!)H<3OWMP%9)`u5o.\jGX.VI o|'s TVQS*9\-<xڜ_PYNiUv^h6.\]4уj .pJu9 ob| 47L)##xSme '<񞟍n 1 psI43m-$@ܗvuY_䀼Rj?G?*jSQ)#qP#$|*uQa{:섥 +8'jrH2ʐ{\,8)T]ͩbC|vkC/H;00xǍ]eeK heZIrO8֢K4vihJVJA'4U-e貋Oh〥$[4-?L#_)x;"= %e4*la ,0(N@ҫnzd%ŕLm((| k^)Z^LoD'rg$cR9B@)'%^n2Q6dGmc%@qMC!*UXtu(2k4? >eF[R[2.R^S֢NNsW2yQSnSx8o9QΤ-hJc7ٴ$wMzn~ZIlޠQ ?MTSDe -.L QQGf {%C@4Cg\lZm䄠+ӌI(]2"isrHQ88K]D$}"f 8JH^ ojA4)ThHmm7ّqOS8`5P$m JtF~*VVԕsX?~%E\}auUc)ÃI4+5ސ!AgVӵH 9^kk!RX(RFx^*v5I~Q%39oޕ mΏ7hiUbfU1Эl8sԶ d8_x寮^C543q)UƨV96W-GaF|Eϛ*vZGDg *l#88ko RLzg#ո{0νC0mre-D}V;-Zʐc><mOHPx}cIi,{AZp>pP Dj }` 2RT6nPݸ@ۏ0)%d2+O\uOa'JRҐ)_m|:Lݥ #īkY1=1!;FGt㪳+9q{S&dTY-c WGAJ̭UoEIi/):Vc{K0V{̶dIBYp-M)D焀y<3bZ-/nK[ۈӲ\*J1ڌjXߛ,,W I)k Rdޛ) ,ͳU[.>\pvʲX)뛼"$}(0x`b Ym+㐮i44+@B>FFKz:6vT˲]›}8_fi= S6Ddrۀxv"™}IK}L/= Ӣl6׻V 븢>tO$'hxV-l׈oymOQ]\E'DqT \B9&9p(yJҁImI8뜕umiH;W0rƷՊTdynl7^r*N RC)$:P!&:ѵ`|~gyButq:S6whH#ڧ䬊#S"y}iǭG(' c8YB#Eׇ!Mr z;~Ìż\c?l~ȧ%ϨuCMœn=#@TVzxqDWnU9 8:R8ϗel9L]a9Rgǟ"0iBPv *U+eX3i9Y`*[BKiEW?`u9T_ UF[Z  hdRNqP)\!ZҴ)R;&Y*@Ϛ;q{N~JۙFG6wU A.*u}RT܁4 qcSmHO0j. Im|HȥJ/rEKZwGځ8 @'J--H[8Hp:Gq!%V;8*3**Qe)ED!8'8ʝE{A&*[&ƽĶUQ1ݥJ J9*`Jrepsnapper-2.3.2a5/src/settings/mendel-max.conf000066400000000000000000000000761231531733200214530ustar00rootroot00000000000000[Global] SettingsName=Mendel Max SettingsImage=mendel-max.jpg repsnapper-2.3.2a5/src/settings/mendel-max.jpg000066400000000000000000000131471231531733200213110ustar00rootroot00000000000000JFIFHHC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((xy"E !1A"Qaq#2BRT$Sbr3Uc%!1AQa"q2 ?^h[ }f5? F WЋmcfmxɤ{Vŷ`*^L,tHJMDLQh/G'\rŲ:()Y+a<|t> e ⶖ]X=DON0/vҝ^ DUu2~&KHf\p`;}N9_̴u1/Whca˖9S]%8+:qQ# bUB3ƻA;PP'$ϟntvKZz-8ʌ|yĨ!RX#T}5l{JT.e5f7 -HJz2H͵dhO=*~xꬴK\V M%QI0B ;I-(t5>GI$e/I9Շfmެ^))iZS ۽\ʰjQmJ1ޢY%y ўp=Mss0uxS#<<^I0ƇORmyk+ifRFXCBL$cvxƷі&VAN]c%= ܧ {1<3[IU$7}$uP1m?-I~4uu Q<"ܣ~( @e s'Fԫ:Tsɤş .Nӏt nEL>CQ=^6^ȐR 9lE Uם<-Ao]QU}ԟP?8za-U3eET❤Ň?]Z*:r:VV/BnGpAtRI=fIS&v|yiU5/>YŅPrߩH7?CLU>߫TSנ5d\7;|cu[Ri# ][m~oƙc@/rAPURv[  S!F3_:ʆ *&h F}f?3i\e 9JəiVIp{7lv.-=+4+Xvoi::1eYR2 r'B ,x]@^lG,qUSΦ)CF8>8xrKW@n_Ok_xQI$k2l#]G9Ӈٖ/݋ =Siӷ;7qk>9aFr =MԤXd?Y[:C H3:-գ-Dp=<*}?9Qt2ӴPNDmeWEu;i`sE.MPibW)ڝԑ2ƽ$$Ml!Lg%cjHA:[l4-kz{MY??.9)%{eʒ j-Sp0NtjnnnFAS?-; %'T`KӰ߀ ?\hV*i(Jﳭһ#}ҕJ}v(>+3'aP~%hGdRGGj}NVUSNų3太$B$ޮ" #^dOWXJV"0NP}tSIx2Nja<>z)GRYԌ\ӔYI1:yN}yqj EV"u,'m IIx ʭKU ݻ`Tƫrm:}-.ۥE]خx f8%7Fi(h$gYGᅀ|ۥ(j<t]Yx.<$`J:ȣ*iK89%J] EۧXjT`LSݻ(rx? r2Ҩ []:$5Lmb7Hn$gU*jfv\1R03yj/V\$3,ccw_9GQ}GI-R7lv:*V%nEe1x>oVM. Jb(V9~;ꊬHBaP?uDpy3}b(!*ݩvYL "TAV!5EtW`"rE'y !0CEESiz4>Psa:3I;]:_X,c Ije=򟫨bSTQIʕ(0md$' -w5:Bc9%'϶䛒ہi\-JXmcFٍOL;ܿR4z;E4hϙ8qi$/+sOi#q?akYdZH` a8cb̃s&98 v("u;^)kX$m2 ;W8ΖzZ[SA$\*v׀4~#uut2a䊔;H#KLx' ?MphibG眃v]}V5fיE$傎0EuHD]tfE)nX9+Ȳ9$ɒYs?~/yAV) kVBwcdr g~LdlGBDc Pl?KvM5hYdxraA h#Ѣr+WvO?%8on2梥UP1{sZ+uĉYNU='SL)%$A06F;|yơF3*-"Ju(ͮIOmuiO TPAC烓ߒө٫RfX2KW/mfY U[\Gd`۔fQQRYy? v8= &v2D}fUTN0Iټ44v??/SODxt?MfHJ=Gp%;?r{5KW'bYR~8 [3(䑟Q`2%ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((wp"<!1A"Qaq#2RBb$3CDr*!1A2a"#q ?OP<,0)}R ,c#s5:58@j"VO 匩#Mk1>`fPA8½b"sKQmkttS0QR^N-GK@ #ٶ{_"\%Y%Coզ1 88Л~ruA)9E\6A,RnTBZ5$lF-A,o |$)[aju%_{ofˉ! ,]ֳɉĭ}j=M~%/rҪOvZi橺 -T|<'*LJfQ)V {Mm5=#8bI+Оo8_Qe&l:x3<tA[lN}K+R1;=Fժ5')_a;2s[BJ.m|5<'m"fᜆ&mFI)Pz xQ#3Wζ ʏ3+G蕉d)y: v*ҷVLXKuB'F_/%3f ejkL [gQʈl#}"1f *rjaaBoF[:ًQ@ qsjvTPL2$6m!l7p !Ƞj:T[(=  "h3Si7[20B{<*OA"v ~9CAG$Dk}^ƝZ (s wөͅث|#Y|s`H@v*/ϯL-\M$=.d#;Emhi3긒/fzږJrzů VF4+Sj6?||mCטBBYo÷M0HPDXGCnʷ@ۘL -}HG+\_ežKfuٍ4H7'n mf&(:hI*Bb0 G}PԄlE4$ fU`G5,b~[ywžuE嵉R4J9$dCY [O~SZSnwv6*.[椖25U/l| _{c̾&c:_>x]=-pI"v%Kě)^UA1iնSBjGST; nF4jePEIQ< ,nη_ =Hm5\MUT92)ٛ:F +s://E,XVwe56r$Q,AXFE.>xTI;ڮ~4JG! YNڀ'9B_ ;LƁ|(3քK)ixy疲&0d)6,nuZ`NS==$IRrK,nQN׹"_n(*|0TJdE:U`$uǥԩܐ~HTU/-6i 5#i Թ" xnrYfjcD事@,y-Sݩo! H6]Ϯ)+Q`jaa-*DA30gm zrN3j#S*4#x 631F8/yS5<*#>s N.<=rTJbtV׊r詸_'i0h-q\D-1ݜ3)NK4(Zåd2Aᗟ"F 6N =(꣪VhїI 7r"m} [53,5i$RCQ#=oc,/g<_gCS3[_SU%?TI3UѳʟmǓg4gQw \QSR!噂ahں k&iꦡk\msqCq*V zuA!SmOkl3ѩK%nXCĠ[a!H'<7Rpއb=pZ\7aTf@,DRca $P{Tk`୿ߖL'Xde`ZOy53 vRE`leiQa"ͻk=j4_@rPT6`*~lEEIƙUVV4l:-X#mr> K5)JŖE:ptL~*~G:ˌj֚$vƲ PнiLpT cjnSIPG.+$1*/3krg5 A BFQ,|7+/_5W̽(Է2`H A:;9SęSTGSIZ+($:-[USTHم[kazH[̌H}/މ1sλĔM4i"3#ı^cg`ɞ_J/p}ϧ[\աHy?xZzvlEO['QT7?y88&Κn*&I#XިYc3I"JG@-!CQ{|GãKHK̉ l,~ᜮo~*$Mf_[_љ}r&QV`[ 2)hZxhCΚ$:t0ΟAشm}6|LfbH H><[l(Nn,i)#K0c"<Ωv>R5joA<h x)WBMyCUG@ٓw~msWTM9ӨƳonĔ9M+ NcR,;|Ӷi଩ ˙B$~>Ēp6@J_esCbsnصZKצ<otpіRO?3Sj[[kb,x^4~q|YSQtPpTp2JnEER*&qgNR!{ W<|Ttaasl.If̔˙o#K#JGPM>VVK$6GqĿM[䭻f8KeIFj\ݚgտKF32Rrel)4Hz1MPFE%u_j2# &X1lGE61repsnapper-2.3.2a5/src/settings/reprap-darwin.conf000066400000000000000000000000751231531733200221760ustar00rootroot00000000000000[Global] SettingsName=Darwin SettingsImage=reprap-darwin.jpg repsnapper-2.3.2a5/src/settings/reprap-darwin.jpg000066400000000000000000000255041231531733200220350ustar00rootroot00000000000000JFIF,, XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((x E!1"AQaq2B#Rb3r$Ct%Sc3!1AQa2q"BR#3C ?՚P٩@ ZFӞ>t?ʨ%qJؠzl8۶[.w608u #&/@E[d]ڞP % 椢:zStSB PB((P(:it6M P $Q@|=(ͭWxۤzm>$GEvK*@^Ot9%VȔ;^[[ra칭[@% 0¹N>J"SQwoրJ{-k}A=X[n)89y*u/j,lgKO4q#@>+ 0(@  XE(P#>; +.:$p1 ^})C봞 R}) [V}mGP-ss0WYKeŬcjTgb4.]؈幉%pִ=!TJ9yW' M~SILRqww#]i;l;Q Zm!+y cd:xpGvÇZ9:~ O rSm"8xB^-Ͻ>xN&Ny#Sg@V+lld ;B>r-I()iC(Լ)IcLIJLf\L+;E hʔ|#M LqȠdP1@ ;`t 3HVVVwOKZ?Й2Q=fp7zBG{Senr8VmηKlc\cIh)> ;0Rm'"]vKRB)A}3Ơ[jmJZ '^V2Eއ,0o=ٶڃtPYpê$n'hJ )>GkIE)&\m/N㡭7ֶgɔwCM<18~Ehh推;S۸%%E c? ҽMN-y\Hy} $ R| y樍injI=[Yqpt9v=2e-+B3%$q:ff6ŋN%'ԭD2l3O 0<4Fh99 Cy-z'yuISlUI}z(vg?ğx Q) 7ʏEQ与oz?b'(MNVlH 6mpE 8pyK)>?9> rߑ)Hq$Jv)H N;9lBbIDp&JJ=zi-Zivÿ]s({ E<_/FL霓ZfmֻYe6V I>{zժ;=#4ՠp  %C.iQz߁b ㍸O]1N?P;ǚM%`(Ȋ E/< p>xWUؗFZ @`խ/x-T Gj(:+=ʖPT$1 ұ7#,x&;KngSe);$$`WFj%xa[՞%ɡ{fy$< ̰մPS.㌊jOދ^QMS> {A}nexێF88)erJg0i`GoK%@tu'uY&4)B1[;:DǶAZiH<TA NUhi]3R.7px_WDNl6))qqq?J'o&n+F[`mݳB* pxNHь^ftz<'[Lkqn{tfo}0YGv hZq{^狓'vulmJtG(Z1-?tT8-|Hu9JǡCIؙ9#Jשvj>0fxt0) TW&+I|zA&TMkCT*Ƌ_!0GBiýNe@p10y5fˍ+o'q9~;__O/\jx6Y^mdI deC ִoV_y?LֲΓݞ.`zK{Rsܳ@$G] .m92RrQ)`(-#9e%t9epV 7.v=×ip#Fa-%-Qbi-1i8 Ñ܃ϝi-i崯s/{䫱CCi>ʇNl:dڮr7a*Rw9бCs'jY)A2Hq>iP#TtBsW$!ɵ͹ϳ]Ie)֖p '?`&*sg݉7{ztk䅇gM+Q,}6OOr}0"HZ'm-=-[okJJ6)t~^RnI=6mGgF="Zj1BZ$'Nq=keu52- ^UA~:}u<bNZ]W= C|Bae(JQjPȭC]W+UCȗ`7[c/.F/V_<&i8S~'P]-6AI.1 k p2\Bk6z} 1QU@킫hB@Rߓ*y zcY-H)J=IMQ社TwFp7;$*EܸY[ͨ8:0B4;ԕ]W@W|z8iRvڴ8|21YЊT]{;ؔIOD}J'#<*HBOiM;Kl-¤Lm@+Q9EElC׽:) a >H )a+pGi!cOcF>m[N} AK*[=;='Zؽ0Vii# '}z jGI~m,d$D-8(Xݵ[HڤWo3ZGy1%JYP<`9PYn{CY=L;9M͹MTUP_?\F.Rzv`ZVbx Ia_52!Zr*Rmϙ$YRra[Q#<(lA'֫{vWJ4}ZuIW#ܑR0]}a;^@'p}TLm? 5!0Ҳ.(w$#o8&Ѽ$y1_%k|Tޗd{|A`GƸGU/Hڿq8坖97q5ma ~/h\ [fɁ1P_r<+j"itQr.2[G}):x0Ku؆b}D..L;]^ NџGՍoЧ/rI%JQϩ$(X ғ$*|#Ġ#^unw+Rr;H8LvSa;@kEypYu^vK]kpsP[^s%ܦޝ+WaEn^򞹻"!.͖hN|-OY#zUCl4DhL$53qHǙ$֏PJ&f/>]%}0oz[cm>i{-<}BBWM'nC)J @C>u8sFrÅީdIZ^Ӕ2irH5|+X8g*u {x$(|sumIJT9>y&Nyc[Y ^Kz'8F:U0u,7xFI{Nqn;Qztg+-lEyZP{j$' I0hӸ{X\ ڔ߰7U";!= p>&̅d ,e_%]@4*U(ؠq`ʀgu/ii(J][lNp)8 "cvH&+c9?byEX aPEZ3pꏒpyLtu2Ĺ\V}@p̆PrAϺ:3@Z5wdڎvjvL}L+ iDw6 ij3Mܚ/TRv玙Qnfwmmzd0>4--SN \!829+!IsOd]7g0&]&9{%1c88nKBcƎ) - /Sb'ƈ&˱㯽уrDž|jz1vʁ:Xu񉯰QJz:I>Cd+lӜK -_'I~8dGljZ8ց5; d7~. R_Խ !6G-D@Dmh.1֝-vI.ǶE. *t((s|B{ O)N6h>ʺ XO4R >ݨ+RcaeIJұzR!wS7qbqE">[2 - o0zQH}ireBUS=Aq\0 AsFJPj'c+s#''>ҟq`Qs_.Dn-XR\?Ucf,ܴܦ2 AKo㍧KOf!ݖim ehF<$Y]Cd'fIiI]xҷ&R8ΐRI{|{/IR6E-9ڈ-'vrOʚ&i٬~&`:*7$TG*U mLiAwEWtj$JT;$~6R۾|RLf?evDž"F H9y527;*DR+m*8M=cw&bRA;DgԣZ}SrlYi#X#`;G5{s*>aƿd u6R/,ZJúfT{uYT1@lceOYEPM5JRnocބNJ3f k$͜IxTqNɠR^,NkR?084Jݿj({%ѡ/hvNM emWZYصFiy)j_ 9lB ~Y.._MŘP԰0]9qG#HQϱqʕFDZ/i+Ht}?4Pq a$HtHw a:w$Re*3@BH@qmHp岓u>Jp&hnZc!G{2P;-j7e ~(#4sKA!ħQd@XJr(.aE,a^*Q!8{*-Ibh(,repsnapper-2.3.2a5/src/settings/reprap-wallace.conf000066400000000000000000000000771231531733200223240ustar00rootroot00000000000000[Global] SettingsName=Wallace SettingsImage=reprap-wallace.jpg repsnapper-2.3.2a5/src/settings/reprap-wallace.jpg000066400000000000000000000160061231531733200221560ustar00rootroot00000000000000JFIFHH XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((xb"E !1AQa"q2#BSb$35DRTr+!1"Qq2BARa ?=j)) 8Ò3hEPy a f=n16=בsp nv[1I#GtPĝ~C#`u5,JSrP˹H=ρ󭶱=݂ 4'6@R9v|WϦ rK 8䂊-+PP\vϪ=5\>3)}Wv{U']GEx<&#Lj8)}[mMAp]ہ(GjaTWK[a.T{AfB@¹+rwo)U%Z3gޕ[$xFQڲ,JTCc;C 6wW wjKc譝; ] p%u2*x\1i<:?IWi 2a5xh}Fb.(菵>4o eшsnM)F?#@!.uf8MfriiښOcm-.HfI'UdF%FIea SQ_{P!W*Ǭ<UOبkn3L z4jeIw@6/lʸM~wJOU } .P: ˞@9#C4]$ m-y})W)P wwO.wq-@4yyVdg-+cUuť~oU%t#/ ~':j)|<3}Db\$bgxɫҴ4g*-,\~+g f"cŨ떶J7n M.]WQ"q8',2?*[{Dq۸DM3O':WkwZdҦU!nmc[ʭ`'6\rNőIPco5ZԴJUf hnl{i˽6Q#=Ӕx][?]\Q._EcXȱA J y|w{=!(̎*/}S_tt~Em41me q^kTt%/$ǯw і1Q $ ֦w1bpۆ2zV۳7s%wz GS6k;I"Q@][F7#m3Pjf.ݢyWrm$0x?:o.3kA{uK{b_2B# Ǧrqҳݔ!nl*+ c˓V5 NUzWGk*p= =InB1n%)!g5"ghܪVC%mZ[q՝NٷM#Vm,!@vh妵KRYǵtc8HkLXyE"4m.$}B( FvxekBz9,d`NGU`~pko-VҴmFK,Ali$~1q/WEԴZ\[]=IJ) w>>k7O*Rle~_5{I{O}Or$_i$T0bxTbšFNv1AGNG$r{bi5 MKDtǷ{t '%XK eHIjri%6JwJYJd|O! GMoP.PJ.Ub@E07hD4څ~ڹwQm:E>V V#u"a!2 RxփzS㷐C&Q'$ב&z=?DUgLm ]c]z`rO Huc5R0ѮI+#?ڋ֚ޢת~ srOrCZ~;_]K0ADn2]> -E;=UPz郊kPhݟ{ѧ_[.NՈw]*劏׵ٙ'< dv+:HY%gS*cU;oi7XLp*񨮹ޘ ik78t'})oF Yvl 9$F3q[%3C4#x7 ڈى[)Ix?ŒA*)AaRB#dHY“^Xy BCD1QI-7[ TȐnPxj=B!͔wo=pw/,P9RK+u s\o4k^Z9ML/w8ʖ qYuDK!Y.8>:i˦E%Zbho2v#íXL;œ?QgDDR{8*H9X¨Wv%/aԂd8v:f.Gh'sOTH^5FD ͓{N(_g5;M~t-QtfXX$*NqcL!rq"3$sR}#*|nHAE*Tlrepsnapper-2.3.2a5/src/settings/reprappro-huxley.conf000066400000000000000000000001001231531733200227360ustar00rootroot00000000000000[Global] SettingsName=Huxley SettingsImage=reprappro-huxley.jpg repsnapper-2.3.2a5/src/settings/reprappro-huxley.jpg000066400000000000000000000104441231531733200226050ustar00rootroot00000000000000JFIFHHC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((xn"@ !1AQ"aq2B#$3R4Dbcr'!1"2AQ#B ?5881Q2 D㓦~H b00s0N5ҭ&tsQ=ǖ]6|smtl]'DK~ IiK[.SR2%bGK<12;#jQm"ezSQ=F8m㐧 Mf:tpIg0 qΘQi cY/Ь5MYYLN!yoN2q.()i䲽Җt#*Z0@*y˒'TUyrxgcK*aA]:V.~Nq[#uUTP~Ĕ"U{$=tZZ8VMH]ؤ0vI'#d5["3$-Q# `($.ܞ9:w h&CZF2I^|ԴVoQ@LjXKID;dtIc""m##:i[ D1n^E(ܒ@8G>Z}=jQUWS! pN؁&9eQ{L0[ODU;.AuzΘ%uDH~YN.I_uBiZr"`1QCG%,SȤ:PdcFiǓG,df><6S`VFH$!q>#P_t6ځק?4UKֶv5w;FɽXsc8tho*T -:>zG:iU^nIC*w+7 tpu$ٸ_Rm U,(&aRՀy?]c3qSK7(#9$h˜+R6ޝ)ⅶ7`8}S| ?˫NuU%G&C%}5 BcX76]*wO1Zx#R{O??1*jzVdr$\W9ݞ'(J=U72ƎL@ 8msz+uj髏,Yb(PӘIジ8yYH`;}uh}K 3SfU8>$aƙd<%?L[bipـGBc_ᣥucn}GwX/vEM=4s$1>UYa(@`RY`[弸05dRDSYje\\dyq"-G"Ug bU]$$Aa<) ۧwUbrr;L\yRVܛn%?y9[6 P7|:z'Iхu΢IҰSU1G$q)7p |SC[M0YdCOohu\~2mH[MLa4Ѯ(#?-+ AUG a#FL#QJnWQ!]RNӂwqsJ`I':![YG%-CO>J/۪z"H1[#_&H'/hVtۧƺ҈@"  gVzj21@}s$z/:ǂt=*?Nݏ\(u'a9qZR4k"[^6?:Zܯ$PFs01gGBuOQ Ȏ\d8v@-tb˓*ϖ}{9%-(w}IubzZ;J&0e,qg~>Z2Pt7Q樕݇;>:DU]T(9bNsu8HԔgd5?Cyj VDiQzhFWʡGa ZkkUU*IYOhgFxqC{ACQG0oq( 8P]W[Pn`< @`ϮEFAӊy?iLV2xw(pOm,+2{ zboK& Uv ϓ8OX%.s>T=:hբFi%hdbhBEXlb.rxl@#\I)RA{TxK&0'=βo ۮԹYCnX. 9 t&,r4"A"Sdrf Y.|Υ|J|ƹ*;56u[sxPvg[u}X㯥(&)$}gD6kU/}9.)TNu-ɺ7x;ww>|AS~t*8x[8.9>ɸ%/bUQ;_z~Inc(q:fSCtJjI Ճ%W E$=Eij*6UW]CHI yuSR\(h Ed6|es3{CM=MDpQ$@,ϖhZ]ǓRI 䓜@W6h&m<ɞSٶQ#叒4LT PY"{u~VKaK5-F˴FW灩qE\SFHY[;euԥm;:1i M7'“5z [cFc 䐆I1YAyC('I8qMZ9҅!,q]?]t*K4țZ6mݹgW\VQOAeL *|d=,k z,#- yU+m ,x<ݧrS_@LTx; }HR,TYp(۾| j,uh?u1"뾜"騾qFEXϣ(4uSS!EA93<Ku5J"H+ }ӕ<|Qҋ5Z`$` ĵ22_j-6N/.El4ע[eF JO"}۳Z8`䕂Fs3TtDik*#T.|H'5&/)Ip⋄\*; 9ۥlz5YՎ9449󥥥hyԕ Vjh]Dt04ҁKKF3})?Q\#_%lKwS }ezii/"1%lArw m(3P}PZZIIːXҘrepsnapper-2.3.2a5/src/shape.cpp000066400000000000000000001040551231531733200165230ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "shape.h" #include "files.h" #include "ui/progress.h" #include "settings.h" #include "clipping.h" #include "render.h" #ifdef _OPENMP #include #endif // Constructor Shape::Shape() : slow_drawing(false), gl_List(-1) { Min.set(0,0,0); Max.set(200,200,200); CalcBBox(); } void Shape::clear() { triangles.clear(); if (gl_List>=0) glDeleteLists(gl_List,1); gl_List = -1; }; void Shape::setTriangles(const vector &triangles_) { triangles = triangles_; CalcBBox(); double vol = volume(); if (vol < 0) { invertNormals(); vol = -vol; } //PlaceOnPlatform(); cerr << _("Shape has volume ") << volume() << _(" mm^3 and ") << triangles.size() << _(" triangles") << endl; } int Shape::saveBinarySTL(Glib::ustring filename) const { if (!File::saveBinarySTL(filename, triangles, transform3D.transform)) return -1; return 0; } bool Shape::hasAdjacentTriangleTo(const Triangle &triangle, double sqdistance) const { bool haveadj = false; int count = (int)triangles.size(); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i = 0; i < count; i++) if (!haveadj) if (triangle.isConnectedTo(triangles[i],sqdistance)) { haveadj = true; } return haveadj; } // recursively build a list of triangles for a shape void addtoshape(uint i, const vector< vector > &adj, vector &tr, vector &done) { if (!done[i]) { // add this index to tr tr.push_back(i); done[i] = true; for (uint j = 0; j < adj[i].size(); j++) { if (adj[i][j]!=i) addtoshape(adj[i][j], adj, tr, done); } } // we have a complete list of adjacent triangles indices } void Shape::splitshapes(vector &shapes, ViewProgress *progress) { int n_tr = (int)triangles.size(); if (progress) progress->start(_("Split Shapes"), n_tr); int progress_steps = max(1,(int)(n_tr/100)); vector done(n_tr); bool cont = true; // make list of adjacent triangles for each triangle vector< vector > adj(n_tr); if (progress) progress->set_label(_("Split: Sorting Triangles ...")); #ifdef _OPENMP omp_lock_t progress_lock; omp_init_lock(&progress_lock); #pragma omp parallel for schedule(dynamic) #endif for (int i = 0; i < n_tr; i++) { if (progress && i%progress_steps==0) { #ifdef _OPENMP omp_set_lock(&progress_lock); #endif cont = progress->update(i); #ifdef _OPENMP omp_unset_lock(&progress_lock); #endif } vector trv; for (int j = 0; j < n_tr; j++) { if (i!=j) { bool add = false; if (jset_label(_("Split: Building shapes ...")); // triangle indices of shapes vector< vector > shape_tri; for (int i = 0; i < n_tr; i++) done[i] = false; for (int i = 0; i < n_tr; i++) { if (progress && i%progress_steps==0) cont = progress->update(i); if (!done[i]){ cerr << _("Shape ") << shapes.size()+1 << endl; vector current; addtoshape(i, adj, current, done); Shape *shape = new Shape(); shapes.push_back(shape); shapes.back()->triangles.resize(current.size()); for (uint i = 0; i < current.size(); i++) shapes.back()->triangles[i] = triangles[current[i]]; shapes.back()->CalcBBox(); } if (!cont) i=n_tr; } if (progress) progress->stop("_(Done)"); } vector cube(Vector3d Min, Vector3d Max) { vector c; const Vector3d diag = Max-Min; const Vector3d dX(diag.x(),0,0); const Vector3d dY(0,diag.y(),0); const Vector3d dZ(0,0,diag.z()); // front c.push_back(Triangle(Min, Min+dX, Min+dX+dZ)); c.push_back(Triangle(Min, Min+dX+dZ, Min+dZ)); // back c.push_back(Triangle(Min+dY, Min+dY+dX+dZ, Min+dY+dX)); c.push_back(Triangle(Min+dY, Min+dY+dZ, Min+dY+dX+dZ)); // left c.push_back(Triangle(Min, Min+dZ, Min+dY+dZ)); c.push_back(Triangle(Min, Min+dY+dZ, Min+dY)); // right c.push_back(Triangle(Min+dX, Min+dX+dY+dZ, Min+dX+dZ)); c.push_back(Triangle(Min+dX, Min+dX+dY, Min+dX+dY+dZ)); // bottom c.push_back(Triangle(Min, Min+dX+dY, Min+dX)); c.push_back(Triangle(Min, Min+dY, Min+dX+dY)); // top c.push_back(Triangle(Min+dZ, Min+dZ+dX, Min+dZ+dX+dY)); c.push_back(Triangle(Min+dZ, Min+dZ+dX+dY, Min+dZ+dY)); return c; } void Shape::makeHollow(double wallthickness) { invertNormals(); const Vector3d wall(wallthickness,wallthickness,wallthickness); Matrix4d invT = transform3D.getInverse(); vector cubet = cube(invT*Min-wall, invT*Max+wall); triangles.insert(triangles.end(),cubet.begin(),cubet.end()); CalcBBox(); } void Shape::invertNormals() { for (uint i = 0; i < triangles.size(); i++) triangles[i].invertNormal(); } // doesn't work void Shape::repairNormals(double sqdistance) { for (uint i = 0; i < triangles.size(); i++) { vector adjacent; uint numadj=0, numwrong=0; for (uint j = i+1; j < triangles.size(); j++) { if (i!=j) { if (triangles[i].isConnectedTo(triangles[j], sqdistance)) { numadj++; if (triangles[i].wrongOrientationWith(triangles[j], sqdistance)) { numwrong++; triangles[j].invertNormal(); } } } } //cerr << i<< ": " << numadj << " - " << numwrong << endl; //if (numwrong > numadj/2) triangles[i].invertNormal(); } } void Shape::mirror() { const Vector3d mCenter = transform3D.getInverse() * Center; for (uint i = 0; i < triangles.size(); i++) triangles[i].mirrorX(mCenter); CalcBBox(); } double Shape::volume() const { double vol=0; for (uint i = 0; i < triangles.size(); i++) vol+=triangles[i].projectedvolume(transform3D.transform); return vol; } string Shape::getSTLsolid() const { stringstream sstr; sstr << "solid " << filename < &tr) { triangles.insert(triangles.end(), tr.begin(), tr.end()); CalcBBox(); } vector Shape::getTriangles(const Matrix4d &T) const { vector tr(triangles.size()); for (uint i = 0; i < triangles.size(); i++) { tr[i] = triangles[i].transformed(T*transform3D.transform); } return tr; } vector Shape::trianglesSteeperThan(double angle) const { vector tr; for (uint i = 0; i < triangles.size(); i++) { // negative angles are triangles facing downwards const double tangle = -triangles[i].slopeAngle(transform3D.transform); if (tangle >= angle) tr.push_back(triangles[i]); } return tr; } void Shape::FitToVolume(const Vector3d &vol) { Vector3d diag = Max-Min; const double sc_x = diag.x() / vol.x(); const double sc_y = diag.y() / vol.y(); const double sc_z = diag.z() / vol.z(); double max_sc = max(max(sc_x, sc_y),sc_z); if (max_sc > 1.) Scale(1./max_sc, true); } void Shape::Scale(double in_scale_factor, bool calcbbox) { transform3D.move(-Center); transform3D.scale(in_scale_factor); transform3D.move(Center); if (calcbbox) CalcBBox(); } void Shape::ScaleX(double x) { transform3D.move(-Center); transform3D.scale_x(x); transform3D.move(Center); } void Shape::ScaleY(double x) { transform3D.move(-Center); transform3D.scale_y(x); transform3D.move(Center); } void Shape::ScaleZ(double x) { transform3D.move(-Center); transform3D.scale_z(x); transform3D.move(Center); } void Shape::CalcBBox() { Min.set(INFTY,INFTY,INFTY); Max.set(-INFTY,-INFTY,-INFTY); for(size_t i = 0; i < triangles.size(); i++) { triangles[i].AccumulateMinMax (Min, Max, transform3D.transform); } Center = (Max + Min) / 2; if (gl_List>=0) glDeleteLists(gl_List,1); gl_List = -1; } Vector3d Shape::scaledCenter() const { return Center * transform3D.get_scale(); } struct SNorm { Vector3d normal; double area; bool operator<(const SNorm &other) const {return (area Shape::getMostUsedNormals() const { vector normals; // vector normals; // vector area; uint ntr = triangles.size(); vector done(ntr); for(size_t i=0;i nv(normals.size()); for (uint n=0; n < normals.size(); n++) nv[n] = normals[n].normal; return nv; } void Shape::OptimizeRotation() { // CenterAroundXY(); vector normals = getMostUsedNormals(); // cycle through most-used normals? Vector3d N; Vector3d Z(0,0,-1); double angle=0; int count = (int)normals.size(); for (int n=0; n < count; n++) { //cerr << n << normals[n] << endl; N = normals[n]; angle = acos(N.dot(Z)); if (angle>0) { Vector3d axis = N.cross(Z); if (axis.squared_length()>0.1) { Rotate(axis,angle); break; } } } CalcBBox(); PlaceOnPlatform(); } int Shape::divideAtZ(double z, Shape *upper, Shape *lower, const Matrix4d &T) const { vector polys; vector supportpolys; double max_grad; bool ok = getPolygonsAtZ(T, z, polys, max_grad, supportpolys, -1); if (!ok) return 0; vector< vector > surfs; triangulate(polys, surfs); vector surf; for (uint i=0; itriangles.insert(lower->triangles.end(),surf.begin(),surf.end()); for (guint i=0; itriangles.insert(upper->triangles.end(),surf.begin(),surf.end()); vector toboth; for (guint i=0; i< triangles.size(); i++) { Triangle tt = triangles[i].transformed(T*transform3D.transform); if (tt.A.z() < z && tt.B.z() < z && tt.C.z() < z ) lower->triangles.push_back(tt); else if (tt.A.z() > z && tt.B.z() > z && tt.C.z() > z ) upper->triangles.push_back(tt); else toboth.push_back(tt); } vector uppersplit,lowersplit; for (guint i=0; i< toboth.size(); i++) { toboth[i].SplitAtPlane(z, uppersplit, lowersplit); } upper->triangles.insert(upper->triangles.end(), uppersplit.begin(),uppersplit.end()); lower->triangles.insert(lower->triangles.end(), lowersplit.begin(),lowersplit.end()); upper->CalcBBox(); lower->CalcBBox(); lower->Rotate(Vector3d(0,1,0),M_PI); upper->move(Vector3d(10+Max.x()-Min.x(),0,0)); lower->move(Vector3d(2*(10+Max.x()-Min.x()),0,0)); upper->PlaceOnPlatform(); lower->PlaceOnPlatform(); return 2; } void Shape::PlaceOnPlatform() { transform3D.move(Vector3d(0,0,-Min.z())); } // Rotate and adjust for the user - not a pure rotation by any means void Shape::Rotate(const Vector3d & axis, const double & angle) { transform3D.rotate(Center, axis, angle); return; // CenterAroundXY(); // // do a real rotation because matrix transform gives errors when slicing // int count = (int)triangles.size(); // #ifdef _OPENMP // #pragma omp parallel for schedule(dynamic) // #endif // for (int i=0; i < count ; i++) // { // triangles[i].rotate(axis, angle); // } // PlaceOnPlatform(); } // this is primitive, it just rotates triangle vertices void Shape::Twist(double angle) { CalcBBox(); double h = Max.z()-Min.z(); double hangle=0; Vector3d axis(0,0,1); int count = (int)triangles.size(); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i=0; i points(triangles.size()*3); for (uint i = 0; i lines, vector< vector > &connectedlines) { uint nlines = lines.size(); //cerr << "lines size " << nlines << endl; if (nlines==0) return true; vector linedone(nlines); for (uint l=0; l < nlines; l++) linedone[l] = false; vector sequence; uint donelines = 0; vector connections; while (donelines < nlines) { connections.clear(); for (uint l=0; l < nlines; l++) { // add next connecting line if ( !linedone[l] && ( (sequence.size()==0) || (lines[l].start == lines[sequence.back()].end) ) ) { connections.push_back(l); //cerr << "found connection" << endl; } } if (connections.size()>0) { //cerr << "found " << connections.size() << " connections" << endl; sequence.push_back(connections[0]); linedone[connections[0]] =true; donelines++; if (lines[sequence.front()].start == lines[sequence.back()].end) { //cerr << "closed sequence" << endl; connectedlines.push_back(sequence); sequence.clear(); } } else { // (!foundconnection) { // new sequence //cerr << "sequence size " << sequence.size() << endl; connectedlines.push_back(sequence); sequence.clear(); for (uint l=0; l < nlines; l++) { // add next best undone line if (!linedone[l]) { sequence.push_back(l); linedone[l] = true; donelines++; break; } } } } if (sequence.size()>0) connectedlines.push_back(sequence); //cerr << "found "<< connectedlines.size() << " sequences" << endl; return true; } bool Shape::getPolygonsAtZ(const Matrix4d &T, double z, vector &polys, double &max_gradient, vector &supportpolys, double max_supportangle, double thickness) const { vector vertices; vector support_triangles; vector lines = getCutlines(T, z, vertices, max_gradient, support_triangles, max_supportangle, thickness); //cerr << vertices.size() << " " << lines.size() << endl; if (!CleanupSharedSegments(lines)) return false; //cerr << vertices.size() << " " << lines.size() << endl; if (!CleanupConnectSegments(vertices,lines,true)) return false; //cerr << vertices.size() << " " << lines.size() << endl; vector< vector > connectedlines; // sequence of connected lines indices if (!getLineSequences(lines, connectedlines)) return false; for (uint i=0; i 1) { // add points of triangle above z for (uint j = 0; j < 3; j++) { if (support_triangles[i][j].z() > z) { p.addVertex(Vector2d(support_triangles[i][j].x(), support_triangles[i][j].y())); } } bool reverse = false; // test for order if we get 4 points (2 until now) if (p.size() > 1) { Vector2d i0, i1; const int is = intersect2D_Segments(p[1], lineStart, lineEnd, p[0], i0, i1); if (is > 0 && is < 3) { reverse = true; } } // add cutline points if (reverse) { p.addVertex(lineEnd); p.addVertex(lineStart); } else { p.addVertex(lineStart); p.addVertex(lineEnd); } } if (p.isHole()) p.reverse(); supportpolys.push_back(p); } // remove polygon areas from triangles // Clipping clipp; // clipp.clear(); // clipp.addPolys(supportpolys, subject); // clipp.addPolys(polys, clip); // supportpolys = clipp.subtract(CL::pftPositive,CL::pftPositive); return true; } int find_vertex(const vector &vertices, const Vector2d &v, double delta = 0.0001) { int found = -1; int count = (int)vertices.size(); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i=0; i Shape::getCutlines(const Matrix4d &T, double z, vector &vertices, double &max_gradient, vector &support_triangles, double supportangle, double thickness) const { Vector2d lineStart; Vector2d lineEnd; vector lines; // we know our own tranform: Matrix4d transform = T * transform3D.transform ; int count = (int)triangles.size(); // #ifdef _OPENMP // #pragma omp parallel for schedule(dynamic) // #endif for (int i = 0; i < count; i++) { Segment line(-1,-1); int num_cutpoints = triangles[i].CutWithPlane(z, transform, lineStart, lineEnd); if (num_cutpoints == 0) { if (supportangle >= 0 && thickness > 0) { if (triangles[i].isInZrange(z-thickness, z, transform)) { const double slope = -triangles[i].slopeAngle(transform); if (slope >= supportangle) { support_triangles.push_back(triangles[i].transformed(transform)); } } } continue; } if (num_cutpoints > 0) { int havev = find_vertex(vertices, lineStart); if (havev >= 0) line.start = havev; else { line.start = vertices.size(); vertices.push_back(lineStart); } if (abs(triangles[i].Normal.z()) > max_gradient) max_gradient = abs(triangles[i].Normal.z()); if (supportangle >= 0) { const double slope = -triangles[i].slopeAngle(transform); if (slope >= supportangle) support_triangles.push_back(triangles[i].transformed(transform)); } } if (num_cutpoints > 1) { int havev = find_vertex(vertices, lineEnd); if (havev >= 0) line.end = havev; else { line.end = vertices.size(); vertices.push_back(lineEnd); } } // Check segment normal against triangle normal. Flip segment, as needed. if (line.start != -1 && line.end != -1 && line.end != line.start) { // if we found a intersecting triangle Vector3d Norm = triangles[i].transformed(transform).Normal; Vector2d triangleNormal = Vector2d(Norm.x(), Norm.y()); Vector2d segment = (lineEnd - lineStart); Vector2d segmentNormal(-segment.y(),segment.x()); triangleNormal.normalize(); segmentNormal.normalize(); if( (triangleNormal-segmentNormal).squared_length() > 0.2){ // if normals do not align, flip the segment int iswap=line.start;line.start=line.end;line.end=iswap; } // cerr << "line "< 0) { for (uint i = 0; i < 3; i++) mat_diffuse.array[i] = 1.-mat_diffuse.array[i]; mat_diffuse[3] = 0.9; } mat_specular.array[0] = mat_specular.array[1] = mat_specular.array[2] = settings.get_double("Display","Highlight");; /* draw sphere in first row, first column * diffuse reflection only; no ambient or specular */ glMaterialfv(GL_FRONT, GL_AMBIENT, low_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, 90); // 0..128 glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); // glEnable (GL_POLYGON_OFFSET_FILL); if(settings.get_boolean("Display","DisplayPolygons")) { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); // glDepthMask(GL_TRUE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //define blending factors draw_geometry(max_triangles); } glDisable (GL_POLYGON_OFFSET_FILL); // WireFrame if(settings.get_boolean("Display","DisplayWireframe")) { if(!settings.get_boolean("Display","DisplayWireframeShaded")) glDisable(GL_LIGHTING); //for (uint i = 0; i < 4; i++) mat_diffuse = settings.get_colour("Display","WireframeColour"); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glColor4fv(mat_diffuse); for(size_t i=0;i= 0; if (!listDraw && haveList) { if (gl_List>=0) glDeleteLists(gl_List,1); gl_List = -1; haveList = false; } if (listDraw && !haveList) { gl_List = glGenLists(1); glNewList(gl_List, GL_COMPILE); } if (!listDraw || !haveList) { uint step = 1; if (max_triangles>0) step = floor(triangles.size()/max_triangles); step = max((uint)1,step); glBegin(GL_TRIANGLES); for(size_t i=0;i= 0) { // have stored list Glib::TimeVal starttime, endtime; if (!slow_drawing) { starttime.assign_current_time(); } glCallList(gl_List); if (!slow_drawing) { endtime.assign_current_time(); Glib::TimeVal usedtime = endtime-starttime; if (usedtime.as_double() > 0.2) slow_drawing = true; } return; } } /* * sometimes we find adjacent polygons with shared boundary * points and lines; these cause grief and slowness in * LinkSegments, so try to identify and join those polygons * now. */ // ??? as only coincident lines are removed, couldn't this be // done easier by just running through all lines and finding them? bool CleanupSharedSegments(vector &lines) { #if 1 // just remove coincident lines vector lines_to_delete; int count = (int)lines.size(); #ifdef _OPENMP //#pragma omp parallel for schedule(dynamic) #endif for (int j = 0; j < count; j++) { const Segment &jr = lines[j]; for (uint k = j + 1; k < lines.size(); k++) { const Segment &kr = lines[k]; if ((jr.start == kr.start && jr.end == kr.end) || (jr.end == kr.start && jr.start == kr.end)) { lines_to_delete.push_back (j); // remove both??? //lines_to_delete.push_back (k); break; } } } // we need to remove from the end first to avoid disturbing // the order of removed items std::sort(lines_to_delete.begin(), lines_to_delete.end()); for (int r = lines_to_delete.size() - 1; r >= 0; r--) { lines.erase(lines.begin() + lines_to_delete[r]); } return true; #endif #if 0 vector vertex_counts; // how many lines have each point vertex_counts.resize (vertices.size()); for (uint i = 0; i < lines.size(); i++) { vertex_counts[lines[i].start]++; vertex_counts[lines[i].end]++; } // ideally all points have an entrance and // an exit, if we have co-incident lines, then // we have more than one; do we ? std::vector duplicate_points; for (uint i = 0; i < vertex_counts.size(); i++) if (vertex_counts[i] > 2) // no more than 2 lines should share a point duplicate_points.push_back (i); if (duplicate_points.size() == 0) return true; // all sane for (uint i = 0; i < duplicate_points.size(); i++) { std::vector dup_lines; // find all line segments with this point in use for (uint j = 0; j < lines.size(); j++) { if (lines[j].start == duplicate_points[i] || lines[j].end == duplicate_points[i]) dup_lines.push_back (j); } // identify and eliminate identical line segments // NB. hopefully by here dup_lines.size is small. std::vector lines_to_delete; for (uint j = 0; j < dup_lines.size(); j++) { const Segment &jr = lines[dup_lines[j]]; for (uint k = j + 1; k < dup_lines.size(); k++) { const Segment &kr = lines[dup_lines[k]]; if ((jr.start == kr.start && jr.end == kr.end) || (jr.end == kr.start && jr.start == kr.end)) { lines_to_delete.push_back (dup_lines[j]); lines_to_delete.push_back (dup_lines[k]); } } } // we need to remove from the end first to avoid disturbing // the order of removed items std::sort(lines_to_delete.begin(), lines_to_delete.end()); for (int r = lines_to_delete.size() - 1; r >= 0; r--) { lines.erase(lines.begin() + lines_to_delete[r]); } } return true; #endif } /* * Unfortunately, finding connections via co-incident points detected by * the PointHash is not perfect. For reasons unknown (probably rounding * errors), this is often not enough. We fall-back to finding a nearest * match from any detached points and joining them, with new synthetic * segments. */ bool CleanupConnectSegments(const vector &vertices, vector &lines, bool connect_all) { vector vertex_types; vertex_types.resize (vertices.size()); // vector vertex_counts; // vertex_counts.resize (vertices.size()); // which vertices are referred to, and how much: int count = lines.size(); for (int i = 0; i < count; i++) { vertex_types[lines[i].start]++; vertex_types[lines[i].end]--; // vertex_counts[lines[i].start]++; // vertex_counts[lines[i].end]++; } // the vertex_types count should be zero for all connected lines, // positive for those ending no-where, and negative for // those starting no-where. std::vector detached_points; // points with only one line count = vertex_types.size(); // #ifdef _OPENMP // #pragma omp parallel for schedule(dynamic) // #endif for (int i = 0; i < count; i++) { if (vertex_types[i]) { #if CUTTING_PLANE_DEBUG cout << "detached point " << i << "\t" << vertex_types[i] << " refs at " << vertices[i].x() << "\t" << vertices[i].y() << "\n"; #endif detached_points.push_back (i); // i = vertex index } } // Lets hope we have an even number of detached points if (detached_points.size() % 2) { cout << "oh dear - an odd number of detached points => an un-pairable impossibility\n"; return false; } // pair them nicely to their matching type count = detached_points.size(); // #ifdef _OPENMP // #pragma omp parallel for schedule(dynamic) // #endif for (int i = 0; i < count; i++) { double nearest_dist_sq = (std::numeric_limits::max)(); uint nearest = 0; int n = detached_points[i]; // vertex index of detached point i if (n < 0) // handled already continue; const Vector2d &p = vertices[n]; // the real detached point // find nearest other detached point to the detached point n: for (int j = i + 1; j < count; j++) { int pt = detached_points[j]; if (pt < 0) continue; // already connected // don't connect a start to a start, or end to end if (vertex_types[n] == vertex_types[pt]) continue; const Vector2d &q = vertices[pt]; // the real other point double dist_sq = (p-q).squared_length(); //pow (p.x() - q.x(), 2) + pow (p.y() - q.y(), 2); if (dist_sq < nearest_dist_sq) { nearest_dist_sq = dist_sq; nearest = j; } } //assert (nearest != 0); if (nearest == 0) continue; // allow points 10mm apart to be joined, not more if (!connect_all && nearest_dist_sq > 100.0) { cout << "oh dear - the nearest connecting point is " << sqrt (nearest_dist_sq) << "mm away - not connecting\n"; continue; //return false; } // warning above 1mm apart if (!connect_all && nearest_dist_sq > 1.0) { cout << "warning - the nearest connecting point is " << sqrt (nearest_dist_sq) << "mm away - connecting anyway\n"; } #if CUTTING_PLANE_DEBUG cout << "add join of length " << sqrt (nearest_dist_sq) << "\n" ; #endif Segment seg(n, detached_points[nearest]); if (vertex_types[n] > 0) // already had start but no end at this point seg.Swap(); lines.push_back(seg); detached_points[nearest] = -1; } return true; } string Shape::info() const { ostringstream ostr; ostr <<"Shape with "< #include #include #include #include #include #include #include #include "stdafx.h" #include "transform3d.h" //#include "settings.h" #include "triangle.h" #include "slicer/geometry.h" #include "poly.h" //#define ABS(a) (((a) < 0) ? -(a) : (a)) struct Segment { Segment(guint s, guint e) { start = s; end = e; } int start; // Vertex index of start point int end; // Vertex index of end point void Swap() { int tmp = start; start = end; end = tmp; } }; #define sqr(x) ((x)*(x)) class Shape { public: virtual short dimensions(){return 3;}; Shape(); /* Shape(string filename, istream &text); */ virtual ~Shape(){}; Glib::ustring filename; int idx; int parseASCIISTL(istream &text, uint max_triangles=0, bool readnormals=false); Transform3D transform3D; virtual void clear(); /* void displayInfillOld(const Settings &settings, CuttingPlane &plane, */ /* guint LayerNr, vector& altInfillLayers); */ void draw (const Settings &settings, bool highlight=false, uint max_triangles=0); virtual void draw_geometry (uint max_triangles=0); void drawBBox() const; virtual bool getPolygonsAtZ(const Matrix4d &T, double z, vector &polys, double &max_gradient, vector &supportpolys, double max_supportangle, double thickness = -1) const; // Extract a 2D polygonset from a 3D model: // void CalcLayer(const Matrix4d &T, CuttingPlane *plane) const; virtual vector getMostUsedNormals() const; // Auto-Rotate object to have the largest area surface down for printing: virtual void OptimizeRotation(); virtual void CalcBBox(); // Rotation for manual rotate and used by OptimizeRotation: virtual void Rotate(const Vector3d & axis, const double &angle); void Twist(double angle); virtual void move(Vector3d delta){ transform3D.move(delta); }; void Scale(double scale_factor, bool calcbbox = true); void ScaleX(double scale_factor); void ScaleY(double scale_factor); virtual void ScaleZ(double scale_factor); double getScaleFactor() { return transform3D.get_scale(); }; double getScaleFactorX(){ return transform3D.get_scale_x(); }; double getScaleFactorY(){ return transform3D.get_scale_y(); }; virtual double getScaleFactorZ(){ return transform3D.get_scale_z(); }; void FitToVolume(const Vector3d &vol); void PlaceOnPlatform(); Vector3d Min, Max, Center; Vector3d t_Min() const {return transform3D.transform * Min;} Vector3d t_Max() const {return transform3D.transform * Max;} Vector3d t_Center() const {return transform3D.transform * Center;} Vector3d scaledCenter() const; /* Poly getOutline(const Matrix4d &T, double maxlen) const;*/ vector trianglesSteeperThan(double angle) const; string getSTLsolid() const; double volume() const; void invertNormals(); void repairNormals(double sqdistance); virtual void mirror(); void makeHollow(double wallthickness); virtual void splitshapes(vector &shapes, ViewProgress *progress=NULL); int divideAtZ(double z, Shape *upper, Shape *lower, const Matrix4d &T) const; int saveBinarySTL(Glib::ustring filename) const; bool slow_drawing; virtual string info() const; vector getTriangles(const Matrix4d &T=Matrix4d::IDENTITY) const; void addTriangles(const vector &tr); void setTriangles(const vector &triangles_); uint size() const {return triangles.size();} protected: int gl_List; private: vector triangles; //vector polygons; // surface polygons instead of triangles void calcPolygons(); // returns maximum gradient vector getCutlines(const Matrix4d &T, double z, vector &vertices, double &max_grad, vector &support_triangles, double supportangle, double thickness) const; bool hasAdjacentTriangleTo(const Triangle &triangle, double sqdistance = 0.05) const; }; bool CleanupConnectSegments(const vector &vertices, vector &lines, bool connect_all=false); bool CleanupSharedSegments(vector &lines); bool CleanupStraightLines(const vector &vertices, vector &lines); repsnapper-2.3.2a5/src/slicer/000077500000000000000000000000001231531733200161735ustar00rootroot00000000000000repsnapper-2.3.2a5/src/slicer/Makefile000066400000000000000000000002411231531733200176300ustar00rootroot00000000000000# Delegate everything to the toplevel makefile # this is only here so 'make' works in src/ all: @$(MAKE) -C ../.. $@ # Catch all rule %: @$(MAKE) -C ../.. $@ repsnapper-2.3.2a5/src/slicer/Makefile.am000066400000000000000000000012611231531733200202270ustar00rootroot00000000000000# # Combined Makefile for Linux and OS/X # # # Copyright 2009+ Joachim Glauche # Copyright 2011 Bas Wijnen # # This file is part of RepSnapper and is made available under # the terms of the GNU General Public License, version 2, or at your # option, any later version, incorporated herein by reference. SHARED_SRC += \ src/slicer/geometry.cpp \ src/slicer/printlines.cpp \ src/slicer/printlines_antiooze.cpp \ src/slicer/clipping.cpp \ src/slicer/layer.cpp \ src/slicer/infill.cpp \ src/slicer/poly.cpp SHARED_INC += \ src/slicer/geometry.h \ src/slicer/printlines.h \ src/slicer/clipping.h \ src/slicer/layer.h \ src/slicer/infill.h \ src/slicer/poly.h repsnapper-2.3.2a5/src/slicer/clipping.cpp000066400000000000000000000413321231531733200205070ustar00rootroot00000000000000 /* This file is a part of the RepSnapper project. Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "clipping.h" ////////////////////////////////////////////////////////////////////////////////////////// // // old API compatibility // polytree to expolygons // http://www.angusj.com/delphi/clipper/documentation/Docs/Overview/Compatibility%20with%20Prior%20Versions.htm void Clipping::AddOuterPolyNodeToExPolygons(const CL::PolyNode * polynode, ExPolygons& expolygons) { size_t cnt = expolygons.size(); expolygons.resize(cnt + 1); expolygons[cnt].outer = polynode->Contour; expolygons[cnt].holes.resize(polynode->ChildCount()); for (int i = 0; i < polynode->ChildCount(); ++i) { expolygons[cnt].holes[i] = polynode->Childs[i]->Contour; //Add outer polygons contained by (nested within) holes ... for (int j = 0; j < polynode->Childs[i]->ChildCount(); ++j) AddOuterPolyNodeToExPolygons(polynode->Childs[i]->Childs[j], expolygons); } } void Clipping::PolyTreeToExPolygons(const CL::PolyTree * polytree, ExPolygons& expolygons) { expolygons.clear(); for (int i = 0; i < polytree->ChildCount(); ++i) AddOuterPolyNodeToExPolygons(polytree->Childs[i], expolygons); } // ////////////////////////////////////////////////////////////////////////////////////////// void printCLpolygon(CL::Path &p) { cout << p.size() << endl; for (uint k = 0; k < p.size(); k++) { cout << p[k].X <<", " << p[k].Y << "," << endl; } cout << endl; } void printCLpolygons(CL::Paths &p) { for (uint j = 0; j < p.size(); j++) { printCLpolygon(p[j]); cout << endl; } } void printCLpolygons(vector &p) { uint numpolys = 0; for (uint i = 0; i < p.size(); i++) numpolys += p[i].size(); cout << numpolys << endl; for (uint i = 0; i < p.size(); i++) { printCLpolygons(p[i]); } } void Clipping::clear() { clpr.Clear(); if(debug) { subjpolygons.clear(); clippolygons.clear(); } } CL::IntPoint Clipping::ClipperPoint(const Vector2d &v) { return CL::IntPoint(CL_FACTOR*(v.x()+CL_OFFSET), CL_FACTOR*(v.y()+CL_OFFSET)); } Vector2d Clipping::getPoint(const CL::IntPoint &p) { return Vector2d(p.X/CL_FACTOR-CL_OFFSET, p.Y/CL_FACTOR-CL_OFFSET); } CL::Path Clipping::getClipperPolygon(const Poly &poly) { CL::Path cpoly(poly.vertices.size()); for(size_t i=0; i0) { lastZ = polys.back().getZ(); lastExtrF = polys.back().getExtrusionFactor(); } } void Clipping::addPolys(const ExPoly &expoly, PolyType type) { vector polys = getPolys(expoly); addPolys(polys, type); } void Clipping::addPolys(const vector &expolys, PolyType type) { for (uint i = 0; i < expolys.size(); i++) addPolys(expolys[i], type); } void Clipping::addPolygons(const CL::Paths &cp, PolyType type) { clpr.AddPaths(cp, CLType(type), true); } // // return intersection polys // vector< vector > Clipping::intersect(const Poly poly1, const Poly poly2) // { // CL::Path cpoly1 = getClipperPolygon(poly1), // cpoly2 = getClipperPolygon(poly2); // clpr.Clear(); // CL::Paths sol; // clpr.AddPath(cpoly1,CL::ptSubject); // clpr.AddPath(cpoly2,CL::ptClip); // clpr.Execute(CL::ctIntersection, sol, CL::pftEvenOdd, CL::pftEvenOdd); // vector< vector > result; // for(size_t i=0; i polypoints; // CL::Path cpoly = sol[i]; // for(size_t j=0; j Clipping::intersect(CL::PolyFillType sft, CL::PolyFillType cft) { CL::Paths inter; clpr.Execute(CL::ctIntersection, inter, sft, cft); return getPolys(inter, lastZ, lastExtrF); } vector Clipping::ext_intersect(CL::PolyFillType sft, CL::PolyFillType cft) { CL::PolyTree inter; clpr.Execute(CL::ctIntersection, inter, sft, cft); return getExPolys(inter, lastZ, lastExtrF); } // have added Polyons by addPolygon(s) vector Clipping::unite(CL::PolyFillType sft, CL::PolyFillType cft) { CL::Paths united; clpr.Execute(CL::ctUnion, united, sft, cft); return getPolys(united, lastZ, lastExtrF); } vector Clipping::ext_unite(CL::PolyFillType sft, CL::PolyFillType cft) { CL::PolyTree inter; clpr.Execute(CL::ctUnion, inter, sft, cft); return getExPolys(inter, lastZ, lastExtrF); } // have added Polyons by addPolygon(s) vector Clipping::subtract(CL::PolyFillType sft, CL::PolyFillType cft) { CL::Paths diff; clpr.Execute(CL::ctDifference, diff, sft, cft); return getPolys(diff, lastZ, lastExtrF); } vector Clipping::ext_subtract(CL::PolyFillType sft, CL::PolyFillType cft) { CL::PolyTree diff; // if (debug) { // try { // clpr.Execute(CL::ctDifference, diff, sft, cft); // } catch (int e){ // cerr << lastZ<<" - " << lastExtrF<< endl; // if (e == 22){ // cout << "Subject" << endl; // printCLpolygons(subjpolygons); // cout << "Clip" << endl; // printCLpolygons(clippolygons); // // vector empty; // // return empty; // } // } // } // else clpr.Execute(CL::ctDifference, diff, sft, cft);//CL::pftEvenOdd, CL::pftEvenOdd); return getExPolys(diff, lastZ, lastExtrF); } vector Clipping::subtractMerged(double dist, CL::PolyFillType sft, CL::PolyFillType cft) { CL::Paths diff; clpr.Execute(CL::ctDifference, diff, sft, cft); return getPolys(getMerged(diff, dist), lastZ, lastExtrF); } vector Clipping::Xor(CL::PolyFillType sft, CL::PolyFillType cft) { CL::Paths xored; clpr.Execute(CL::ctXor, xored, sft, cft); return getPolys(xored, lastZ, lastExtrF); } vector Clipping::getOffset(const Poly &poly, double distance, JoinType jtype, double miterdist) { CL::Paths cpolys(1); cpolys[0]=getClipperPolygon(poly); CL::Paths offset = CLOffset(cpolys, CL_FACTOR*distance, CLType(jtype), miterdist); return getPolys(offset, poly.getZ(), poly.getExtrusionFactor()); } vector Clipping::getOffset(const vector &polys, double distance, JoinType jtype, double miterdist) { CL::Paths cpolys = getClipperPolygons(polys); CL::Paths offset = CLOffset(cpolys, CL_FACTOR*distance, CLType(jtype), miterdist); double z=0, extrf=1.;; if (polys.size()>0) { z = polys.back().getZ(); extrf = polys.back().getExtrusionFactor(); } return getPolys(offset,z,extrf); } vector Clipping::getOffset(const ExPoly &expoly, double distance, JoinType jtype, double miterdist) { vector polys = getPolys(expoly); return getOffset(polys,distance,jtype,miterdist); } vector Clipping::getOffset(const vector &expolys, double distance, JoinType jtype, double miterdist) { return getOffset(getPolys(expolys),distance,jtype,miterdist); } // vector Clipping::getOffset(const vector expolys, double distance, // JoinType jtype, double miterdist) // { // CL::ExPolygons excpolys = getClipperPolygons(expolys); // double z=0, extrf=1.;; // vector polys(excpolys.size()); // if (expolys.size()>0) { // z = expolys.back().outer.getZ(); // extrf = expolys.back().outer.getExtrusionFactor(); // } // for (uint i = 0 ; i < expolys.size(); i++) { // CL::Paths outer = CLOffset(excpolys[i].outer, // CL_FACTOR*distance, CLType(jtype), miterdist); // polys[i].outer = getPoly(outer, z, extrusionfactor); // vector polys[i].holes; // for (uint h = 0 ; h < polys[i].holes.size(); h++) { // CL::Paths holes = CLOffset(excpolys[i].holes[h], // CL_FACTOR*distance, CLType(jtype), miterdist); // vector hpolys = CL:getPolys(holes, z, extrusionfactor); // polys[i].holes.insert(polys[i].holes.end(),hpolys.begin(),hpolys.end()); // } // } // return getExPolys(offset,z,extrf); // } // first goes in then out to get capped corners vector Clipping::getShrinkedCapped(const vector &polys, double distance, JoinType jtype, double miterdist) { CL::Paths cpolys = getClipperPolygons(polys); CL::Paths offset1 = CLOffset(cpolys, -2*CL_FACTOR*distance, CLType(jtype), 0);// CL::jtRound); CL::Paths offset = CLOffset(offset1, 1*CL_FACTOR*distance, CLType(jtype), 0); double z=0, extrf=1.;; if (polys.size()>0) { z= polys.back().getZ(); extrf = polys.back().getExtrusionFactor(); } return getPolys(offset,z,extrf); } // offset with reverse test CL::Paths Clipping::CLOffset(const CL::Paths &cpolys, int cldist, CL::JoinType cljtype, double miter_limit, bool reverse) { CL::Paths opolys; if (reverse) CL::ReversePaths(opolys); CL::OffsetPaths(cpolys, opolys, cldist, cljtype, CL::etClosed, miter_limit); CL::SimplifyPolygons(opolys);//, CL::pftNonZero); return opolys; } // overlap a bit and unite to merge adjacent polys vector Clipping::getMerged(const vector &polys, double overlap) { CL::Paths cpolys = getClipperPolygons(polys); CL::Paths merged = getMerged(cpolys, CL_FACTOR*overlap); double z=0, extrf = 1.; if (polys.size()>0) { z= polys.back().getZ(); extrf = polys.back().getExtrusionFactor(); } return getPolys(merged, z, extrf); } // overlap a bit and unite to merge adjacent polys CL::Paths Clipping::getMerged(const CL::Paths &cpolys, int overlap) { CL::Clipper clpr; // return polys; // make wider to get overlap CL::Paths offset; offset = CLOffset(cpolys, overlap, CL::jtMiter, 1); //CL::OffsetPolygons(cpolys, offset, 10, ClipperLib::jtMiter, 1); // return getPolys(offset, polys.back().getZ(),polys.back().getExtrusionFactor()); clpr.AddPaths(offset, CL::ptSubject, true); CL::Paths cpolys3; clpr.Execute(CL::ctUnion, cpolys3, CL::pftEvenOdd, CL::pftEvenOdd); //cerr << cpolys3.size() << " - "< Clipping::getPolys(const CL::Paths &cpolys, double z, double extrusionfactor) { uint count = cpolys.size(); vector polys(count); for (uint i = 0 ; i Clipping::getExPolys(const CL::PolyTree &ctree, double z, double extrusionfactor) { ExPolygons cexpolys; PolyTreeToExPolygons(&ctree, cexpolys); vector expolys(cexpolys.size()); for (uint j = 0 ; j < cexpolys.size(); j++) { expolys[j].outer = getPoly(cexpolys[0].outer, z, extrusionfactor); for (uint i = 0 ; i < cexpolys[j].holes.size(); i++) expolys[j].holes.push_back(getPoly(cexpolys[j].holes[i], z, extrusionfactor)); } return expolys; } vector Clipping::getPolys(const ExPoly &expoly) { Clipping clipp; clipp.addPoly(expoly.outer, subject); clipp.addPolys(expoly.holes, clip); vector polys = clipp.subtract(); return polys; } vector Clipping::getPolys(const vector &expolys) { vector polys; for (uint i = 0; i< expolys.size(); i++) { vector p = getPolys(expolys[i]); polys.insert(polys.end(),p.begin(),p.end()); } return polys; } vector Clipping::getExPolys(const vector &polys) { /* CL::PolyTree tree = getClipperTree(polys); return getExPolys(tree, polys.back().getZ(), polys.back().getExtrusionFactor()); */ vector expolys; vector holes; for (uint i = 0; i0) if (expolys[j].outer.vertexInside(holes[i].vertices[0])) // just test one point //if (holes[i].isInside(expolys[j].outer)) // test all expolys[j].holes.push_back(holes[i]); return expolys; } vector Clipping::getExPolys(const vector &polys, double z, double extrusionfactor) { vector ppolys(polys.size()); for (uint i = 0; i &polys) { CL::Paths cpolys = getClipperPolygons(polys); CL::Clipper clpr; clpr.AddPaths(cpolys, CL::ptSubject, true); CL::PolyTree ctree; clpr.Execute(CL::ctUnion, ctree, CL::pftEvenOdd, CL::pftEvenOdd); return ctree; } double Clipping::Area(const Poly &poly){ CL::Path cp = getClipperPolygon(poly); return (double)((long double)(CL::Area(cp))/CL_FACTOR/CL_FACTOR); } double Clipping::Area(const vector &polys){ double a=0; for (uint i=0; i &expolys){ double a=0; for (uint i=0; i &polys) { for (uint i=0; i #else #include #endif #include "poly.h" // Clipper uses non-negative long long integers, so we transform by: const double CL_FACTOR = 10000; // 1 = 1/10000 mm const double CL_OFFSET = 10000; // 10 meters namespace CL = ClipperLib; enum PolyType{subject,clip}; enum JoinType{jsquare,jmiter,jround}; class Clipping { friend class Poly; CL::Clipper clpr; double lastZ; // remember last added polygon's Z for output double lastExtrF; // remember last added polygon's extrusion factor for output static CL::JoinType CLType(JoinType type); static CL::PolyType CLType(PolyType type); static CL::IntPoint ClipperPoint(const Vector2d &v); static Vector2d getPoint(const CL::IntPoint &p); static CL::Paths CLOffset(const CL::Paths &cpolys, int cldist, CL::JoinType cljtype, double miter_limit=1, bool reverse=false); bool debug; vector subjpolygons; // for debugging vector clippolygons; public: Clipping(bool debugclipper=false){debug = debugclipper;}; ~Clipping(){clear();}; void clear(); void addPoly (const Poly &poly, PolyType type); void addPolys (const vector &poly, PolyType type); void addPolys (const vector &expolys, PolyType type); void addPolys (const ExPoly &poly, PolyType type); void addPolygons(const CL::Paths &cp, PolyType type); // do after addPoly... and before clipping/results void setZ(double z) {lastZ = z;}; double getZ() const {return lastZ;}; void setExtrusionFactor(double e) {lastExtrF = e;}; vector intersect (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector unite (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector subtract (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector subtractMerged (double overlap=0.001, CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector Xor (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector ext_intersect (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector ext_unite (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); vector ext_subtract (CL::PolyFillType sft=CL::pftEvenOdd, CL::PolyFillType cft=CL::pftEvenOdd); static vector getMerged(const vector &polys, double overlap=0.001); static CL::Paths getMerged(const CL::Paths &cpolys, int overlap=3); static vector getOffset(const Poly &poly, double distance, JoinType jtype=jmiter, double miterdist=1); static vector getOffset(const vector &polys, double distance, JoinType jtype=jmiter,double miterdist=1); static vector getOffset(const ExPoly &expoly, double distance, JoinType jtype=jmiter, double miterdist=1); static vector getOffset(const vector &expolys, double distance, JoinType jtype=jmiter, double miterdist=1); static vector getShrinkedCapped(const vector &polys, double distance, JoinType jtype=jmiter,double miterdist=1); //vector< vector > intersect(const Poly poly1, const Poly poly2) const; static Poly getPoly(const CL::Path &cpoly, double z, double extrusionfactor); static vector getPolys(const ExPoly &expoly); static vector getPolys(const vector &expolys); static vector getPolys(const CL::Paths &cpoly, double z, double extrusionfactor); static vector getExPolys(const CL::PolyTree &ctree, double z, double extrusionfactor); static vector getExPolys(const vector &polys, double z, double extrusionfactor); static vector getExPolys(const vector &polys); static CL::PolyTree getClipperTree(const vector &polys); static CL::Path getClipperPolygon (const Poly &poly); static CL::Paths getClipperPolygons(const vector &polys); static CL::Paths getClipperPolygons(const ExPoly &expoly); //static CL::PolyTree getClipperTree(const vector &expolys); static double Area(const Poly &poly); static double Area(const vector &polys); static double Area(const ExPoly &expoly); static double Area(const vector &expolys); static void ReversePoints(vector &polys); protected: // old API compatibility // polytree to expolygons struct ExPolygon { CL::Path outer; CL::Paths holes; }; typedef std::vector< ExPolygon > ExPolygons; static void AddOuterPolyNodeToExPolygons(const CL::PolyNode *polynode, ExPolygons& expolygons); static void PolyTreeToExPolygons(const CL::PolyTree * polytree, ExPolygons& expolygons); }; repsnapper-2.3.2a5/src/slicer/geometry.cpp000066400000000000000000001266411231531733200205440ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2013 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "geometry.h" #include "poly.h" #include "clipping.h" #include "triangle.h" // limfit library for arc fitting #include // #ifdef WIN32 // # include // Header GLUT Library // #endif #ifdef _MSC_VER # pragma warning( disable : 4018 4267) #endif /* // call me before glutting void checkGlutInit() { static bool inited = false; if (inited) return; inited = true; int argc = 1; char *argv[] = { (char *) "repsnapper" }; //glutInit (&argc, argv); } void drawString(const Vector3d &pos, const string &text) { //drawString(pos,GLUT_BITMAP_HELVETICA_12,text); } void drawString(const Vector3d &pos, void* font, const string &text) { checkGlutInit(); //glRasterPos3d(pos.x(), pos.y(), pos.z()); //for (uint c=0;cpx[i], arcdata->py[i]); const double distance_sq = center.squared_distance(arcpoint); fvec[i] = abs(par[2] - distance_sq); // sq.radius difference = residue } } bool fit_arc(const int m_dat, const arc_data_struct data, const int n_par, double *par, double sq_error, Vector2d &result_center, double &result_radiussq) { lm_status_struct status; lm_control_struct control = lm_control_double; control.ftol = sq_error; // max square error sum // printf( "Fitting:\n" ); lmmin( n_par, par, m_dat, (const void*) &data, evaluate_arcfit, &control, &status); result_center.x() = par[0]; result_center.y() = par[1]; result_radiussq = par[2]; double fvec[m_dat]; int info; evaluate_arcfit(par, m_dat, (const void*) &data, fvec, &info); double totres = 0; for (int i=0; i &points, double sq_error, Vector2d &result_center, double &result_radiussq) { if (points.size() < 3) return false; const int n_par = 3; // center x,y and arc radius_sq // start values: const Vector2d P = points[0]; const Vector2d Q = points.back(); const Vector2d startxy = (P+Q)/2.; double par[3] = { startxy.x(), startxy.y(), P.squared_distance(Q) }; int m_dat = points.size(); arc_data_struct data; data.px = new double[m_dat]; data.py = new double[m_dat]; for (int i = 0; i < m_dat; i++) { data.px[i] = points[i].x(); data.py[i] = points[i].y(); } return fit_arc(m_dat, data, n_par, par, sq_error, result_center, result_radiussq); } ///////////////////////////////////////////////////////////////////////////// /// VMML helpers void move(const Vector3f &delta, Matrix4f &mat){ Vector3f trans; mat.get_translation(trans); mat.set_translation(trans+delta); } Vector3d normalized(const Vector3d &v){ Vector3d n(v); n.normalize(); return n; } Vector2d normalized(const Vector2d &v){ Vector2d n(v); n.normalize(); return n; } void moveArcballTrans(Matrix4fT &matfT, const Vector3d &delta) { Matrix4f matf; typedef Matrix4f::iterator mIt; for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); *it = matfT.M[i]; } move(delta,matf); for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); matfT.M[i] = *it; } } void setArcballTrans(Matrix4fT &matfT, const Vector3d &trans) { Matrix4f matf; typedef Matrix4f::iterator mIt; for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); *it = matfT.M[i]; } matf.set_translation(trans); for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); matfT.M[i] = *it; } } void rotArcballTrans(Matrix4fT &matfT, const Vector3d &axis, double angle) { Matrix4f rot = Matrix4f::IDENTITY; Vector3d naxis(axis); naxis.normalize(); rot.rotate(angle, naxis); Matrix4f matf; typedef Matrix4f::iterator mIt; for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); *it = matfT.M[i]; } matf = rot * matf; for (mIt it = matf.begin(); it!=matf.end(); ++it){ uint i = it - matf.begin(); matfT.M[i] = *it; } } // // from V1 to V2 // template< size_t M, typename T > // long double angleBetween(const vmml::vector< M, T > V1, const vmml::vector< M, T > V2 ) // { // long double dotproduct = V1.dot(V2); // long double length = V1.length() * V2.length(); // long double quot = dotproduct / length; // if (quot > 1 && quot < 1.0001) quot = 1; // strange case where acos => NaN // if (quot < -1 && quot > -1.0001) quot = -1; // long double result = acosl( quot ); // 0 .. pi // if (isleftof(T(), V2, V1)) // result = -result; // return result; // } // from V1 to V2 long double angleBetween(const Vector3d &V1, const Vector3d &V2) { long double dotproduct = V1.dot(V2); long double length = V1.length() * V2.length(); if (length==0) return 0; long double quot = dotproduct / length; if (quot > 1 && quot < 1.0001) quot = 1; // strange case where acos => NaN if (quot < -1 && quot > -1.0001) quot = -1; long double result = acosl( quot ); // 0 .. pi if (isleftof(Vector3d(0,0,0), V2, V1)) result = -result; return result; } long double angleBetween(const Vector2d &V1, const Vector2d &V2) { long double dotproduct = V1.dot(V2); long double length = V1.length() * V2.length(); if (length==0) return 0; long double quot = dotproduct / length; if (quot > 1 && quot < 1.0001) quot = 1; if (quot < -1 && quot > -1.0001) quot = -1; long double result = acosl( quot ); // 0 .. pi if (isleftof(Vector2d(0,0), V2, V1)) result = -result; return result; } // return A halfway rotated around center in direction of B Vector2d angle_bipartition(const Vector2d ¢er, const Vector2d &A, const Vector2d &B) { double angle = angleBetween(center-A, B-center) / 2; return rotated(A, center, angle); } // is B left of A wrt center? bool isleftof(const Vector2d ¢er, const Vector2d &A, const Vector2d &B) { double position = (B.x()-A.x())*(center.y()-A.y()) - (B.y()-A.y())*(center.x()-A.x()); return (position >= 0); } bool isleftof(const Vector3d ¢er, const Vector3d &A, const Vector3d &B) { return ((B-A).cross(center-A).z() > 0); } // // http://www.cs.uwaterloo.ca/~tmchan/ch3d/ch3dquad.cc // double turn(Point p, Point q, Point r) { // <0 iff cw // return (q.x()-p.x())*(r.y()-p.y()) - (r.x()-p.x())*(q.y()-p.y()); // } void center_perpendicular(const Vector2d &from, const Vector2d &to, Vector2d &p1, Vector2d &p2) { Vector2d center = (from+to)/2.; Vector2d dir = Vector2d(from.y()-to.y(), to.x()-from.x()); p1 = center; p2 = center + dir; } double cross(const Vector2d &a, const Vector2d &b) { return (b.x()*a.y()) - (b.y()*a.x()); } Vector3d cross2d(const Vector2d &A, const Vector2d &B, double z) { Vector3d A3(A.x(),A.y(),z), B3(B.x(),B.y(),z); return A3.cross(B3); } Vector2d normalV(const Vector2d &a) { return Vector2d(-a.y(),a.x()); } Vector3d random_displaced(const Vector3d &v, double delta) { double randdelta = delta * (rand()%1000000)/1000000 - delta/2.; return Vector3d(v.x()+randdelta, v.y()+randdelta, v.z()+randdelta); } Vector2d random_displaced(const Vector2d &v, double delta) { double randdelta = delta * (rand()%1000000)/1000000 - delta/2.; return Vector2d(v.x()+randdelta, v.y()+randdelta); } void rotate(Vector2d &p, const Vector2d ¢er, double angle, bool ccw) { if (p==center) return ; if (!ccw) angle = -angle; double cosa = cos(angle); double sina = sin(angle); Vector2d r(p - center); p.x() = center.x() + r.x() * cosa - r.y() * sina; p.y() = center.y() + r.x() * sina + r.y() * cosa; } Vector2d rotated(const Vector2d &p, const Vector2d ¢er, double angle, bool ccw) { Vector2d r(p); rotate(r,center,angle,ccw); return r; // Vector3d center3 (center.x(), center.y(), 0); // Vector3d radius3 (p.x() - center.x(), p.y() - center.y(), 0); // Vector3d axis(0.,0., ccw?1.:-1.); // Vector3d rrotated3 = radius3.rotate(angle, axis); // return center + Vector2d(rrotated3.x(), rrotated3.y()); } // squared minimum distance of p to segment s1--s2, onseg = resulting point on segment // http://stackoverflow.com/a/1501725 double point_segment_distance_Sq(const Vector2d &s1, const Vector2d &s2, const Vector2d &p, Vector2d &onseg) { const double l2 = (s2-s1).squared_length(); // i.e. |w-v|^2 - avoid a sqrt if (l2 == 0.0) { // s1 == s2 case onseg = s1; return (p-s1).squared_length(); } // Consider the line extending the segment, parameterized as s1 + t (s2 - s1). // We find projection of point p onto the line. // It falls where t = [(p-s1) . (s2-s1)] / |s2-s1|^2 const double t = (p-s1).dot(s2-s1) / l2; if (t < 0.0) { onseg = s1; return (p-s1).squared_length(); // Beyond the 's1' end of the segment } else if (t > 1.0) { onseg = s2; return (p-s2).squared_length(); // Beyond the 's2' end of the segment } onseg = s1 + (s2 - s1) * t; // Projection falls on the segment return (onseg-p).squared_length(); } vector thick_lines(const vector &points, double width) { vector poly; for (uint i = 0; i thick_l = thick_line(points[i],points[i+1],width); poly.insert(poly.end(),thick_l.begin(),thick_l.end()); } return poly; } vector thick_line(const Vector2d &from, const Vector2d &to, double width) { vector p; if (width < 0.001) return p; if (to.squared_distance(from) < 0.001) return p; Poly poly; Vector2d dir = (to-from); dir.normalize(); dir *= width/4.; Vector2d dirp(-dir.y(),dir.x()); poly.addVertex(from-dir-dirp); poly.addVertex(from-dir+dirp); poly.addVertex(to+dir+dirp); poly.addVertex(to+dir-dirp); p.push_back(poly); return Clipping::getOffset(poly, width/4, jmiter, 0); // slow: // poly.addVertex(from); // poly.addVertex(to); // return Clipping::getOffset(poly, distance/2, jround, distance/2.); } // directed (one end is wider than the other) vector dir_thick_line(const Vector2d &from, const Vector2d &to, double fr_width, double to_width) { vector p; if (fr_width < 0.001 || to_width < 0.001) return p; if (to.squared_distance(from) < 0.001) return p; if ((fr_width < 0) != (to_width < 0)) return p; Poly poly; Vector2d fdir = (to-from); fdir.normalize(); Vector2d tdir = fdir; fdir *= fr_width/4.; tdir *= to_width/4.; Vector2d fr_dirp(-fdir.y(), fdir.x()); Vector2d to_dirp(-tdir.y(), tdir.x()); poly.addVertex(from-fdir-fr_dirp); poly.addVertex(from-fdir+fr_dirp); poly.addVertex(to+tdir+to_dirp); poly.addVertex(to+tdir-to_dirp); p.push_back(poly); return p; //return Clipping::getOffset(poly, distance/4, jmiter, 0); // slow: // poly.addVertex(from); // poly.addVertex(to); // return Clipping::getOffset(poly, distance/2, jround, distance/2.); } ////////////////////////////////////////////////////////////// ///////////////////////////// LINE INTERSECTION ////////////// ////////////////////////////////////////////////////////////// // Line Segment Intersection // http://wiki.processing.org/w/Line-Line_intersection // bool segIntersection(const Vector2d &p1, const Vector2d &p2, // const Vector2d &p3, const Vector2d &p4, // Intersection &hit, // double maxoffset) // { // double bx = p2.x() - p1.x(); // double by = p2.y() - p1.y(); // double dx = p4.x() - p3.x(); // double dy = p4.y() - p3.y(); // double b_dot_d_perp = bx * dy - by * dx; // if (abs(b_dot_d_perp) < maxoffset) { // parallel // return false; // } // double cx = p3.x() - p1.x(); // double cy = p3.y() - p1.y(); // double t = (cx * dy - cy * dx) / b_dot_d_perp; // if (t < maxoffset || t > 1-maxoffset) { // return false; // } // double u = (cx * by - cy * bx) / b_dot_d_perp; // if (u < maxoffset || u > 1-maxoffset) { // return false; // } // hit.p = Vector2d(p1.x() + t*bx, p2.y() + t*by); // hit.t = t; // hit.d = (p1-hit.p).length(); // return true; // } // Check the segments p1-p2 and p3-p4 for intersection, // If the segments intersection, the intersection // also checks that the intersection point is actually on // the line segment p1-p2 bool IntersectXY(const Vector2d &p1, const Vector2d &p2, const Vector2d &p3, const Vector2d &p4, Intersection &hit, double maxoffset) { Vector2d inter2; int is = intersect2D_Segments(p1,p2,p3,p4, hit.p, inter2); if (is > 0 && is < 3) { hit.d = (p1-hit.p).length(); return true; } return false; } // The following functions // (inSegment, intersect2D_Segments and dist3D_Segment_to_Segment) // are licensed as: // // Copyright 2001 softSurfer, 2012-13 Dan Sunday // This code may be freely used, distributed and modified for any // purpose providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. // // inSegment(): determine if a point is inside a segment // Input: a point P, and a collinear segment p1--p2 // Return: true = P is inside p1--p2 // fasle = P is not inside p1--p2 bool inSegment( const Vector2d &P, const Vector2d &p1, const Vector2d &p2) { if (p1.x() != p2.x()) { // S is not vertical if (p1.x() <= P.x() && P.x() <= p2.x()) return true; if (p1.x() >= P.x() && P.x() >= p2.x()) return true; } else { // S is vertical, so test y coordinate if (p1.y() <= P.y() && P.y() <= p2.y()) return true; if (p1.y() >= P.y() && P.y() >= p2.y()) return true; } return false; } // intersect2D_2Segments(): the intersection of 2 finite 2D segments // Input: two finite segments p1-p2 and p3-p4 // Output: *I0 = intersect point (when it exists) // *I1 = endpoint of intersect segment [I0,I1] (when it exists) // Return: 0=disjoint (no intersect) // 1=intersect in unique point I0 // 2=overlap in segment from I0 to I1 // 3=lines intersect outside the segments #define perp(u,v) ((u).x() * (v).y() - (u).y() * (v).x()) // perp product (2D) int intersect2D_Segments( const Vector2d &p1, const Vector2d &p2, const Vector2d &p3, const Vector2d &p4, Vector2d &I0, Vector2d &I1, double maxerr) { Vector2d u = p2 - p1; Vector2d v = p4 - p3; Vector2d w = p1 - p3; double D = perp(u,v); double t0, t1; // Temp vars for parametric checks // test if they are parallel (includes either being a point) if (abs(D) < maxerr) { // S1 and S2 are parallel if (perp(u,w) != 0 || perp(v,w) != 0) { return 0; // they are NOT collinear } // they are collinear or degenerate // check if they are degenerate points double du = u.dot(u); double dv = v.dot(v); if (du==0 && dv==0) { // both segments are points if (p1 != p3) // they are distinct points return 0; I0 = p1; // they are the same point return 1; } if (du==0) { // S1 is a single point if (!inSegment(p1, p3, p4)) // but is not in S2 return 0; I0 = p1; return 1; } if (dv==0) { // S2 a single point if (!inSegment(p3, p1,p2)) // but is not in S1 return 0; I0 = p3; return 1; } // they are collinear segments - get overlap (or not) Vector2d w2 = p2 - p3; if (v.x() != 0) { t0 = w.x() / v.x(); t1 = w2.x() / v.x(); } else { t0 = w.y() / v.y(); t1 = w2.y() / v.y(); } if (t0 > t1) { // must have t0 smaller than t1 double t=t0; t0=t1; t1=t; // swap if not } if (t0 > 1 || t1 < 0) { return 0; // NO overlap } t0 = t0<0? 0 : t0; // clip to min 0 t1 = t1>1? 1 : t1; // clip to max 1 if (t0 == t1) { // intersect is a point I0 = p3 + v*t0; return 1; } // they overlap in a valid subsegment I0 = p3 + v*t0; I1 = p3 + v*t1; return 2; } // end parallel bool outside = false; // the segments are skew and may intersect in a point // get the intersect parameter for S1 t0 = perp(v,w) / D; if (t0 < 0 || t0 > 1) // no intersect in S1 outside = true; //return 0; // get the intersect parameter for S2 t1 = perp(u,w) / D; if (t1 < 0 || t1 > 1) // no intersect in S2 outside = true; // return 0; I0 = p1 + u * t0; // compute S1 intersect point if (outside) return 3; return 1; } // dist3D_Segment_to_Segment(): // Input: two 3D line segments S1 and S2 // Return: the shortest distance between S1 and S2 double dist3D_Segment_to_Segment(const Vector3d &S1P0, const Vector3d &S1P1, const Vector3d &S2P0, const Vector3d &S2P1, double SMALL_NUM) { Vector3d u = S1P1 - S1P0; Vector3d v = S2P1 - S2P0; Vector3d w = S1P0 - S2P0; double a = u.dot(u); // always >= 0 double b = u.dot(v); double c = v.dot(v); // always >= 0 double d = u.dot(w); double e = v.dot(w); double D = a*c - b*b; // always >= 0 double sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0 double tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0 // compute the line parameters of the two closest points if (D < SMALL_NUM) { // the lines are almost parallel sN = 0.0; // force using point P0 on segment S1 sD = 1.0; // to prevent possible division by 0.0 later tN = e; tD = c; } else { // get the closest points on the infinite lines sN = (b*e - c*d); tN = (a*e - b*d); if (sN < 0.0) { // sc < 0 => the s=0 edge is visible sN = 0.0; tN = e; tD = c; } else if (sN > sD) { // sc > 1 => the s=1 edge is visible sN = sD; tN = e + b; tD = c; } } if (tN < 0.0) { // tc < 0 => the t=0 edge is visible tN = 0.0; // recompute sc for this edge if (-d < 0.0) sN = 0.0; else if (-d > a) sN = sD; else { sN = -d; sD = a; } } else if (tN > tD) { // tc > 1 => the t=1 edge is visible tN = tD; // recompute sc for this edge if ((-d + b) < 0.0) sN = 0; else if ((-d + b) > a) sN = sD; else { sN = (-d + b); sD = a; } } // finally do the division to get sc and tc sc = (abs(sN) < SMALL_NUM ? 0.0 : sN / sD); tc = (abs(tN) < SMALL_NUM ? 0.0 : tN / tD); // get the difference of the two closest points Vector3d dP = w + (u * sc ) - (v * tc); // = S1(sc) - S2(tc) return dP.length(); // return the closest distance } /////////////////// PATH IN POLYGON ////////////////////// bool pointInPolys(const Vector2d &point, const vector &polys) { for (uint i=0; i< polys.size(); i++) if (polys[i].vertexInside(point)) return true; return false; } // Public-domain code by Darel Rex Finley, 2006. // http://alienryderflex.com/shortest_path/ // will return false // if the line cuts any of the given polygons except excluded one bool lineInPolys(const Vector2d &from, const Vector2d &to, const vector &polys, uint excludepoly, double maxerr) { uint ninter = 0; for (uint i=0; i< polys.size(); i++) { if (i != excludepoly){ if (polys[i].vertexInside(from)) ninter++; if (polys[i].vertexInside(to)) ninter++; vector inter = polys[i].lineIntersections(from,to,maxerr); ninter += inter.size(); } } return (ninter != 0); } // Finds the shortest path from from to to that stays within the polygon set. // // Note: To be safe, the solutionX and solutionY arrays should be large enough // to accommodate all the corners of your polygon set (although it is // unlikely that anywhere near that many elements will ever be needed). // // Returns true if the optimal solution was found, or false if there is no solution. // If a solution was found, the solution vector will contain the coordinates // of the intermediate nodes of the path, in order. (The startpoint and endpoint // are assumed, and will not be included in the solution.) struct pathpoint { Vector2d v; double totalDist; int prev; }; // excludepoly: poly not to test, contains from and to vectors. bool shortestPath(const Vector2d &from, const Vector2d &to, const vector &polys, int excludepoly, vector &path, double maxerr) { // Fail if either the startpoint or endpoint is outside the polygon set. if (!pointInPolys(from, polys) || !pointInPolys(to, polys)) return false; // If there is a straight-line solution, no path vertices added if (lineInPolys(from, to, polys, excludepoly, maxerr)) return true; const double INF = 9999999.; // (larger than total solution dist could ever be) double bestDist, newDist ; // uint numpoints=0; // for (uint i=0; i pointList; // Build a point list that refers to the corners of the // polygons, as well as to the startpoint and endpoint. pointList.push_back((pathpoint){from, 0, 0}); for (uint i=0; i 0) { path.push_back(pointList[i].v); i = pointList[i].prev; numsolutions++; cerr << treeCount << " - " << numsolutions << " - " << i << endl; } return true; int j = numsolutions-1; if (j > 0) { int psize = path.size(); path.resize(psize + j); i = treeCount-1; while (j >= 0) { i = pointList[i].prev; path[psize + j] = pointList[i].v; j--; } } // Success. return true; } /////////////////////////// CONVEX HULL ///////////////////////// // http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product. // Returns a positive value, if OAB makes a counter-clockwise turn, // negative for clockwise turn, and zero if the points are collinear. double cross_2(const Vector2d &O, const Vector2d &A, const Vector2d &B) { return (A.x() - O.x()) * (B.y() - O.y()) - (A.y() - O.y()) * (B.x() - O.x()); } struct sortable_point { Vector2d v; bool operator <(const sortable_point &p) const { return (v.x() < p.v.x()) || ((v.x() == p.v.x()) && (v.y() < p.v.y())); } }; // calc convex hull and Min and Max of layer // Monotone chain algo Poly convexHull2D(const vector &polygons) { Poly hullPolygon; vector P; for (uint i = 0; i H(2*n); if (n<2) return hullPolygon; if (n<4) { for (int i = 0; i < n; i++) hullPolygon.addVertex(P[i].v); return hullPolygon; } sort(P.begin(), P.end()); // Build lower hull int k=0; for (int i = 0; i < n; i++) { while (k >= 2 && cross_2(H[k-2], H[k-1], P[i].v) <= 0) k--; H[k++] = P[i].v; } // Build upper hull for (int i = n-2, t = k+1; i >= 0; i--) { while (k >= t && cross_2(H[k-2], H[k-1], P[i].v) <= 0) k--; H[k++] = P[i].v; } H.resize(k); hullPolygon.vertices = H; hullPolygon.reverse(); return hullPolygon; } ///////////////////// CLEANUP/SIMPILFY ////////////////////// // make vertices at least epsilon apart int cleandist(vector &vert, double epsilon) { uint n_vert = vert.size(); double sqeps = epsilon * epsilon; uint n_moved = 0; if (vert[0].squared_distance(vert[n_vert-1]) < sqeps){ const Vector2d center = (vert[0]+vert[n_vert-1])/2; Vector2d dir = vert[0]-center; dir.normalize(); vert[0] = center + dir*epsilon; n_moved++; } for (uint i = 1; i < n_vert ; i++) { if (vert[i].squared_distance(vert[i-1]) < sqeps){ const Vector2d center = (vert[i]+vert[i-1])/2; Vector2d dir = vert[i]-center; dir.normalize(); vert[i] = center + dir*epsilon; n_moved++; } } return n_moved; } // Douglas-Peucker algorithm vector simplified(const vector &vert, double epsilon) { if (epsilon == 0) return vert; uint n_vert = vert.size(); if (n_vert<3) return vert; double dmax = 0; //Find the point with the maximum distance from line start-end uint index = 0; Vector2d normal = normalV(vert.back()-vert.front()); normal.normalize(); if( (normal.length()==0) || ((abs(normal.length())-1)>epsilon) ) return vert; for (uint i = 1; i < n_vert-1 ; i++) { double dist = abs((vert[i]-vert.front()).dot(normal)); if (dist >= epsilon && dist > dmax) { index = i; dmax = dist; } } vector newvert; if (index > 0) // there is a point > epsilon { // divide at max dist point and cleanup both parts recursively vector part1; part1.insert(part1.end(), vert.begin(), vert.begin()+index+1); vector c1 = simplified(part1, epsilon); vector part2; part2.insert(part2.end(), vert.begin()+index, vert.end()); vector c2 = simplified(part2, epsilon); newvert.insert(newvert.end(), c1.begin(), c1.end()-1); newvert.insert(newvert.end(), c2.begin(), c2.end()); } else { // all points are nearer than espilon newvert.push_back(vert.front()); newvert.push_back(vert.back()); } return newvert; } ///////////////////// POLY2TRI TRIANG //////////////////// #include vector getP2Tpoints(const Poly &poly) { vector points(poly.size()); for (uint i=0; iGetPoint(0); const p2t::Point *tp1 = cdttriangle->GetPoint(1); const p2t::Point *tp2 = cdttriangle->GetPoint(2); const Vector3d A((tp0->x), (tp0->y), z); const Vector3d B((tp1->x), (tp1->y), z); const Vector3d C((tp2->x), (tp2->y), z); return Triangle(A, B, C); } vector getTriangles(p2t::CDT &cdt, double z) { vector ptriangles = cdt.GetTriangles(); vector triangles(ptriangles.size()); for (guint i=0; i < ptriangles.size(); i++) { triangles[i] = getTriangle(ptriangles[i], z); } return triangles; } int triangulate(const vector &polys, vector< vector > &triangles, double z) { vector expolys = Clipping::getExPolys(polys, 0, 0); cerr << expolys.size() << endl; for (uint i = 0; i outerpoints = getP2Tpoints(expolys[i].outer); p2t::CDT cdt(outerpoints); for (uint h = 0; h < expolys[i].holes.size(); h++) { vector holespoints = getP2Tpoints(expolys[i].holes[h]); cdt.AddHole(holespoints); } cdt.Triangulate(); triangles.push_back(getTriangles(cdt, z)); } return triangles.size(); } ///////////////////// DELAUNAY TRIANG //////////////////// #define REAL double //#include "triangle/triangle/triangle.h" //#include "triangle/PolygonTriangulator.h" int delaunayTriang(const vector &points, vector &triangles, double z) { #define PTRIANGULATOR 0 #if PTRIANGULATOR vector spoints = simplified(points, 1); uint npoints = spoints.size(); vector xpoints(npoints); vector ypoints(npoints); for (uint i = 0; i < npoints; i++) { xpoints[i] = spoints[npoints-i-1].x(); ypoints[i] = spoints[npoints-i-1].y(); } polytri::PolygonTriangulator pt(xpoints, ypoints); const polytri::PolygonTriangulator::Triangles * tr = pt.triangles(); uint ntr = tr->size(); cerr << npoints << " -> " << ntr << endl; triangles.resize(ntr); uint itri=0; for (polytri::PolygonTriangulator::Triangles::const_iterator itr = tr->begin(); itr != tr->end(); ++itr) { const polytri::PolygonTriangulator::Triangle t = *itr; triangles[itri] = Triangle(Vector3d(xpoints[t[0]], ypoints[t[0]], z), Vector3d(xpoints[t[1]], ypoints[t[1]], z), Vector3d(xpoints[t[2]], ypoints[t[2]], z)); itri++; } return ntr; #endif // struct triangulateio in; // in.numberofpoints = npoints; // in.numberofpointattributes = (int)0; // in.pointlist = // in.pointattributelist = NULL; // in.pointmarkerlist = (int *) NULL; // in.numberofsegments = 0; // in.numberofholes = 0; // in.numberofregions = 0; // in.regionlist = (REAL *) NULL; // delclass = new piyush; // piyush *pdelclass = (piyush *)delclass; // triswitches.push_back('\0'); // char *ptris = &triswitches[0]; // pmesh = new piyush::__pmesh; // pbehavior = new piyush::__pbehavior; // piyush::__pmesh * tpmesh = (piyush::__pmesh *) pmesh; // piyush::__pbehavior * tpbehavior = (piyush::__pbehavior *) pbehavior; // pdelclass->triangleinit(tpmesh); // pdelclass->parsecommandline(1, &ptris, tpbehavior); // pdelclass->transfernodes(tpmesh, tpbehavior, in.pointlist, // in.pointattributelist, // in.pointmarkerlist, in.numberofpoints, // in.numberofpointattributes); // tpmesh->hullsize = pdelclass->delaunay(tpmesh, tpbehavior); // /* Ensure that no vertex can be mistaken for a triangular bounding */ // /* box vertex in insertvertex(). */ // tpmesh->infvertex1 = (piyush::vertex) NULL; // tpmesh->infvertex2 = (piyush::vertex) NULL; // tpmesh->infvertex3 = (piyush::vertex) NULL; // /* Calculate the number of edges. */ // tpmesh->edges = (3l * tpmesh->triangles.items + tpmesh->hullsize) / 2l; // pdelclass->numbernodes(tpmesh, tpbehavior); /////////////////////////////////////////////// triangle++ crap // typedef reviver::dpoint Point; // vector p(points.size()); // for (uint i = 0; i < p.size(); i++) { // p[i] = Point(points[i].x(),points[i].y()); // } // tpp::Delaunay del(p); // /* // -p Triangulates a Planar Straight Line Graph (.poly file). // -r Refines a previously generated mesh. // -q Quality mesh generation. A minimum angle may be specified. // -a Applies a maximum triangle area constraint. // -u Applies a user-defined triangle constraint. // -A Applies attributes to identify triangles in certain regions. // -c Encloses the convex hull with segments. // -D Conforming Delaunay: all triangles are truly Delaunay. // -j Jettison unused vertices from output .node file. // -e Generates an edge list. // -v Generates a Voronoi diagram. // -n Generates a list of triangle neighbors. // -g Generates an .off file for Geomview. // -B Suppresses output of boundary information. // -P Suppresses output of .poly file. // -N Suppresses output of .node file. // -E Suppresses output of .ele file. // -I Suppresses mesh iteration numbers. // -O Ignores holes in .poly file. // -X Suppresses use of exact arithmetic. // -z Numbers all items starting from zero (rather than one). // -o2 Generates second-order subparametric elements. // -Y Suppresses boundary segment splitting. // -S Specifies maximum number of added Steiner points. // -i Uses incremental method, rather than divide-and-conquer. // -F Uses Fortune's sweepline algorithm, rather than d-and-c. // -l Uses vertical cuts only, rather than alternating cuts. // -s Force segments into mesh by splitting (instead of using CDT). // -C Check consistency of final mesh. // -Q Quiet: No terminal output except errors. // */ // string switches = "pq0DzQ"; // del.Triangulate(switches); // int ntri = del.ntriangles(); // if (ntri>0) { // triangles.resize(ntri); // uint itri=0; // for (tpp::Delaunay::fIterator dit = del.fbegin(); dit != del.fend(); ++dit) { // Point pA = del.point_at_vertex_id(del.Org (dit)); // Point pB = del.point_at_vertex_id(del.Dest(dit)); // Point pC = del.point_at_vertex_id(del.Apex(dit)); // triangles[itri] = Triangle(Vector3d(pA[0],pA[1],z), // Vector3d(pB[0],pB[1],z), // Vector3d(pC[0],pC[1],z)); // // Vector2d vA = points[del.Org (dit)]; // // Vector2d vB = points[del.Dest(dit)]; // // Vector2d vC = points[del.Apex(dit)]; // // triangles[itri] = Triangle(Vector3d(vA.x(),vA.y(),z), // // Vector3d(vB.x(),vB.y(),z), // // Vector3d(vC.x(),vC.y(),z)); // itri++; // } // } // return ntri; return 0; } // typedef struct { // Vector2d a,b,c; // } triangle2; // bool pointInCircumcircle(const triangle2 &t, const Vector2d &p) // { // Vector2d l1p1,l1p2; // center_perpendicular(t.a, t.b, l1p1, l1p2); // Vector2d l2p1,l2p2; // center_perpendicular(t.a, t.c, l2p1, l2p2); // Vector2d center, ip; // double t0, t1; // int is = intersect2D_Segments(l1p1, l1p2, l2p1, l2p2, // center, ip, t0,t1); // if (is > 0) { // if (t.a.squared_distance(center) > p.squared_distance(center)) // return true; // } // return false; // } // int delaunayTriang(const vector &points, vector &triangles, // double z) // { // if (points.size() < 3) return 0; // triangles.clear(); // uint nump = points.size(); // vector seq(nump,1); // 1,1,1... // partial_sum(seq.begin(), seq.end(), seq.begin()); // 1,2,3,...,20 // srand(time(NULL)); // random_shuffle(seq.begin(), seq.end()); // shuffle // vector d_triangles; // triangle2 t = { points[seq[0]-1], points[seq[1]-1], points[seq[2]-1] }; // d_triangles.push_back(t); // for (uint i = 3; i < nump; i+=3) { // //triangle2 t = { points[seq[i]-1], points[seq[i+1]-1], points[seq[i+2]-1] }; // bool deleted = false; // for (int ti = d_triangles.size()-1; ti >= 0 ; ti--) { // if (pointInCircumcircle( d_triangles[ti], points[seq[i]-1] )) { // d_triangles.erase(d_triangles.begin()+ti); // deleted = true; // } // } // if (deleted) { // // make new triangles in hole // } // else { // // make new triangle from next points and new point // } // } // return triangles.size(); // // double xy[point_num*2]; // // for (uint i=0; i < point_num; i+=2) { // // xy[i] = poly.vertices[i].x(); // // xy[i+1] = poly.vertices[i].y(); // // } // // int tri_num; // // int tri_vert[2*point_num*3]; // // int tri_nabe[2*point_num*3]; // // int result = dtris2(point_num, xy, &tri_num, tri_vert, tri_nabe); // // if (result != 0) // // return triangles; // // double z = poly.getZ(); // // for (int i=0; i Matrix3d getMatrix(const Cairo::RefPtr context) { /* A #cairo_matrix_t holds an affine transformation, such as a scale, * rotation, shear, or a combination of those. The transformation of * a point (x, y) is given by: * * x_new = xx * x + xy * y + x0; * y_new = yx * x + yy * y + y0; * **/ // typedef struct _cairo_matrix { // double xx; double yx; // double xy; double yy; // double x0; double y0; // } cairo_matrix_t; // In a cairo.matrix(1,2,3,4,5,6), 1 is a11, 2 is a21, 3 is a12, 4 is a22, 5 is a13 and 6 is a23. a31 and a32 are 0, a33 is 1. Cairo::Matrix cm; context->get_matrix(cm); Matrix3d m; m[0][0] = cm.xx; m[0][1] = cm.xy; m[0][2] = cm.x0; m[1][0] = cm.yx; m[1][1] = cm.yy; m[1][2] = cm.y0; m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; return m; } bool rasterpolys(const vector &polys, const Vector2d &min, const Vector2d &max, double resolution, Cairo::RefPtr &surface, Cairo::RefPtr &context) { Vector2d diag = max - min; int width = (int)ceil(diag.x()/resolution); int height = (int)ceil(diag.y()/resolution); if (height <= 0 || width <= 0) return false; surface = Cairo::ImageSurface::create(Cairo::FORMAT_A8, width, height); //surface->set_device_offset(-min.x()/resolution, -min.y()/resolution); context = Cairo::Context::create (surface); context->set_fill_rule(Cairo::FILL_RULE_WINDING); context->set_antialias(Cairo::ANTIALIAS_DEFAULT); context->scale(1/resolution, 1/resolution); context->translate(-min.x(), -min.y()); context->set_source_rgb (0,0,0); //cerr << min << endl <begin_new_path(); // context->set_line_width(0.5); // context->move_to(min.x(),min.y()); // context->line_to(max.x(),min.y()); // context->line_to(max.x(),max.y()); // context->line_to(min.x(),max.y()); // // context->move_to(0,0); // // context->line_to(diag.x(),0); // // context->line_to(diag.x(),diag.y()); // // context->line_to(0,diag.y()); // context->close_path(); // context->stroke(); context->begin_new_path(); context->set_line_width(0); for (uint i=0; imove_to(v.x(),v.y()); for (uint j=0; jline_to(v.x(),v.y()); } } context->fill(); return true; } void glDrawPolySurfaceRastered(const vector &polys, const Vector2d &min, const Vector2d &max, const double z, const double resolution) { Cairo::RefPtr surface; Cairo::RefPtr context; if (!rasterpolys(polys, min, max, resolution, surface, context)) return; glDrawCairoSurface(surface, min, max,z); } void glDrawCairoSurface(const Cairo::RefPtr surface, const Vector2d &min, const Vector2d &max, const double z) { if (surface==0) return; int w = surface->get_width(); int h = surface->get_height(); unsigned char * data = surface->get_data(); GLuint texture; glGenTextures( 1, &texture ); glBindTexture( GL_TEXTURE_2D, texture ); // http://www.nullterminator.net/gltexture.html // select modulate to mix texture with color for shading glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); // when texture area is small, bilinear filter the closest mipmap glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); // when texture area is large, bilinear filter the original glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); // build our texture mipmaps gluBuild2DMipmaps( GL_TEXTURE_2D, GL_ALPHA, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, data ); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2d(0.0,0.0); glVertex3d(min.x(),min.y(),z); glTexCoord2d(1.0,0.0); glVertex3d(max.x(),min.y(),z); glTexCoord2d(1.0,1.0); glVertex3d(max.x(),max.y(),z); glTexCoord2d(0.0,1.0); glVertex3d(min.x(),max.y(),z); glEnd(); glDisable(GL_TEXTURE_2D); glDeleteTextures( 1, &texture ); } int getCairoSurfaceDatapoint(const Cairo::RefPtr surface, const Vector2d &min, const Vector2d &max, const Vector2d &p) { if (surface==0) return 0; const int w = surface->get_stride(); const int h = surface->get_height(); const unsigned char * data = surface->get_data(); const Vector2d diag = max - min; const Vector2d relp = p - min; const int ipx = (int)(relp.x() / diag.x() * (double)w); const int ipy = (int)(relp.y() / diag.y() * (double)h); int value = data[ipy*w + ipx]; return value; } repsnapper-2.3.2a5/src/slicer/geometry.h000066400000000000000000000122501231531733200201770ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "stdafx.h" #include "arcball.h" #define PI 3.141592653589793238462643383279502884197169399375105820974944592308 #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /* void drawString(const Vector3d &pos, void* font, const string &text); */ /* void drawString(const Vector3d &pos, const string &text); */ /* void checkGlutInit(); */ void move(const Vector3f &delta, Matrix4f &mat); Vector3d normalized(const Vector3d &v); Vector2d normalized(const Vector2d &v); Vector2d normalV(const Vector2d &a); double cross(const Vector2d &a, const Vector2d &b); void moveArcballTrans(Matrix4fT &matfT, const Vector3d &delta); void setArcballTrans(Matrix4fT &matfT, const Vector3d &trans); void rotArcballTrans(Matrix4fT &transform, const Vector3d &axis, double angle); /* template< size_t M, typename T > */ /* long double angleBetween(const vmml::vector< M, T > V1, const vmml::vector< M, T > V2 ); */ long double angleBetween(const Vector3d &V1, const Vector3d &V2); long double angleBetween(const Vector2d &V1, const Vector2d &V2); Vector2d angle_bipartition(const Vector2d ¢er, const Vector2d &A, const Vector2d &B); void center_perpendicular(const Vector2d &from, const Vector2d &to, Vector2d &p1, Vector2d &p2); bool isleftof(const Vector2d ¢er, const Vector2d &A, const Vector2d &B); bool isleftof(const Vector3d ¢er, const Vector3d &A, const Vector3d &B); Vector3d cross2d(const Vector2d &A, const Vector2d &B, double z=0); double point_segment_distance_Sq(const Vector2d &s1, const Vector2d &s2, const Vector2d &p, Vector2d &onseg); void rotate ( Vector2d &p, const Vector2d ¢er, double angle, bool ccw=true); Vector2d rotated(const Vector2d &p, const Vector2d ¢er, double angle, bool ccw=true); struct printline; struct Intersection { Vector2d p; // The intersection point double d; // Distance from the start point, used for sorting hits bool operator <(const Intersection &p) const { return (d simplified(const vector &vert, double epsilon); int cleandist(vector &vert, double epsilon); Poly convexHull2D(const vector &polygons); int delaunayTriang(const vector &points, vector &triangles, double z); int triangulate(const vector &polys, vector< vector > &triangles, double z = 0); void testangles(); Vector3d random_displaced(const Vector3d &v, double delta=0.05); Vector2d random_displaced(const Vector2d &v, double delta=0.05); bool shortestPath(const Vector2d &from, const Vector2d &to, const vector &polys, int excludepoly, vector &path, double maxerr); vector thick_line(const Vector2d &from, const Vector2d &to, double width); vector thick_lines(const vector &points, double width); vector dir_thick_line(const Vector2d &from, const Vector2d &to, double fr_width, double to_width); bool fit_arc(const vector &points, double sq_error, Vector2d &result_center, double &result_radius); typedef struct { double *px, *py; // arc points } arc_data_struct; bool fit_arc(const int m_dat, const arc_data_struct data, const int n_par, double *par, double sq_error, Vector2d &result_center, double &result_radiussq); bool rasterpolys(const vector &polys, const Vector2d &min, const Vector2d &max, double resolution, Cairo::RefPtr &surface, Cairo::RefPtr &context); void glDrawPolySurfaceRastered(const vector &polys, const Vector2d &min, const Vector2d &max, const double z, const double resolution); void glDrawCairoSurface(const Cairo::RefPtr surface, const Vector2d &min, const Vector2d &max, const double z); int getCairoSurfaceDatapoint(const Cairo::RefPtr surface, const Vector2d &min, const Vector2d &max, const Vector2d &p); repsnapper-2.3.2a5/src/slicer/infill.cpp000066400000000000000000000572171231531733200201700ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "infill.h" #include "poly.h" #include "layer.h" vector Infill::savedPatterns; #ifdef _OPENMP omp_lock_t Infill::save_lock; #endif void hilbert(int level,int direction, double infillDistance, vector &v); Infill::Infill() : extrusionfactor(1), cached(false) { m_tofillpolys.clear(); } Infill::Infill (Layer *mlayer, double extrfactor) : cached(false) { layer = mlayer; extrusionfactor = extrfactor; m_tofillpolys.clear(); } Infill::~Infill() { clear(); extrusionfactor = 1.; } void Infill::clear() { infillpolys.clear(); infillvertices.clear(); m_tofillpolys.clear(); } void Infill::clearPatterns() { for (uint i=0; i polys; polys.push_back(poly); addPolys(z, polys, type, infillDistance, offsetDistance, rotation); } void Infill::addPolys(double z, const vector &polys, InfillType type, double infillDistance, double offsetDistance, double rotation) { this->infillDistance = infillDistance; #ifdef _OPENMP omp_set_lock(&save_lock); #endif ClipperLib::Paths patterncpolys = makeInfillPattern(type, polys, infillDistance, offsetDistance, rotation); #ifdef _OPENMP omp_unset_lock(&save_lock); #endif addPolys(z, polys, patterncpolys, offsetDistance); } void Infill::addPoly(double z, const ExPoly &expoly, InfillType type, double infillDistance, double offsetDistance, double rotation) { vector polys = Clipping::getPolys(expoly); addPolys (z, polys, type, infillDistance, offsetDistance, rotation); } void Infill::addPolys(double z, const vector &expolys, InfillType type, double infillDistance, double offsetDistance, double rotation) { vector polys = Clipping::getPolys(expolys); addPolys (z, polys, type, infillDistance, offsetDistance, rotation); } // calculates angles for bridges // void Infill::addBridgeInfill(double z, const vector polys, // double infillDistance, double offsetDistance, // vector bridgepillars) // { // type = BridgeInfill; // this->infillDistance = infillDistance; // omp_set_lock(&save_lock); // ClipperLib::Paths patterncpolys = // makeInfillPattern(type, polys, infillDistance, offsetDistance, rotation); // addPolys(z, polys, patterncpolys, offsetDistance); // omp_unset_lock(&save_lock); // } // fill polys with fillpolys void Infill::addPolys(double z, const vector &polys, const vector &fillpolys, double offsetDistance) { addPolys(z, polys, Clipping::getClipperPolygons(fillpolys), offsetDistance); } // clip infill pattern polys against polys void Infill::addPolys(double z, const vector &polys, const ClipperLib::Paths &patterncpolys, double offsetDistance) { Clipping clipp; clipp.addPolys (polys, subject); clipp.addPolygons(patterncpolys, clip); clipp.setExtrusionFactor(extrusionfactor); // set my extfactor clipp.setZ(z); vector result = clipp.intersect(); if (m_type==PolyInfill) // reversal from evenodd clipping for (uint i = 0; i &tofillpolys, double infillDistance, double offsetDistance, double rotation) { ClipperLib::Paths cpolys; m_tofillpolys = tofillpolys; m_type = type; if (tofillpolys.size()==0) return cpolys; cached = false; //cerr << "have " << savedPatterns.size()<<" saved patterns " << endl; // look for saved pattern for this rotation const Vector2d Min = layer->getMin(); const Vector2d Max = layer->getMax(); while (rotation > 2*M_PI) rotation -= 2*M_PI; while (rotation < 0) rotation += 2*M_PI; m_angle = rotation; if (type == HexInfill) { if (layer->LayerNo%2 != 0) m_angle = M_PI/2; else m_angle = 0.; } //omp_set_lock(&save_lock); //int tid = omp_get_thread_num( ); //cerr << "thread "<0){ vector too_small; for (vector::iterator sIt=savedPatterns.begin(); sIt != savedPatterns.end(); sIt++){ if (sIt->type == type && abs((sIt->distance-infillDistance)/infillDistance) < 0.01 && abs((sIt->angle-m_angle)/m_angle) < 0.01 ) { //cerr << name << " found saved pattern no " << sIt-savedPatterns.begin() << " with " << sIt->cpolys.size() <<" polys"<< endl << "type "<< sIt->type << sIt->Min << sIt->Max << endl; // is it too small for this layer? if (sIt->Min.x() > Min.x() || sIt->Min.y() > Min.y() || sIt->Max.x() < Max.x() || sIt->Max.y() < Max.y()) { too_small.push_back(sIt-savedPatterns.begin()); //break; // there is no other match } else { cached = true; return sIt->cpolys; } } } sort(too_small.rbegin(), too_small.rend()); for (uint i = 0; i < too_small.size(); i++) { savedPatterns.erase(savedPatterns.begin()+too_small[i]); } } } //omp_unset_lock(&save_lock); // none found - make new: bool zigzag = false; switch (type) { case HexInfill: { Vector2d pMin=Vector2d::ZERO, pMax=Max*1.1; double hexd = infillDistance;// /(1+sqrt(3.)/4.); double hexa = hexd*sqrt(3.)/2.; // the two parts have to fit Poly poly(this->layer->getZ()); if (layer->LayerNo%2 != 0) { // two alternating parts double ymax = pMax.y();; for (double x = pMin.x(); x < pMax.x(); x += 2*hexa) { poly.addVertex(x, pMin.y()); for (double y = pMin.y(); y < pMax.y(); ) { poly.addVertex(x, y); poly.addVertex(x+hexa, y+hexd/2); y+=1.5*hexd; poly.addVertex(x+hexa, y); poly.addVertex(x, y+hexd/2); y+=1.5*hexd; ymax = y; } for (double y = ymax; y > pMin.y(); y-=2*hexd) { double x2 = x+hexa+layer->thickness/10.; // offset to not combine polys y+=0.5*hexd; poly.addVertex(x2, y); poly.addVertex(x2+hexa, y-hexd/2); y-=1.5*hexd; poly.addVertex(x2+hexa, y); poly.addVertex(x2, y-hexd/2); } } poly.addVertex(pMax.x(), pMin.y()-infillDistance); poly.addVertex(pMin.x(), pMin.y()-infillDistance); } else { // other layer, simpler double xmax = pMax.x();; for (double y = pMin.y(); y < pMax.y(); y += 3*hexd) { for (double x = pMin.x(); x < pMax.x(); ) { poly.addVertex(x, y); poly.addVertex(x+hexa, y+hexd/2.); x += 2*hexa; xmax = x; } for (double x = xmax; x > pMin.y(); x -= 2*hexa) { double y2 = y+1.5*hexd; poly.addVertex(x+hexa, y2); poly.addVertex(x, y2+hexd/2); } } poly.addVertex(pMin.x(), pMax.y()-infillDistance); poly.addVertex(pMin.x(), pMin.y()-infillDistance); } // Poly poly2 = poly; poly2.move(Vector2d(infillDistance/2,0)); vector polys(1); polys[0] = poly; // polys[1] = poly2; cpolys = Clipping::getClipperPolygons(polys); } break; case SmallZigzagInfill: // small zigzag lines -> square pattern zigzag = true; //case ZigzagInfill: // long zigzag lines case SupportInfill: case RaftInfill: case BridgeInfill: case ParallelInfill: { Vector2d center = (Min+Max)/2.; // make square that masks everything even when rotated Vector2d diag = Max-Min; double square = max(diag.x(),diag.y()); Vector2d sqdiag(square*2/3,square*2/3); Vector2d pMin=center-sqdiag, pMax=center+sqdiag; if (zigzag) pMin=Vector2d::ZERO; // fixed position // cerr << pMin << "--"<layer->getZ()); uint count = 0; for (double x = pMin.x(); x < pMax.x(); ) { double x2 = x+infillDistance; poly.addVertex(x, pMin.y()); if (zigzag) { // zigzag -> squares double ymax=pMax.y();; for (double y = pMin.y(); y < pMax.y(); y += 2*infillDistance) { poly.addVertex(x, y); poly.addVertex(x2, y+infillDistance); ymax = y; } for (double y = ymax; y > pMin.y(); y -= 2*infillDistance) { poly.addVertex(x2, y+infillDistance); poly.addVertex(x2+infillDistance, y); } x += 2*infillDistance; } else { // normal line infill if (count%2){ poly.addVertex(x, pMin.y()); poly.addVertex(x2, pMin.y()); } else { poly.addVertex(x, pMax.y()); poly.addVertex(x2, pMax.y()); } x += infillDistance; } count ++; } poly.addVertex(pMax.x(), pMin.y()-infillDistance); poly.addVertex(pMin.x(), pMin.y()-infillDistance); // Poly poly2 = poly; poly2.move(Vector2d(infillDistance/2,0)); if (!zigzag) poly.rotate(center,m_angle); // poly2.rotate(center,rotation); vector polys(1); polys[0] = poly; // polys[1] = poly2; cpolys = Clipping::getClipperPolygons(polys); } break; case HilbertInfill: { Poly poly(this->layer->getZ()); double square = MAX(Max.x()-Min.x(),Max.y()-Min.y()); if (infillDistance<=0) break; int level = (int)ceil(log2(2*square/infillDistance)); if (level<0) break; //cerr << "level " << level; // start at 0,0 to get the same location for all layers poly.addVertex(0,0); hilbert(level, 0, infillDistance, poly.vertices); vector polys(1); polys[0] = poly; cpolys = Clipping::getClipperPolygons(polys); } break; case ThinInfill: { // just use the poly itself at half extrusion rate cpolys = Clipping::getClipperPolygons(tofillpolys); // adjust extrusion rate - see how thin it is: const uint num_div = 10; double shrink = 0.5*infillDistance/num_div; //cerr << "shrink " << shrink << endl; uint count = 0; // uint num_polys = tofillpolys.size(); vector shrinked = tofillpolys; while (true) { shrinked = Clipping::getOffset(shrinked,-shrink); count++; //cerr << shrinked.size() << " - " << num_polys << endl; if (shrinked.size() == 0) break; // stop when poly is gone } extrusionfactor = 0.5 + 0.5/num_div * count; //cerr << "ex " << extrusionfactor << endl; //cpolys = Clipping::getClipperPolygons(opolys); } break; case PolyInfill: // fill all polygons with their shrinked polys { vector< vector > ipolys; // all offset shells for (uint i=0; i < tofillpolys.size(); i++){ double parea = Clipping::Area(tofillpolys[i]); // make first larger to get clip overlap double firstshrink = 0.5*infillDistance; if (parea<0) firstshrink = -firstshrink; vector shrinked = Clipping::getOffset(tofillpolys[i], firstshrink); vector shrinked2 = Clipping::getOffset(shrinked, 0.5*infillDistance); for (uint i=0;i0){ if (area*parea < 0) break; // went beyond zero size // cerr << "shr " < opolys; for (uint i=0;i &nums, double &minimum) { minimum = INFTY; int minind = -1; for (uint i = 0; i < nums.size(); i++ ) { if (nums[i] < minimum) { minimum = nums[i]; minind = i; } } return minind; } bool intersectsPolys(const Vector2d &P1, const Vector2d &P2, const vector &polys, double err=0.01) { Intersection inter; for (size_t ci = 0; ci < polys.size(); ci++) { // bool in1 = polys[ci].vertexInside(P1); // bool in2 = polys[ci].vertexInside(P2); // if (in1 != in2) return true; vector inter = polys[ci].lineIntersections(P1, P2, err); if (inter.size() > 0) { return true; } } return false; } // sort (parallel) lines into polys so that each poly can be an extrusion path // polys will later be connected by moves (as printlines) // that is: connect nearest lines, but when connection intersects anything, // start a new path (poly) vector Infill::sortedpolysfromlines(const vector &lines, double z) { vector polys; uint count = lines.size(); if (count == 0) return polys; vector clippolys = Clipping::getOffset(m_tofillpolys,0.1); vector done(count); for (uint i = 0; i < count; i++ ) done[i] = false; Poly p(z, extrusionfactor); p.setClosed(false); p.addVertex(lines[0].from); p.addVertex(lines[0].to); uint donelines = 1; while(donelines < count) { vector dist(4); Vector2d l1,l2; double mindistline = INFTY; uint minindline = 0; uint minind = 0; double mindist = INFTY; // find nearest line for current p endpoints: for (uint j = 1; j < count; j++) if (!done[j]) { dist[0] = (p.front()-lines[j].from).squared_length(); dist[1] = (p.front()-lines[j].to ).squared_length(); dist[2] = (p.back() -lines[j].from).squared_length(); dist[3] = (p.back() -lines[j].to ).squared_length(); uint mind = smallest(dist, mindist); if (mindist < mindistline) { minindline = j; mindistline = mindist; minind = mind; } } uint i = minindline; // make new line l1--l2: if (minind % 2 == 0) { l1 = lines[i].from; l2 = lines[i].to; } else { l1 = lines[i].to; l2 = lines[i].from; } // connection to last/first Vector2d conn1, conn2 = l1; if (minind < 2) conn1 = p.front(); else conn1 = p.back(); // try polygons intersect bool intersects = intersectsPolys(conn1, conn2, clippolys); if (!intersects) { // detect crossings: try intersect with any line Intersection inter; for (uint li = 0; li 0.1 && t < 0.9) { intersects = true; break; } } } } if (intersects) { // start new poly if (p.size() > 0) { p.cleanup(infillDistance/2.); polys.push_back(p); } p = Poly(z, extrusionfactor); p.setClosed(false); } // add new line to current p if (minind < 2) { p.push_front(l1); p.push_front(l2); } else { p.push_back(l1); p.push_back(l2); } done[i] = true; donelines++; } if (p.size() > 0) { p.cleanup(infillDistance/2.); polys.push_back(p); } return polys; } bool sameAngle(double angle1, double angle2, double err) { while (angle1 < 0) angle1+=2.*M_PI; while (angle2 < 0) angle2+=2.*M_PI; while (angle1 >= 2*M_PI) angle1-=2.*M_PI; while (angle2 >= 2*M_PI) angle2-=2.*M_PI; return (abs(angle1-angle2) < err); } void Infill::addInfillPolys(const vector &polys) { if (polys.size() == 0) return; #define NEWINFILL 1 #if NEWINFILL switch (m_type) { case BridgeInfill: case RaftInfill: case ParallelInfill: { vector lines; const Vector2d UNITX(1,0); for (uint j = 0; j < polys.size(); j++) { for (uint i = 0; i < polys[j].size() ; i++ ) { Vector2d l = (polys[j][i+1] - polys[j][i]); double langle = angleBetween(UNITX, l) + M_PI/2; if (sameAngle(langle, m_angle, 0.2) || sameAngle(langle+M_PI, m_angle, 0.2)) { infillline il = { polys[j][i], polys[j][i+1] }; lines.push_back( il );; } } } infillpolys = sortedpolysfromlines(lines, polys.back().getZ()); break; } default: #endif #if NEWINFILL infillpolys = polys; // Poly newpoly(p.getZ(), extrusionfactor); // infillpolys.push_back(newpoly); } #else for (uint i=0; i 0.1) { // if (zigzagpoly) { // zigzagpoly->addVertex(p.getVertexCircular(i+i%2)); // zigzagpoly->addVertex(p.getVertexCircular(i+1+i%2)); // } else { Poly newpoly(p.getZ(), extrusionfactor); newpoly.vertices.push_back(p[i]); newpoly.vertices.push_back(p[i+1]); infillpolys.push_back(newpoly); } } // else // if (zigzagpoly) { // zigzagpoly->addVertex(p.getVertexCircular(i)); // } } // if (zigzagpoly) { // cerr << zigzagpoly->size()<< endl; // if (zigzagpoly->size()>0) // infillpolys.push_back(*zigzagpoly); // else delete zigzagpoly; // cerr << infillpolys.size()<< endl; // } } break; default: { Poly newpoly(p.getZ(), extrusionfactor); infillpolys.push_back(newpoly); } } #endif } // not used void Infill::getLines(vector &lines) const { cerr << "infill getlines" << endl; for (uint i=0; i Infill::getCachedPattern(double z) { vector cached; if (m_type != PolyInfill) // can't save PolyInfill if (savedPatterns.size()>0) for (vector::iterator sIt=savedPatterns.begin(); sIt != savedPatterns.end(); sIt++) if (sIt->type == m_type && abs(sIt->distance-infillDistance) < 0.01 && abs(sIt->angle-m_angle) < 0.01 ) { cached = Clipping::getPolys(sIt->cpolys,z,extrusionfactor); break; } return cached; }; string Infill::info() const { ostringstream ostr; ostr << "Infill " << name << ": type=" << m_type << ", extrf=" << extrusionfactor << ", polygons: " << infillpolys.size() << ", vertices: " << infillvertices.size(); return ostr.str(); } // Hilbert curve // http://www.compuphase.com/hilbert.htm enum { UP, LEFT, DOWN, RIGHT, }; void move(int direction, double infillDistance, vector &v){ Vector2d d(0,0); switch (direction) { case LEFT: d.x()=-infillDistance;break; case RIGHT: d.x()= infillDistance;break; case UP: d.y()=-infillDistance;break; case DOWN: d.y()= infillDistance;break; } Vector2d last; if (v.size()==0) last = Vector2d(0,0); else last = v.back(); //cerr <<"move " << direction << " : "< &v) { //cerr <<"hilbert level " << level<< endl; if (level==1) { switch (direction) { case LEFT: move(RIGHT,infillDistance,v); /* move() could draw a line in... */ move(DOWN, infillDistance,v); /* ...the indicated direction */ move(LEFT, infillDistance,v); break; case RIGHT: move(LEFT, infillDistance,v); move(UP, infillDistance,v); move(RIGHT,infillDistance,v); break; case UP: move(DOWN, infillDistance,v); move(RIGHT,infillDistance,v); move(UP, infillDistance,v); break; case DOWN: move(UP, infillDistance,v); move(LEFT, infillDistance,v); move(DOWN, infillDistance,v); break; } /* switch */ } else { switch (direction) { case LEFT: hilbert(level-1,UP,infillDistance,v); move(RIGHT,infillDistance,v); hilbert(level-1,LEFT,infillDistance,v); move(DOWN,infillDistance,v); hilbert(level-1,LEFT,infillDistance,v); move(LEFT,infillDistance,v); hilbert(level-1,DOWN,infillDistance,v); break; case RIGHT: hilbert(level-1,DOWN,infillDistance,v); move(LEFT,infillDistance,v); hilbert(level-1,RIGHT,infillDistance,v); move(UP,infillDistance,v); hilbert(level-1,RIGHT,infillDistance,v); move(RIGHT,infillDistance,v); hilbert(level-1,UP,infillDistance,v); break; case UP: hilbert(level-1,LEFT,infillDistance,v); move(DOWN,infillDistance,v); hilbert(level-1,UP,infillDistance,v); move(RIGHT,infillDistance,v); hilbert(level-1,UP,infillDistance,v); move(UP,infillDistance,v); hilbert(level-1,RIGHT,infillDistance,v); break; case DOWN: hilbert(level-1,RIGHT,infillDistance,v); move(UP,infillDistance,v); hilbert(level-1,DOWN,infillDistance,v); move(LEFT,infillDistance,v); hilbert(level-1,DOWN,infillDistance,v); move(DOWN,infillDistance,v); hilbert(level-1,LEFT,infillDistance,v); break; } /* switch */ } /* if */ } repsnapper-2.3.2a5/src/slicer/infill.h000066400000000000000000000067151231531733200176320ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once /* #include */ #ifdef _OPENMP #include #endif #include "stdafx.h" #include "clipping.h" // user selectable have to be first enum InfillType {ParallelInfill, SmallZigzagInfill, HexInfill, PolyInfill, HilbertInfill, SupportInfill, RaftInfill, BridgeInfill, ZigzagInfill, ThinInfill, INVALIDINFILL}; // these are available for user selection (order must be same as types): const string InfillNames[] = {_("Parallel"), _("Zigzag"), _("Hexagons"), _("Polygons"), _("Hilbert Curve")}; class Infill { Layer *layer; struct pattern { InfillType type; double angle; double distance; Vector2d Min,Max; ClipperLib::Paths cpolys; } ; static vector savedPatterns; #ifdef _OPENMP static omp_lock_t save_lock; #endif ClipperLib::Paths makeInfillPattern(InfillType type, const vector &tofillpolys, double infillDistance, double offsetDistance, double rotation) ; Infill(); void addInfillPoly(const Poly &p); void addInfillPolys(const vector &polys); vector m_tofillpolys; // the polygons that are being filled public: Infill(Layer *layer, double extrfactor); ~Infill(); double extrusionfactor; string name; bool cached; // if this pattern comes from savedPatterns void setName(string s){name=s;}; string getName(){return name;}; static void clearPatterns(); InfillType m_type; double m_angle; double infillDistance; vector infillpolys; // for clipper polygon types vector infillvertices; // for lines types void addPoly (double z, const Poly &poly, InfillType type, double infillDistance, double offsetDistance, double rotation); void addPolys(double z, const vector &polys, InfillType type, double infillDistance, double offsetDistance, double rotation); void addPolys(double z, const vector &polys, const vector &fillpolys, double offsetDistance); void addPolys(double z, const vector &polys, const ClipperLib::Paths &ifcpolys, double offsetDistance); void addPoly (double z, const ExPoly &expoly, InfillType type, double infillDistance, double offsetDistance, double rotation); void addPolys(double z, const vector &expolys, InfillType type, double infillDistance, double offsetDistance, double rotation); void getLines(vector &lines) const; typedef struct { Vector2d from; Vector2d to; } infillline; vector sortedpolysfromlines(const vector &lines, double z); void clear(); uint size() const {return infillpolys.size();}; vector getCachedPattern(double z); string info() const; }; repsnapper-2.3.2a5/src/slicer/layer.cpp000066400000000000000000001203411231531733200200140ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "layer.h" #include "poly.h" #include "shape.h" #include "infill.h" #include "render.h" // polygons will be simplified to thickness/CLEANFACTOR #define CLEANFACTOR 7 Layer::Layer(Layer * prevlayer, int layerno, double thick, uint skins) : LayerNo(layerno), thickness(thick), previous(prevlayer), skins(skins) { normalInfill = NULL; fullInfill = NULL; skirtInfill = NULL; supportInfill = NULL; decorInfill = NULL; thinInfill = NULL; Min = Vector2d(G_MAXDOUBLE, G_MAXDOUBLE); Max = Vector2d(G_MINDOUBLE, G_MINDOUBLE); } Layer::~Layer() { Clear(); } void Layer::Clear() { delete normalInfill; normalInfill = NULL; delete fullInfill; fullInfill = NULL; delete skirtInfill; skirtInfill = NULL; delete supportInfill; supportInfill = NULL; delete decorInfill; decorInfill = NULL; delete thinInfill; thinInfill = NULL; skinFullInfills.clear(); clearpolys(polygons); clearpolys(shellPolygons); clearpolys(fillPolygons); clearpolys(thinPolygons); clearpolys(fullFillPolygons); clearpolys(bridgePolygons); clearpolys(bridgePillars); bridge_angles.clear(); bridgeInfills.clear(); clearpolys(decorPolygons); clearpolys(supportPolygons); clearpolys(toSupportPolygons); clearpolys(skinPolygons); clearpolys(skinFullFillPolygons); hullPolygon.clear(); clearpolys(skirtPolygons); } // void Layer::setBBox(Vector2d min, Vector2d max) // { // Min.x() = MIN(Min.x(),min.x()); // Min.y = MIN(Min.y,min.y); // Max.x() = MAX(Max.x(),max.x()); // Max.y = MAX(Max.y,max.y); // } // void Layer::setBBox(vector minmax) // { // setBBox(minmax[0],minmax[1]); // } // void Layer::setBBox(Vector3d min, Vector3d max) // { // Min.x() = MIN(Min.x(),min.x()); // Min.y = MIN(Min.y,min.y); // Max.x() = MAX(Max.x(),max.x()); // Max.y = MAX(Max.y,max.y); // } void Layer::SetPolygons(vector &polys) { this->polygons = polys; for(uint i=0;i maxdist) { maxdist = pdist; pindex = i; pvindex = fi; } } return polygons[pindex][pvindex]; } bool Layer::pointInPolygons(const Vector2d &p) const { for (uint i = 0; i polys; int num_polys=-1; // try to slice until polygons can be made, otherwise hack z while (!polys_ok && hackedZ < z+thickness) { polys.clear(); polys_ok = shape.getPolygonsAtZ(T, hackedZ, // slice shape at hackedZ polys, max_gradient, toSupportPolygons, max_supportangle, thickness); hackedZ += thickness/10; if (polys_ok) { num_polys = polys.size(); addPolygons(polys); } else { num_polys=-1; cerr << "hacked Z " << z << " -> " << hackedZ << endl; } } cleanupPolygons(); return num_polys; } void Layer::cleanupPolygons() { double clean = thickness/CLEANFACTOR; for(uint i=0; i < polygons.size(); i++){ polygons[i].cleanup(clean); } } void Layer::addPolygons(vector &polys) { for(uint i=0;i polysbelow = *(layerbelow->GetInnerShell());//clipp.getOffset(polygons,3*thickness); bridgePillars.resize(bridgePolygons.size()); for (uint i=0; i rotating infill? // get average direction of the mutual connections of all the intersections Vector2d dir(0,0); for (uint p=0; p Layer::getBridgeRotations(const vector &polys) const{ cerr << "Layer::getBridgeRotations" << endl; vector angles; angles.resize(polys.size()); Clipping clipp; vector offset = polygons;//clipp.getOffset(polygons,3*thickness); for (uint i=0; i pillars = clipp.intersect(); // get average direction of the connection lines of all the intersections Vector2d dir(0,0); for (uint p=0; p &polys, double extrusionfactor, double infilldistance, double rotation) { setMinMax(polys); normalInfill = new Infill(this, extrusionfactor); normalInfill->setName("Raft"); normalInfill->addPolys(Z, polys, RaftInfill, infilldistance, infilldistance, rotation); } void Layer::CalcInfill (const Settings &settings) { // inFill distances in real mm: // for full polys/layers: double fullInfillDistance=0; double infillDistance=0; // normal fill double altInfillDistance=0; double altInfillPercent=settings.get_double("Slicing","InfillPercent"); double normalInfilldist=0; bool shellOnly = !settings.get_boolean("Slicing","DoInfill"); fullInfillDistance = settings.GetInfillDistance(thickness, 100); if (settings.get_double("Slicing","InfillPercent") == 0) shellOnly = true; else infillDistance = settings.GetInfillDistance(thickness,altInfillPercent); int altinfill = settings.get_integer("Slicing","AltInfillLayers"); normalInfilldist = infillDistance; if ( altinfill != 0 && LayerNo % altinfill == 0 && altInfillPercent != 0) { altInfillDistance = settings.GetInfillDistance(thickness, settings.get_double("Slicing","AltInfillPercent")); normalInfilldist = altInfillDistance; } // first layers: if (LayerNo < (int)settings.get_integer("Slicing","FirstLayersNum")) { double first_infdist = fullInfillDistance * (1.+settings.get_double("Slicing","FirstLayersInfillDist")); normalInfilldist = max(normalInfilldist, first_infdist); fullInfillDistance = max(fullInfillDistance, first_infdist); } // relative extrusion for skins: double skinfillextrf = settings.get_double("Slicing","FullFillExtrusion")/skins/skins; normalInfill = new Infill(this,settings.get_double("Slicing","NormalFillExtrusion")); normalInfill->setName("normal"); fullInfill = new Infill(this,settings.get_double("Slicing","FullFillExtrusion")); fullInfill->setName("full"); skirtInfill = new Infill(this,settings.get_double("Slicing","FullFillExtrusion")); skirtInfill->setName("skirt"); skinFullInfills.clear(); supportInfill = new Infill(this,settings.get_double("Slicing","SupportExtrusion")); supportInfill->setName("support"); decorInfill = new Infill(this,1.); decorInfill->setName("decor"); thinInfill = new Infill(this, 1.); thinInfill->setName("thin"); double rot = (settings.get_double("Slicing","InfillRotation"), + (double)LayerNo*settings.get_double("Slicing","InfillRotationPrLayer"))/180.0*M_PI; if (!shellOnly) normalInfill->addPolys(Z, fillPolygons, (InfillType)settings.get_integer("Slicing","NormalFilltype"), normalInfilldist, fullInfillDistance, rot); if (settings.get_boolean("Slicing","FillSkirt")) { vector skirtFill; Clipping clipp; clipp.addPolys(skirtPolygons, subject); clipp.addPolys(*GetOuterShell(), clip); clipp.addPolys(supportPolygons, clip); skirtFill = clipp.subtract(); skirtFill = Clipping::getOffset(skirtFill, -fullInfillDistance); skirtInfill->addPolys(Z, skirtFill, (InfillType)settings.get_integer("Slicing","FullFilltype"), fullInfillDistance, fullInfillDistance, rot); } fullInfill->addPolys(Z, fullFillPolygons, (InfillType)settings.get_integer("Slicing","FullFilltype"), fullInfillDistance, fullInfillDistance, rot); decorInfill->addPolys(Z, decorPolygons, (InfillType)settings.get_integer("Slicing","DecorFilltype"), settings.get_double("Slicing","DecorInfillDistance"), settings.get_double("Slicing","DecorInfillDistance"), settings.get_double("Slicing","DecorInfillRotation")/180.0*M_PI); assert(bridge_angles.size() >= bridgePolygons.size()); bridgeInfills.resize(bridgePolygons.size()); for (uint b=0; b < bridgePolygons.size(); b++){ bridgeInfills[b] = new Infill(this, settings.get_double("Slicing","BridgeExtrusion")); bridgeInfills[b]->addPoly(Z, bridgePolygons[b], BridgeInfill, fullInfillDistance, fullInfillDistance, bridge_angles[b]+M_PI/2); } if (skins>1) { double skindistance = fullInfillDistance/skins; for (uint s = 0; ssetName("skin"); inf->addPolys(sz, skinFullFillPolygons, (InfillType)settings.get_integer("Slicing","FullFilltype"), skindistance, skindistance, drot); skinFullInfills.push_back(inf); } } supportInfill->addPolys(Z, supportPolygons, (InfillType)settings.get_integer("Slicing","SupportFilltype"), settings.get_double("Slicing","SupportInfillDistance"), settings.get_double("Slicing","SupportInfillDistance"), 0); thinInfill->addPolys(Z, thinPolygons, ThinInfill, fullInfillDistance, fullInfillDistance, 0); } // call before full fill areas are multiplied void Layer::makeSkinPolygons() { if (skins<2) return; skinFullFillPolygons = fullFillPolygons; fullFillPolygons.clear(); } // add bridge polys and subtract them from normal and full fill polys // each given ExPoly is a single bridge with its holes void Layer::addBridgePolygons(const vector &newexpolys) { // clip against normal fill and make these areas into bridges: Clipping clipp; uint num_bridges = newexpolys.size(); if (num_bridges==0) return; clipp.clear(); bridgePolygons.clear(); for (uint i=0; i < num_bridges; i++){ vector newpolys = Clipping::getPolys(newexpolys[i]); clipp.clear(); clipp.addPolys(fillPolygons,subject); clipp.addPolys(newpolys, clip); vector exbridges = clipp.ext_intersect(); bridgePolygons.insert(bridgePolygons.end(),exbridges.begin(),exbridges.end()); } // subtract from normal fill clipp.clear(); clipp.addPolys(fillPolygons,subject); clipp.addPolys(newexpolys, clip); setNormalFillPolygons(clipp.subtract()); } void Layer::addFullPolygons(const vector &newpolys, bool decor) { addFullPolygons(Clipping::getPolys(newpolys),decor); } // add full fill and subtract them from normal fill polys void Layer::addFullPolygons(const vector &newpolys, bool decor) { if (newpolys.size()==0) return; Clipping clipp; clipp.clear(); // full fill only where already normal fill clipp.addPolys(fillPolygons,subject); if (decor) clipp.addPolys(fullFillPolygons,subject); clipp.addPolys(newpolys,clip); clipp.setZ(Z); vector inter = clipp.intersect(); vector normals = clipp.subtractMerged(thickness/2.); if (decor) {// && LayerNo != 0) // no decor on base layers decorPolygons.insert(decorPolygons.end(), inter.begin(), inter.end()); Clipping clipp; clipp.addPolys(fullFillPolygons,subject); clipp.addPolys(inter,clip); clipp.setZ(Z); setFullFillPolygons(clipp.subtract()); } else { fullFillPolygons.insert(fullFillPolygons.end(),inter.begin(),inter.end()); } setNormalFillPolygons(normals); // mergeFullPolygons(false); // done separately } void cleanup(vector &polys, double error) { for (uint i = 0; i normals = clipp.subtractMerged(); setNormalFillPolygons(normals); // } } void Layer::mergeSupportPolygons() { setSupportPolygons(Clipping::getMerged(GetSupportPolygons())); } const vector * Layer::GetInnerShell() const { // if (fillPolygons.size()>0) return fillPolygons; // // no offset if (shellPolygons.size()>0) return &(shellPolygons.back()); // no shells: if (skinPolygons.size()>0) return &skinPolygons; // no skins return &polygons; } const vector * Layer::GetOuterShell() const { if (skinPolygons.size()>0) return &skinPolygons; // no skins if (shellPolygons.size()>0) return &(shellPolygons.front()); // no shells: if (fillPolygons.size()>0) return &fillPolygons; // no offset return &polygons; } vector Layer::GetExPolygons() const { return Clipping::getExPolys(polygons,0,0); } // circular numbering vector Layer::GetShellPolygonsCirc(int number) const { number = (shellPolygons.size() + number) % shellPolygons.size(); return shellPolygons[number]; } void Layer::setNormalFillPolygons(const vector &polys) { clearpolys(fillPolygons); fillPolygons = polys; for (uint i=0; i &polys) { clearpolys(fullFillPolygons); fullFillPolygons = polys; for (uint i=0; i &expolys) { uint count = expolys.size(); // vector polygroups; // vector done; done.resize(count); // for (uint i=0; i group; // group.push_back(polys[i]); // done[i] = true; // } // for (uint j=i+1; j &angles) { bridge_angles=angles; // .insert(bridge_angles.begin(),angles.begin(),angles.end()); } void Layer::setSupportPolygons(const vector &polys) { clearpolys(supportPolygons); supportPolygons = polys; const double minarea = 10*thickness*thickness; for (int i = supportPolygons.size()-1; i >= 0; i--) { supportPolygons[i].cleanup(thickness/CLEANFACTOR); if (abs(Clipping::Area(supportPolygons[i])) < minarea) { supportPolygons.erase(supportPolygons.begin() + i); continue; } vector minmax = supportPolygons[i].getMinMax(); Min.x() = min(minmax[0].x(),Min.x()); Min.y() = min(minmax[0].y(),Min.y()); Max.x() = max(minmax[1].x(),Max.x()); Max.y() = max(minmax[1].y(),Max.y()); } } void Layer::setSkirtPolygons(const vector &poly) { clearpolys(skirtPolygons); skirtPolygons = poly; for (uint i=0; i &polys, double extrwidth, vector &thickpolys, vector &thinpolys) { #define THINPOLYS 1 #if THINPOLYS // go in thickpolys = Clipping::getOffset(polys, -0.5*extrwidth); // go out again, now thin polys are gone thickpolys = Clipping::getOffset(thickpolys, 0.55*extrwidth); // (need overlap to really clip) // use bigger (longer) polys for clip to avoid overlap of thin and thick extrusion lines vector bigthick = Clipping::getOffset(thickpolys, extrwidth); // difference to original are thin polys Clipping clipp; clipp.addPolys(polys, subject); clipp.addPolys(bigthick, clip); thinpolys = clipp.subtract(); // remove overlap thickpolys = Clipping::getOffset(thickpolys, -0.05*extrwidth); #else thickpolys = polys; #endif } void Layer::MakeShells(const Settings &settings) { double extrudedWidth = settings.GetExtrudedMaterialWidth(thickness); double roundline_extrfactor = settings.RoundedLinewidthCorrection(extrudedWidth,thickness); double distance = 0.5 * extrudedWidth; double cleandist = min(distance/CLEANFACTOR, thickness/CLEANFACTOR); double shelloffset = settings.get_double("Slicing","ShellOffset"); uint shellcount = settings.get_integer("Slicing","ShellCount"); double infilloverlap = settings.get_double("Slicing","InfillOverlap"); // first shrink with global offset vector shrinked = Clipping::getOffset(polygons, -2.0/M_PI*extrudedWidth-shelloffset); vector thickPolygons; FindThinpolys(shrinked, extrudedWidth, thickPolygons, thinPolygons); shrinked = thickPolygons; for (uint i = 0; i shrinked = Clipping::getShrinkedCapped(polygons,distance); // outmost shells if (shellcount > 0) { if (skins>1) { // either skins for (uint i = 0; i thinpolys; FindThinpolys(shrinked, extrudedWidth, thickPolygons, thinpolys); shrinked = thickPolygons; thinPolygons.insert(thinPolygons.end(), thinpolys.begin(),thinpolys.end()); for (uint j = 0; j " << fillPolygons.size()<< endl; } calcConvexHull(); //cerr << " .. made " << fillPolygons.size() << " offsetpolys " << endl; // for (uint i =0; i all; if (single) { // single skirt all.push_back(hullPolygon); all.insert(all.end(),supportPolygons.begin(),supportPolygons.end()); Poly hull = convexHull2D(all); vector skp = Clipping::getOffset(hull, distance, jround); if (skp.size()>0){ skirtPolygons.push_back(skp.front()); skirtPolygons[0].setZ(Z); skirtPolygons[0].cleanup(thickness); } } else { // skirt for each shape skirtPolygons = Clipping::getOffset(*GetOuterShell(), distance, jround); } } // calc convex hull and Min and Max of layer void Layer::calcConvexHull() { hullPolygon = convexHull2D(polygons); // see geometry.cpp hullPolygon.setZ(Z); setMinMax(hullPolygon); } bool Layer::setMinMax(const vector &polys) { Vector2d NewMin = Vector2d( INFTY, INFTY); Vector2d NewMax = Vector2d(-INFTY, -INFTY); for (uint i = 0; i< polys.size(); i++) { vector minmax = polys[i].getMinMax(); NewMin.x() = min(NewMin.x(), minmax[0].x()); NewMin.y() = min(NewMin.y(), minmax[0].y()); NewMax.x() = max(NewMax.x(), minmax[1].x()); NewMax.y() = max(NewMax.y(), minmax[1].y()); } if (NewMin==Min && NewMax==Max) return false; Min = NewMin; Max = NewMax; return true; } bool Layer::setMinMax(const Poly &poly) { vector minmax = poly.getMinMax(); if (minmax[0]==Min && minmax[1]==Max) return false; Min = minmax[0]; Max = minmax[1]; return true; } // Convert to GCode void Layer::MakeGCode (Vector3d &start, GCodeState &gc_state, double offsetZ, Settings &settings) const { vector plines; MakePrintlines(start, plines, offsetZ, settings); Printlines::makeAntioozeRetract(plines, settings); Printlines::getCommands(plines, settings, gc_state); } // Convert to Printlines void Layer::MakePrintlines(Vector3d &lastPos, //GCodeState &state, vector &lines3, double offsetZ, Settings &settings) const { const double linewidth = settings.GetExtrudedMaterialWidth(thickness); const double cornerradius = linewidth*settings.get_double("Slicing","CornerRadius"); const bool clipnearest = settings.get_boolean("Slicing","MoveNearest"); const uint supportExtruder = settings.GetSupportExtruder(); const double minshelltime = settings.get_double("Slicing","MinShelltime"); const double maxshellspeed = settings.get_double("Extruder","MaxShellSpeed"); const bool ZliftAlways = settings.get_boolean("Extruder","ZliftAlways"); Vector2d startPoint(lastPos.x(),lastPos.y()); const double extr_per_mm = settings.GetExtrusionPerMM(thickness); //vector lines3; Printlines printlines(this, &settings, offsetZ); vector lines; vector polys; // intermediate collection // polys to keep line movements inside //const vector * clippolys = &polygons; const vector * clippolys = GetOuterShell(); // 1. Skins, all but last, because they are the lowest lines, below layer Z if (skins > 1) { for(uint s = 0; s < skins; s++) { // z offset from bottom to top: double skin_z = Z - thickness + (s+1)*thickness/skins; if ( skin_z < 0 ){ cerr << "Skin Z<0! " << s << " -- " << Z << " -- "<infillpolys.begin(), skinFullInfills[s]->infillpolys.end()); // add skin infill to lines printlines.addPolys(INFILL, polys, false); polys.clear(); // make polygons at skin_z: for(size_t p = 0; p < skinPolygons.size(); p++) { polys.push_back(Poly(skinPolygons[p], skin_z)); } // add skin to lines printlines.addPolys(SKIN, polys, (s==0), // displace at first skin maxshellspeed * 60, minshelltime); if (s < skins-1) { // not on the last layer, this handle with all other lines // have to get all these separately because z changes printlines.makeLines(startPoint, lines); if (!ZliftAlways) printlines.clipMovements(*clippolys, lines, clipnearest, linewidth); printlines.optimize(linewidth, minshelltime, cornerradius, lines); printlines.getLines(lines, lines3, extr_per_mm); printlines.clear(); lines.clear(); } polys.clear(); } } // last skin layer now still in lines lines.clear(); // 2. Skirt printlines.addPolys(SKIRT, skirtPolygons, false, maxshellspeed * 60, minshelltime); // 3. Support if (supportInfill) { uint extruderbefore = settings.selectedExtruder; settings.SelectExtruder(supportExtruder); printlines.addPolys(SUPPORT, supportInfill->infillpolys, false); settings.SelectExtruder(extruderbefore); } // 4. all other polygons: // Shells for(int p=shellPolygons.size()-1; p>=0; p--) { // inner to outer //cerr << "displace " << p << endl; printlines.addPolys(SHELL, shellPolygons[p], (p==(int)(shellPolygons.size())-1), maxshellspeed * 60, minshelltime); } // Infill if (normalInfill) printlines.addPolys(INFILL, normalInfill->infillpolys, false); if (thinInfill) printlines.addPolys(INFILL, thinInfill->infillpolys, false); if (fullInfill) printlines.addPolys(INFILL, fullInfill->infillpolys, false); if (skirtInfill) printlines.addPolys(INFILL, skirtInfill->infillpolys, false); if (decorInfill) printlines.addPolys(INFILL, decorInfill->infillpolys, false); for (uint b=0; b < bridgeInfills.size(); b++) if (bridgeInfills[b]) printlines.addPolys(INFILL, bridgeInfills[b]->infillpolys, false); double polyspeedfactor = printlines.makeLines(startPoint, lines); // FINISH Command lchange(LAYERCHANGE, LayerNo); lchange.where = Vector3d(0.,0.,Z); lchange.comment += info(); lines3.push_back(PLine3(lchange)); if (!ZliftAlways) printlines.clipMovements(*clippolys, lines, clipnearest, linewidth); printlines.optimize(linewidth, settings.get_double("Slicing","MinLayertime"), cornerradius, lines); if ((guint)LayerNo < (guint)settings.get_integer("Slicing","FirstLayersNum")) printlines.setSpeedFactor(settings.get_double("Slicing","FirstLayersSpeed"), lines); double slowdownfactor = printlines.getSlowdownFactor() * polyspeedfactor; if (settings.get_boolean("Slicing","FanControl")) { int fanspeed = settings.get_integer("Slicing","MinFanSpeed"); if (slowdownfactor < 1 && slowdownfactor > 0) { double fanfactor = 1-slowdownfactor; fanspeed += int(fanfactor * (settings.get_integer("Slicing","MaxFanSpeed")-settings.get_integer("Slicing","MinFanSpeed"))); fanspeed = CLAMP(fanspeed, settings.get_integer("Slicing","MinFanSpeed"), settings.get_integer("Slicing","MaxFanSpeed")); //cerr << slowdownfactor << " - " << fanfactor << " - " << fanspeed << " - " << endl; } Command fancommand(FANON, fanspeed); lines3.push_back(PLine3(fancommand)); } printlines.getLines(lines, lines3, extr_per_mm); if (lines3.size()>0) lastPos = lines3.back().to; } double Layer::area() const { return Clipping::Area(polygons); } string Layer::info() const { ostringstream ostr; ostr <<"Layer at Z=" << Z << " No=" << LayerNo <<", thickn=" << thickness <<", "<size() ; if (fullInfill) ostr <<", full "<size() ; if (bridgeInfills.size()>0) ostr <<", bridges "<size() ; ostr <<", skinfills "<" << endl; for (uint i = 0; i"; return ostr.str(); } void Layer::Draw(const Settings &settings) { #if 0 // test single area expolys vector expolys = Clipping::getExPolys(polygons); draw_polys(expolys, GL_LINE_LOOP, 1, 3, RED, 1); cerr << expolys.size() << endl; Infill exinf(this, 1.); exinf.setName("infill"); double infilldistance = settings.GetInfillDistance(thickness, settings.Slicing.InfillPercent); exinf.addPolys(Z, expolys, HexInfill, infilldistance, infilldistance, 0.4); draw_polys(exinf.infillpolys, GL_LINE_LOOP, 1, 3, (exinf.cached?BLUEGREEN:GREEN), 1); return; #endif bool randomized = settings.get_boolean("Display","RandomizedLines"); bool filledpolygons = settings.get_boolean("Display","DisplayFilledAreas"); // glEnable(GL_LINE_SMOOTH); // glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); draw_polys(polygons, GL_LINE_LOOP, 1, 3, RED, 1, randomized); draw_polys(polygons, GL_POINTS, 1, 3, RED, 1, randomized); if(settings.get_boolean("Display","DrawCPOutlineNumbers")) for(size_t p=0; p0) { if (filledpolygons) draw_polys_surface(supportPolygons, Min, Max, Z, thickness/2., BLUE2, 0.4); draw_polys(supportPolygons, GL_LINE_LOOP, 3, 3, BLUE2, 1, randomized); if(settings.get_boolean("Display","DrawVertexNumbers")) for(size_t p=0; pinfillpolys, GL_LINE_LOOP, 1, 3, (normalInfill->cached?BLUEGREEN:GREEN), 1, randomized); if(DebugInfill && normalInfill->cached) draw_polys(normalInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3, ORANGE, 0.5, randomized); if (thinInfill) draw_polys(thinInfill->infillpolys, GL_LINE_LOOP, 1, 3, GREEN, 1, randomized); if (fullInfill) draw_polys(fullInfill->infillpolys, GL_LINE_LOOP, 1, 3, (fullInfill->cached?BLUEGREEN:GREEN), 0.8, randomized); if (skirtInfill) draw_polys(skirtInfill->infillpolys, GL_LINE_LOOP, 1, 3, YELLOW, 0.6, randomized); if(DebugInfill && fullInfill->cached) draw_polys(fullInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3, ORANGE, 0.5, randomized); if (decorInfill) draw_polys(decorInfill->infillpolys, GL_LINE_LOOP, 1, 3, (decorInfill->cached?BLUEGREEN:GREEN), 0.8, randomized); if(DebugInfill && decorInfill->cached) draw_polys(decorInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3, ORANGE, 0.5, randomized); uint bridgecount = bridgeInfills.size(); if (bridgecount>0) for (uint i = 0; iinfillpolys, GL_LINE_LOOP, 2, 3, RED3,0.9, randomized); if (supportInfill) draw_polys(supportInfill->infillpolys, GL_LINE_LOOP, 1, 3, (supportInfill->cached?BLUEGREEN:GREEN), 0.8, randomized); if(DebugInfill && supportInfill->cached) draw_polys(supportInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3, ORANGE, 0.5, randomized); for(size_t s=0;sinfillpolys, GL_LINE_LOOP, 1, 3, (skinFullInfills[s]->cached?BLUEGREEN:GREEN), 0.6, randomized); } //draw_polys(GetInnerShell(), GL_LINE_LOOP, 2, 3, WHITE, 1); glLineWidth(1); if(settings.get_boolean("Display","DrawCPVertexNumbers")) // poly vertex numbers for(size_t p=0; p overhangs = getOverhangs(); draw_polys(overhangs, GL_LINE_LOOP, 1, 3, VIOLET, 0.8, randomized); //draw_polys_surface(overhangs, Min, Max, Z, thickness/5, VIOLET , 0.5); Cairo::RefPtr surface; Cairo::RefPtr context; if (rasterpolys(overhangs, Min, Max, thickness/5, surface, context)) if(surface!=0) { glColor4f(RED[0],RED[1],RED[2], 0.5); glDrawCairoSurface(surface, Min, Max, Z); glColor4f(RED[0],RED[1],RED[2], 0.6); glPointSize(3); glBegin(GL_POINTS); for (double x = Min.x(); x *polys = GetOuterShell(); glColor4f(RED[0],RED[1],RED[2], 0.6); glPointSize(3); glBegin(GL_POINTS); for (double x = Min.x(); xsize(); i++) { if ((*polys)[i].vertexInside(Vector2d(x,y))){ inpoly=true; break; } } if (inpoly) glVertex3d(x,y,Z); // else // glColor4f(0.3,0.3,0.3, 0.6); } glEnd(); #endif } void Layer::DrawRulers(const Vector2d &point) { Vector2d x0(Min.x()-10, point.y()); Vector2d x1(Max.x()+10, point.y()); Vector2d y0(point.x(), Min.y()-10); Vector2d y1(point.x(), Max.y()+10); // cut axes with layer polygons vector xint, yint; Intersection hit; hit.p = Vector2d(Min.x(),point.y()); hit.d = 10; xint.push_back(hit); hit.p = Vector2d(Max.x(),point.y()); hit.d = Max.x()-Min.x()+10; xint.push_back(hit); hit.p = Vector2d(point.x(),Min.y()); hit.d = 10; yint.push_back(hit); hit.p = Vector2d(point.x(),Max.y()); hit.d = Max.y()-Min.y()+10; yint.push_back(hit); for(size_t p=0; p lint = polygons[p].lineIntersections(x0,x1,0.1); xint.insert(xint.end(),lint.begin(),lint.end()); lint = polygons[p].lineIntersections(y0,y1,0.1); yint.insert(yint.end(),lint.begin(),lint.end()); } //cerr << xint.size() << " - "<< xint.size() << endl; std::sort(xint.begin(),xint.end()); std::sort(yint.begin(),yint.end()); glColor4f(1.,1.,1.,1.); glLineWidth(1); glBegin(GL_LINES); // draw lines glVertex3d(Min.x(), x0.y(), Z); glVertex3d(Max.x(), x1.y(), Z); glVertex3d(y0.x(), Min.y(), Z); glVertex3d(y1.x(), Max.y(), Z); // draw ticks double ticksize=2; for(guint i = 0; i #include #include #include "poly.h" #include "gcode/gcodestate.h" #include "printlines.h" #include // // A Layer containing and maintaining all polygons to be printed // class Layer { public: Layer(); Layer(Layer * previous, int layerno=-1, double thick=0., uint skins=1); ~Layer(); int LayerNo; double thickness; double Z; double getZ() const {return Z;} void setZ(double z){Z=z;} void setSkins(uint skins_){skins = skins_;} Layer * getPrevious() const {return previous;}; void setPrevious(Layer * prevlayer){previous = prevlayer;}; Vector2d getMin() const {return Min;}; Vector2d getMax() const {return Max;}; bool setMinMax(const Poly &poly); bool setMinMax(const vector &polys); bool pointInPolygons(const Vector2d &p) const; Vector2d getRandomPolygonPoint() const; Vector2d getFarthestPolygonPoint(const Vector2d &from) const; /* void setBBox(Vector2d min, Vector2d max); */ /* void setBBox(vector minmax); */ /* void setBBox(Vector3d min, Vector3d max); */ // ClipperLib::Paths getClipperPolygons(const vector polygons, // bool reverse=true) const; vector getMergedPolygons(const vector &polys); //ClipperLib::Paths getMergedPolygons(const ClipperLib::Paths cpolys) const; void mergeFullPolygons(bool bridge); void mergeSupportPolygons(); // vector getFillPolygons(const vector polys, long dist) const; void CalcInfill (const Settings &settings); void CalcRaftInfill (const vector &polys, double extrusionfactor, double infilldistance, double rotation); vector getBridgeRotations(const vector &poly) const; void calcBridgeAngles(const Layer *layerbelow); static void FindThinpolys(const vector &polys, double extrwidth, vector &thickpolys, vector &thinpolys); void MakeShells(const Settings &settings); // uint shellcount, double extrudedWidth, double shelloffset, // bool makeskirt, double skirtdistance, double infilloverlap); /* vector ShrinkedPolys(const vector poly, */ /* double distance, */ /* ClipperLib::JoinType join_type = ClipperLib::jtMiter); */ void calcConvexHull(); void MakeSkirt(double distance, bool single=true); vector GetPolygons() const { return polygons; }; vector GetExPolygons() const; void SetPolygons(vector &polys) ; /* void SetPolygons(const Matrix4d &T, const Shape &shape, double z); */ vector GetFillPolygons() const { return fillPolygons; } vector GetFullFillPolygons() const { return fullFillPolygons; } vector GetBridgePolygons() const { return bridgePolygons; } vector GetSkinFullPolygons() const { return skinFullFillPolygons; } vector GetSupportPolygons() const { return supportPolygons; } vector GetToSupportPolygons() const { return toSupportPolygons; } vector GetDecorPolygons() const { return decorPolygons; } vector< vector > GetShellPolygons() const {return shellPolygons; } vector GetShellPolygonsCirc(int number) const; vector GetSkirtPolygons() const {return skirtPolygons; }; const vector * GetInnerShell() const; const vector * GetOuterShell() const; Poly GetHullPolygon() const {return hullPolygon;}; vector getOverhangs() const; void setFullFillPolygons(const vector &polys); void addFullFillPolygons(const vector &polys); void addFullPolygons(const vector &fullpolys, bool decor=false); void addFullPolygons(const vector &expolys, bool decor=false); void setBridgePolygons(const vector &polys); void addBridgePolygons(const vector &polys); void setBridgeAngles(const vector &angles); void makeSkinPolygons(); void setNormalFillPolygons(const vector &polys); void setSupportPolygons(const vector &polys); void setSkirtPolygons(const vector &poly); void setDecorPolygons(const vector &polys); /* void getOrderedPrintLines(const vector polys, */ /* Vector2d &startPoint, */ /* vector &lines, */ /* double linewidth,double linewidthratio,double optratio) const; */ void MakePrintlines (Vector3d &start, vector &plines, double offsetZ, Settings &settings) const; void MakeGCode (Vector3d &start, GCodeState &gc_state, double offsetZ, Settings &settings) const; string info() const ; void Draw(const Settings &settings); void DrawRulers(const Vector2d &point); void Clear(); void addPolygons(vector &polys); void cleanupPolygons(); int addShape(const Matrix4d &T, const Shape &shape, double z, double &max_gradient, double max_supportangle); double area() const; string SVGpath(const Vector2d &trans=Vector2d::ZERO) const; private: Layer * previous; Vector2d Min, Max; // Bounding box Infill * normalInfill; Infill * fullInfill; Infill * skirtInfill; vector bridgeInfills; // an infill for every brigde (different angles) vector skinFullInfills; Infill * supportInfill; Infill * decorInfill; Infill * thinInfill; // one-line infill for thin features vector polygons; // original polygons directly from model vector< vector > shellPolygons; // all shells except innermost vector thinPolygons; // areas thinner than 2 extrusion lines vector fillPolygons; // innermost shell vector fullFillPolygons; // fully filled polygons (uncovered) vector bridgePolygons; // fully filled ex-polygons with holes for bridges vector bridge_angles; // angles of each bridge ex-polygon vector< vector > bridgePillars; // bridge pillars for debugging vector supportPolygons; // polygons to be filled with support pattern vector toSupportPolygons; // triangles that should be supported uint skins; // number of skin divisions vector skinPolygons; // outer skin polygons vector skinFullFillPolygons; // skin polygons of fully filled areas Poly hullPolygon; // convex hull around everything vector skirtPolygons; // skirt polygon vector decorPolygons; // decoration polygons // uses too much memory /* Cairo::RefPtr raster_surface; */ /* Cairo::RefPtr raster_context; */ }; repsnapper-2.3.2a5/src/slicer/poly.cpp000066400000000000000000000621741231531733200176740ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "poly.h" #include "layer.h" #include "shape.h" #include "clipping.h" #include "render.h" #include Poly::Poly() { closed = true; holecalculated = false; this->z = -10; extrusionfactor = 1.; } Poly::Poly(double z, double extrusionfactor) { closed = true; this->z = z; this->extrusionfactor = extrusionfactor; holecalculated = false; hole=false; //cout << "POLY WITH PLANE"<< endl; //plane->printinfo(); //printinfo(); } Poly::Poly(const Poly &p, double z_) { closed = p.closed; this->z = z_; this->extrusionfactor = p.extrusionfactor; //uint count = p.vertices.size(); // vertices.resize(count); this->vertices = p.vertices; holecalculated = p.holecalculated; if (holecalculated) { hole = p.hole; center = p.center; } else calcHole(); } Poly::~Poly() { } void Poly::cleanup(double epsilon) { vertices = simplified(vertices, epsilon); if (!closed) return; uint n_vert = vertices.size(); vector invert; invert.insert(invert.end(),vertices.begin()+n_vert/2,vertices.end()); invert.insert(invert.end(),vertices.begin(),vertices.begin()+n_vert/2); vertices = simplified(invert, epsilon); //calcHole(); } /* * Iterate the vertices, and calculate whether this * shape is a hole or enclosed, based on whether the * segment normals point outward (a hole) or inward * (enclosing) */ void Poly::calcHole() const // hole is mutable { if(vertices.size() < 3) return; // hole is undefined Vector2d p(-INFTY, -INFTY); int v=0; center = Vector2d(0,0); Vector2d q; for(size_t vert=0;vert p.x()) { p = q; v=vert; } else if(q.x() == p.x() && q.y() > p.y()) { p.y() = q.y(); v=vert; } } center /= vertices.size(); // we have the x-most vertex (with the highest y if there was a contest), v Vector2d V1 = getVertexCircular(v-1); Vector2d V2 = getVertexCircular(v); Vector2d V3 = getVertexCircular(v+1); // Vector2d Va=V2-V1; // Vector2d Vb=V3-V2; hole = isleftof(V2, V3, V1); //cross(Vb,Va) > 0; holecalculated = true; } bool Poly::isHole() const { if (!holecalculated) calcHole(); return hole; } Vector2d Poly::getCenter() const { if (!holecalculated) calcHole(); return center; } void Poly::rotate(const Vector2d &rotcenter, double angle) { for (uint i = 0; i < vertices.size(); i++) { ::rotate(vertices[i], rotcenter, angle); } } void Poly::move(const Vector2d &delta) { for (uint i = 0; i < vertices.size(); i++) { vertices[i] += delta; } center+=delta; } void Poly::transform(const Matrix4d &T) { for (uint i = 0; i < vertices.size(); i++) { const Vector3d v = T * getVertexCircular3(i) ; vertices[i].set(v.x(),v.y()); } setZ((T * Vector3d(0,0,z)).z()); calcHole(); } void Poly::transform(const Matrix3d &T) { for (uint i = 0; i < vertices.size(); i++) { vertices[i] = T * vertices[i]; } calcHole(); } void Poly::mirrorX(const Vector3d ¢er) { uint count = size(); for (uint i = 0; i < count; i++) vertices[i].x() = center.x() - vertices[i].x(); reverse(); calcHole(); } uint Poly::getFarthestIndex(uint &thisindex) const { return getFarthestIndex(vertices[thisindex]); } uint Poly::getFarthestIndex(const Vector2d &from) const { uint findex = 0; double maxdist = 0.; for (uint i = 0; i < size(); i++) { double d = from.squared_distance(vertices[i]); if (d > maxdist) { maxdist = d; findex = i; } } return findex; } // nearest connection point indices of this and other poly // if poly is not closed, only test first and last point void Poly::nearestIndices(const Poly &p2, int &thisindex, int &otherindex) const { double mindist = INFTY; for (uint i = 0; i < size(); i++) { if (!closed && i != 0 && i != size()-1) continue; for (uint j = 0; j < p2.size(); j++) { if (!p2.closed && j != 0 && j != p2.size()-1) continue; double d = vertices[i].squared_distance(p2.vertices[j]); if (d < mindist) { mindist = d; thisindex = i; otherindex= j; } } } } // Find the vertex in the poly closest to point p // if not closed, only look for first and last point uint Poly::nearestDistanceSqTo(const Vector2d &p, double &mindist) const { assert(vertices.size() > 0); // Start with first vertex as closest uint nindex = 0; mindist = (vertices[0]-p).squared_length(); if (isnan(mindist)) { // for infinity point p return point 0 and distance 0 mindist = 0.; return 0; } // check the rest of the vertices for a closer one. for (uint i = 1; i < vertices.size(); i++) { if (!closed && i != 0 && i != vertices.size()-1) continue; double d = (vertices[i]-p).squared_length(); if (d min(p1->y(), p2->y())) { if (p.y() <= max(p1->y(), p2->y())) { if (p.x() <= max(p1->x(), p2->x())) { if (p1->y() != p2->y()) { xinters = (p.y()-p1->y())*(p2->x()-p1->x())/(p2->y()-p1->y())+p1->x(); if (p1->x() == p2->x() || p.x() <= xinters) counter++; } } } } p1 = p2; } return (counter % 2 != 0); #else // not really working? bool c = false; //Poly off = Clipping::getOffset(*this,maxoffset).front(); for (uint i = 0; i < vertices.size(); i++) { const Vector2d Pi = vertices[i]; const Vector2d Pj = getVertexCircular(i+1); if ( ((Pi.y() > p.y()) != (Pj.y() > p.y())) && (abs(p.x() - (Pj.x()-Pi.x()) * (p.y()-Pi.y()) / (Pj.y()-Pi.y()) + Pi.x()) > maxoffset) ) c = !c; } if (!c) for (uint i = 0; i < vertices.size(); i++) if ((vertices[i]-p).length() < maxoffset) return true; // on a vertex return c; #endif } // this polys completely contained in other bool Poly::isInside(const Poly &poly, double maxoffset) const { uint i, count=0; for (i = 0; i < vertices.size(); i++) { if (poly.vertexInside(vertices[i],maxoffset)) count++; } return count == vertices.size(); } void Poly::addVertex(const Vector2d &v, bool front) { if (front) vertices.insert(vertices.begin(),v); else vertices.push_back(v); holecalculated=false; } void Poly::addVertexUnique(const Vector2d &v, bool front) { for (uint i = 0; i < vertices.size(); i++) { if (vertices[i] == v) return; } addVertex(v,front); } void Poly::addVertex(double x, double y, bool front) { addVertex(Vector2d(x,y), front); } void Poly::addVertexUnique(double x, double y, bool front) { addVertexUnique(Vector2d(x,y), front); } Vector2d const &Poly::getVertexCircular(int index) const { int size = vertices.size(); index = (index + size) % size; //cerr << vertices->size() <<" > "<< points[pointindex] << endl; return vertices[index]; } Vector3d Poly::getVertexCircular3(int pointindex) const { Vector2d v = getVertexCircular(pointindex); return Vector3d(v.x(),v.y(),z); } vector Poly::getVertexRangeCircular(int from, int to) const { vector v; int size = vertices.size(); for (int i = from; i<=to; i++) v.push_back(vertices[(i+size)%size]); return v; } vector Poly::lineIntersections(const Vector2d &P1, const Vector2d &P2, double maxerr) const { vector HitsBuffer; Vector2d P3,P4; for(size_t i = 0; i < vertices.size(); i++) { P3 = getVertexCircular(i); P4 = getVertexCircular(i+1); Intersection hit; if (IntersectXY(P1,P2,P3,P4,hit,maxerr)) { HitsBuffer.push_back(hit); } } // std::sort(HitsBuffer.begin(),HitsBuffer.end()); // vector v(HitsBuffer.size()); // for(size_t i = 0; i < v.size(); i++) // v[i] = HitsBuffer[i].p; return HitsBuffer; } // double Poly::getLayerNo() const { return plane->LayerNo;} // length of the line starting at startindex double Poly::getLinelengthSq(uint startindex) const { const double length = (getVertexCircular(startindex+1) - getVertexCircular(startindex)).squared_length(); return length; } double Poly::averageLinelengthSq() const { double l=0; for (uint i = 0; i &lines, Vector2d &startPoint) const { if (size()<2) return; double mindist = INFTY; uint index = nearestDistanceSqTo(startPoint, mindist); makeLines(lines,index); startPoint = Vector2d(lines.back().x(),lines.back().y()); } void Poly::makeLines(vector &lines, Vector2d &startPoint) const { if (size()<2) return; double mindist = INFTY; uint index = nearestDistanceSqTo(startPoint, mindist); makeLines(lines,index); startPoint = Vector2d(lines.back()); } // add to lines starting with given index // closed lines sequence if number of vertices > 2 and poly is closed void Poly::makeLines(vector &lines, uint startindex) const { size_t count = vertices.size(); if (count<2) return; // one point no line bool closedlines = closed; if (count<3) closedlines = false; // two points one line vector mylines; for(size_t i = startindex; i < count+startindex; i++) { if (!closedlines && i == count-1) continue; mylines.push_back(getVertexCircular(i)); mylines.push_back(getVertexCircular(i+1)); } if (!closedlines && startindex == count-1) lines.insert(lines.end(),mylines.rbegin(),mylines.rend()); else lines.insert(lines.end(),mylines.begin(),mylines.end()); } void Poly::makeLines(vector &lines, uint startindex) const { vector mylines; size_t count = vertices.size(); if (count<2) return; // one point no line bool closedlines = closed; if (count<3) closedlines = false; // two points one line for(size_t i = startindex; i < count+startindex; i++) { if (!closedlines && i == count-1) continue; lines.push_back(getVertexCircular3(i)); lines.push_back(getVertexCircular3(i+1)); } if (!closedlines && startindex == count-1) lines.insert(lines.end(),mylines.rbegin(),mylines.rend()); else lines.insert(lines.end(),mylines.begin(),mylines.end()); } #if 0 vector Poly::getCenterline() const { vector line; for (uint i=0; i < vertices.size(); i++){ Vector2d abp = angle_bipartition(vertices[i], getVertexCircular(i-1), getVertexCircular(i+1)); // int intersect2D_Segments( const Vector2d &p1, const Vector2d &p2, // const Vector2d &p3, const Vector2d &p4, // Vector2d &I0, Vector2d &I1, // double &t0, double &t1, // double maxerr) } return line; } #endif vector Poly::getPathAround(const Vector2d &from, const Vector2d &to) const { double dist; vector path1, path2; // Poly off = Clipping::getOffset(*this, 0, jround).front(); //cerr << size()<< " Off " << off.size()<< endl; int nvert = size(); if (nvert==0) return path1; int fromind = (int)nearestDistanceSqTo(from, dist); int toind = (int)nearestDistanceSqTo(to, dist); if (fromind==toind) { path1.push_back(vertices[fromind]); return path1; } //calc both direction paths if(fromind < toind) { for (int i=fromind; i<=toind; i++) path1.push_back(getVertexCircular(i)); for (int i=fromind+nvert; i>=toind; i--) path2.push_back(getVertexCircular(i)); } else { for (int i=fromind; i>=toind; i--) path1.push_back(getVertexCircular(i)); for (int i=fromind; i<=toind+nvert; i++) path2.push_back(getVertexCircular(i)); } // find shorter one double len1=0,len2=0; for (uint i=1; i Poly::getMinMax() const{ double minx=6000,miny=6000; double maxx=-6000,maxy=-6000; vector range; range.resize(2); Vector2d v; for (uint i=0; i < vertices.size();i++){ v = vertices[i]; if (v.x()maxx) maxx=v.x(); if (v.y()maxy) maxy=v.y(); } range[0] = Vector2d(minx,miny); range[1] = Vector2d(maxx,maxy); return range; } int Poly::getTriangulation(vector &triangles) const { if(vertices.size()<3) return 0; triangles.clear(); // return delaunayTriang(vertices, triangles, z); vector points(vertices.size()); // add offset because poly2tri crashes on some negative values? const double OFF = 0; for (guint i=0; i ptriangles = cdt.GetTriangles(); for (guint i=0; iGetPoint(0); const p2t::Point *tp1 = ptriangles[i]->GetPoint(1); const p2t::Point *tp2 = ptriangles[i]->GetPoint(2); Vector3d A((tp0->x-OFF), (tp0->y-OFF), z); Vector3d B((tp1->x-OFF), (tp1->y-OFF), z); Vector3d C((tp2->x-OFF), (tp2->y-OFF), z); triangles.push_back(Triangle(A, B, C)); } return triangles.size(); } Vector3d rotatedZ(Vector3d v, double angle) { double sina = sin(angle); double cosa = cos(angle); return Vector3d(v.x()*cosa-v.y()*sina, v.y()*cosa+v.x()*sina, v.z()); } void Poly::draw_as_surface() const { vector triangles; getTriangulation(triangles); glBegin(GL_TRIANGLES); for(size_t i=0;i"; return ostr.str(); } string Poly::SVGpath(const Vector2d &trans) const { if (size()==0) return ""; ostringstream ostr; Poly transpoly(*this,0); transpoly.move(trans); ostr.precision(5); if (closed) if (hole) ostr << ""; return ostr.str(); } string Poly::gnuplot_path(const Vector2d &trans) const { ostringstream ostr; ostr.precision(5); Poly transpoly(*this,0); transpoly.move(trans); ostr << "# " << size() << endl; for (uint i=0; i &polys, const Vector2d &trans) { for (uint i=0; i &polys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized) { glColor4f(rgb[0],rgb[1],rgb[2], a); glLineWidth(linewidth); glPointSize(pointsize); for(size_t p=0; p > &polys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized) { for(size_t p=0; p &expolys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized) { for(size_t p=0; p < expolys.size();p++) { draw_poly(expolys[p], gl_type, linewidth, pointsize, rgb, a, randomized); } } void draw_polys_surface(const vector &polys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a) { glColor4f(rgb[0],rgb[1],rgb[2], a); glDrawPolySurfaceRastered(polys, Min, Max, z, cleandist); // glColor4f(rgb[0],rgb[1],rgb[2], a); // for(size_t p=0; p > &polys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a) { for(size_t p=0; p < polys.size();p++) draw_polys_surface(polys[p], Min, Max, z, cleandist, rgb, a); } void draw_polys_surface(const vector< ExPoly > &expolys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a) { for(size_t p=0; p < expolys.size();p++) draw_polys_surface(Clipping::getPolys(expolys[p]), Min, Max, z, cleandist, rgb, a); } void clearpolys(vector &polys){ for (uint i=0; i &polys){ for (uint i=0; i > &polys){ for (uint i=0; i holes; mutable bool holecalculated; mutable bool hole; // this polygon is a hole bool closed; public: Poly(); Poly(double z, double extrusionfactor=1.); Poly(const Poly &p, double z); /* Poly(double z, */ /* const ClipperLib::Path cpoly, bool reverse=false); */ ~Poly(); void setClosed(bool c) { closed = c; }; bool isClosed() const { return closed; }; Vector2d operator[](int i) const { if (i >= 0 && i < (int)vertices.size()) return vertices[i]; else return vertices[(vertices.size()+i)%vertices.size()]; }; uint nextVertex(uint i) const {return (i+1)%vertices.size();}; /* Poly Shrinked(double distance) const; */ /* Poly Shrinked(vector *vertices, double distance); */ // simplify douglas-peucker void cleanup(double maxerror); void reverse() {std::reverse(vertices.begin(),vertices.end());holecalculated = false;}; void clear(){vertices.clear(); holecalculated = false;}; void transform(const Matrix4d &T); void transform(const Matrix3d &T); void mirrorX(const Vector3d ¢er); //vector< vector > intersect(Poly &poly1, Poly &poly2) const; bool vertexInside(const Vector2d &point, double maxoffset=0.0001) const; bool vertexInside2(const Vector2d &point, double maxoffset=0.0001) const; bool isInside(const Poly &poly, double maxoffset=0.0001) const; uint nearestDistanceSqTo(const Vector2d &p, double &mindist) const; void nearestIndices(const Poly &p2, int &thisindex, int &otherindex) const; double shortestConnectionSq(const Poly &p2, Vector2d &start, Vector2d &end) const; double angleAtVertex(uint i) const; vector getCenterline() const; uint getFarthestIndex(uint &thisindex) const; uint getFarthestIndex(const Vector2d &from) const; void rotate(const Vector2d ¢er, double angle); void move(const Vector2d &delta); void calcHole() const; // calc center and whether this is a hole bool isHole() const; vector getMinMax() const; vector lineIntersections(const Vector2d &P1, const Vector2d &P2, double maxerr=0.0001) const; // ClipperLib::Paths getOffsetClipperPolygons(double dist) const ; // ClipperLib::Path getClipperPolygon(bool reverse=false) const; Vector2d const &getVertexCircular(int pointindex) const; // 2d point at index Vector3d getVertexCircular3(int pointindex) const; // 3d point at index vector getVertexRangeCircular(int from, int to) const; vector vertices; // vertices void addVertex(const Vector2d &v, bool front=false); void addVertexUnique(const Vector2d &v, bool front=false); void addVertex(double x, double y, bool front=false); void addVertexUnique(double x, double y, bool front=false); mutable Vector2d center; Vector2d getCenter() const; double getZ() const {return z;} void setZ(double z) {this->z = z;}; double getExtrusionFactor() const{return extrusionfactor;}; void setExtrusionFactor(double e){extrusionfactor = e;}; double getLayerNo() const; void draw(int gl_type, bool randomized=true) const; void draw(int gl_type, double z, bool randomized=true) const; // draw at given z void drawVertexNumbers() const; void drawVertexAngles() const; void drawLineNumbers() const; void draw_as_surface() const; void makeLines(vector &lines, Vector2d &startPoint) const; void makeLines(vector &lines, Vector2d &startPoint) const; void makeLines(vector &lines,uint startindex=0) const; void makeLines(vector &lines,uint startindex=0) const; double getLinelengthSq(uint startindex) const; double averageLinelengthSq() const; double totalLineLength() const; vector getPathAround(const Vector2d &from, const Vector2d &to) const; int getTriangulation(vector &triangles) const ; uint size() const {return vertices.size(); }; Vector2d front() {return vertices.front(); }; Vector2d back() {return vertices.back(); }; void push_back (Vector2d v) { vertices.push_back(v); holecalculated = false;}; void push_front(Vector2d v) { vertices.insert(vertices.begin(),v); holecalculated = false;}; string info() const; string SVGpolygon(string style="fill: black") const; string SVGpath(const Vector2d &trans=Vector2d::ZERO) const; string gnuplot_path(const Vector2d &trans=Vector2d::ZERO) const; // for debugging static void move(vector &polys, const Vector2d &trans); }; //////////////////////////////////////////////////////////////////// class ExPoly { public: ExPoly(){}; ~ExPoly(){}; Poly outer; vector holes; void clear(); double getZ() const {return outer.getZ();} void draw(int gl_type, bool randomized=false) const; void draw(int gl_type, double z, bool randomized=false) const; // draw at given z void drawVertexNumbers() const; void drawLineNumbers() const; void cleanup(double maxerror); }; //////////////////////////////////////////////////////////////////// void draw_poly (const Poly &poly, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized = false); void draw_polys(const vector &polys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized = false); void draw_polys(const vector< vector > &polys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized = false); void draw_poly (const ExPoly &expoly, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized = false); void draw_polys(const vector &expolys, int gl_type, int linewidth, int pointsize, const float *rgb, float a, bool randomized = false); void draw_polys_surface(const vector &polys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a); void draw_polys_surface(const vector< vector > &polys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a); void draw_polys_surface(const vector &expolys, const Vector2d &Min, const Vector2d &Max, double z, double cleandist, const float *rgb, float a); void clearpolys(vector &polys); void clearpolys(vector &polys); void clearpolys(vector< vector > &polys); repsnapper-2.3.2a5/src/slicer/printlines.cpp000066400000000000000000001475751231531733200211110ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "printlines.h" #include "poly.h" #include "layer.h" #include "gcode/gcodestate.h" #include "ui/progress.h" //////// Generic PLine functions template double PLine::length() const { if (area == COMMAND) return 0; if (!arc) return from.distance(to); else { double radius = from.distance(arccenter); return radius * angle; } } template double PLine::lengthSq() const { if (area == COMMAND) return 0; if (!arc) return from.squared_distance(to); else return pow(length(),2); } template double PLine::time() const { if (area == COMMAND) return 0; assert(speed >= 0); return length()/speed; } template vmml::vector PLine::splitpoint(double at_length) const { if (area == COMMAND) return vmml::vector::ZERO; const double lratio = at_length/length(); if (!arc) return from + dir() * lratio; else { vmml::vector point = from; const double rangle = angle * lratio; if (M == 3) { Vector2d from_rot(from.x(), from.y()); rotate(from_rot, arccenter, rangle, (arc < 0)); double dz = to.z()-from.z(); point.set(from_rot.x(), from_rot.y(), from.z() + dz*lratio); } else { point = rotated(from, arccenter, rangle, (arc < 0)); } return point; } } template void PLine::move_to(const vmml::vector &from_, const vmml::vector &to_, const double angle_) { if (area == COMMAND) return; from = from_; to = to_; if (!arc) angle = calcangle(); else angle = angle_; } template double PLine::calcangle() const { if (area == COMMAND) return 0; if (M==3) return angle; else return angleBetween(Vector2d(1,0), (Vector2d)dir()); } ///////////// PLine3: single 3D printline ////////////////////// PLine3::PLine3(PLineArea area_, const uint extruder_no_, const Vector3d &from_, const Vector3d &to_, double speed_, double extrusion_) : extrusion(extrusion_) { area = area_; from = from_; to = to_; speed = speed_; arc = 0; angle = 0; extruder_no = extruder_no_; absolute_extrusion = 0; lifted = 0; } PLine3::PLine3(const PLine3 &rhs) { area = rhs.area; command = rhs.command; from = rhs.from; to = rhs.to; speed = rhs.speed; arc = rhs.arc; arccenter = rhs.arccenter; angle = rhs.angle; extruder_no = rhs.extruder_no; extrusion = rhs.extrusion; absolute_extrusion = rhs.absolute_extrusion; lifted = rhs.lifted; } PLine3::PLine3(const PLine2 &pline, double z, double extrusion_per_mm) { lifted = pline.lifted; area = pline.area; from = Vector3d(pline.from.x(), pline.from.y(), z); to = Vector3d(pline.to.x(), pline.to.y(), z); speed = pline.speed; absolute_extrusion = pline.absolute_extrusion; arc = pline.arc; arccenter = pline.arccenter; angle = pline.angle; extruder_no = pline.extruder_no; extrusion = pline.feedratio * extrusion_per_mm * length(); } // to insert an explicit Command into an array of lines PLine3::PLine3(const Command &command_) { area = COMMAND; command = command_; extruder_no = command.extruder_no; arc = 0; } Vector3d PLine3::arcIJK() const { assert(arc); return Vector3d(arccenter.x(), arccenter.y(), to.z()) - from; } //nonsense ??? double PLine3::max_abs_speed(double max_Espeed, double max_AOspeed) const { // if have absolute extrusion, allow AOspeed double allowedspeed = max_Espeed; if (abs(absolute_extrusion) > 0.01) { allowedspeed = max_AOspeed; } double t = time(); if (t != 0) { double tot_speed = abs(extrusion+absolute_extrusion) / t; return speed * allowedspeed / tot_speed; } else // halting command return allowedspeed; } int PLine3::getCommands(Vector3d &lastpos, vector &commands, const double &minspeed, const double &movespeed, const double &minZspeed, const double &maxZspeed, const double &maxAOspeed, bool useTCommand) const { if (area == COMMAND) { // it is an explicit command line commands.push_back(command); return 1; } const Vector3d lift (0,0,lifted); const Vector3d lifted_from = from + lift; const Vector3d lifted_to = to + lift; int command_count = 0; // insert move first if necessary if (lastpos.squared_distance(lifted_from) > 0.005) { uint extruder = extruder_no; // keep last extruder for move if (commands.size()>0) extruder = commands.back().extruder_no; PLine3 move3(area, extruder, lastpos, lifted_from, movespeed, 0); // get recursive ... vector movecommands; command_count += move3.getCommands(lastpos, movecommands, minspeed, movespeed, minZspeed, maxZspeed, maxAOspeed, useTCommand); commands.insert(commands.end(), movecommands.begin(), movecommands.end()); lastpos = lifted_from; } // insert extruder change command if (useTCommand) if (commands.size()>0 && commands.back().extruder_no != extruder_no) { Command extr_change(SELECTEXTRUDER, extruder_no); commands.push_back(extr_change); Command extr_reset(RESET_E); commands.push_back(extr_reset); command_count += 2; } const double travel_length = length(); double extrudedMaterial = extrusion; double travel_speed = speed; if (abs(absolute_extrusion) < 0.00001) travel_speed = max(minspeed, speed); // in case speed is too low if (!isnan(absolute_extrusion)) // allowed to push/pull at arbitrary speed extrudedMaterial += absolute_extrusion; else cerr << "absolute Extrusion (retract) is NaN!" << endl << info() << endl; // slow down if too fast for z axis const double dZ = lifted_to.z() - lifted_from.z(); if (abs(dZ) > 0.00001) { const double xyztime = travel_length / travel_speed; const double zspeed = abs(dZ / xyztime); if ( zspeed > maxZspeed ) { travel_speed *= maxZspeed / zspeed; // insert feedrate-only command to avoid deceleration on z move Command preFeedrate(COORDINATEDMOTION, lifted_from, 0, travel_speed); commands.push_back(preFeedrate); command_count++; } } travel_speed = max(minZspeed, travel_speed); if (abs(travel_length) < 0.00001) // extrusion on halt travel_speed = maxAOspeed; Command command; if (arc) { GCodes gc = (arc==-1 ? ARC_CCW : ARC_CW); command = Command (gc, lifted_to, extrudedMaterial, travel_speed); command.arcIJK = arcIJK(); ostringstream o; o << (int)(angle*180/M_PI) << "° "; if (arc<0) o << "c"; o << "cw arc"; command.comment += o.str(); } else { command = Command (COORDINATEDMOTION, lifted_to, extrudedMaterial, travel_speed); } command.extruder_no = extruder_no; command.not_layerchange = (lifted != 0); command.abs_extr += absolute_extrusion; command.travel_length = travel_length; if (!command.hasNoEffect(lifted_from, 0, 0,true)) { commands.push_back(command); command_count++; } //else cerr << command.info() << endl; lastpos = lifted_to; return command_count; } // ??? really have to write all this twice? vector PLine2::division(const Vector2d &point) const { vector points; if (area != COMMAND) points.push_back(point); return division(points); } vector PLine3::division(const Vector3d &point) const { vector points; if (area != COMMAND) points.push_back(point); return division(points); } vector PLine2::division(const vector &points) const { uint npoints = points.size(); vector newlines; if (npoints == 0) return newlines; PLine2 l(*this); newlines.push_back(l); newlines.back().to = points[0]; for (uint i = 0; i < npoints-1; i++) { newlines.push_back(l); newlines.back().move_to(points[i], points[i+1]); } newlines.push_back(l); newlines.back().from = points[npoints-1]; double totlength = 0; for (uint i = 0; i < newlines.size(); i++){ totlength += newlines[i].length(); } for (uint i = 0; i < newlines.size(); i++){ double factor; if (totlength>0) factor = newlines[i].length() / totlength; else factor = 1./newlines.size(); newlines[i].absolute_extrusion *= factor; assert(!isnan(newlines[i].absolute_extrusion)); } return newlines; } vector PLine3::division(const vector &points) const { uint npoints = points.size(); vector newlines; if (npoints == 0) return newlines; PLine3 l(*this); double totlength = 0; newlines.push_back(l); newlines.back().to = points[0]; totlength += newlines.back().length(); for (uint i = 0; i < npoints-1; i++) { newlines.push_back(l); newlines.back().move_to(points[i], points[i+1]); totlength += newlines.back().length(); } newlines.push_back(l); newlines.back().from = points[npoints-1]; totlength += newlines.back().length(); // normal extrusion adjusted to new length, but absolute extrusion is kept double newextrusion = extrusion * totlength / length(); for (uint i = 0; i < newlines.size(); i++){ double factor; if (totlength>0) factor = newlines[i].length() / totlength; else factor = 1./newlines.size(); newlines[i].absolute_extrusion *= factor; newlines[i].extrusion = newextrusion * factor; } double totext = 0; for (uint i = 0; i < newlines.size(); i++) totext += newlines[i].extrusion; if (abs(totext/extrusion - totlength/length())>0.00000001) cerr << totext << " " << extrusion << " -- " <0 && feedt > ltime ) // too fast speed *= ltime / feedt; //cerr << "added abs at speed " << ( absolute_extrusion)/time() << endl; } double PLine3::addMaxAbsoluteExtrusionAmount(double max_absspeed) { if (area == COMMAND) return 0; const double maxamount = time() * max_absspeed - absolute_extrusion; absolute_extrusion += maxamount; //cerr << "added max abs at speed " << ( absolute_extrusion)/time() << endl; return maxamount; } string PLine3::info() const { if (area == COMMAND) { return "command-line " + command.info(); } ostringstream ostr; ostr << "line "<< AreaNames[area] << " " << from; if (to!=from) ostr << to; ostr << ", speed=" << speed << ", extrusion=" << extrusion << "mm, arc=" << arc; if (has_absolute_extrusion()) ostr << ", abs_extr="<settings = settings; this->layer = layer; // save overhang polys of layer for point-in-overhang detection if (layer!=NULL) { Cairo::RefPtr context; vector overhangs = layer->getOverhangs(); rasterpolys(overhangs, layer->getMin(), layer->getMax(), layer->thickness/5, overhangs_surface, context); } } void Printlines::clear() { for (vector::iterator i = printpolys.begin(); i != printpolys.end(); i++) delete *i; printpolys.clear(); } void Printlines::addLine(PLineArea area, uint extruder_no, vector &lines, const Vector2d &from, const Vector2d &to, double speed, double movespeed, double feedrate) const { if (to==from) return; Vector2d lfrom = from; if (lines.size() > 0) { const Vector2d lastpos = lines.back().to; const bool extruder_change = (lines.back().extruder_no != extruder_no); if (extruder_change || lfrom.squared_distance(lastpos) > 0.01) { // add moveline // use last extruder for move PLine2 move(area, lines.back().extruder_no, lastpos, lfrom, movespeed, 0); if (extruder_change || settings->get_boolean("Extruder","ZliftAlways")) { move.lifted = settings->get_double("Extruder","AntioozeZlift"); } lines.push_back(move); } else { lfrom = lastpos; } } lines.push_back(PLine2(area, extruder_no, lfrom, to, speed, feedrate)); } // // // // // // // // // // // // PrintPoly // // // // // // // // // // // // PrintPoly::PrintPoly(const Poly &poly, const Printlines * printlines_, double speed_, double overhangspeed, double min_time_, bool displace_start_, PLineArea area_) : printlines(printlines_), area(area_), speed(speed_), min_time(min_time_), displace_start(displace_start_), overhangingpoints(0), priority(1.), length(0), speedfactor(1.) { extruder_no = printlines->settings->selectedExtruder; // Take a copy of the reference poly m_poly = new Poly(poly); m_poly->move(Vector2d(-printlines->settings->get_double("Extruder","OffsetX"), -printlines->settings->get_double("Extruder","OffsetY"))); if (area==SHELL || area==SKIN) { priority *= 5; // may be 5 times as far away to get preferred as next poly for (uint j=0; jsize();j++){ if (getCairoSurfaceDatapoint(printlines->overhangs_surface, printlines->layer->getMin(), printlines->layer->getMax(), m_poly->vertices[j]) != 0) { overhangingpoints++; priority /= 10; // must be 10 times nearer for each overhang point } } } else if (area==SKIRT) { priority *= 1000; // may be 1000 times as far away to get preferred } else if (area==SUPPORT) { priority *= 100; // may be 100 times as far away to get preferred } length = m_poly->totalLineLength(); if (overhangingpoints>0) speed = overhangspeed; if (min_time > 0 && speed > 0) { const double time = length / speed * 60; // minutes -> seconds! //cerr << AreaNames[area] << ": " << time << " - " << speed ; if (time !=0 && time < min_time){ speedfactor = time / min_time; speed *= speedfactor; } //cerr << " -> "<< speed << " = " << totlength / speed * 60<< endl; } } PrintPoly::~PrintPoly() { delete m_poly; } void PrintPoly::getLinesTo(vector &lines, int startindex, double movespeed) const { vector pvert; m_poly->makeLines(pvert,startindex); if (pvert.size() == 0) return; assert(pvert.size() % 2 == 0); for (uint i=0; i 0.001) printlines->addLine(area, extruder_no, lines, pvert[i], pvert[i+1], speed, movespeed, m_poly->getExtrusionFactor()); } } uint PrintPoly::getDisplacedStart(uint start) const { //cerr << start << " --> "; if (displace_start) { #if 0 // find next sharp corner (>pi/4) uint oldstart = start; // save start position start = m_poly->nextVertex(start); while (start != oldstart && abs(m_poly->angleAtVertex(start) < M_PI/4)) { start = m_poly->nextVertex(start); } // no sharp corner found: if (start == oldstart) #endif // start = rand()%m_poly->size(); // randomize //start = m_poly->getFarthestIndex(start); // take farthest point } //cerr << start << endl; return start; } string PrintPoly::info() const { ostringstream ostr; ostr << "PrintPoly " << AreaNames[area] << ", " << m_poly->size() <<" vertices" << ", prio=" << priority << ", speed=" << speed ; return ostr.str(); } // // // // // // // // // // // // // // // // // // // // // // // // // // // // void Printlines::addPolys(PLineArea area, const vector &polys, bool displace_start, double maxspeed, double min_time) { if (polys.size() == 0) return; if (maxspeed == 0) maxspeed = settings->get_double("Extruder","MaxLineSpeed") * 60; // default double maxoverhangspeed = settings->get_double("Slicing","MaxOverhangSpeed"); for(size_t q = 0; q < polys.size(); q++) { if (polys[q].size() > 0) { PrintPoly *ppoly = new PrintPoly(polys[q], this, /* Takes a copy of the poly */ maxspeed, maxoverhangspeed * 60, min_time, displace_start, area); printpolys.push_back(ppoly); setZ(polys[q].getZ()); } } } // bool priority_sort(const PrintPoly &p1, const PrintPoly &p2) // { // return (p1.getPriority() >= p2.getPriority()); // } // return total speedfactor due to single poly slowdown double Printlines::makeLines(Vector2d &startPoint, vector &lines) { const uint count = printpolys.size(); if (count == 0) return 1; // // sort into contiguous areas // vector layerexpolys = layer->GetExPolygons(); // vector< vector > towers(layerexpolys.size()); // for (uint q = 0; q < printpolys.size(); q++) { // bool intower = false; // for (uint i = 0; i < layerexpolys.size(); i++) { // if (layerexpolys[i].vertexInside(printpolys[q]->poly[0])) { // towers[i].push_back(printpolys[q]); // intower = true; // } // } // if (!intower) ; // } //std::sort(printpolys.begin(), printpolys.end(), priority_sort); int nvindex=-1; int npindex=-1; uint nindex; vector done(count); // polys not yet handled for(size_t q=0; q < count; q++) done[q]=false; uint ndone=0; //double nlength; double movespeed = settings->get_double("Hardware","MaxMoveSpeedXY") * 60; double totallength = 0; double totalspeedfactor = 0; while (ndone < count) { double nstdist = INFTY; double pdist; for(size_t q = 0; q < count; q++) { // find nearest polygon if (!done[q]) { //cerr << printpolys[q].info() << endl; if (printpolys[q]->m_poly->size() == 0) {done[q] = true; ndone++;} else { pdist = INFTY; nindex = printpolys[q]->m_poly->nearestDistanceSqTo(startPoint, pdist); pdist /= printpolys[q]->priority; if (pdist < nstdist){ npindex = q; // index of nearest poly in polysleft nstdist = pdist; // distance of nearest poly nvindex = nindex; // nearest point in nearest poly } } } } if (ndone==0) { // only first in layer nvindex = printpolys[npindex]->getDisplacedStart(nvindex); } if (npindex >= 0 && nvindex >= 0) { printpolys[npindex]->getLinesTo(lines, nvindex, movespeed); totallength += printpolys[npindex]->length; totalspeedfactor += printpolys[npindex]->length * printpolys[npindex]->speedfactor; done[npindex]=true; ndone++; } if (lines.size()>0) startPoint = lines.back().to; } if (totallength !=0) totalspeedfactor /= totallength; else totalspeedfactor = 1.; return totalspeedfactor; } // #if 0 // void Printlines::oldMakeLines(PLineArea area, // const vector &polys, // bool displace_startpoint, // Vector2d &startPoint, // vector &lines, // double maxspeed) // { // //cerr << "makeLines " << AreaNames[area] << " " << layer->info() << endl; // // double linewidthratio = hardware.ExtrudedMaterialWidthRatio; // //double linewidth = layerthickness/linewidthratio; // if ( maxspeed == 0 ) maxspeed = settings->Hardware.MaxPrintSpeedXY * 60; // double movespeed = settings->Hardware.MoveSpeed * 60; // const uint count = polys.size(); // if (count == 0) return; // int nvindex=-1; // int npindex=-1; // uint nindex; // vector done(count); // polys not yet handled // for(size_t q=0; q < count; q++) done[q]=false; // uint ndone=0; // //double nlength; // while (ndone < count) // { // double nstdist = INFTY; // double pdist; // // if (sortbyoverhang) { // // } // // else // for(size_t q=0; qpi/4) // if (displace_startpoint && ndone==0) { // int oldnvindex = nvindex; // if none found, stay here // nvindex = polys[npindex].nextVertex(nvindex); // while (nvindex != oldnvindex && // abs(polys[npindex].angleAtVertex(nvindex) < M_PI/4)) // nvindex = polys[npindex].nextVertex(nvindex); // } // if (npindex >= 0 && npindex >=0) { // addPoly(area, lines, polys[npindex], nvindex, maxspeed, movespeed); // done[npindex]=true; // ndone++; // } // if (lines.size()>0) // startPoint = lines.back().to; // } // } // #endif void Printlines::optimize(double linewidth, double slowdowntime, double cornerradius, vector &lines) { //optimizeLinedistances(linewidth); // double OPTRATIO = 1.5; // double optratio = OPTRATIO; //corner cap // optimizeCorners(linewidth,linewidthratio,optratio); // double E=0;Vector3d start(0,0,0); // cout << GCode(start,E,1,1000); //cerr << "optimize" << endl; makeArcs(linewidth, lines); double minarclength = settings->get_double("Slicing","MinArcLength"); if (!settings->get_boolean("Slicing","UseArcs")) minarclength = cornerradius; if (settings->get_boolean("Slicing","RoundCorners")) roundCorners(cornerradius, minarclength, lines); slowdownTo(slowdowntime, lines); //double totext = total_Extrusion(lines); //makeAntioozeRetract(lines); //double totext2 = total_Extrusion(lines); // if (abs(totext-totext2)>0.01) // cerr << "extrusion difference after antiooze " << totext2-totext << endl; // else // cerr << " ok" << endl; } #define FITARC_FIND 0 #if FITARC_FIND // find center for best fit of arclines bool fit_arc(const vector &lines, uint fromind, uint toind, double sq_error, Vector2d &result_center, double &result_radiussq) { if (toind-fromind < 2) return false; if (toind > lines.size()) return false; const int n_par = 3; // center x,y and arc radius_sq // start values: const Vector2d &P = lines[fromind].getFrom(); const Vector2d &Q = lines[toind].getTo(); const Vector2d startxy = (P+Q)/2.; double par[3] = { startxy.x(), startxy.y(), P.squared_distance(Q) }; int m_dat = toind-fromind+1; arc_data_struct data; data.px = new double[m_dat]; data.py = new double[m_dat]; data.px[0] = P.x(); data.py[0] = P.y(); for (int i = 0; i < m_dat; i++) { data.px[i] = lines[fromind+i].getTo().x(); data.py[i] = lines[fromind+i].getTo().y(); } return fit_arc(m_dat, data, n_par, par, sq_error, result_center, result_radiussq); } // max offset of the arc from the line double arc_offset(const Vector2d ¢er, const PLine2 &line) { const double r = center.distance(line.getFrom()); const double angle = abs(angleBetween(line.getFrom()-center, line.getTo()-center)); const double off = r - r*sin(angle/2); //cerr << "offset " << off << endl; return off; } bool continues_arc(const Vector2d ¢er, uint index, double maxAngle, const vector &lines) { if (index < 2 || index >= lines.size()) return false; const PLine2 &l1 = lines[index-2]; const PLine2 &l2 = lines[index-1]; const PLine2 &l3 = lines[index]; const double angle1 = l1.angle_to(l2); const double angle2 = l2.angle_to(l3); if (abs(angle1) < 0.001) return false; if (abs(angle2) < 0.001) return false; const double len2 = l2.length(); const double len3 = l3.length(); if (abs(len2) < 0.001) return false; if (abs(len3) < 0.001) return false; return ( angle1 < maxAngle && angle2 < maxAngle && abs(angle1/angle2-1) < 0.3 && abs(len2/len3-1) < 0.3 ); } uint Printlines::makeArcs(double linewidth, vector &lines) const { if (!slicing.UseArcs) return 0; if (lines.size() < 3) return 0; const double maxAngle = settings->Slicing.ArcsMaxAngle * M_PI/180; const double linewidth_sq = linewidth*linewidth; if (maxAngle <= 0) return 0; double arcRadiusSq = 0; Vector2d arccenter(1000000,1000000); guint arcstart = 0; Vector2d newcenter; double newradiusSq = 0; uint i = arcstart; uint arcend = i; while (arcstart < lines.size()-4) { i = arcstart+2; arcend = arcstart; while ( continues_arc(arccenter, i, maxAngle, lines) ) { if ( fit_arc (lines, arcstart, i, linewidth_sq, newcenter, newradiusSq) //&& arc_offset(newcenter, lines[i]) < 5*linewidth ) { arccenter = newcenter; arcend = i; } i++; } if (arcend > arcstart + 2) { cerr << "found arc from " << arcstart << " to " << arcend << endl; i -= makeIntoArc(arccenter, arcstart, arcend, lines); } arcstart = i+1; } } #else // gets center of common arc of 2 lines if radii match inside maxSqerr range Vector2d Printlines::arcCenter(const PLine2 &l1, const PLine2 &l2, double maxSqerr) const { Vector2d l1p1,l1p2; center_perpendicular(l1.from, l1.to, l1p1, l1p2); Vector2d l2p1,l2p2; center_perpendicular(l2.from, l2.to, l2p1, l2p2); Vector2d center, ip; int is = intersect2D_Segments(l1p1, l1p2, l2p1, l2p2, center, ip); if (is > 0) { // radii match? if (abs(l1p1.squared_distance(center) - l2p1.squared_distance(center)) < maxSqerr) return center; } return Vector2d(10000000,10000000); } uint Printlines::makeArcs(double linewidth, vector &lines) const { if (!settings->get_boolean("Slicing","UseArcs")) return 0; if (lines.size() < 2) return 0; double maxAngle = settings->get_double("Slicing","ArcsMaxAngle") * M_PI/180; if (maxAngle < 0) return 0; double arcRadiusSq = 0; Vector2d arccenter(1000000,1000000); guint arcstart = 0; for (uint i=1; i < lines.size(); i++) { const PLine2 &l1 = lines[i-1]; const PLine2 &l2 = lines[i]; if (l1.arc) { arcstart = i+1; cerr << "1 arc" << endl;continue; } if (l2.arc) { i++; arcstart = i+1;cerr << "2 arc" << endl; continue; } double dangle = l2.angle_to(l1); double feedratechange = l2.feedratio - l1.feedratio; Vector2d nextcenter = arcCenter(l2, l1, 0.05*arcRadiusSq); double radiusSq = nextcenter.squared_distance(l2.from); // test if NOT continue arc: if (l2.from.squared_distance(l1.to) > 0.001 // not adjacent || abs(feedratechange) > 0.1 // different feedrate || abs(dangle) < 0.0001 // straight continuation || abs(dangle) > maxAngle // too big angle || ( i>1 && arccenter.squared_distance(nextcenter) > 0.05*radiusSq ) // center displacement ) { arccenter = nextcenter; arcRadiusSq = radiusSq; // this one doesn't fit, so i-1 is last line of the arc if (arcstart+2 < i-1) // at least three lines to make an arc i -= makeIntoArc(arcstart, i-1, lines); // set start for potential next arc arcstart = i; } } // remaining if (arcstart+2 < lines.size()-1) makeIntoArc(arcstart, lines.size()-1, lines); return 0; } #endif uint Printlines::makeIntoArc(const Vector2d ¢er, guint fromind, guint toind, vector &lines) const { if (toind < fromind+1 || toind+1 > lines.size()) return 0; const Vector2d &P = lines[fromind].from; const Vector2d &Q = lines[toind].to; bool fullcircle = (P==Q); double angle; if (fullcircle) angle = 2*M_PI; else angle = angleBetween(P-center, Q-center); bool ccw = isleftof(center, lines[fromind].from, lines[fromind].to); if (!ccw) angle = -angle; if (angle<=0) angle+=2*M_PI; short arctype = ccw ? -1 : 1; PLine2 newline(lines[fromind].area, lines[fromind].extruder_no, P, Q, lines[fromind].speed, lines[fromind].feedratio, arctype, center, angle, lines[fromind].lifted); lines[fromind] = newline; lines.erase(lines.begin()+fromind+1, lines.begin()+toind+1); return toind-fromind; } // return how many lines are removed uint Printlines::makeIntoArc(guint fromind, guint toind, vector &lines) const { if (toind < fromind+1 || toind+1 > lines.size()) return 0; //cerr<< "arcstart = " << fromind << endl; const Vector2d &P = lines[fromind].from; #define FITARC 0 #if FITARC Vector2d center; double fitradius_sq; vector arcpoints; arcpoints.push_back(P); for (uint i = fromind; i <= toind; i++) arcpoints.push_back(lines[i].to); if ( fit_arc(arcpoints, 0.1, center, fitradius_sq) ) { cerr << " found center " << center << " radius="<< sqrt(fitradius_sq) << endl; #else const Vector2d &Q = lines[toind].to; //bool fullcircle = (P==Q); // get center: intersection of center perpendiculars of 2 chords // center perp of start -- endpoint: guint end1ind = toind; //if (fullcircle) { // take one-third for first center_perp end1ind = fromind + (toind-fromind)/2; //} Vector2d chord1p1, chord1p2; center_perpendicular(P, lines[end1ind].to, chord1p1, chord1p2); // center perp of midpoint -- endpoint: guint start2ind = fromind + (toind-fromind)/2; Vector2d chord2p1, chord2p2; center_perpendicular(lines[start2ind].from, Q, chord2p1, chord2p2); // intersection = center Vector2d center, ip; int is = intersect2D_Segments(chord1p1, chord1p2, chord2p1, chord2p2, center, ip); if (is > 0) { #endif return makeIntoArc(center, fromind, toind, lines); } // else cerr << "arc not possible" << endl; return 0; } uint Printlines::roundCorners(double maxdistance, double minarclength, vector &lines) const { if (lines.size() < 2) return 0; uint num = 0; for (uint i=0; i < lines.size()-1; i++) { uint n = makeCornerArc(maxdistance, minarclength, i, lines); i+=n; if (n>0) i--; num+=n; } return num; } // make corner of lines[ind], lines[ind+1] into arc // or rounded sequence of lines // maxdistance is distance of arc begin from corner uint Printlines::makeCornerArc(double maxdistance, double minarclength, uint ind, vector &lines) const { if (ind > lines.size()-2) return 0; if (lines[ind].arc != 0 || lines[ind+1].arc != 0) return 0; // movement in between? if ((lines[ind].to - lines[ind+1].from).squared_length() > 0.01) return 0; // if ((lines[ind].from - lines[ind+1].to).squared_length() // < maxdistance*maxdistance) return 0; const double len1 = lines[ind].length(); const double len2 = lines[ind+1].length(); maxdistance = min(maxdistance, len1); // ok to eat up line 1 maxdistance = min(maxdistance, len2 / 2.1); // only eat up less than half of second line const Vector2d dir1 = lines[ind].to - lines[ind].from; const Vector2d dir2 = lines[ind+1].to - lines[ind+1].from; double angle = angleBetween(dir1, dir2); // arc start and end point: const Vector2d p1 = lines[ind].to - normalized(dir1)*maxdistance; const Vector2d p2 = lines[ind+1].from + normalized(dir2)*maxdistance; // intersect perpendiculars at arc start/end Vector2d center, I1; int is = intersect2D_Segments(p1, p1 + Vector2d(-dir1.y(),dir1.x()), p2, p2 + Vector2d(-dir2.y(),dir2.x()), center, I1); if (is==0) return 0; const double radius = center.distance(p1); if (radius > 10*maxdistance) return 0; // calc error(?) const bool ccw = isleftof(center, p1, p2); if (!ccw) angle = -angle; if (angle <= 0) angle += 2*M_PI; const short arctype = ccw ? -1 : 1; // need 2 half arcs? const bool split = (lines[ind].feedratio != lines[ind+1].feedratio) || (lines[ind].extruder_no != lines[ind+1].extruder_no); const double arc_len = radius * angle; // too small for arc, replace by 2 straight lines const bool not_arc = !settings->get_boolean("Slicing","UseArcs") || (arc_len < (split?minarclength:(minarclength*2))); // too small to make 2 lines, just make 1 line const bool toosmallfortwo = (arc_len < (split?(minarclength/2):minarclength)); // if (toosmallfortwo) return 0; vector newlines; if (p1 != lines[ind].from) { // straight line 1 newlines.push_back(lines[ind]); newlines.back().move_to(lines[ind].from, p1); } if (p2 != p1) { if (toosmallfortwo) { // 1 line const double feedr = ( lines[ind].feedratio + lines[ind+1].feedratio ) / 2; newlines.push_back(PLine2(lines[ind].area, lines[ind].extruder_no, p1, p2, lines[ind].speed, feedr, (feedr!=0)?lines[ind].lifted:0)); } else if (split || not_arc) { // calc arc midpoint const Vector2d splitp = rotated(p1, center, angle/2, ccw); if (not_arc) { // 2 straight lines newlines.push_back(lines[ind]); newlines.back().move_to(p1, splitp); newlines.push_back(lines[ind+1]); newlines.back().move_to(splitp, p2); } else if (split) { // 2 arcs newlines.push_back(PLine2(lines[ind].area, lines[ind].extruder_no, p1, splitp, lines[ind].speed, lines[ind].feedratio, arctype, center, angle/2, lines[ind].lifted)); newlines.push_back(PLine2(lines[ind+1].area, lines[ind+1].extruder_no, splitp, p2, lines[ind+1].speed, lines[ind+1].feedratio, arctype, center, angle/2, lines[ind+1].lifted)); } } else { // 1 arc newlines.push_back(PLine2(lines[ind].area, lines[ind].extruder_no, p1, p2, lines[ind].speed, lines[ind].feedratio, arctype, center, angle, lines[ind].lifted)); } } if (p2 != lines[ind+1].to) { // straight line 2 newlines.push_back(lines[ind+1]); newlines.back().move_to(p2, lines[ind+1].to); } const uint numnew = newlines.size(); if (numnew>0) lines[ind] = newlines[0]; if (numnew>1) lines[ind+1] = newlines[1]; if (numnew>2) lines.insert(lines.begin()+ind+2, newlines.begin()+2, newlines.end()); return max(0, (int)numnew - 2); } // split line at given length uint Printlines::divideline(uint lineindex, const double length, vector< PLine3 > &lines) { typedef Vector3d vec; PLine3 *l = &lines[lineindex]; double linelen = l->length(); if (length > linelen) return 0; vec splitp = l->splitpoint(length); if ( !l->arc ) { uint nlines = divideline(lineindex, splitp, lines); return nlines; } else { const double angle = l->angle * length/linelen; PLine3 line1(*l); line1.to = splitp; line1.angle = angle; PLine3 line2(*l); line2.from = splitp; line2.angle = l->angle - angle; if (l->absolute_extrusion != 0) { // distribute absolute extrusion const double totlength = line1.length() + line2.length(); line1.absolute_extrusion = l->absolute_extrusion * line1.length()/totlength; line2.absolute_extrusion = l->absolute_extrusion * line2.length()/totlength; } line1.extrusion *= line1.angle/l->angle; line2.extrusion *= line2.angle/l->angle; lines[lineindex] = line1; lines.insert(lines.begin() + lineindex + 1, line2); return 1; } return 0; } uint Printlines::divideline(uint lineindex, const Vector2d &point, vector< PLine2 > &lines) { vector< PLine2 > newlines = lines[lineindex].division(point); replace(lines, lineindex, newlines); return newlines.size()-1; } uint Printlines::divideline(uint lineindex, const vector &points, vector< PLine2 > &lines) { vector< PLine2 > newlines = lines[lineindex].division(points); replace(lines, lineindex, newlines); return newlines.size()-1; } uint Printlines::divideline(uint lineindex, const Vector3d &point, vector< PLine3 > &lines) { vector< PLine3 > newlines = lines[lineindex].division(point); replace(lines, lineindex, newlines); return newlines.size()-1; } uint Printlines::divideline(uint lineindex, const vector< Vector3d > &points, vector< PLine3 > &lines) { vector newlines = lines[lineindex].division(points); replace(lines, lineindex, newlines); return newlines.size(); } // walk around holes #define NEWCLIP 1 #if NEWCLIP // polys are clippolys (shells) void Printlines::clipMovements(const vector &polys, vector &lines, bool findnearest, double maxerr) const { if (polys.size()==0 || lines.size()==0) return; vector newlines; for (guint i=0; i < lines.size(); i++) { if (lines[i].is_move()) { // // don't clip a lifted line // if (lines[i].lifted > 0) continue; int frompoly=-1, topoly=-1; // get start and end poly of move for (uint p = 0; p < polys.size(); p++) { if ((frompoly==-1) && polys[p].vertexInside(lines[i].from, maxerr)) frompoly=(int)p; if ((topoly==-1) && polys[p].vertexInside(lines[i].to, maxerr)) topoly=(int)p; } int div = 0; //cerr << frompoly << " --> "<< topoly << endl; if (frompoly >=0 && topoly >=0) { if (findnearest && frompoly != topoly) { int fromind, toind; polys[frompoly].nearestIndices(polys[topoly], fromind, toind); vector path(2); path[0] = polys[frompoly].vertices[fromind]; path[1] = polys[topoly]. vertices[toind]; // for (uint pi=0; pi < path.size(); pi++) // cerr << path[pi] << endl; div += divideline(i, path, lines); // cerr << i << " _ "<< frompoly<<":"< "<< topoly<<":"<=0 && topoly >=0) { // vector allpolys; // allpolys.push_back(polys[frompoly]); // // add holes // for (int p = 0; p < polys.size(); p++) { // if (p != frompoly && polys[p].isInside(polys[frompoly])) // allpolys.push_back(polys[p]); // } // cerr << allpolys.size() << " holes" << endl; vector path; bool ispath = shortestPath(lines[i].from, lines[i].to, polys, frompoly, path, maxerr); //cerr << path.size() << " path points" << endl; if (ispath) { div += (divideline(i,path,lines)); if (divisions>0) cerr << divisions << " div in poly " << topoly << " - " << ispath << " path " << path.size()< pinter = polys[p].lineIntersections(lines[i].from,lines[i].to, maxerr); if (pinter.size() > 0) { // if (pinter.size()%2 == 0) { vector path = polys[p].getPathAround(lines[i].from, lines[i].to); // after divide, skip number of added lines -> test remaining line later div += (divideline(i, path, lines)); //continue; // } } } #endif i += div; } } } #else // old clip void Printlines::clipMovements(const vector &polys, vector &lines, double maxerr) const { if (polys.size()==0 || lines.size()==0) return; vector newlines; for (guint i=0; i < lines.size(); i++) { if (lines[i].is_move()) { int frompoly=-1, topoly=-1; for (uint p = 0; p < polys.size(); p++) { if ((frompoly==-1) && polys[p].vertexInside(lines[i].from, maxerr)) frompoly=(int)p; if ((topoly==-1) && polys[p].vertexInside(lines[i].to, maxerr)) topoly=(int)p; } if ((frompoly == -1) || (topoly == -1)) { //cerr < holes; //holes.push_back((*polys)[frompoly]); for (uint p = 0; p < polys->size(); p++) { // //if ((*polys)[p].isHole()) if (polys[frompoly].polyInside(polys[p])) holes.push_back(polys[p]); } vector path; bool ispath = shortestPath(lines[i].from,lines[i].to, holes, frompoly, path, maxerr); if (ispath) { int divisions = (divideline(i,path,lines)); i += divisions; if (divisions>0) cerr << divisions << " div in poly " << topoly << " - " << ispath << " path " << path.size()< pinter = polys[p].lineIntersections(lines[i].from,lines[i].to, maxerr); if (pinter.size() > 0) { if (pinter.size()%2 == 0) { // holes std::sort(pinter.begin(), pinter.end()); vector path = polys[p].getPathAround(pinter.front().p, pinter.back().p); // after divide, skip number of added lines -> test remaining line later i += (divideline(i, path, lines)); } } } #endif } else if (frompoly != -1 && topoly != -1 && frompoly != topoly) { cerr << i << " : "<> " << topoly << endl; // vector frominter = // polys[frompoly].lineIntersections(lines[i].from,lines[i].to, maxerr); // vector tointer = // polys[topoly].lineIntersections(lines[i].from,lines[i].to, maxerr); // cerr << frominter.size() << " -- " << tointer.size() << endl; // vector frompath = // polys[frompoly].getPathAround(lines[i].from, lines[i].to); // vector topath = // polys[topoly].getPathAround(lines[i].from, lines[i].to); // cerr << frompath.size() << " -- " << topath.size() << endl; int fromind, toind; polys[frompoly].nearestIndices(polys[topoly], fromind, toind); vector path; //path.push_back(lines[i].from); path.push_back(polys[frompoly].vertices[fromind]); path.push_back(polys[topoly].vertices[toind]); //path.push_back(lines[i].to); for (uint pi=0; pi < path.size(); pi++) cerr << path[pi] << endl; int div=(divideline(i, path, lines)); cerr << fromind << "--" << toind << " - " << div < &lines) const { if (speedfactor == 1) return; for (uint i=0; i < lines.size(); i++){ if (!lines[i].is_move()) lines[i].speed *= speedfactor; } } double Printlines::slowdownTo(double totalseconds, vector &lines) { double totalnow = totalSecondsExtruding(lines); if (totalseconds == 0 || totalnow == 0) return 1; double speedfactor = totalnow / totalseconds; if (speedfactor < 1.){ setSpeedFactor(speedfactor,lines); slowdownfactor *= speedfactor; } return slowdownfactor; } // merge too near parallel lines void Printlines::mergelines(PLine2 &l1, PLine2 &l2, double maxdist) const { Vector2d d2 = l2.to - l2.from; double len2 = d2.length(); if (len2==0) return; double dist2 = abs(cross2d(d2,l1.from-l2.from).length()) / len2 ; // by area of parallelogram //cerr << len2 << " - " << len2b << endl; // Vector2d dp = l1.to - l2.from; // double l = dot(dp,d2); // Vector2d pproj = l2.from + d2 * l/len2; // proj. of l1.to on l2 // double d = (l1.to - pproj).length(); // = distance of parallel lines // cerr << "dist " << d<< " - " << dist2 < &lines) const { uint count = lines.size(); for (uint i=0; i linewidth ) return done; double da = l1.angle_to(l2); while (da>=2*M_PI) da-=2*M_PI; while (da<=-2*M_PI)da+=2*M_PI; double tana = abs(tan((da)/2.)); // new endpoints should have this distance: double dist = linewidth * linewidthratio ; //dafactor * linewidth * linewidthratio * optratio ; // cut until endpoints have the distance double cutlength = dist*tana/2. ; // cut both lines by this length cerr << "da=" << da<< " -> "<< cutlength< MINLEN && d1l > cutlength){ double newlenfact1 = 1-cutlength/d1l; l1.to = l1.from + d1*newlenfact1; done = true; } // else l1.to=l1.from; // delete line if too short Vector2d d2 = l2.from-l2.to; double d2l = d2.length(); if (d2l > MINLEN && d2l > cutlength){ double lenfact2 = 1-cutlength/d2l; l2.from = l2.to + d2*lenfact2; done = true; } //else l2.to=l2.from; // delete line if too short return done; } void Printlines::optimizeCorners(double linewidth, double linewidthratio, double optratio, vector &lines) const { //cout << "optimizecorners " ; printinfo(); uint count = lines.size(); uint j; uint done = 1; while (done>0) { done=0; for (uint i=0; i &lines, vector &olines) const { for (lineCIt lIt = lines.begin(); lIt!=lines.end(); ++lIt){ if (lIt->is_noop()) continue; olines.push_back(lIt->from); olines.push_back(lIt->to); } } void Printlines::getLines(const vector &lines, vector &olines) const { for (lineCIt lIt = lines.begin(); lIt!=lines.end(); ++lIt){ if (lIt->is_noop()) continue; olines.push_back(Vector3d(lIt->from.x(),lIt->from.y(),z)); olines.push_back(Vector3d(lIt->to.x(),lIt->to.y(),z)); } } void Printlines::getLines(const vector &lines, vector &plines, double extrusion_per_mm) const { for (lineCIt lIt = lines.begin(); lIt!=lines.end(); ++lIt){ if (lIt->is_noop()) continue; plines.push_back( PLine3(*lIt, z, extrusion_per_mm) ); } } double Printlines::totalLength(const vector &lines) const { double l = 0; for (lineCIt lIt = lines.begin(); lIt!=lines.end();++lIt){ l += lIt->length(); } return l; } double Printlines::total_rel_Extrusion(const vector< PLine3 > &lines) { double l = 0; for (line3CIt lIt = lines.begin(); lIt!=lines.end();++lIt){ l += lIt->extrusion; } return l; } double Printlines::total_abs_Extrusion(const vector< PLine3 > &lines) { double l = 0; for (line3CIt lIt = lines.begin(); lIt!=lines.end();++lIt){ l += lIt->absolute_extrusion; } return l; } double Printlines::total_Extrusion(const vector< PLine3 > &lines) { double l = 0; for (line3CIt lIt = lines.begin(); lIt!=lines.end();++lIt){ l += lIt->extrusion + lIt->absolute_extrusion; } return l; } double Printlines::totalSeconds(const vector &lines) const { double t = 0; for (lineCIt lIt = lines.begin(); lIt!=lines.end();++lIt){ t += lIt->time() ; } return t * 60; } double Printlines::totalSecondsExtruding(const vector &lines) const { double t = 0; for (lineCIt lIt = lines.begin(); lIt!=lines.end();++lIt){ if (!lIt->is_move() || lIt->absolute_extrusion!=0) t += lIt->time() ; } return t * 60; } void Printlines::getCommands(const vector &plines, const Settings & settings, GCodeState &gc_state, ViewProgress * progress) { // push all lines to commands PLineArea lastArea = UNDEF; uint count = plines.size(); if (count==0) return; if (progress) progress->restart (_("Making GCode"), count); Vector3d lastPos = plines[0].from; int progress_steps=(int)(count/100); if (progress_steps==0) progress_steps=1; bool cont = true; vector commands; const double minspeed = settings.get_double("Hardware","MinMoveSpeedXY") * 60, movespeed = settings.get_double("Hardware","MaxMoveSpeedXY") * 60, //maxspeed = min(movespeed, (double)settings.Extruder.MaxLineSpeed * 60), minZspeed = settings.get_double("Hardware","MinMoveSpeedZ") * 60, maxZspeed = settings.get_double("Hardware","MaxMoveSpeedZ") * 60, //maxEspeed = settings.Extruder.EMaxSpeed * 60, maxAOspeed = settings.get_double("Extruder","AntioozeSpeed") * 60; const bool useTCommand = settings.get_boolean("Slicing","UseTCommand"); for (uint i = 0; i < plines.size(); i++) { if (progress && i%progress_steps==0){ cont = (progress->update(i)) ; if (!cont) break; } if (plines[i].area != COMMAND && plines[i].area != lastArea) { lastArea = plines[i].area; commands.push_back(Command(AreaNames[lastArea])); } plines[i].getCommands(lastPos, commands, minspeed, movespeed, minZspeed, maxZspeed, maxAOspeed, useTCommand); } gc_state.AppendCommands(commands, settings.get_boolean("Slicing","RelativeEcode")); } string Printlines::info() const { ostringstream ostr; ostr << "Printlines "< class PLine { public: PLineArea area; vmml::vector from, to; double speed; uint extruder_no; double lifted; short arc; // -1: ccw arc, 1: cw arc, 0: not an arc double angle; // angle of line (in 2d lines), or arc angle Vector2d arccenter; // always 2d, the arc is a 2d rotation double absolute_extrusion; // additional absolute extrusion /mm (retract/repush f.e.) bool has_absolute_extrusion() const {return (abs(absolute_extrusion)>0.00001);} // virtual vector< PLine > division(double length) const; vmml::vector dir() const { return to - from; } vmml::vector splitpoint(double at_length) const; virtual double time() const; virtual double lengthSq() const; virtual double length() const; bool is_command() const {return (area == COMMAND);} void move_to(const vmml::vector &from_, const vmml::vector &to_, const double angle = 0); double calcangle() const; // virtual bool is_move() const; // virtual string info() const; }; // 3D printline for making GCode class PLine3 : public PLine<3> { public: PLine3(PLineArea area_, const uint extruder_no, const Vector3d &from_, const Vector3d &to_, double speed_, double extrusion_); PLine3(const PLine3 &rhs); PLine3(const PLine2 &pline, double z, double extrusion_per_mm_); PLine3(const Command &command); ~PLine3(){} Command command; double extrusion; // total extrusion in mm of filament Vector3d arcIJK() const; // if is an arc int getCommands(Vector3d &lastpos, vector &commands, const double &minspeed, const double &movespeed, const double &minZspeed, const double &maxZspeed, const double &maxAOspeed, bool useTCommand) const; // // not used // string GCode(Vector3d &lastpos, double &lastE, double feedrate, // double minspeed, double maxspeed, double movespeed, // bool relativeE) const; double calcangle() const {return angle;} void addAbsoluteExtrusionAmount(double amount, double max_absspeed, double time=0); double addMaxAbsoluteExtrusionAmount(double max_absspeed); double max_abs_speed(double max_espeed, double max_absspeed) const; vector< PLine3 > division(double length) const; vector< PLine3 > division(const Vector3d &point) const; vector< PLine3 > division(const vector &points) const; bool is_move() const {return (abs(extrusion) < 0.00001);} string info() const; }; // single 2D printline class PLine2 : public PLine<2> { friend class PLine3; friend class Printlines; // non-arc double feedratio; // relative extrusion feedrate, normally 1 public: PLine2(); PLine2(PLineArea area_, const uint extruder_no, const Vector2d &from, const Vector2d &to, double speed, double feedratio, double lifted = 0.); // arc PLine2(PLineArea area_, const uint extruder_no, const Vector2d &from, const Vector2d &to, double speed, double feedratio, short arc, const Vector2d &arccenter, double angle, double lifted = 0.); PLine2(const PLine2 &rhs); ~PLine2(){}; vector< PLine2 > division(double length) const; vector< PLine2 > division(const Vector2d &point) const; vector< PLine2 > division(const vector &points) const; //double calcangle() const; double angle_to(const PLine2 rhs) const; bool is_noop() const; bool is_move() const {return (abs(feedratio) < 0.00001);} string info() const; }; class Printlines; class PrintPoly { friend class Printlines; PrintPoly(const Poly &poly, const Printlines * printlines, double speed, double overhangspeed, double min_time, bool displace_start, PLineArea area); Poly *m_poly; const Printlines * printlines; PLineArea area; double speed; double min_time; bool displace_start; int overhangingpoints; double priority; // distance for next poly search will be divided by this double length; double speedfactor; // is set after slowdown uint extruder_no; public: ~PrintPoly(); void getLinesTo(vector &lines, int startindex, double movespeed) const; double getPriority() const {return priority;}; double getSpeedfactor() const {return speedfactor;}; uint getDisplacedStart(uint start) const; uint getExtruderNo() const {return extruder_no;}; string info() const; }; typedef struct { uint movestart, moveend, tractstart, pushend; void add(uint a) { movestart+=a, moveend+=a; tractstart+=a; pushend+=a; } } AORange; // a bunch of printlines: lines with feedrate // optimize for corners etc. class Printlines { friend class PrintPoly; vector printpolys; double z; double Zoffset; // global offset for generated PLine3s, always added at setZ() string name; /* void addPoly(PLineArea area, vector &lines, */ /* const Poly &poly, int startindex=0, */ /* double speed=1, double movespeed=1); */ void addLine(PLineArea area, uint extruder_no, vector &lines, const Vector2d &from, const Vector2d &to, double speed=1, double movespeed=1, double feedratio=1.0) const; public: Printlines(const Layer * layer, const Settings *settings, double z_offset=0); ~Printlines(){ clear(); }; void clear(); const Settings *settings; const Layer * layer; Cairo::RefPtr overhangs_surface; void setName(string s){name=s;}; Vector2d lastPoint() const; void addPolys(PLineArea area, const vector &polys, bool displace_start, double maxspeed = 0, double min_time = 0); double makeLines(Vector2d &startPoint, vector &lines); #if 0 void oldMakeLines(PLineArea area, const vector &polys, bool displace_startpoint, Vector2d &startPoint, vector &lines, double maxspeed = 0); #endif void optimize(double linewidth, double slowdowntime, double cornerradius, vector &lines); uint makeArcs(double linewidth, vector &lines) const; uint makeIntoArc(guint fromind, guint toind, vector &lines) const; uint makeIntoArc(const Vector2d ¢er, guint fromind, guint toind, vector &lines) const; uint roundCorners(double maxdistance, double minarclength, vector &lines) const; uint makeCornerArc(double maxdistance, double minarclength, uint ind, vector &lines) const; static bool find_nextmoves(double minlength, uint startindex, AORange &range, const vector< PLine3 > &lines); static uint makeAntioozeRetract(vector< PLine3 > &lines, const Settings &settings, ViewProgress * progress = NULL); static uint insertAntioozeHaltBefore(uint index, double amount, double speed, vector< PLine3 > &lines); inline static double length(const vector< PLine3 > &lines, uint from, uint to) { double totaldistance = 0; for (uint j = from; j <= to; j++) totaldistance += lines[j].length(); return totaldistance; } inline static double time (const vector< PLine3 > &lines, uint from, uint to) { double totaltime= 0; for (uint j = from; j <= to; j++) totaltime += lines[j].time(); return totaltime; } // slow down to total time needed (cooling) double slowdownTo(double totalseconds, vector &lines) ; // returns slowdownfactor void setSpeedFactor(double speedfactor, vector &lines) const; // keep movements inside polys when possible (against stringing) void clipMovements(const vector &polys, vector &lines, bool findnearest, double maxerr=0.0001) const; void getLines(const vector &lines, vector &linespoints) const; void getLines(const vector &lines, vector &linespoints) const; void getLines(const vector &lines, vector &plines, double extrusion_per_mm) const; double totalLength(const vector &lines) const; double totalSeconds(const vector &lines) const; double totalSecondsExtruding(const vector &lines) const; static double total_Extrusion(const vector< PLine3 > &lines); static double total_rel_Extrusion(const vector< PLine3 > &lines); static double total_abs_Extrusion(const vector< PLine3 > &lines); // every added poly will set this void setZ(double z) {this->z = z + Zoffset;}; double getZ() const {return z;}; double getSlowdownFactor() const {return slowdownfactor;}; static void getCommands(const vector &plines, const Settings &settings, GCodeState &state, ViewProgress * progress = NULL); string info() const; private: void optimizeLinedistances(double maxdist, vector &lines) const; void mergelines(PLine2 &l1, PLine2 &l2, double maxdist) const; double distance(const Vector2d &p, const PLine2 &l2) const; void optimizeCorners(double linewidth, double linewidthratio, double optratio, vector &lines) const; bool capCorner(PLine2 &l1, PLine2 &l2, double linewidth, double linewidthratio, double optratio) const; static void replace(vector< PLine2 > &lines, uint lineindex, const vector< PLine2 > &newlines){ lines[lineindex] = newlines[0]; if (newlines.size() > 1) lines.insert(lines.begin() + lineindex+1, newlines.begin()+1, newlines.end()); } static void replace(vector< PLine3 > &lines, uint lineindex, const vector< PLine3 > &newlines){ lines[lineindex] = newlines[0]; if (newlines.size() > 1) lines.insert(lines.begin() + lineindex+1, newlines.begin()+1, newlines.end()); } // insert single point static uint divideline(uint lineindex, const Vector2d &point, vector< PLine2 > &lines); static uint divideline(uint lineindex, const Vector3d &point, vector< PLine3 > &lines); // insert points static uint divideline(uint lineindex, const vector< Vector2d > &points, vector< PLine2 > &lines); static uint divideline(uint lineindex, const vector< Vector3d > &points, vector< PLine3 > &lines); // insert point at length static uint divideline(uint lineindex, const double length, vector< PLine3 > &lines); static int distribute_AntioozeAmount(double AOamount, double AOspeed, uint fromline, uint &toline, vector< PLine3 > &lines, double &havedistributed); Vector2d arcCenter(const PLine2 &l1, const PLine2 &l2, double maxerr) const; double slowdownfactor; // result of slowdown/setspeedfactor. not used here. /* string GCode(PLine2 l, Vector3d &lastpos, double &E, double feedrate, */ /* double minspeed, double maxspeed, double movespeed, */ /* bool relativeE) const; */ typedef vector::const_iterator line3CIt ; typedef vector::iterator line3It ; typedef vector::const_iterator lineCIt ; typedef vector::iterator lineIt ; //list::iterator lIt; }; repsnapper-2.3.2a5/src/slicer/printlines_antiooze.cpp000066400000000000000000000327051231531733200230050ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011-12 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "printlines.h" #include "ui/progress.h" #define AODEBUG 0 #if AODEBUG void test_range(AORange range, const vector &lines) { ostringstream o; bool error=false; for (uint i = range.tractstart; i < range.movestart; i++) if (lines[i].is_command()) o << "C"; else if (lines[i].is_move()) { error = true; //cerr < &lines) { uint i = from; movestart = from; uint num_lines = lines.size(); while (i < num_lines && (!lines[i].is_move() || lines[i].is_command()) ) { i++; movestart = i; } while (movestart < num_lines-1 && lines[movestart].is_command()) movestart++; if (!lines[movestart].is_move()) return false; if (movestart == num_lines-1) return false; return true; } inline bool move_end(uint from, uint &moveend, const vector &lines) { uint i = from; moveend = i; uint num_lines = lines.size(); while (i < num_lines && (lines[i].is_move() || lines[i].is_command() ) ) { moveend = i; i++; } while (moveend>0 && lines[moveend].is_command()) moveend--; if (!lines[moveend].is_move()) return false; if (moveend > num_lines-1) moveend = num_lines-1; return true; } inline bool find_moverange(double minlength, uint startindex, uint &movestart, uint &moveend, const vector &lines) { uint i = startindex; uint num_lines = lines.size(); while (i < num_lines-2) { if (move_start (i, movestart, lines)) { // find move start if (!move_end (movestart, moveend, lines)) {// find move end i = movestart+1; continue; } if ( Printlines::length(lines, movestart, moveend) >= minlength ) return true; } else return false; // not found i = moveend+1; // not long enough, continue search } return false; } // find ranges for retract and repush bool Printlines::find_nextmoves(double minlength, uint startindex, AORange &range, const vector &lines) { if (!find_moverange(minlength, startindex, range.movestart, range.moveend, lines)) return false; uint num_lines = lines.size(); // find previous move if (range.movestart == 0) range.tractstart = 0; else { int i = range.movestart-1; range.tractstart = range.movestart; while ( i >= (int)startindex && ( !(lines[i].is_move() || lines[i].has_absolute_extrusion()) || lines[i].is_command() )) { range.tractstart = i; i--; } } while (range.tractstart < num_lines-1 && lines[range.tractstart].is_command()) range.tractstart++; // find next move after if (range.moveend == num_lines-1) range.pushend = range.moveend; else { uint i = range.moveend+1; range.pushend = range.moveend; while ( i < num_lines && (!(lines[i].is_move() || lines[i].has_absolute_extrusion()) || lines[i].is_command()) ) { range.pushend = i; i++; } } while (range.pushend > 0 && lines[range.pushend].is_command()) range.pushend--; #if AODEBUG test_range(range, lines); #endif // cerr << "found move " << tractstart << "..." < &lines) { Vector3d where; if (index > lines.size()) return 0; if (index == lines.size()) where = lines.back().to; else where = lines[index].from; PLine3 halt (lines[index].area, lines.front().extruder_no, where, where, AOspeed, 0); halt.addAbsoluteExtrusionAmount(amount, AOspeed); lines.insert(lines.begin()+index, halt); // (inserts before) return 1; } #if AODEBUG static int distCase = 0; #endif int Printlines::distribute_AntioozeAmount(double AOamount, double AOspeed, uint fromline, uint &toline, vector< PLine3 > &lines, double &havedistributed) { if (AOamount == 0) return 0; bool negative = (AOamount < 0); bool reverse = (toline < fromline); // begin distribution at end of range // CASE 1: no lines to distribute the amount could be found // negative means retract which normally means reverse distribution // if this is not the case, no lines were found if (negative != reverse) { uint added = 0; uint at_line = fromline; #if AODEBUG distCase = 1; #endif if (!reverse) { // retract case // add retracting halt _after_ fromline #if AODEBUG distCase = -1; #endif at_line++; } toline = at_line; //cerr << "halt at " << at_line <<" - " < 0); #endif double AOtime = abs(AOamount) / AOspeed; // time needed for AO on move // time all lines normally need: double linestime = Printlines::time(lines, fromline, toline); // CASE 2: simple case, fit AOamount exactly into whole range while slowing down: if (linestime > 0 && linestime <= AOtime) { #if AODEBUG distCase = 2; #endif for (uint i=fromline; i<=toline; i++) { const double time = lines[i].time(); const double ratio = time / linestime; lines[i].addAbsoluteExtrusionAmount(AOamount * ratio, AOspeed, time);// will slow line down #if AODEBUG havedistributed += AOamount * ratio; #endif } return 0; } #if AODEBUG distCase = 3; #endif // CASE 3: distribute on the needed part of possible range // distribute in range fromline--toline int di = ( reverse ? -1 : 1); double restamount = AOamount; const double sign = (negative?-1.:1.); const double signedSpeed = AOspeed * sign; int i; int end = (int)toline+di; for (i = (int)fromline; i != end; i+=di) { if (i<0) break; double lineamount = lines[i].addMaxAbsoluteExtrusionAmount(signedSpeed); // +- havedistributed += lineamount; restamount -= lineamount; if (restamount * sign < 0) break; } // restamount is negative -> done too much lines[i].absolute_extrusion += restamount; havedistributed += restamount; uint added = 0; // now split last line (i) #if 1 const double line_ex = lines[i].absolute_extrusion; const double neededtime = abs(line_ex / AOspeed); double fraction = neededtime/lines[i].time(); if (fraction < 0.9) { // allow 10% slower AO to avoid split if (reverse) fraction = 1-fraction; added = divideline(i, fraction * lines[i].length(), lines); if (added == 1) { if (reverse) { lines[i].absolute_extrusion = 0; lines[i+1].absolute_extrusion = line_ex; } else { lines[i].absolute_extrusion = line_ex; lines[i+1].absolute_extrusion = 0; } } } #endif toline = i + added; // cerr << "rest " << AOamount - havedistributed << endl; return added; } uint Printlines::makeAntioozeRetract(vector &lines, const Settings &settings, ViewProgress * progress) { if (!settings.get_boolean("Extruder","EnableAntiooze")) return 0; double AOmindistance = settings.get_double("Extruder","AntioozeDistance"), AOamount = settings.get_double("Extruder","AntioozeAmount"), AOspeed = settings.get_double("Extruder","AntioozeSpeed") * 60; //AOonhaltratio = settings.Slicing.AntioozeHaltRatio; if (lines.size() < 2 || AOmindistance <=0 || AOamount == 0) return 0; // const double onhalt_amount = AOamount * AOonhaltratio; // const double onmove_amount = AOamount - onhalt_amount; uint linescount = lines.size(); uint total_added = 0; #if AODEBUG double total_extrusionsum = 0; double total_ext = total_Extrusion(lines); double total_rel = total_rel_Extrusion(lines); #endif uint count = 0; if (progress) if (!progress->restart (_("Antiooze Retract find ranges"), linescount)) return 0; vector ranges; AORange range; uint lastend = 0; while ( find_nextmoves(AOmindistance, lastend, // set range, //get lines) ) { if (range.movestart > linescount-1) break; if (progress){ if (count%20 == 0) if (!progress->update(range.movestart)) break; } count++; ranges.push_back(range); lastend = range.pushend+1; } // copy all lines successively to avoid mid-insertion vector newlines; // at most count*2 lines will be added newlines.reserve(linescount + count*2); if (progress) if (!progress->restart (_("Antiooze Retract"), ranges.size())) return 0; int progress_steps = max(1,(int)(ranges.size()/100)); lastend = 0; for (uint r = 0; r < ranges.size(); r++) { //for (int r = ranges.size()-1; r >= 0; r--) { if (progress && r%progress_steps == 0){ if (!progress->update(r)) break; } ranges[r].add(total_added); // shift by previous insertion uint added = 0; // get next slice of lines uint endcopy = min(ranges[r].pushend+1, linescount); newlines.insert(newlines.end(), lines.begin()+lastend, lines.begin()+endcopy); lastend = endcopy; if (ranges[r].moveend > newlines.size()-2) ranges[r].moveend = newlines.size()-2; // lift move-only range const double zlift = settings.get_double("Extruder","AntioozeZlift"); if (zlift > 0) for (uint i = ranges[r].movestart; i <= ranges[r].moveend; i++) { newlines[i].lifted = zlift; } // do repush first to keep indices before right double havedist = 0; uint newl = distribute_AntioozeAmount(AOamount, AOspeed, ranges[r].moveend+1, ranges[r].pushend, newlines, havedist); added += newl; ranges[r].pushend += newl; //test_range(movestart,moveend,tractstart,pushend, newlines); #if AODEBUG double extrusionsum = 0; double linesext = 0; for (uint i = ranges[r].moveend+1; i<=ranges[r].pushend; i++) linesext+=newlines[i].absolute_extrusion; if (abs(linesext-AOamount)>0.01) cerr << "wrong lines dist push " << linesext << endl; extrusionsum += havedist; if (abs(havedist-AOamount)>0.01) cerr << " wrong distrib push " << havedist << endl; #endif // find lines to distribute retract if (ranges[r].movestart < 1) ranges[r].movestart = 1; #if AODEBUG double linesextbefore = 0; for (uint i = ranges[r].tractstart; i < ranges[r].movestart; i++) linesextbefore += newlines[i].absolute_extrusion; #endif havedist = 0; newl = distribute_AntioozeAmount(-AOamount, AOspeed, ranges[r].movestart-1, ranges[r].tractstart, newlines, havedist); added += newl; ranges[r].movestart += newl; ranges[r].moveend += newl; ranges[r].pushend += newl; total_added += added; #if AODEBUG linesext = -linesextbefore; for (uint i = ranges[r].tractstart; i < ranges[r].movestart; i++) linesext += newlines[i].absolute_extrusion; if (abs(linesext+AOamount)>0.01) cerr << "wrong lines dist tract " << distCase << " : "<" << ranges[r].movestart << " new: "<< newl << " -- before: "<0.01) cerr << " wrong distrib tract " << havedist << endl; if (abs(extrusionsum) > 0.01) cerr << "wrong AO extr.: " << extrusionsum << endl; total_extrusionsum += extrusionsum; #endif } #if AODEBUG if (abs(total_extrusionsum) > 0.01) cerr << "wrong total AO extr.: " << total_extrusionsum << endl; double totalabs = total_abs_Extrusion(newlines); if (abs(totalabs)>0.01) cerr << "abs-extrusion difference after antiooze " << totalabs << endl; double total_rel2 = total_rel_Extrusion(newlines) - total_rel; if (abs(total_rel2)>0.01) cerr << "rel-extrusion difference after antiooze " << total_rel2 << endl; double total_ext2 = total_Extrusion(newlines) - total_ext; if (abs(total_ext2)>0.01) cerr << "total extrusion difference after antiooze " << total_ext2 << endl; #endif //cerr << lines.size() << " - " << newlines.size() << "- " <cuttingPlane = cuttingPlane; vector planePolygons = cuttingPlane->GetPolygons(); vector planeVertices = cuttingPlane->GetVertices(); std::list unsortedPolys; positivePolygons.clear(); // first add solids. This builds the tree, placing the holes afterwards is easier/faster for(uint p = 0; p < planePolygons.size(); p++) { Poly *poly = &planePolygons[p]; poly->calcHole(); if( !poly->hole ) { Polygon2d* newPoly = new Polygon2d(); newPoly->hole = poly->hole; newPoly->index = p; size_t count = poly->size(); for(size_t i=0; ivertices.push_back(planeVertices[i]); } PushPoly(newPoly); } } // then add holes for(uint p = 0; p < planePolygons.size(); p++) { Poly* poly = &planePolygons[p]; if( poly->hole ) { Polygon2d* newPoly = new Polygon2d(); newPoly->hole = poly->hole; size_t count = poly->size(); for (size_t i = 0; i < count; i++) { newPoly->vertices.push_back(planeVertices[i]); } PushPoly(newPoly); } } } void CuttingPlaneOptimizer::Dispose() { for(list::iterator pIt =positivePolygons.begin(); pIt!=positivePolygons.end(); pIt++) { delete (*pIt); *pIt = NULL; } } void CuttingPlaneOptimizer::MakeOffsetPolygons(vector& polys) { for(list::iterator pIt=this->positivePolygons.begin(); pIt!=this->positivePolygons.end(); pIt++) { DoMakeOffsetPolygons(*pIt, polys); } } void CuttingPlaneOptimizer::DoMakeOffsetPolygons(Polygon2d* pPoly, vector& polys) { Poly p(this->cuttingPlane->getZ()); for( vector::iterator pIt = pPoly->vertices.begin(); pIt!=pPoly->vertices.end(); pIt++) { p.vertices.push_back(*pIt); } p.hole = pPoly->hole; polys.push_back(p); for( list::iterator pIt = pPoly->containedSolids.begin(); pIt!=pPoly->containedSolids.end(); pIt++) { DoMakeOffsetPolygons(*pIt, polys); } for( list::iterator pIt = pPoly->containedHoles.begin(); pIt!=pPoly->containedHoles.end(); pIt++) { DoMakeOffsetPolygons(*pIt, polys); } } void CuttingPlaneOptimizer::RetrieveLines(vector& lines) { for(list::iterator pIt=this->positivePolygons.begin(); pIt!=this->positivePolygons.end(); pIt++) { DoRetrieveLines(*pIt, lines); } } void CuttingPlaneOptimizer::DoRetrieveLines(Polygon2d* pPoly, vector& lines) { if( pPoly->vertices.size() == 0) return; lines.reserve(lines.size()+pPoly->vertices.size()*2); { vector::iterator pIt = pPoly->vertices.begin(); lines.push_back(Vector3d(pIt->x, pIt->y, Z)); pIt++; for( ; pIt!=pPoly->vertices.end(); pIt++) { lines.push_back(Vector3d(pIt->x, pIt->y, Z)); lines.push_back(Vector3d(pIt->x, pIt->y, Z)); } lines.push_back(Vector3d(pPoly->vertices.front().x, pPoly->vertices.front().y, Z)); } for( list::iterator pIt = pPoly->containedSolids.begin(); pIt!=pPoly->containedSolids.end(); pIt++) { DoRetrieveLines(*pIt, lines); } for( list::iterator pIt = pPoly->containedHoles.begin(); pIt!=pPoly->containedHoles.end(); pIt++) { DoRetrieveLines(*pIt, lines); } } void CuttingPlaneOptimizer::PushPoly(Polygon2d* poly) { poly->PlaceInList(positivePolygons); } void CuttingPlaneOptimizer::Draw() { float color = 1; if (positivePolygons.size()>0){ Polygon2d::DisplayPolygons(positivePolygons, Z, 0,color,0,1); for(list::iterator pIt =positivePolygons.begin(); pIt!=positivePolygons.end(); pIt++) { Polygon2d::DrawRecursive(*pIt, Z, color); } } } void CuttingPlaneOptimizer::Shrink(double distance, list &resPolygons) { for(list::iterator pIt =positivePolygons.begin(); pIt!=positivePolygons.end(); pIt++) { list parentPolygons; (*pIt)->Shrink(distance, parentPolygons, resPolygons); } } /* * We bucket space up into a grid of size 1/mult and generate hash values * from this. We use a margin of 2 * double_epsilon to detect values near * the bottom or right hand edge of the bucket, and check the adjacent * grid entries for similar values within double_epsilon of us. */ struct PointHash::Impl { typedef std::vector< std::pair< uint, Vector2d > > IdxPointList; hash_map points; typedef hash_map::iterator iter; typedef hash_map::const_iterator const_iter; static uint GetHashes (uint *hashes, double x, double y) { uint xh = x * mult; uint yh = y * mult; int xt, yt; uint c = 0; hashes[c++] = xh + yh * 1000000; if ((xt = (uint)((x + 2*PointHash::double_epsilon) * PointHash::mult) - xh)) hashes[c++] = xh + xt + yh * 1000000; if ((yt = (uint)((y + 2*PointHash::double_epsilon) * PointHash::mult) - yh)) hashes[c++] = xh + (yt + yh) * 1000000; if (xt && yt) hashes[c++] = xh + xt + (yt + yh) * 1000000; #if CUTTING_PLANE_DEBUG > 1 cout << "hashes for " << x << ", " << y << " count: " << c << ": "; for (int i = 0; i < c; i++) cout << hashes[i] << ", "; cout << "\n"; #endif return c; } }; const double PointHash::mult = 100; const double PointHash::double_epsilon = 0.001; PointHash::PointHash() { impl = new Impl(); } PointHash::~PointHash() { clear(); delete impl; } PointHash::PointHash(const PointHash ©) { impl = new Impl(); Impl::const_iter it; for (it = copy.impl->points.begin(); it != copy.impl->points.end(); it++) impl->points[it->first] = it->second; } void PointHash::clear() { impl->points.clear(); } int PointHash::IndexOfPoint(const Vector2d &p) { uint hashes[4]; uint c = Impl::GetHashes (hashes, p.x, p.y); for (uint i = 0; i < c; i++) { Impl::const_iter iter = impl->points.find (hashes[i]); if (iter == impl->points.end()) continue; const Impl::IdxPointList &pts = iter->second; for (uint j = 0; j < pts.size(); j++) { const Vector2d &v = pts[j].second; if( ABS(v.x - p.x) < double_epsilon && ABS(v.y - p.y) < double_epsilon) return pts[j].first; #if CUTTING_PLANE_DEBUG > 1 else if( ABS(v.x-p.x) < maxoffset && ABS(v.y-p.y) < maxoffset) cout << "hash " << hashes[i] << " missed idx " << pts[j].first << " by " << (v.x - p.x) << ", " << (v.y - p.y) << " hash: " << v.x << ", " << v.y << " vs. p " << p.x << ", " << p.y << "\n"; #endif } } return -1; } void PointHash::InsertPoint (uint idx, const Vector2d &p) { uint hashes[4]; int c = Impl::GetHashes (hashes, p.x, p.y); for (int i = 0; i < c; i++) { Impl::IdxPointList &pts = impl->points[hashes[i]]; pts.push_back (pair( idx, p )); #if CUTTING_PLANE_DEBUG > 1 cout << "insert " << hashes[i] << " idx " << idx << " vs. p " << p.x << ", " << p.y << "\n"; #endif } } repsnapper-2.3.2a5/src/slicer/slicer_logick.h000066400000000000000000000043611231531733200211610ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "types.h" #pragma once #include // for PointHash #ifdef __GNUC__ # define _BACKWARD_BACKWARD_WARNING_H 1 // kill annoying warning # include namespace std { using namespace __gnu_cxx; } #else # include using namespace stdext; #endif #include #include #include "cuttingplane.h" using namespace vmml; using namespace PolyLib; #define RESOLUTION 4 #define FREE(p) {if (p) {free(p); (p)= NULL;}} /* associates adjacent points with integers */ class PointHash { struct Impl; Impl *impl; public: PointHash(); ~PointHash(); PointHash(const PointHash ©); int IndexOfPoint (const Vector2d &p); void InsertPoint (uint idx, const Vector2d &p); void clear(); static const double mult; static const double double_epsilon; }; // For Logick shrinker ... class CuttingPlaneOptimizer { public: double Z; //CuttingPlaneOptimizer(double z) { Z = z; }; CuttingPlaneOptimizer(CuttingPlane* cuttingPlane, double z); CuttingPlane* cuttingPlane; list positivePolygons; void Shrink(double distance, list &resPolygons); void Draw(); void Dispose(); void MakeOffsetPolygons(vector& polys); void RetrieveLines(vector& lines); private: void PushPoly(Polygon2d* poly); void DoMakeOffsetPolygons(Polygon2d* pPoly, vector& polys); void DoRetrieveLines(Polygon2d* pPoly, vector& lines); }; repsnapper-2.3.2a5/src/stdafx.h000066400000000000000000000060011231531733200163510ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #ifndef STDAFX_H #define STDAFX_H #include "config.h" #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifdef _MSC_VER // Visual C++ compiler # pragma warning( disable : 4311 4312 4244 4267 4800) #endif typedef unsigned int uint; #define DEBUG_ECHO (1<<0) #define DEBUG_INFO (1<<1) #define DEBUG_ERRORS (1<<2) #ifdef WIN32 #include // Header File For Windows #include #undef interface // Undo braindead define from Windows that conflicts with glibmm DBUS binding typedef unsigned int guint; #define random rand #define srandom srand #endif #include "platform.h" // OpenGL, glu, glut in cross-platform way #include #include #include #include "math.h" // Needed for sqrtf #include "types.h" #define VMMLIB_BASIC_ONLY #include // Unpleasant needs un-winding ... using namespace std; //using namespace vmml; typedef vmml::vec2d Vector2d; typedef vmml::vec2f Vector2f; typedef vmml::vec3d Vector3d; typedef vmml::vec3f Vector3f; typedef vmml::vec4d Vector4d; typedef vmml::vec4f Vector4f; typedef vmml::mat4d Matrix4d; typedef vmml::mat4f Matrix4f; typedef vmml::mat3d Matrix3d; float const GREEN[] = {0.1, 1, 0.1}; float const GREEN2[] = {0.3, 0.8, 0.3}; float const BLUEGREEN[] = {0.1, 0.9, 0.7}; float const BLUE2[] = {0.5,0.5,1.0}; float const RED[] = {1, 0, 0}; float const RED2[] = {0.8,0.5,0.5}; float const RED3[] = {0.8,0.3,0.1}; float const ORANGE[] = {1, 0.5, 0}; float const YELLOW[] = {1, 1, 0}; float const YELLOW2[] = {1, 1, 0.2}; float const WHITE[] = {1, 1, 1}; float const GREY[] = {0.5,0.5,0.5}; float const VIOLET[] = {0.8,0.0,0.8}; //utility macros //assuming IEEE-754(GLfloat), which i believe has max precision of 7 bits # define Epsilon 1.0e-5 #ifdef __GNUC__ #define UNUSED __attribute__ ((unused)) #else #define UNUSED #endif const double UNUSED INFTY = numeric_limits::infinity(); #endif // STDAFX_H repsnapper-2.3.2a5/src/transform3d.cpp000066400000000000000000000102641231531733200176630ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "transform3d.h" Transform3D::Transform3D() { identity(); } void Transform3D::update_transform() { transform = Matrix4d::IDENTITY; // scale the unrotated object for (uint i = 0; i < 3; i++) transform(i,i) *= xyz_scale(i); transform *= m_transform; // for (uint i = 0; i < 3; i++) // transform(3,i) = 0; // translate for (uint i = 0; i < 3; i++) transform(3,i) = m_transform(3,i); } void Transform3D::identity() { m_transform = Matrix4d::IDENTITY; xyz_scale = Vector3d(1,1,1); update_transform(); } Matrix4f Transform3D::getFloatTransform() const { return (Matrix4f) transform; } void Transform3D::setTransform(const Matrix4f &matr) { m_transform = (Matrix4d) matr; update_transform(); } Vector3d Transform3D::getTranslation() const { Vector3d p; m_transform.get_translation(p); return p; } void Transform3D::move(const Vector3d &delta) { Vector3d trans = getTranslation(); m_transform.set_translation(trans + delta * transform(3,3)); // unscale delta update_transform(); } void Transform3D::scale(double x) { if (x==0) return; m_transform[3][3] = 1/x; update_transform(); } void Transform3D::scale_x(double x) { xyz_scale(0) = x; update_transform(); } void Transform3D::scale_y(double x) { xyz_scale(1) = x; update_transform(); } void Transform3D::scale_z(double x) { xyz_scale(2) = x; update_transform(); } void Transform3D::rotate_to(const Vector3d ¢er, const Vector3d &axis, double angle) { // save translation & scale const Vector3d trans = getTranslation(); const double scale = m_transform(3,3); // rotate only Matrix4d rot; Vector3d naxis = axis; naxis.normalize(); m_transform.rotate(angle, naxis); // this creates the matrix! //cerr << m_transform << endl; m_transform.set_translation(trans); m_transform(3,3) = scale; update_transform(); } void Transform3D::rotate(const Vector3d &axis, double angle) { rotate(Vector3d::ZERO, axis, angle); } void Transform3D::rotate(const Vector3d ¢er, const Vector3d &axis, double angle) { // save translation const Vector3d trans = getTranslation(); // rotate only Vector3d naxis = axis; naxis.normalize(); Matrix4d rot; rot.rotate(angle, naxis); // this creates the matrix! m_transform = rot * m_transform ; //cerr << angle << axis << m_transform << endl; // rotate center and translation Vector3d rotcenter = rot * center; Vector3d rottrans = rot * trans; m_transform.set_translation((center-rotcenter)*m_transform[3][3] + rottrans); update_transform(); } //not used void Transform3D::rotate(const Vector3d ¢er, double x, double y, double z) { cerr << "Transform3D::rotate has no effect " << x << y << z << endl; } void Transform3D::rotate_to(const Vector3d ¢er, double x, double y, double z) { const Vector3d trans = getTranslation(); rotate_to (center, Vector3d(1.,0.,0.), x); rotate (center, Vector3d(0.,1.,0.), y); rotate (center, Vector3d(0.,0.,1.), z); m_transform.set_translation(trans); update_transform(); } double Transform3D::getRotX() const { return atan2(m_transform(2,1), m_transform(2,2)); } double Transform3D::getRotY() const { return -asin(m_transform(2,0)); } double Transform3D::getRotZ() const { return atan2(m_transform(1,0), m_transform(0,0)); } Matrix4d Transform3D::getInverse() const { Matrix4d im; m_transform.inverse(im); return im; } repsnapper-2.3.2a5/src/transform3d.h000066400000000000000000000036331231531733200173320ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "stdafx.h" class Transform3D { Matrix4d m_transform; Vector3d xyz_scale; void update_transform(); public: Transform3D(); Matrix4d transform; void identity(); Matrix4d getTransform() const; Matrix4f getFloatTransform() const; Vector3d getTranslation() const; Matrix4d getInverse() const; void setTransform(const Matrix4f &matrf); void scale(double x); void scale_x(double x); void scale_y(double x); void scale_z(double x); void move(const Vector3d &delta); void rotate(const Vector3d ¢er, double x, double y, double z); void rotate_to(const Vector3d ¢er, double x, double y, double z); void rotate(const Vector3d &axis, double angle); void rotate(const Vector3d ¢er, const Vector3d &axis, double angle); void rotate_to(const Vector3d ¢er, const Vector3d &axis, double angle); double getRotX() const; double getRotY() const; double getRotZ() const; double get_scale() const {return 1/transform(3,3);}; double get_scale_x() const {return xyz_scale(0);}; double get_scale_y() const {return xyz_scale(1);}; double get_scale_z() const {return xyz_scale(2);}; }; repsnapper-2.3.2a5/src/triangle.cpp000066400000000000000000000264451231531733200172360ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "triangle.h" #include "geometry.h" Triangle::Triangle(const Vector3d &Point1, const Vector3d &Point2, const Vector3d &Point3) { A=Point1;B=Point2;C=Point3; calcNormal(); } void Triangle::calcNormal() { Vector3d AA=C-A; Vector3d BB=C-B; Normal = normalized(AA.cross(BB)); } Triangle Triangle::transformed(const Matrix4d &T) const { return Triangle(T*A,T*B,T*C); } void Triangle::invertNormal() { Vector3d swap = A; A=C; C=swap; calcNormal(); } void Triangle::mirrorX(const Vector3d ¢er) { for (uint i = 0; i < 3; i++) operator[](i).x() = center.x()-operator[](i).x(); invertNormal(); } Vector3d &Triangle::operator[] (const uint index) { switch(index) { case 0: return A; case 1: return B; case 2: return C; } return A; } Vector3d const &Triangle::operator[] (const uint index) const { switch(index) { case 0: return A; case 1: return B; case 2: return C; } return A; } // for 2 adjacent triangles test if normals match bool Triangle::wrongOrientationWith(Triangle const &other, double maxsqerr) const { // find the 2 common vertices vector thisv, otherv; for (uint j = 0; j < 3; j++) { if ( A == other[j] || A.squared_distance(other[j]) < maxsqerr){ thisv.push_back(0); otherv.push_back(j); } if ( B == other[j] || B.squared_distance(other[j]) < maxsqerr) { thisv.push_back(1); otherv.push_back(j); } if ( C == other[j] || C.squared_distance(other[j]) < maxsqerr) { thisv.push_back(2); otherv.push_back(j); } } if (thisv.size()!=2 || otherv.size()!=2) { //cerr << "only " << thisv.size() << " common vertex! " << endl; return false; // "ok" because non-adjacent } int diff = thisv[1] - thisv[0]; const bool thisorient = ( diff == 1 || diff == -2 ); diff = otherv[1] - otherv[0]; const bool otherorient = ( diff == 1 || diff == -2 ); // cerr << "have 2: " << thisorient <<" / " << otherorient << endl; return (thisorient == otherorient); // they have different(!) orientation } bool Triangle::isConnectedTo(Triangle const &other, double maxsqerr) const { // for (uint i = 0; i < 3; i++) { // Vector3d p = (Vector3d)(operator[](i)); // first test equal, faster for (uint j = 0; j < 3; j++) { if (( A == other[j])) return true; if (( B == other[j])) return true; if (( C == other[j])) return true; } if (maxsqerr>0) // if not, test distance for (uint j = 0; j < 3; j++) { if ( A.squared_distance(other[j]) < maxsqerr) return true; if ( B.squared_distance(other[j]) < maxsqerr) return true; if ( C.squared_distance(other[j]) < maxsqerr) return true; } return false; } double Triangle::slopeAngle(const Matrix4d &T) const { const double scale = T(3,3); Vector3d trans; T.get_translation(trans); // get scaled translation out of matrix const Vector3d n = T * Normal - trans/scale; return asin(n.z()/n.length()); } double Triangle::area() const { return 0.5* ((C-A).cross(B-A)).length() ; } // add all these to get shape volume double Triangle::projectedvolume(const Matrix4d &T) const { if (Normal.z()==0) return 0; Triangle xyproj = Triangle(Vector3d(A.x(),A.y(),0), Vector3d(B.x(),B.y(),0), Vector3d(C.x(),C.y(),0)); Vector3d min = GetMin(T); Vector3d max = GetMax(T); double vol = xyproj.area()*0.5*(max.z()+min.z()); if (Normal.z()<0) vol=-vol; return vol; } Vector3d Triangle::GetMax(const Matrix4d &T) const { Vector3d max(-99999999.0, -99999999.0, -99999999.0); Vector3d TA=T*A,TB=T*B,TC=T*C; for (uint i = 0; i < 3; i++) { max[i] = MAX(max[i], TA[i]); max[i] = MAX(max[i], TB[i]); max[i] = MAX(max[i], TC[i]); } return max; } Vector3d Triangle::GetMin(const Matrix4d &T) const { Vector3d min(99999999.0, 99999999.0, 99999999.0); Vector3d TA=T*A,TB=T*B,TC=T*C; for (uint i = 0; i < 3; i++) { min[i] = MIN(min[i], TA[i]); min[i] = MIN(min[i], TB[i]); min[i] = MIN(min[i], TC[i]); } return min; } void Triangle::AccumulateMinMax(Vector3d &min, Vector3d &max, const Matrix4d &T) { Vector3d tmin = GetMin(T); Vector3d tmax = GetMax(T); for (uint i = 0; i < 3; i++) { min[i] = MIN(tmin[i], min[i]); max[i] = MAX(tmax[i], max[i]); } } void Triangle::Translate(const Vector3d &vector) { A += vector; B += vector; C += vector; } void Triangle::rotate(const Vector3d &axis, double angle) { A = A.rotate(angle, axis); B = B.rotate(angle, axis); C = C.rotate(angle, axis); calcNormal(); } void triangulateQuadrilateral(vector fourpoints, vector &triangles) { assert(fourpoints.size()==4); vector tr(2); double SMALL = 0.01; // find diagonals double dist = dist3D_Segment_to_Segment(fourpoints[0],fourpoints[2], fourpoints[1],fourpoints[3], SMALL*SMALL); if (dist < SMALL) { // found -> divide at shorter diagonal if ((fourpoints[0]-fourpoints[2]).squared_length() < (fourpoints[1]-fourpoints[3]).squared_length()) { tr[0] = Triangle(fourpoints[0],fourpoints[1],fourpoints[2]); tr[1] = Triangle(fourpoints[2],fourpoints[3],fourpoints[0]); } else { tr[0] = Triangle(fourpoints[0],fourpoints[1],fourpoints[3]); tr[1] = Triangle(fourpoints[1],fourpoints[2],fourpoints[3]); } } else { // take other 2 double dist = dist3D_Segment_to_Segment(fourpoints[1],fourpoints[2], fourpoints[0],fourpoints[3], SMALL*SMALL); if (dist < SMALL) { if ((fourpoints[1]-fourpoints[2]).squared_length() < (fourpoints[0]-fourpoints[3]).squared_length()) { tr[0] = Triangle(fourpoints[1],fourpoints[2],fourpoints[3]); tr[1] = Triangle(fourpoints[0],fourpoints[1],fourpoints[2]); } else { tr[0] = Triangle(fourpoints[1],fourpoints[0],fourpoints[3]); tr[1] = Triangle(fourpoints[0],fourpoints[2],fourpoints[3]); } } else { // take 3rd possibility, not the case here, because 2-3 is cut line double dist = dist3D_Segment_to_Segment(fourpoints[0],fourpoints[1], fourpoints[2],fourpoints[3], SMALL*SMALL); if (dist < SMALL) { tr[0] = Triangle(fourpoints[0],fourpoints[2],fourpoints[3]); tr[1] = Triangle(fourpoints[2],fourpoints[1],fourpoints[3]); } else { //cerr << dist << " cannot find diagonals" << endl; return; } } } triangles.insert(triangles.end(), tr.begin(), tr.end()); } int Triangle::SplitAtPlane(double z, vector &uppertriangles, vector &lowertriangles, const Matrix4d &T) const { vector upper, lower; if ((T*A).z()>z) upper.push_back(T*A); else lower.push_back(T*A); if ((T*B).z()>z) upper.push_back(T*B); else lower.push_back(T*B); if ((T*C).z()>z) upper.push_back(T*C); else lower.push_back(T*C); Vector2d lstart,lend; int cut = CutWithPlane(z,T,lstart,lend); if (cut==0) return 0; else if (cut==1) { // cut at a triangle point if (upper.size()>lower.size()) upper.push_back(Vector3d(lstart.x(),lstart.y(),z)); else lower.push_back(Vector3d(lstart.x(),lstart.y(),z)); } else if (cut==2) { upper.push_back(Vector3d(lstart.x(),lstart.y(),z)); upper.push_back(Vector3d(lend.x(),lend.y(),z)); lower.push_back(Vector3d(lstart.x(),lstart.y(),z)); lower.push_back(Vector3d(lend.x(),lend.y(),z)); } vector uppertr,lowertr; if (upper.size()==3) { // half of triangle with 1 triangle point uppertr.push_back(Triangle(upper[0],upper[1],upper[2])); } else if (upper.size()==4) { // 0 and 1 are triangle points, 2 and 3 are cutline triangulateQuadrilateral(upper, uppertr); } else cerr << "upper size " << upper.size() << endl; if (lower.size()==3) { lowertr.push_back(Triangle(lower[0],lower[1],lower[2])); } else if (lower.size()==4) { triangulateQuadrilateral(lower, lowertr); } else cerr << "lower size " << lower.size() << endl; Vector3d TN = T*Normal; TN.normalize(); for (guint i=0; i < uppertr.size(); i++) if ((uppertr[i].Normal + TN).length()<0.1) uppertr[i].invertNormal(); for (guint i=0; i < lowertr.size(); i++) if ((lowertr[i].Normal + TN).length()<0.1) lowertr[i].invertNormal(); uppertriangles.insert(uppertriangles.end(),uppertr.begin(),uppertr.end()); lowertriangles.insert(lowertriangles.end(),lowertr.begin(),lowertr.end()); return cut; } bool Triangle::isInZrange(double zmin, double zmax, const Matrix4d &T) const { const Vector3d TA = T * A; if (TA.z() < zmin || TA.z() > zmax) return false; const Vector3d TB = T * B; if (TB.z() < zmin || TB.z() > zmax) return false; const Vector3d TC = T * C; if (TC.z() < zmin || TC.z() > zmax) return false; return true; } int Triangle::CutWithPlane(double z, const Matrix4d &T, Vector2d &lineStart, Vector2d &lineEnd) const { Vector3d p; double t; const Vector3d TA = T * A; const Vector3d TB = T * B; const Vector3d TC = T * C; int num_cutpoints = 0; // Are the points on opposite sides of the plane? if ((z <= TA.z()) != (z <= TB.z())) { t = (z - TA.z())/(TB.z()-TA.z()); p = TA + (TB - TA) * t; lineStart = Vector2d(p.x(),p.y()); num_cutpoints = 1; } if ((z <= TB.z()) != (z <= TC.z())) { t = (z - TB.z())/(TC.z() - TB.z()); p = TB + (TC - TB) * t; if(num_cutpoints > 0) { lineEnd = Vector2d(p.x(),p.y()); num_cutpoints = 2; } else { lineStart = Vector2d(p.x(),p.y()); num_cutpoints = 1; } } if ((z <= TC.z()) != (z <= TA.z())) { t = (z - TC.z())/(TA.z() - TC.z()); p = TC + (TA - TC) * t; lineEnd = Vector2d(p.x(),p.y()); if( lineEnd != lineStart ) num_cutpoints = 2; } return num_cutpoints; } void Triangle::draw(int gl_type) const { glBegin(gl_type); glVertex3f(A.x(),A.y(),A.z()); glVertex3f(B.x(),B.y(),B.z()); glVertex3f(C.x(),C.y(),C.z()); glEnd(); } string Triangle::getSTLfacet(const Matrix4d &T) const { Vector3d TA=T*A,TB=T*B,TC=T*C,TN=T*Normal;TN.normalize(); stringstream sstr; sstr << " facet normal " << TN.x() << " " << TN.x() << " " << TN.z() < &uppertriangles, vector &lowertriangles, const Matrix4d &T=Matrix4d::IDENTITY) const; string getSTLfacet(const Matrix4d &T=Matrix4d::IDENTITY) const; void draw(int gl_type) const; double projectedvolume(const Matrix4d &T=Matrix4d::IDENTITY) const; bool isConnectedTo(Triangle const &other, double maxsqerr=0.0001) const; bool wrongOrientationWith(Triangle const &other, double maxsqerr) const; string info() const; }; repsnapper-2.3.2a5/src/types.h000066400000000000000000000030361231531733200162310ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* #ifndef TYPES_H */ /* #define TYPES_H */ #pragma once // try to avoid compile time explosion by reducing includes class GUI; class Poly; class View; class GCode; class GCodeState; class GCodeIter; class Printlines; class PLine2; class PLine3; class Model; class Render; class Command; class Printer; class Settings; class PrefsDlg; class Triangle; class RepRapSerial; class Layer; class PrintInhibitor; class ProcessController; class ObjectsTree; class TreeObject; class Shape; class FlatShape; class Transform3D; class Infill; class ViewProgress; class ConnectView; class Transform3D; enum SerialState { SERIAL_DISCONNECTED, SERIAL_DISCONNECTING, SERIAL_CONNECTED, SERIAL_CONNECTING }; /* #endif // TYPES_H */ repsnapper-2.3.2a5/src/ui/000077500000000000000000000000001231531733200153275ustar00rootroot00000000000000repsnapper-2.3.2a5/src/ui/Makefile000066400000000000000000000002411231531733200167640ustar00rootroot00000000000000# Delegate everything to the toplevel makefile # this is only here so 'make' works in src/ all: @$(MAKE) -C ../.. $@ # Catch all rule %: @$(MAKE) -C ../.. $@ repsnapper-2.3.2a5/src/ui/Makefile.am000066400000000000000000000011551231531733200173650ustar00rootroot00000000000000# # Combined Makefile for Linux and OS/X # # # Copyright 2009+ Joachim Glauche # Copyright 2011 Bas Wijnen # # This file is part of RepSnapper and is made available under # the terms of the GNU General Public License, version 2, or at your # option, any later version, incorporated herein by reference. SHARED_SRC += \ src/ui/widgets.cpp \ src/ui/view.cpp \ src/ui/prefs_dlg.cpp \ src/ui/connectview.cpp \ src/ui/filechooser.cpp \ src/ui/progress.cpp SHARED_INC += \ src/ui/widgets.h \ src/ui/view.h \ src/ui/prefs_dlg.h \ src/ui/connectview.h \ src/ui/filechooser.h \ src/ui/progress.h repsnapper-2.3.2a5/src/ui/connectview.cpp000066400000000000000000000075031231531733200203640ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "settings.h" #include "connectview.h" #include "model.h" void ConnectView::serial_state_changed(SerialState state) { bool sensitive; const char *label; Gtk::BuiltinStockID id; switch (state) { case SERIAL_DISCONNECTING: id = Gtk::Stock::NO; label = _("Disconnecting..."); sensitive = false; break; case SERIAL_DISCONNECTED: m_combo.set_sensitive (true); id = Gtk::Stock::NO; label = _("Connect"); sensitive = true; break; case SERIAL_CONNECTING: m_combo.set_sensitive (false); id = Gtk::Stock::NO; label = _("Connecting..."); sensitive = false; break; case SERIAL_CONNECTED: default: id = Gtk::Stock::YES; label = _("Disconnect"); sensitive = true; break; } m_image.set (id, Gtk::ICON_SIZE_BUTTON); m_connect.set_label (label); m_connect.set_sensitive (sensitive); if (sensitive) { m_setting_state = true; // inhibit unhelpful recursion. m_connect.set_active (state == SERIAL_CONNECTED); m_setting_state = false; } } void ConnectView::connect_toggled() { if (!m_setting_state) m_printer->Connect (m_connect.get_active ()); } void ConnectView::signal_entry_changed() { // Use the value of the entry widget, rather than the // active text, so the user can enter other values. Gtk::Entry *entry = m_combo.get_entry(); m_settings->set_string("Hardware","PortName", entry->get_text()); } void ConnectView::find_ports() { m_combo.clear(); string port_setting = m_settings->get_string("Hardware","PortName"); #if GTK_VERSION_GE(2, 24) m_combo.append(port_setting); #else m_combo.append_text(port_setting); #endif vector ports = PrinterSerial::FindPorts(); for(size_t i = 0; i < ports.size(); i++) { if (ports[i] != port_setting) { #if GTK_VERSION_GE(2, 24) m_combo.append(ports[i]); #else m_combo.append_text(ports[i]); #endif } } } ConnectView::ConnectView (Printer *printer, Settings *settings, bool show_connect) : Gtk::VBox(), m_connect(), m_port_label(_("Port:")), m_settings(settings), m_printer(printer) { m_port_align.set_padding(0, 0, 6, 0); m_port_align.add (m_port_label); m_setting_state = false; add (m_hbox); m_hbox.set_spacing(2); m_hbox.add (m_image); m_hbox.add (m_connect); m_hbox.add (m_port_align); m_hbox.add (m_combo); m_connect.signal_toggled().connect(sigc::mem_fun(*this, &ConnectView::connect_toggled)); m_combo.signal_changed().connect(sigc::mem_fun(*this, &ConnectView::signal_entry_changed)); //m_combo.signal_popup_menu().connect(sigc::mem_fun(*this, &ConnectView::find_ports)); show_all (); if (!show_connect) m_connect.hide (); serial_state_changed (SERIAL_DISCONNECTED); m_printer->signal_serial_state_changed.connect (sigc::mem_fun(*this, &ConnectView::serial_state_changed)); // TODO: Execute find_ports every time the dropdown is displayed find_ports(); m_combo.set_active(0); } repsnapper-2.3.2a5/src/ui/connectview.h000066400000000000000000000030511231531733200200230ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef CONNECT_VIEW_H #define CONNECT_VIEW_H #include #include "types.h" #include "printer/printer.h" class ConnectView : public Gtk::VBox { Gtk::HBox m_hbox; Gtk::Image m_image; Gtk::ToggleButton m_connect; Gtk::Label m_port_label; Gtk::Alignment m_port_align; Gtk::ComboBoxEntryText m_combo; bool m_setting_state; Settings *m_settings; Printer *m_printer; void connect_toggled(); void serial_state_changed (SerialState state); void signal_entry_changed(); void find_ports(); public: ConnectView (Printer *printer, Settings *m_settings, bool show_connect = true); void try_set_state (bool connected); }; #endif // CONNECT_VIEW_H repsnapper-2.3.2a5/src/ui/filechooser.cpp000066400000000000000000000134311231531733200203370ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #include "filechooser.h" #include "view.h" #include "model.h" RSFilechooser::RSFilechooser(View * view_) : view(view_), filetype(MODEL) { builder = view->getBuilder(); builder->get_widget("filechooser", chooser); if (!chooser) { cerr << "no 'filechooser' in GUI!" << endl; return; } chooser->signal_update_preview().connect_notify ( sigc::bind(sigc::mem_fun (*this, &RSFilechooser::on_filechooser_preview), chooser) ); // file patterns allfiles.set_name(_("All Files")); allfiles.add_pattern("*"); modelfiles.set_name(_("Models")); modelfiles.add_pattern("*.amf"); modelfiles.add_pattern("*.AMF"); modelfiles.add_pattern("*.stl"); modelfiles.add_pattern("*.STL"); modelfiles.add_pattern("*.svg"); modelfiles.add_pattern("*.SVG"); modelfiles.add_pattern("*.wrl"); modelfiles.add_pattern("*.WRL"); gcodefiles.set_name(_("GCode")); gcodefiles.add_pattern("*.g"); gcodefiles.add_pattern("*.G"); gcodefiles.add_pattern("*.gcode"); gcodefiles.add_pattern("*.GCODE"); settingsfiles.set_name(_("Settings")); settingsfiles.add_pattern("*.conf"); chooser->add_filter(allfiles); chooser->add_filter(modelfiles); chooser->add_filter(gcodefiles); chooser->add_filter(settingsfiles); view->connect_button ("load_save_button", sigc::mem_fun(*this, &RSFilechooser::do_action)); chooser->signal_file_activated().connect (sigc::mem_fun(*this, &RSFilechooser::do_action)); set_loading(filetype); } RSFilechooser::~RSFilechooser() { chooser = NULL; } void RSFilechooser::set_filetype(FileType type) { if (!chooser) return; Gtk::Button *button = NULL; // if no argument re-apply the filetype we have already // to prevent "recent files" if ( type == UNDEF ) { type = filetype; } else { builder->get_widget ("load_save_button", button); } string labeltext = ""; switch(type) { case GCODE: chooser->set_select_multiple (false); chooser->set_current_folder (GCodePath); chooser->set_filter(gcodefiles); labeltext += _("GCode"); break; case SETTINGS: chooser->set_select_multiple (false); chooser->set_current_folder (SettingsPath); chooser->set_filter(settingsfiles); labeltext += _("Settings"); break; case SVG: chooser->set_current_folder (ModelPath); chooser->set_filter(modelfiles); labeltext += _("SVG"); break; case MODEL: default: chooser->set_current_folder (ModelPath); chooser->set_filter(modelfiles); labeltext += _("Model"); break; } if (button != NULL) button->set_label(button->get_label() + " " + labeltext); filetype = type; } void RSFilechooser::set_loading(FileType type) { chooser->set_action(Gtk::FILE_CHOOSER_ACTION_OPEN); chooser->set_select_multiple (true); view->show_widget("load_buttons", true); view->show_widget("save_buttons", false); Gtk::Button *button = NULL; builder->get_widget ("load_save_button", button); if (button) button->set_label(_("Load")); set_filetype(type); } void RSFilechooser::set_saving(FileType type) { chooser->set_select_multiple (false); chooser->set_action(Gtk::FILE_CHOOSER_ACTION_SAVE); chooser->set_do_overwrite_confirmation(true); view->show_widget("save_buttons", true); view->show_widget("load_buttons", false); Gtk::Button *button = NULL; builder->get_widget ("load_save_button", button); if (button) button->set_label(_("Save")); set_filetype(type); } void RSFilechooser::do_action() { const Gtk::FileChooserAction action = ((Gtk::FileChooser*)chooser)->get_action(); if (action == Gtk::FILE_CHOOSER_ACTION_OPEN) view->do_load(); else if (action == Gtk::FILE_CHOOSER_ACTION_SAVE) { switch(filetype) { case MODEL: view->do_save_stl(); break; case GCODE: view->do_save_gcode(); break; case SETTINGS: view->do_save_settings_as(); break; case SVG: { bool singlelayer = false; Gtk::CheckButton *mult; builder->get_widget("save_multiple_svg", mult); if (mult) singlelayer = mult->get_state(); view->do_slice_svg(singlelayer); } break; default: break; } } // get updated paths Model * model = view->get_model(); if (model) { ModelPath = model->settings.STLPath; GCodePath = model->settings.GCodePath; SettingsPath = model->settings.SettingsPath; } else cerr << "no settings default paths" << endl; if (filetype == GCODE) view->show_notebooktab("gcode_tab", "controlnotebook"); else view->show_notebooktab("model_tab", "controlnotebook"); } bool RSFilechooser::on_filechooser_key(GdkEventKey* event) { if (event->state & GDK_SHIFT_MASK) { switch (event->keyval) { case GDK_Return: do_action(); } return true; } return false; } void RSFilechooser::on_filechooser_preview(Gtk::FileChooserWidget *chooser) { if (!chooser) return; Glib::RefPtr< Gio::File > pfile = chooser->get_preview_file(); if (!pfile) return; //cerr << "file " << pfile->get_path() << endl; Gio::FileType ftype = pfile->query_file_type(); //cerr << ftype << endl; if (ftype != Gio::FILE_TYPE_NOT_KNOWN) view->preview_file(pfile); } repsnapper-2.3.2a5/src/ui/filechooser.h000066400000000000000000000032751231531733200200110ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2012 martin.dieringer@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #pragma once #include "stdafx.h" #include #include class View; class RSFilechooser { public: enum FileType { UNDEF, MODEL, SVG, RFO, GCODE, SETTINGS }; RSFilechooser(View * view); ~RSFilechooser(); void set_loading(FileType type); void set_saving (FileType type); void set_filetype(FileType type = UNDEF); FileType get_filetype() { return filetype; }; void do_action(); vector< Glib::RefPtr < Gio::File > > get_files() { return chooser->get_files(); }; private: View * view; Gtk::FileChooserWidget *chooser; Glib::RefPtr builder; FileType filetype; string ModelPath, GCodePath, SettingsPath; Gtk::FileFilter allfiles, modelfiles, gcodefiles, settingsfiles; void on_filechooser_preview (Gtk::FileChooserWidget *chooser); bool on_filechooser_key (GdkEventKey* event); void on_controlnotebook_switch (Gtk::Widget* page, guint page_num); }; repsnapper-2.3.2a5/src/ui/prefs_dlg.cpp000066400000000000000000000104401231531733200177770ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "prefs_dlg.h" #define MULTI_SETTINGS 0 // test some GUI / hardware selector fun #if MULTI_SETTINGS namespace { // Find all the .conf hardware settings templates std::vector get_settings_configs() { std::vector ret; std::vector dirs = Platform::getConfigPaths(); for (std::vector::const_iterator i = dirs.begin(); i != dirs.end(); ++i) { std::string settings_name = Glib::build_filename (*i, "settings"); Glib::RefPtr dir = Gio::File::create_for_path(settings_name); if(dir->query_exists()) { Glib::RefPtr entries = dir->enumerate_children(); if (!entries) continue; Glib::RefPtr info; while ( (info = entries->next_file()) ) { if (Platform::has_extension(info->get_name(), "conf")) ret.push_back(Glib::build_filename(settings_name,info->get_name())); } } } return ret; } } #endif void PrefsDlg::handle_response(int, Gtk::Dialog *dialog) { dialog->hide(); } PrefsDlg::PrefsDlg(Model *model, Glib::RefPtr &builder) : m_model (model) { builder->get_widget ("preferences_dlg", m_preferences_dlg); builder->get_widget ("settings_icons", m_settings_icons); builder->get_widget ("settings_overview", m_settings_overview); builder->get_widget ("settings_notebook", m_settings_notebook); m_preferences_dlg->set_icon_name("gtk-convert"); m_preferences_dlg->signal_response().connect ( sigc::bind(sigc::mem_fun(*this, &PrefsDlg::handle_response), m_preferences_dlg)); } PrefsDlg::~PrefsDlg() { } bool PrefsDlg::load_settings() { #if MULTI_SETTINGS if (!m_settings.empty()) return false; std::vector m_settings; std::vector configs = get_settings_configs(); for (std::vector::const_iterator i = configs.begin(); i != configs.end(); ++i) { Settings *set = new Settings(); fprintf (stderr, "load from %s\n", (*i).c_str()); try { set->load_settings(Gio::File::create_for_path(*i)); cerr << "settings '" << set->get_string("Global","SettingsName") << "' icon '" << set->get_string("Global","SettingsImage") << "'\n"; m_settings.push_back(set); } catch (...) { g_warning ("Error parsing '%s'", i->c_str()); } } Gtk::VBox *vbox = new Gtk::VBox(); for (std::vector::const_iterator set = m_settings.begin(); set != m_settings.end(); ++set) { Glib::RefPtr pixbuf; try { pixbuf = Gdk::Pixbuf::create_from_file((*set)->get_image_path()); } catch (...) { g_warning ("Failed to load '%s'", (*set)->get_image_path().c_str()); continue; } Gtk::Button *button = new Gtk::ToggleButton(); Gtk::VBox *box = new Gtk::VBox(); Gtk::Label *label = new Gtk::Label((*set)->get_string("Global","SettingsName")); box->pack_end(*label, true, true); Gtk::Image *image = new Gtk::Image(pixbuf); box->pack_end(*image, true, true); button->add(*box); vbox->pack_end(*button, true, true); } m_settings_icons->add(*vbox); m_settings_icons->show_all(); #else // disable it all for now static bool hidden = false; if (!hidden) { m_settings_icons->hide(); m_settings_overview->hide(); m_settings_notebook->get_nth_page(0)->hide(); hidden = true; } #endif return true; } void PrefsDlg::show() { load_settings(); m_preferences_dlg->show(); m_preferences_dlg->raise(); } repsnapper-2.3.2a5/src/ui/prefs_dlg.h000066400000000000000000000026431231531733200174520ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SETTINGS_UI_H #define SETTINGS_UI_H #include "settings.h" #include class PrefsDlg { Model *m_model; Gtk::Dialog *m_preferences_dlg; Gtk::VBox *m_settings_overview; Gtk::Notebook *m_settings_notebook; Gtk::ScrolledWindow *m_settings_icons; void handle_response(int, Gtk::Dialog *dialog); std::vector m_settings; bool load_settings(); public: PrefsDlg(Model *model, Glib::RefPtr &builder); ~PrefsDlg(); void show(); void set_icon_from_file(const string path) {m_preferences_dlg->set_icon_from_file(path);} }; #endif // SETTINGS_H repsnapper-2.3.2a5/src/ui/progress.cpp000066400000000000000000000110751231531733200177030ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "model.h" #include "progress.h" //ViewProgress::ViewProgress(Progress *progress, Gtk::Box *box, Gtk::ProgressBar *bar, Gtk::Label *label) : ViewProgress::ViewProgress(Gtk::Box *box, Gtk::ProgressBar *bar, Gtk::Label *label) : m_box (box), m_bar(bar), m_label(label), to_terminal(true) { m_bar_max = 0.0; box->hide(); // progress->m_signal_progress_start.connect (sigc::mem_fun(*this, &ViewProgress::start)); // progress->m_signal_progress_update.connect (sigc::mem_fun(*this, &ViewProgress::update)); // progress->m_signal_progress_stop.connect (sigc::mem_fun(*this, &ViewProgress::stop)); // progress->m_signal_progress_label.connect (sigc::mem_fun(*this, &ViewProgress::set_label)); } void ViewProgress::start (const char *label, double max) { do_continue = true; m_box->show(); m_bar_max = max; this->label = label; m_label->set_label (label); m_bar_cur = 0.0; m_bar->set_fraction(0.0); start_time.assign_current_time(); Gtk::Main::iteration(false); } bool ViewProgress::restart (const char *label, double max) { if (!do_continue) return false; //m_box->show(); if (to_terminal) { Glib::TimeVal now; now.assign_current_time(); const int time_used = (int) round((now - start_time).as_double()); // seconds cerr << m_label->get_label() << " -- " << _(" done in ") << time_used << _(" seconds") << " " << endl; } m_bar_max = max; this->label = label; m_label->set_label (label); m_bar_cur = 0.0; m_bar->set_fraction(0.0); start_time.assign_current_time(); //g_main_context_iteration(NULL,false); Gtk::Main::iteration(false); return true; } void ViewProgress::stop (const char *label) { if (to_terminal) { Glib::TimeVal now; now.assign_current_time(); const int time_used = (int) round((now - start_time).as_double()); // seconds cerr << m_label->get_label() << " -- " << _(" done in ") << time_used << _(" seconds") << " " << endl; } this->label = label; m_label->set_label (label); m_bar_cur = m_bar_max; m_bar->set_fraction(1.0); m_box->hide(); Gtk::Main::iteration(false); } string timeleft_str(long seconds) { ostringstream ostr; int hrs = (int)(seconds/3600); if (hrs>0) { if (hrs>1) ostr << hrs << _("h "); else ostr << hrs << _("h "); seconds -= 3600*hrs; } if (seconds > 60) ostr << (int)seconds/60 << _("m "); if (hrs == 0 && seconds<300) ostr << (int)seconds%60 << _("s"); return ostr.str(); } bool ViewProgress::update (const double value, bool take_priority) { // Don't allow progress to go backward if (value < m_bar_cur) return do_continue; m_bar_cur = CLAMP(value, 0, 1.0); m_bar->set_fraction(value / m_bar_max); ostringstream o; if(floor(value) != value && floor(m_bar_max) != m_bar_max) o.precision(1); else o.precision(0); o << fixed << value <<"/"<< m_bar_max; m_bar->set_text(o.str()); if (to_terminal) { int perc = (int(m_bar->get_fraction()*100)); cerr << m_label->get_label() << " " << o.str() << " -- " << perc << "% \r"; } if (value > 0) { Glib::TimeVal now; now.assign_current_time(); const double used = (now - start_time).as_double(); // seconds const double total = used * m_bar_max / value; const long left = (long)(total-used); m_label->set_label(label+" ("+timeleft_str(left)+")"); } if (take_priority) while( gtk_events_pending () ) gtk_main_iteration (); Gtk::Main::iteration(false); return do_continue; } void ViewProgress::set_label (const std::string label) { std::string old = m_label->get_label(); this->label = label; if (old != label) m_label->set_label (label); Gtk::Main::iteration(false); } void ViewProgress::set_terminal_output (bool terminal) { to_terminal=terminal; } repsnapper-2.3.2a5/src/ui/progress.h000066400000000000000000000050341231531733200173460ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PROGRESS_H #define PROGRESS_H #include #include class Progress { // ViewProgress * v_progress; public: // Progress(ViewProgress * v_progress){this->v_progress = v_progress;}; // Progress reporting sigc::signal< void, const char *, double > m_signal_progress_start; sigc::signal< void, double > m_signal_progress_update; sigc::signal< void, const char * > m_signal_progress_stop; sigc::signal< void, const char * > m_signal_progress_label; // helpers void start (const char *label, double max) const { m_signal_progress_start.emit (label, max); } void stop (const char *label) const { m_signal_progress_stop.emit (label); } void update (const double value) const { m_signal_progress_update.emit (value); } void set_label (const char * label) const { m_signal_progress_label.emit (label); } }; class ViewProgress { Gtk::Box *m_box; Gtk::ProgressBar *m_bar; Gtk::Label *m_label; double m_bar_max; double m_bar_cur; Glib::TimeVal start_time; string label; public: void start (const char *label, double max); bool restart (const char *label, double max); void stop (const char *label = ""); bool update (const double value, bool take_priority=true); //ViewProgress(Progress *model, Gtk::Box *box, Gtk::ProgressBar *bar, Gtk::Label *label); ViewProgress(){}; ViewProgress(Gtk::Box *box, Gtk::ProgressBar *bar, Gtk::Label *label); void set_label (std::string label); double maximum() { return m_bar_max; } double value() { return m_bar_cur; } bool to_terminal; void set_terminal_output(bool terminal); bool do_continue; void stop_running(){do_continue = false;}; }; #endif // PROGRESS_H repsnapper-2.3.2a5/src/ui/view.cpp000066400000000000000000001676401231531733200170230ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #if HAVE_GTK_NEW_KEYSMS #include #endif #include "view.h" #include "model.h" #include "objtree.h" #include "flatshape.h" #include "render.h" #include "settings.h" #include "prefs_dlg.h" #include "progress.h" #include "connectview.h" #include "widgets.h" #include "gitversion.h" bool View::on_delete_event(GdkEventAny* event) { Gtk::Main::quit(); return false; } void View::connect_button(const char *name, const sigc::slot &slot) { Gtk::Widget *bw = NULL; m_builder->get_widget (name, bw); // try Button Gtk::Button *button = dynamic_cast(bw); if (button) button->signal_clicked().connect (slot); else { // try ToolButton Gtk::ToolButton *button = dynamic_cast(bw); if (button) button->signal_clicked().connect (slot); else { std::cerr << "missing button " << name << "\n"; } } } void View::connect_action(const char *name, const sigc::slot &slot) { Glib::RefPtr object; object = m_builder->get_object (name); Glib::RefPtr action = Glib::RefPtr::cast_dynamic(object); if (action) action->signal_activate().connect (slot); else { std::cerr << "missing action " << name << "\n"; } } void View::connect_toggled(const char *name, const sigc::slot &slot) { Gtk::ToggleButton *button = NULL; m_builder->get_widget (name, button); if (button) button->signal_toggled().connect (sigc::bind(slot, button)); else { std::cerr << "missing toggle button " << name << "\n"; } } void View::connect_tooltoggled(const char *name, const sigc::slot &slot) { Gtk::ToggleToolButton *button = NULL; m_builder->get_widget (name, button); if (button) button->signal_toggled().connect (sigc::bind(slot, button)); else { std::cerr << "missing toggle button " << name << "\n"; } } void View::move_gcode_to_platform () { m_model->translateGCode(- m_model->gcode.Min + m_model->settings.getPrintMargin()); } void View::convert_to_gcode () { extruder_selected(); // be sure to get extruder settings from gui PrintInhibitor inhibitPrint(m_printer); if (m_printer->IsPrinting()) { m_printer->error (_("Complete print before converting"), _("Converting to GCode while printing will abort the print")); return; } m_model->ConvertToGCode(); } void View::preview_file (Glib::RefPtr< Gio::File > file) { if (!m_model) return; m_model->preview_shapes.clear(); if (!m_model->settings.get_boolean("Display","PreviewLoad")) return; if (!file) return; //cerr << "view " <get_path() << endl; m_model->preview_shapes = m_model->ReadShapes(file,10000); bool display_poly = m_model->settings.get_boolean("Display","DisplayPolygons"); m_model->settings.set_boolean("Display","DisplayPolygons", true); if (m_model->preview_shapes.size()>0) { Vector3d pMax = Vector3d(G_MINDOUBLE, G_MINDOUBLE, G_MINDOUBLE); Vector3d pMin = Vector3d(G_MAXDOUBLE, G_MAXDOUBLE, G_MAXDOUBLE); for (uint i = 0; i < m_model->preview_shapes.size(); i++) { m_model->preview_shapes[i]->PlaceOnPlatform(); Vector3d stlMin = m_model->preview_shapes[i]->t_Min(); Vector3d stlMax = m_model->preview_shapes[i]->t_Max(); for (uint k = 0; k < 3; k++) { pMin[k] = min(stlMin[k], pMin[k]); pMax[k] = max(stlMax[k], pMax[k]); } } //cerr << pMin << pMax << endl; m_renderer->set_zoom((pMax - pMin).find_max()*2); // Matrix4fT tr; // setArcballTrans(tr,(pMin+pMax)/2); // m_renderer->set_transform(tr); } queue_draw(); m_model->settings.set_boolean("Display","DisplayPolygons",display_poly); } void View::load_stl () { m_filechooser->set_loading(RSFilechooser::MODEL); show_notebooktab("file_tab", "controlnotebook"); // FileChooser::ioDialog (m_model, this, FileChooser::OPEN, FileChooser::STL); } void View::autoarrange () { vector path = m_treeview->get_selection()->get_selected_rows(); m_model->AutoArrange(path); } void View::toggle_fullscreen() { static bool is_fullscreen = false; if (is_fullscreen) { unfullscreen(); is_fullscreen = false; } else { fullscreen(); is_fullscreen = true; } } void View::do_load () { PrintInhibitor inhibitPrint(m_printer); RSFilechooser::FileType type = m_filechooser->get_filetype(); if (type == RSFilechooser::GCODE) if (m_printer->IsPrinting()) { m_printer->error (_("Complete print before reading"), _("Reading GCode while printing will abort the print")); return; } m_model->preview_shapes.clear(); vector< Glib::RefPtr < Gio::File > > files = m_filechooser->get_files(); for (uint i= 0; i < files.size(); i++) { if (!files[i]) continue; // should never happen if (type == RSFilechooser::SETTINGS) m_model->LoadConfig(files[i]); else m_model->Read(files[i]); } show_notebooktab("model_tab", "controlnotebook"); } void View::do_slice_svg (bool singlelayer) { PrintInhibitor inhibitPrint(m_printer); std::vector< Glib::RefPtr < Gio::File > > files = m_filechooser->get_files(); if (files.size()>0) { if (!files[0]) return; // should never happen if (files[0]->query_exists()) if (!get_userconfirm(_("Overwrite File?"), files[0]->get_basename())) return; m_model->SliceToSVG(files[0], singlelayer); } } bool View::get_userconfirm(string maintext, string secondarytext) const { Gtk::MessageDialog *dialog = new Gtk::MessageDialog(maintext); if (secondarytext != "") dialog->set_secondary_text (secondarytext); dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); int response = dialog->run(); bool result = false; if (response == Gtk::RESPONSE_OK) result = true; delete dialog; return result; } void View::do_save_stl () { PrintInhibitor inhibitPrint(m_printer); std::vector< Glib::RefPtr < Gio::File > > files = m_filechooser->get_files(); if (files.size()>0) { if (!files[0]) return; // should never happen if (files[0]->query_exists()) if (!get_userconfirm(_("Overwrite File?"), files[0]->get_basename())) return; string file_path = files[0]->get_path(); uint len = file_path.length(); if (file_path.find(".amf") == len-4 || file_path.find(".AMF") == len-4) m_model->SaveAMF (files[0]); else m_model->SaveStl (files[0]); } } void View::do_save_gcode () { PrintInhibitor inhibitPrint(m_printer); std::vector< Glib::RefPtr < Gio::File > > files = m_filechooser->get_files(); if (files.size()>0) { if (!files[0]) return; // should never happen if (files[0]->query_exists()) if (!get_userconfirm(_("Overwrite File?"), files[0]->get_basename())) return; m_model->WriteGCode (files[0]); } } void View::save_stl () { PrintInhibitor inhibitPrint(m_printer); m_filechooser->set_saving (RSFilechooser::MODEL); show_notebooktab("file_tab", "controlnotebook"); // FileChooser::ioDialog (m_model, this, FileChooser::SAVE, FileChooser::STL); } void View::load_gcode () { PrintInhibitor inhibitPrint(m_printer); if (m_printer->IsPrinting()) { m_printer->error (_("Complete print before reading"), _("Reading GCode while printing will abort the print")); return; } m_filechooser->set_loading (RSFilechooser::GCODE); show_notebooktab("file_tab", "controlnotebook"); // FileChooser::ioDialog (m_model, this, FileChooser::OPEN, FileChooser::GCODE); } void View::save_gcode () { m_filechooser->set_saving (RSFilechooser::GCODE); show_notebooktab("file_tab", "controlnotebook"); //FileChooser::ioDialog (m_model, this, FileChooser::SAVE, FileChooser::GCODE); } void View::slice_svg () { m_filechooser->set_saving (RSFilechooser::SVG); show_notebooktab("file_tab", "controlnotebook"); //FileChooser::ioDialog (m_model, this, FileChooser::SAVE, FileChooser::SVG); } void View::send_gcode () { m_printer->Send (m_gcode_entry->get_text()); m_gcode_entry->select_region(0,-1); //m_gcode_entry->set_text(""); } View *View::create(Model *model) { std::vector dirs = Platform::getConfigPaths(); Glib::ustring ui; for (std::vector::const_iterator i = dirs.begin(); i != dirs.end(); ++i) { std::string f_name = Glib::build_filename (*i, "repsnapper.ui"); Glib::RefPtr file = Gio::File::create_for_path(f_name); try { char *ptr; gsize length; file->load_contents(ptr, length); ui = Glib::ustring(ptr); g_free(ptr); break; } catch(Gio::Error e) { switch(e.code()) { case Gio::Error::NOT_FOUND: continue; default: Gtk::MessageDialog dialog (_("Error reading UI description!!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text(e.what()); dialog.run(); return NULL; } } } if(ui.empty()) { Gtk::MessageDialog dialog (_("Couldn't find UI description!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text (_("Check that repsnapper has been correctly installed.")); dialog.run(); return NULL; } Glib::RefPtr builder; try { builder = Gtk::Builder::create_from_string(ui); } catch(const Gtk::BuilderError& ex) { Gtk::MessageDialog dialog (_("Error loading UI!"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); dialog.set_secondary_text(ex.what()); dialog.run(); throw ex; } View *view = 0; builder->get_widget_derived("main_window", view); view->setModel (model); return view; } void View::printing_changed() { bool printing = m_printer->IsPrinting(); if ( printing ) m_progress->start (_("Printing"), m_printer->GetTotalPrintingLines() ); else m_progress->stop (_("Done")); //rGlib::Mutex::Lock lock(mutex); m_model->SetIsPrinting(printing); //m_print_button->set_active(printing); if ( printing ) m_pause_button->set_active( false ); // while(Gtk::Main::events_pending()) // Gtk::Main::iteration(); } void View::enable_logging_toggled (Gtk::ToggleButton *button) { m_model->settings.set_boolean("Printer","Logging", button->get_active()); } void View::temp_monitor_enabled_toggled (Gtk::ToggleButton *button) { m_model->settings.set_boolean("Misc","TempReadingEnabled", button->get_active()); m_printer->UpdateTemperatureMonitor(); } void View::fan_enabled_toggled (Gtk::ToggleButton *button) { if (toggle_block) return; if (!button->get_active()) { if (!m_printer->Send ("M107")) { toggle_block = true; button->set_active(true); toggle_block = false; } } else { std::stringstream oss; oss << "M106 S" << (int)m_fan_voltage->get_value(); if (!m_printer->Send (oss.str())) { toggle_block = true; button->set_active(false); toggle_block = false; } } } void View::run_extruder () { double amount = m_extruder_length->get_value(); m_printer->RunExtruder (m_extruder_speed->get_value() * 60, amount, false, m_extruder_row->get_selected()); } void View::clear_logs() { log_view ->get_buffer()->set_text(""); echo_view->get_buffer()->set_text(""); err_view ->get_buffer()->set_text(""); m_model->ClearLogs(); } // open dialog to edit user gcode button void View::edit_custombutton(string name, string code, Gtk::ToolButton *button) { Gtk::Dialog *dialog; m_builder->get_widget ("custom_button_dialog", dialog); Gtk::Entry *nameentry; m_builder->get_widget ("custom_name", nameentry); nameentry->set_text(name); //if (name!="") nameentry->set_sensitive(false); Gtk::TextView *tview; m_builder->get_widget ("custom_gcode", tview); tview->get_buffer()->set_text(code); dialog->show(); // send result: dialog->signal_response().connect (sigc::bind(sigc::mem_fun(*this, &View::hide_custombutton_dlg), dialog)); } void View::hide_custombutton_dlg(int code, Gtk::Dialog *dialog) { Gtk::Entry *nameentry; m_builder->get_widget ("custom_name", nameentry); string name = nameentry->get_text(); Gtk::TextView *tview; m_builder->get_widget ("custom_gcode", tview); string gcode = tview->get_buffer()->get_text(); if (code==1) { // OK clicked // save in settings: m_model->settings.set_user_button(name, gcode); } dialog->hide(); } void View::add_custombutton(string name, string gcode) { Gtk::Toolbar *toolbar; m_builder->get_widget ("i_custom_toolbar", toolbar); if (toolbar) { //cerr << toolbar->get_n_items() << " items" << endl; Gtk::ToolButton *button = new Gtk::ToolButton(name); button->set_is_important(true); toolbar->append(*button, sigc::bind(sigc::mem_fun(*this, &View::custombutton_pressed), name, button)); button->set_tooltip_text(gcode); button->set_sensitive(true); toolbar->set_sensitive(true); toolbar->show_all(); } else cerr << "no Toolbar for button!" << endl; } void View::custombutton_pressed(string name, Gtk::ToolButton *button) { Gtk::ToggleButton *rembutton; m_builder->get_widget ("i_remove_custombutton", rembutton); Gtk::ToggleButton *editbutton; m_builder->get_widget ("i_edit_custombutton", editbutton); Gtk::Toolbar *toolbar; m_builder->get_widget ("i_custom_toolbar", toolbar); if (!toolbar) return; if (rembutton->get_active()) { rembutton->set_active(false); if (m_model->settings.del_user_button(name)) { toolbar->remove(*button); } } else if (editbutton->get_active()) { editbutton->set_active(false); edit_custombutton(name, m_model->settings.get_user_gcode(name), button); } else { m_printer->Send(m_model->settings.get_user_gcode(name)); } } void View::log_msg(Gtk::TextView *tview, string s) { //Glib::Mutex::Lock lock(mutex); if (!tview || s.length() == 0) return; if (!m_model || !m_model->settings.get_boolean("Printer","Logging")) return; Glib::RefPtr c_buffer = tview->get_buffer(); Gtk::TextBuffer::iterator tend = c_buffer->end(); c_buffer->insert (tend, s); tend = c_buffer->end(); tview->scroll_to(tend); //tview->queue_draw(); // while(Gtk::Main::events_pending()) // Gtk::Main::iteration(); } void View::err_log(string s) { log_msg(err_view,s); } void View::comm_log(string s) { log_msg(log_view,s); } void View::echo_log(string s) { log_msg(echo_view,s); } void View::set_logging(bool logging) { // cerr << "set log " << logging<< endl; // if (logging) { // logprint_timeout = Glib::signal_timeout().connect // (sigc::mem_fun(*this, &View::logprint_timeout_cb), 500); // } else { // if (logprint_timeout.connected()) { // logprint_timeout_cb(); // logprint_timeout.disconnect(); // } // } } bool View::logprint_timeout_cb() { // GDK_THREADS_ENTER (); // cerr << "log "; // // while(Gtk::Main::events_pending()) // // Gtk::Main::iteration(); // if (m_printer->error_buffer.length() > 0) { // err_log (m_printer->error_buffer); // m_printer->error_buffer = ""; // } // if (m_printer->echo_buffer.length() > 0) { // echo_log(m_printer->echo_buffer); // m_printer->echo_buffer = ""; // } // if (m_printer->commlog_buffer.length() > 0) { // comm_log(m_printer->commlog_buffer); // m_printer->commlog_buffer = ""; // } // // while(Gtk::Main::events_pending()) // // Gtk::Main::iteration(); // GDK_THREADS_LEAVE (); return true; } void View::hide_on_response(int, Gtk::Dialog *dialog) { dialog->hide(); } void View::set_icon_file(Glib::RefPtr file) { iconfile = file; if (iconfile) { set_icon_from_file(iconfile->get_path()); m_settings_ui->set_icon_from_file(iconfile->get_path()); } else set_icon_name("gtk-convert"); } void View::show_dialog(const char *name) { Gtk::Dialog *dialog; m_builder->get_widget (name, dialog); if (!dialog) { cerr << "no such dialog " << name << "\n"; return; } if (iconfile) dialog->set_icon_from_file(iconfile->get_path()); else dialog->set_icon_name("gtk-convert"); dialog->signal_response().connect (sigc::bind(sigc::mem_fun(*this, &View::hide_on_response), dialog)); dialog->show(); // dialog->set_transient_for (*this); } void View::show_preferences() { m_settings_ui->show(); } void View::about_dialog() { show_dialog ("about_dialog"); } void View::load_settings() { m_filechooser->set_loading(RSFilechooser::SETTINGS); show_notebooktab("file_tab", "controlnotebook"); } // save to standard config file void View::save_settings() { std::vector user_config_bits(3); user_config_bits[0] = Glib::get_user_config_dir(); user_config_bits[1] = "repsnapper"; user_config_bits[2] = "repsnapper.conf"; std::string user_config_file = Glib::build_filename (user_config_bits); Glib::RefPtr conffile = Gio::File::create_for_path(user_config_file); save_settings_to(conffile); } // gets config file from user void View::save_settings_as() { m_filechooser->set_saving (RSFilechooser::SETTINGS); show_notebooktab("file_tab", "controlnotebook"); } // callback from m_filechooser for settings file void View::do_save_settings_as() { std::vector< Glib::RefPtr < Gio::File > > files = m_filechooser->get_files(); if (files.size()>0) { if (!files[0]) return; // should never happen if (files[0]->query_exists()) if (!get_userconfirm(_("Overwrite File?"), files[0]->get_basename())) return; save_settings_to(files[0]); } //FileChooser::ioDialog (m_model, this, FileChooser::SAVE, FileChooser::SETTINGS); } // save to given config file void View::save_settings_to(Glib::RefPtr < Gio::File > file) { m_model->settings.SettingsPath = file->get_parent()->get_path(); saveWindowSizeAndPosition(m_model->settings); m_model->SaveConfig(file); } void View::inhibit_print_changed() { if (m_printer->IsInhibited()) { if (!m_printer->IsPrinting()) m_pause_button->set_sensitive (false); m_print_button->set_sensitive (false); } else { m_pause_button->set_sensitive (true); m_print_button->set_sensitive (true); } } void View::alert (Gtk::MessageType t, const char *message, const char *secondary) { Gtk::MessageDialog dialog (*this, message, false /* markup */, t, Gtk::BUTTONS_CLOSE, true); if (secondary) dialog.set_secondary_text (secondary); dialog.run(); } void View::rot_object_from_spinbutton() { if (toggle_block) return; Gtk::SpinButton *spB; m_builder->get_widget("rot_x", spB); const double xangle = spB->get_value()*M_PI/180.; m_builder->get_widget("rot_y", spB); const double yangle = spB->get_value()*M_PI/180.; m_builder->get_widget("rot_z", spB); const double zangle = spB->get_value()*M_PI/180.; vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; itransform3D.rotate_to(shapes[i]->Center, xangle, yangle, zangle); } else if (objects.size()>0) for (uint i=0; itransform3D.rotate_to(objects[i]->center(), xangle, yangle, zangle); } update_scale_value(); m_model->ModelChanged(); queue_draw(); } bool View::rotate_selection (Vector3d axis, double angle) { vector shapes; vector objects; get_selected_objects (objects, shapes); if (objects.size()>0) for (uint o=0; otransform3D; transf.rotate(objects[o]->center(),axis, angle); } else if (shapes.size()>0) { for (uint i=0; iRotate(axis, angle); } update_scale_value(); update_rot_value(); return true; } void View::update_rot_value() { toggle_block = true; vector shapes; vector objects; get_selected_objects (objects, shapes); Transform3D *trans = NULL; if (objects.size()>0) { trans = &objects.back()->transform3D; } else if (shapes.size()>0) { trans = &shapes.back()->transform3D; } if (trans != NULL) { Gtk::SpinButton *rot_sb; m_builder->get_widget("rot_x", rot_sb); rot_sb->set_value(trans->getRotX()*180/M_PI); m_builder->get_widget("rot_y", rot_sb); rot_sb->set_value(trans->getRotY()*180/M_PI); m_builder->get_widget("rot_z", rot_sb); rot_sb->set_value(trans->getRotZ()*180/M_PI); } toggle_block = false; } void View::twist_selection (double angle) { vector shapes; vector objects; get_selected_objects (objects, shapes); for (uint i=0; iTwistObject (shapes[i], NULL, angle); queue_draw(); } void View::invertnormals_selection () { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; iInvertNormals(shapes[i], NULL); else for (uint i=0; iInvertNormals(NULL, objects[i]); queue_draw(); } void View::hollow_selection () { vector shapes; vector transforms; get_selected_shapes (shapes, transforms); for (uint i=0; imakeHollow(3); m_model->ModelChanged(); queue_draw(); } void View::placeonplatform_selection () { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; iPlaceOnPlatform(shapes[i], NULL); else for (uint i=0; iPlaceOnPlatform(NULL, objects[i]); queue_draw(); } void View::mirror_selection () { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; iMirror(shapes[i], NULL); else for (uint i=0; iMirror(NULL, objects[i]); queue_draw(); } void View::stl_added (Gtk::TreePath &path) { m_treeview->expand_all(); m_treeview->get_selection()->unselect_all(); m_treeview->get_selection()->select (path); } void View::set_SliderBBox(Vector3d bbmin, Vector3d bbmax) { double smin = 0, //max(0.0, bbmin.z()), smax = max(smin+0.001, bbmax.z()); Gtk::HScale * scale; m_builder->get_widget ("Display.LayerValue", scale); if (scale) scale->set_range (smin, smax); m_builder->get_widget ("Display.GCodeDrawStart", scale); if (scale) scale->set_range (smin, smax); m_builder->get_widget ("Display.GCodeDrawEnd", scale); if (scale) scale->set_range (smin, smax); } void View::model_changed () { m_translation_row->selection_changed(); set_SliderBBox(m_model->Min, m_model->Max); show_notebooktab("model_tab", "controlnotebook"); queue_draw(); } void View::show_widget (string name, bool visible) const { Gtk::Widget *w; m_builder->get_widget (name, w); if (w) if (visible) w->show(); else w->hide(); else cerr << "no '" << name << "' in GUI" << endl; } void View::show_notebooktab (string name, string notebookname) const { Gtk::Notebook *nb; m_builder->get_widget (notebookname, nb); if (!nb) { cerr << "no notebook " << notebookname << endl; return;} Gtk::Widget *w; m_builder->get_widget (name, w); if (!w) { cerr << "no widget " << name << endl; return;} int num = nb->page_num(*w); if (num >= 0) nb->set_current_page(num); else cerr << "no page " << num << endl; } void View::gcode_changed () { set_SliderBBox(m_model->gcode.Min, m_model->gcode.Max); // show gcode result show_notebooktab("gcode_result_win", "gcode_text_notebook"); show_notebooktab("gcode_tab", "controlnotebook"); } void View::auto_rotate() { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; iOptimizeRotation(shapes[i], NULL); else for (uint i=0; iOptimizeRotation(NULL, objects[i]); update_scale_value(); update_rot_value(); } void View::power_toggled(Gtk::ToggleToolButton *button) { m_printer->SwitchPower (button->get_active()); } void View::print_clicked() { m_printer->StartPrinting(); //printing_changed(); } // void View::stop_clicked() // { // m_printer->StopButton(); // printing_changed(); // } void View::pause_toggled(Gtk::ToggleToolButton *button) { if (button->get_active()) m_printer->StopPrinting(); else m_printer->ContinuePrinting(); } void View::reset_clicked() { if (get_userconfirm(_("Reset Printer?"))) { m_printer->Reset(); //printing_changed(); } } void View::home_all() { if (m_printer->IsPrinting()) return; m_printer->Send ("G28"); for (uint i = 0; i < 3; i++) m_axis_rows[i]->notify_homed(); } void View::update_settings_gui() { // awful cast-ness to avoid having glibmm headers everywhere. m_model->settings.set_to_gui (m_builder); Gtk::AboutDialog *about; m_builder->get_widget ("about_dialog", about); about->set_version(VERSION); if (GIT_COMMIT != "Unknown") about->set_comments("git version:\n"+GIT_COMMIT + "\nDate:\n" + GIT_COMMIT_DATE); Gtk::Toolbar *toolbar; m_builder->get_widget ("i_custom_toolbar", toolbar); if (toolbar) { vector buts = toolbar->get_children(); for (guint i=buts.size(); i>0; i--) { toolbar->remove(*buts[i-1]); } vector buttonlabels = m_model->settings.get_string_list("UserButtons","Labels"); for (guint i=0; i< buttonlabels.size(); i++) { add_custombutton(buttonlabels[i], m_model->settings.get_user_gcode(buttonlabels[i])); } } update_extruderlist(); } void View::handle_ui_settings_changed() { m_model->ClearPreview(); queue_draw(); } void View::temp_changed() { for (int i = 0; i < TEMP_LAST; i++) m_temps[i]->update_temp (m_printer->get_temp((TempType) i)); } bool View::move_selection(float x, float y, float z) { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) { for (uint s=0; smove(Vector3d(x,y,z)); } } else if (objects.size()>0) { for (uint o=0; otransform3D.move(Vector3d(x,y,z)); } } else { m_model->translateGCode(Vector3d(10*x,10*y,z)); } return true; } bool View::key_pressed_event(GdkEventKey *event) { // cerr << "key " << event->keyval << endl; // if (m_treeview->get_selection()->count_selected_rows() <= 0) // return false; switch (event->keyval) { case GDK_Tab: { if (event->state & GDK_CONTROL_MASK) { Gtk::Notebook *nb; m_builder->get_widget ("controlnotebook", nb); if (nb) { if (event->state & GDK_SHIFT_MASK) nb->prev_page(); else nb->next_page(); } return true; } } break; case GDK_Escape: { stop_progress(); return true; } break; case GDK_Delete: case GDK_KP_Delete: delete_selected_objects(); return true; default: return false; } return false; } View::View(BaseObjectType* cobject, const Glib::RefPtr& builder) : Gtk::Window(cobject), m_builder(builder), m_model(NULL), printtofile_name("") { toggle_block = false; // Menus connect_action ("OpenStl", sigc::mem_fun(*this, &View::load_stl) ); connect_action ("OpenGCode", sigc::mem_fun(*this, &View::load_gcode) ); connect_action ("Quit", sigc::ptr_fun(&Gtk::Main::quit)); connect_action ("About", sigc::mem_fun(*this, &View::about_dialog) ); connect_action ("Fullscreen", sigc::mem_fun(*this, &View::toggle_fullscreen) ); connect_action ("PreferencesDialog", sigc::mem_fun(*this, &View::show_preferences) ); connect_action ("LoadSettings", sigc::mem_fun(*this, &View::load_settings)); connect_action ("SaveSettings", sigc::mem_fun(*this, &View::save_settings)); connect_action ("SaveSettingsAs", sigc::mem_fun(*this, &View::save_settings_as)); // pronterface-mode connect_button ("printtofilebutton", sigc::mem_fun(*this, &View::PrintToFile) ); #if 0 // Simple tab connect_button ("s_load_stl", sigc::mem_fun(*this, &View::load_stl) ); connect_button ("s_convert_gcode", sigc::mem_fun(*this, &View::ConvertToGCode) ); connect_button ("s_load_gcode", sigc::mem_fun(*this, &View::load_gcode) ); connect_button ("s_print", sigc::mem_fun(*this, &View::SimplePrint) ); #endif // View tab connect_button ("m_load_stl", sigc::mem_fun(*this, &View::load_stl) ); connect_button ("Misc.AutoArrange",sigc::mem_fun(*this, &View::autoarrange) ); connect_button ("m_save_stl", sigc::mem_fun(*this, &View::save_stl) ); connect_button ("m_slice_svg", sigc::mem_fun(*this, &View::slice_svg) ); connect_button ("m_delete", sigc::mem_fun(*this, &View::delete_selected_objects) ); connect_button ("m_duplicate", sigc::mem_fun(*this, &View::duplicate_selected_objects) ); connect_button ("m_split", sigc::mem_fun(*this, &View::split_selected_objects) ); connect_button ("m_merge", sigc::mem_fun(*this, &View::merge_selected_objects) ); connect_button ("m_divide", sigc::mem_fun(*this, &View::divide_selected_objects) ); connect_button ("m_auto_rotate", sigc::mem_fun(*this, &View::auto_rotate) ); connect_button ("m_normals", sigc::mem_fun(*this, &View::invertnormals_selection)); connect_button ("m_hollow", sigc::mem_fun(*this, &View::hollow_selection)); connect_button ("m_platform", sigc::mem_fun(*this, &View::placeonplatform_selection)); connect_button ("m_mirror", sigc::mem_fun(*this, &View::mirror_selection)); connect_button ("twist_neg", sigc::bind(sigc::mem_fun(*this, &View::twist_selection), -M_PI/12)); connect_button ("twist_pos", sigc::bind(sigc::mem_fun(*this, &View::twist_selection), M_PI/12)); connect_button ("progress_stop", sigc::mem_fun(*this, &View::stop_progress)); connect_button ("copy_extruder", sigc::mem_fun(*this, &View::copy_extruder)); connect_button ("remove_extruder", sigc::mem_fun(*this, &View::remove_extruder)); m_builder->get_widget ("m_treeview", m_treeview); // Insert our keybindings all around the place signal_key_press_event().connect (sigc::mem_fun(*this, &View::key_pressed_event) ); m_treeview->signal_key_press_event().connect (sigc::mem_fun(*this, &View::key_pressed_event) ); // m_treeview->set_reorderable(true); // this is too simple m_treeview->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); m_translation_row = new TranslationSpinRow (this, m_treeview); Gtk::SpinButton *scale_value; m_builder->get_widget("m_scale_value", scale_value); scale_value->set_range(0.01, 10.0); scale_value->set_value(1.0); m_treeview->get_selection()->signal_changed().connect (sigc::mem_fun(*this, &View::tree_selection_changed)); scale_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::scale_selection)); m_builder->get_widget("scale_x", scale_value); scale_value->set_range(0.01, 10.0); scale_value->set_value(1.0); scale_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::scale_object_x)); m_builder->get_widget("scale_y", scale_value); scale_value->set_range(0.01, 10.0); scale_value->set_value(1.0); scale_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::scale_object_y)); m_builder->get_widget("scale_z", scale_value); scale_value->set_range(0.01, 10.0); scale_value->set_value(1.0); scale_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::scale_object_z)); Gtk::SpinButton *rot_value; m_builder->get_widget("rot_x", rot_value); rot_value->set_range(0.00, 360.0); rot_value->set_value(0); rot_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::rot_object_from_spinbutton)); m_builder->get_widget("rot_y", rot_value); rot_value->set_range(0.00, 360.0); rot_value->set_value(0); rot_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::rot_object_from_spinbutton)); m_builder->get_widget("rot_z", rot_value); rot_value->set_range(0.00, 360.0); rot_value->set_value(0); rot_value->signal_value_changed().connect (sigc::mem_fun(*this, &View::rot_object_from_spinbutton)); //add_statusbar_msg("m_scale_event_box", _("Scale the selected object")); // GCode tab m_builder->get_widget ("g_gcode", m_gcode_entry); m_gcode_entry->set_activates_default(); m_gcode_entry->signal_activate().connect (sigc::mem_fun(*this, &View::send_gcode));; connect_button ("g_load_gcode", sigc::mem_fun(*this, &View::load_gcode) ); connect_button ("g_convert_gcode", sigc::mem_fun(*this, &View::convert_to_gcode) ); connect_button ("g_save_gcode", sigc::mem_fun(*this, &View::save_gcode) ); connect_button ("g_send_gcode", sigc::mem_fun(*this, &View::send_gcode) ); connect_button ("g_platform", sigc::mem_fun(*this, &View::move_gcode_to_platform) ); // Print tab m_builder->get_widget ("p_print", m_print_button); connect_button ("p_print", sigc::mem_fun(*this, &View::print_clicked) ); m_builder->get_widget ("p_pause", m_pause_button); connect_tooltoggled("p_pause", sigc::mem_fun(*this, &View::pause_toggled)); // m_builder->get_widget ("p_stop", m_stop_button); // m_stop_button->signal_clicked().connect (sigc::mem_fun(*this, &View::stop_clicked) ); connect_button ("p_home", sigc::mem_fun(*this, &View::home_all)); connect_button ("p_reset", sigc::mem_fun(*this, &View::reset_clicked)); connect_tooltoggled("p_power", sigc::mem_fun(*this, &View::power_toggled) ); // Interactive tab connect_toggled ("Printer.Logging", sigc::mem_fun(*this, &View::enable_logging_toggled)); connect_button ("Printer.ClearLog", sigc::mem_fun(*this, &View::clear_logs) ); //m_builder->get_widget ("i_reverse", m_extruder_reverse); m_builder->get_widget ("Printer.ExtrudeSpeed", m_extruder_speed); // m_extruder_speed->set_range(10.0, 10000.0); // m_extruder_speed->set_increments (10, 100); // m_extruder_speed->set_value (300.0); m_builder->get_widget ("Printer.ExtrudeAmount", m_extruder_length); // m_extruder_length->set_range(0.0, 1000.0); // m_extruder_length->set_increments (1, 10); // m_extruder_length->set_value (10.0); // FIXME: connect i_update_interval (etc.) connect_toggled ("Misc.TempReadingEnabled", sigc::mem_fun(*this, &View::temp_monitor_enabled_toggled)); connect_toggled ("i_fan_enabled", sigc::mem_fun(*this, &View::fan_enabled_toggled)); m_builder->get_widget ("Printer.FanVoltage", m_fan_voltage); // m_fan_voltage->set_range(0.0, 255.0); // m_fan_voltage->set_increments (1, 2); // m_fan_voltage->set_value (180.0); connect_button ("i_extrude_length", sigc::mem_fun(*this, &View::run_extruder) ); connect_button ("i_new_custombutton", sigc::mem_fun(*this, &View::new_custombutton) ); // 3D preview of the bed Gtk::Box *pBox = NULL; m_builder->get_widget("viewarea", pBox); if (!pBox) std::cerr << "missing box!"; else { m_renderer = manage(new Render (this, m_treeview->get_selection())); pBox->add (*m_renderer); } m_settings_ui = new PrefsDlg(m_model, m_builder); // file chooser m_filechooser = new RSFilechooser(this); // show_widget("save_buttons", false); // signal callback for notebook page-switch Gtk::Notebook *cnoteb; m_builder->get_widget ("controlnotebook", cnoteb); if (cnoteb) cnoteb->signal_switch_page().connect (sigc::mem_fun(*this, &View::on_controlnotebook_switch)); else cerr << "no 'controlnotebook' in GUI" << endl; m_printer = NULL; m_builder->get_widget ("extruder_treeview", extruder_treeview); if (extruder_treeview) { extruder_treeview->signal_cursor_changed().connect (sigc::mem_fun(*this, &View::extruder_selected) ); Gtk::TreeModel::ColumnRecord colrec; colrec.add(extrudername); extruder_liststore = Gtk::ListStore::create(colrec); extruder_treeview->set_model(extruder_liststore); extruder_treeview->set_headers_visible(false); extruder_treeview->append_column("Extruder",extrudername); // Gtk::TreeModel::Row row = *(extruder_liststore->append()); // row[extrudername] = "Extruder 1"; // extruder_treeview->get_selection()->select(row); // extruder_treeview->set_reorderable(true); } showAllWidgets(); update_extruderlist(); } void View::extruder_selected() { std::vector< Gtk::TreeModel::Path > path = extruder_treeview->get_selection()->get_selected_rows(); if(path.size()>0 && path[0].size()>0) { // copy selected extruder from Extruders to current Extruder m_model->settings.SelectExtruder(path[0][0], &m_builder); } m_model->ClearPreview(); queue_draw(); } void View::copy_extruder() { if (!m_model) return; std::vector< Gtk::TreeModel::Path > path = extruder_treeview->get_selection()->get_selected_rows(); if(path.size()>0 && path[0].size()>0) { m_model->settings.CopyExtruder(path[0][0]); } update_extruderlist(); Gtk::TreeNodeChildren ch = extruder_treeview->get_model()->children(); Gtk::TreeIter row = ch[ch.size()-1]; extruder_treeview->get_selection()->select(row); extruder_selected(); } void View::remove_extruder() { if (!m_model) return; std::vector< Gtk::TreeModel::Path > path = extruder_treeview->get_selection()->get_selected_rows(); if (path.size()>0 && path[0].size()>0) { m_model->settings.RemoveExtruder(path[0][0]); } update_extruderlist(); } void View::update_extruderlist() { if (!m_model) return; if (!extruder_liststore) return; extruder_liststore->clear(); uint num = m_model->settings.getNumExtruders(); if (num==0) return; Gtk::TreeModel::Row row; for (uint i = 0; i < num ; i++) { row = *(extruder_liststore->append()); ostringstream o; o << "Extruder " << i+1; //cerr << o.str() << m_model->settings.Extruders[i].UseForSupport<< endl; row[extrudername] = o.str(); //row[extrudername] = m_model->settings.Extruders[i].name; } Gtk::TreeModel::Row firstrow = extruder_treeview->get_model()->children()[0]; extruder_treeview->get_selection()->select(firstrow); extruder_selected(); m_extruder_row->set_number(num); } // stop file preview when leaving file tab void View::on_controlnotebook_switch(GtkNotebookPage* page, guint page_num) { if (!page) return; if (m_filechooser) m_filechooser->set_filetype(); if (m_model) m_model->preview_shapes.clear(); if (m_renderer) m_renderer->zoom_to_model(); } View::~View() { delete m_settings_ui; delete m_translation_row; for (uint i = 0; i < 3; i++) { delete m_axis_rows[i]; } delete m_extruder_row; delete m_temps[TEMP_NOZZLE]; delete m_temps[TEMP_BED]; delete m_cnx_view; delete m_progress; m_progress = NULL; delete m_printer; delete m_gcodetextview; RSFilechooser *chooser = m_filechooser; m_filechooser = NULL; delete chooser; m_renderer = NULL; } /* Recursively sets all widgets in the window to visible */ void View::showAllWidgets() { Gtk::Window *pWindow = NULL; m_builder->get_widget("main_window", pWindow); if (pWindow) pWindow->show_all(); } // this mode will not connect to a printer // instead shows a "save gcode" button // for use with pronterface // call repsnapper with -i and -o filenames void View::setNonPrintingMode(bool noprinting, string filename) { if (noprinting) { Gtk::HBox *hbox = NULL; m_builder->get_widget("printer controls", hbox); if (hbox) hbox->hide(); else cerr << "No printer controls GUI element found" << endl; Gtk::Notebook *nb = NULL; m_builder->get_widget("controlnotebook", nb); if (nb) { Gtk::VBox *vbox = NULL; m_builder->get_widget("printer_tab", vbox); if (vbox) { int num = nb->page_num(*vbox); nb->remove_page(num); } else cerr << "No printer_tab GUI element found" << endl; m_builder->get_widget("logs_tab", vbox); if (vbox) { int num = nb->page_num(*vbox); nb->remove_page(num); } else cerr << "No logs_tab GUI element found" << endl; } else cerr << "No controlnotebook GUI element found" << endl; Gtk::Label *lab = NULL; m_builder->get_widget("outfilelabel", lab); if (lab) { lab->set_label(_("Output File: ")+filename); printtofile_name = filename; } else cerr << "No outfilelabel GUI element found" << endl; show_notebooktab("model_tab", "controlnotebook"); } else { Gtk::HBox *hbox = NULL; m_builder->get_widget("printtofile", hbox); if (hbox) hbox->hide(); else cerr << "No printtfile GUI element found" << endl; } } void View::PrintToFile() { if (printtofile_name != "") { if (m_model) { if (m_model->gcode.commands.size() == 0) { alert(Gtk::MESSAGE_WARNING,"No GCode","Generate GCode first"); return; } Glib::RefPtr file = Gio::File::create_for_path(printtofile_name); m_model->WriteGCode(file); cerr << "saved GCode to file " << printtofile_name << endl; Gtk::Main::quit(); } else cerr << " no model " << endl; } else cerr << " no filename " << endl; } bool View::saveWindowSizeAndPosition(Settings &settings) const { Gtk::Window *pWindow = NULL; m_builder->get_widget("main_window", pWindow); if (pWindow) { settings.set_integer("Misc","WindowWidth", pWindow->get_width()); settings.set_integer("Misc","WindowHeight", pWindow->get_height()); int x,y; pWindow->get_position(x,y); settings.set_integer("Misc","WindowPosX", x); settings.set_integer("Misc","WindowPosY", y); return true; } return false; } void View::setModel(Model *model) { m_model = model; m_renderer->set_model (m_model); m_model->settings.m_signal_visual_settings_changed.connect (sigc::mem_fun(*this, &View::handle_ui_settings_changed)); m_model->settings.m_signal_update_settings_gui.connect (sigc::mem_fun(*this, &View::update_settings_gui)); m_treeview->set_model (m_model->objtree.m_model); m_treeview->append_column_editable("Name", m_model->objtree.m_cols->m_name); // m_treeview->append_column_editable("Extruder", m_model->objtree.m_cols->m_material); //m_treeview->append_column("Extruder", m_model->objtree.m_cols->m_extruder); // m_treeview->set_headers_visible(true); m_gcodetextview = NULL; m_builder->get_widget ("GCode.Result", m_gcodetextview); m_gcodetextview->set_buffer (m_model->GetGCodeBuffer()); m_gcodetextview->get_buffer()->signal_mark_set(). connect( sigc::mem_fun(this, &View::on_gcodebuffer_cursor_set) ); // Main view progress bar Gtk::Box *box = NULL; Gtk::Label *label = NULL; Gtk::ProgressBar *bar = NULL; m_builder->get_widget("progress_box", box); m_builder->get_widget("progress_bar", bar); m_builder->get_widget("progress_label", label); // Create ViewProgress widget and inform model about it m_progress = new ViewProgress (box, bar, label); m_model->SetViewProgress(m_progress); Gtk::Statusbar *sbar = NULL; m_builder->get_widget("statusbar", sbar); m_model->statusbar = sbar; m_builder->get_widget("i_txt_comms", log_view); log_view->set_buffer(Gtk::TextBuffer::create()); log_view->set_reallocate_redraws(false); m_builder->get_widget("i_txt_errs", err_view); err_view->set_buffer(m_model->errlog); err_view->set_reallocate_redraws(false); m_builder->get_widget("i_txt_echo", echo_view); echo_view->set_buffer(m_model->echolog); echo_view->set_reallocate_redraws(false); m_printer = new Printer(this); m_printer->signal_temp_changed.connect (sigc::mem_fun(*this, &View::temp_changed)); m_printer->signal_printing_changed.connect (sigc::mem_fun(*this, &View::printing_changed)); m_printer->signal_now_printing.connect (sigc::mem_fun(*this, &View::showCurrentPrinting)); // m_printer->signal_logmessage.connect // (sigc::mem_fun(*this, &View::showPrinterLog)); // Connect / dis-connect button m_cnx_view = new ConnectView(m_printer, &m_model->settings); Gtk::Box *connect_box = NULL; m_builder->get_widget ("p_connect_button_box", connect_box); connect_box->add (*m_cnx_view); // Gtk::Box *control_box; // m_builder->get_widget ("printer_controls", control_box); // if (control_box) // control_box->set_sensitive(false); Gtk::Box *temp_box; m_builder->get_widget ("i_temp_box", temp_box); // Gtk::SpinButton *nozzle; // m_builder->get_widget ("Printer.NozzleTemp", nozzle); m_temps[TEMP_NOZZLE] = new TempRow(m_model, m_printer, TEMP_NOZZLE); // Gtk::SpinButton *bed; // m_builder->get_widget ("Printer.BedTemp", bed); m_temps[TEMP_BED] = new TempRow(m_model, m_printer, TEMP_BED); temp_box->add (*m_temps[TEMP_NOZZLE]); temp_box->add (*m_temps[TEMP_BED]); Gtk::Box *axis_box; m_builder->get_widget ("i_axis_controls", axis_box); for (uint i = 0; i < 3; i++) { m_axis_rows[i] = new AxisRow (m_model, m_printer, i); axis_box->add (*m_axis_rows[i]); } Gtk::Box *extruder_box; m_builder->get_widget ("i_extruder_box", extruder_box); m_extruder_row = new ExtruderRow(m_printer); extruder_box->add(*m_extruder_row); inhibit_print_changed(); m_printer->signal_inhibit_changed. connect (sigc::mem_fun(*this, &View::inhibit_print_changed)); m_model->m_signal_stl_added.connect (sigc::mem_fun(*this, &View::stl_added)); m_model->m_model_changed.connect (sigc::mem_fun(*this, &View::model_changed)); m_model->m_signal_gcode_changed.connect (sigc::mem_fun(*this, &View::gcode_changed)); m_model->signal_alert.connect (sigc::mem_fun(*this, &View::alert)); m_printer->signal_alert.connect (sigc::mem_fun(*this, &View::alert)); // connect settings // FIXME: better have settings here and delegate to model AND printer m_model->settings.connect_to_ui (m_builder); m_printer->setModel(m_model); showAllWidgets(); } void View::on_gcodebuffer_cursor_set(const Gtk::TextIter &iter, const Glib::RefPtr &refMark) { if (m_model) m_model->gcode.updateWhereAtCursor(m_model->settings.get_extruder_letters()); if (m_renderer) m_renderer->queue_draw(); } void View::delete_selected_objects() { vector path = m_treeview->get_selection()->get_selected_rows(); m_model->DeleteObjTree(path); m_treeview->expand_all(); } void View::tree_selection_changed() { if (m_model) { m_model->m_current_selectionpath = m_treeview->get_selection()->get_selected_rows(); m_model->ClearPreview(); vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size() > 0) { ostringstream ostr; ostr << shapes.back()->filename << ": " << shapes.back()->size() << " triangles" ; statusBarMessage(ostr.str()); } m_model->m_inhibit_modelchange = true; update_scale_value(); update_rot_value(); m_model->m_inhibit_modelchange = false; } } bool View::get_selected_objects(vector &objects, vector &shapes) { vector iter = m_treeview->get_selection()->get_selected_rows(); m_model->objtree.get_selected_objects(iter, objects, shapes); return objects.size() != 0 || shapes.size() != 0; } bool View::get_selected_shapes(vector &shapes, vector &transforms) { vector iter = m_treeview->get_selection()->get_selected_rows(); m_model->objtree.get_selected_shapes(iter, shapes, transforms); return shapes.size() != 0; } void View::duplicate_selected_objects() { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; i(shapes[i]); if (flatshape != NULL) newshape = new FlatShape(*flatshape); else newshape = new Shape(*shapes[i]); // duplicate TreeObject* object = m_model->objtree.getParent(shapes[i]); if (object !=NULL) m_model->AddShape (object, newshape, shapes[i]->filename); queue_draw(); } } void View::split_selected_objects() { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) { for (uint i=0; iobjtree.getParent(shapes[i]); if (object !=NULL) if (m_model->SplitShape (object, shapes[i], shapes[i]->filename) > 1) { // delete shape? } } queue_draw(); } } void View::merge_selected_objects() { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) { TreeObject* parent = m_model->objtree.getParent(shapes[0]); m_model->MergeShapes(parent, shapes); queue_draw(); } } void View::divide_selected_objects() { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) { for (uint i=0; iobjtree.getParent(shapes[i]); if (object !=NULL) if (m_model->DivideShape (object, shapes[i], shapes[i]->filename) > 1) { // delete shape? } } queue_draw(); } } // // Given a widget by label, adds a statusbar message on rollover // void View::add_statusbar_msg(const char *name, const char *msg) // { // Gtk::Widget *widget = NULL; // m_builder->get_widget (name, widget); // add_statusbar_msg (widget, msg); // } // // Given a widget by pointer reference, adds a statusbar message on rollover // void View::add_statusbar_msg(Gtk::Widget *widget, const char *msg) // { // widget->signal_enter_notify_event().connect // (sigc::bind(sigc::mem_fun(*this, &View::updateStatusBar), msg)); // widget->signal_leave_notify_event().connect // (sigc::bind(sigc::mem_fun(*this, &View::updateStatusBar), "")); // } /* Handler for widget rollover. Displays a message in the window status bar */ bool View::statusBarMessage(Glib::ustring message) { Gtk::Statusbar *statusbar; m_builder->get_widget("statusbar", statusbar); // if(event->type == GDK_ENTER_NOTIFY) { statusbar->push(message); // } else { // event->type == GDK_LEAVE_NOTIFY // /* 2 pops because sometimes a previous leave event may have be missed // * leaving a message on the statusbar stack */ // statusbar->pop(); // statusbar->pop(); // } return false; } void View::stop_progress() { m_progress->stop_running(); } void View::scale_selection() { if (toggle_block) return; double scale=1; Gtk::SpinButton *scale_value; m_builder->get_widget("m_scale_value", scale_value); scale = scale_value->get_value(); scale_selection_to(scale); } void View::scale_selection_to(const double factor) { vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; itransform3D.scale(factor); } else if (objects.size()>0) for (uint i=0; itransform3D.scale(factor); } m_model->ModelChanged(); } void View::scale_object_x() { if (toggle_block) return; double scale=1; Gtk::SpinButton *scale_value; m_builder->get_widget("scale_x", scale_value); scale = scale_value->get_value(); vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; itransform3D.scale_x(scale); } else if (objects.size()>0) for (uint i=0; itransform3D.scale_x(scale); } m_model->ModelChanged(); } void View::scale_object_y() { if (toggle_block) return; double scale=1; Gtk::SpinButton *scale_value; m_builder->get_widget("scale_y", scale_value); scale = scale_value->get_value(); vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; itransform3D.scale_y(scale); } else if (objects.size()>0) for (uint i=0; itransform3D.scale_y(scale); } m_model->ModelChanged(); } void View::scale_object_z() { if (toggle_block) return; double scale=1; Gtk::SpinButton *scale_value; m_builder->get_widget("scale_z", scale_value); scale = scale_value->get_value(); vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) for (uint i=0; itransform3D.scale_z(scale); } else if (objects.size()>0) for (uint i=0; itransform3D.scale_z(scale); } m_model->ModelChanged(); } /* Updates the scale value when a new STL is selected, * giving it the new STL's current scale factor */ void View::update_scale_value() { toggle_block = true; vector shapes; vector objects; get_selected_objects (objects, shapes); if (shapes.size()>0) { Gtk::SpinButton *scale_sb; m_builder->get_widget("m_scale_value", scale_sb); scale_sb->set_value(shapes.back()->getScaleFactor()); m_builder->get_widget("scale_x", scale_sb); scale_sb->set_value(shapes.back()->getScaleFactorX()); m_builder->get_widget("scale_y", scale_sb); scale_sb->set_value(shapes.back()->getScaleFactorY()); m_builder->get_widget("scale_z", scale_sb); scale_sb->set_value(shapes.back()->getScaleFactorZ()); } else if (objects.size()>0) { Gtk::SpinButton *scale_sb; m_builder->get_widget("m_scale_value", scale_sb); scale_sb->set_value(objects.back()->transform3D.get_scale()); m_builder->get_widget("scale_x", scale_sb); scale_sb->set_value(objects.back()->transform3D.get_scale_x()); m_builder->get_widget("scale_y", scale_sb); scale_sb->set_value(objects.back()->transform3D.get_scale_y()); m_builder->get_widget("scale_z", scale_sb); scale_sb->set_value(objects.back()->transform3D.get_scale_z()); } toggle_block = false; } // GPL bits below from model.cpp ... void View::DrawGrid() { Vector3d volume = m_model->settings.getPrintVolume(); glEnable (GL_BLEND); glEnable (GL_DEPTH_TEST); glDisable (GL_LIGHTING); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // define blending factors glColor4f (0.5f, 0.5f, 0.5f, 1.0f); // Draw outer border double width glLineWidth (2.0); glBegin(GL_LINES); //glColor4f (0.8f, 0.8f, 0.8f, 1.0f); // left edge glVertex3f (0.0f, 0.0f, 0.0f); glVertex3f (0.0f, volume.y(), 0.0f); // near edge glVertex3f (0.0f, 0.0f, 0.0f); glVertex3f (volume.x(), 0.0f, 0.0f); glColor4f (0.5f, 0.5f, 0.5f, 1.0f); // right edge glVertex3f (volume.x(), 0.0f, 0.0f); glVertex3f (volume.x(), volume.y(), 0.0f); // far edge glVertex3f (0.0f, volume.y(), 0.0f); glVertex3f (volume.x(), volume.y(), 0.0f); // top glColor4f (0.5f, 0.5f, 0.5f, 0.5f); // left edge glVertex3f (0.0f, 0.0f, volume.z()); glVertex3f (0.0f, volume.y(), volume.z()); // near edge glVertex3f (0.0f, 0.0f, volume.z()); glVertex3f (volume.x(), 0.0f, volume.z()); // right edge glVertex3f (volume.x(), 0.0f, volume.z()); glVertex3f (volume.x(), volume.y(), volume.z()); // far edge glVertex3f (0.0f, volume.y(), volume.z()); glVertex3f (volume.x(), volume.y(), volume.z()); // verticals at rear glVertex3f (0.0f, volume.y(), 0); glVertex3f (0.0f, volume.y(), volume.z()); glVertex3f (volume.x(), volume.y(), 0); glVertex3f (volume.x(), volume.y(), volume.z()); glEnd(); // Draw thin internal lines glLineWidth (1.0); glBegin(GL_LINES); for (uint x = 10; x < volume.x(); x += 10) { glVertex3f (x, 0.0f, 0.0f); glVertex3f (x, volume.y(), 0.0f); } for (uint y = 10; y < volume.y(); y += 10) { glVertex3f (0.0f, y, 0.0f); glVertex3f (volume.x(), y, 0.0f); } glEnd(); glEnable (GL_LIGHTING); glEnable (GL_CULL_FACE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Draw print margin in faint red Vector3d pM = m_model->settings.getPrintMargin(); float no_mat[] = {0.0f, 0.0f, 0.0f, 0.5f}; float mat_diffuse[] = {1.0f, 0.1f, 0.1f, 0.2f}; float mat_specular[] = {0.025f, 0.025f, 0.025f, 0.3f}; glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, 0.5f); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); // bottom glBegin(GL_TRIANGLE_STRIP); glNormal3f (0.0f, 0.0f, 1.0f); glVertex3f (pM.x(), pM.y(), 0.0f); glVertex3f (0.0f, 0.0f, 0.0f); glVertex3f (volume.x() - pM.x(), pM.y(), 0.0f); glVertex3f (volume.x(), 0.0f, 0.0f); glVertex3f (volume.x() - pM.x(), volume.y() - pM.y(), 0.0f); glVertex3f (volume.x(), volume.y(), 0.0f); glVertex3f (pM.x(), volume.y() - pM.y(), 0.0f); glVertex3f (0.0f, volume.y(), 0.0f); glVertex3f (pM.x(), pM.y(), 0.0f); glVertex3f (0.0f, 0.0f, 0.0f); glEnd(); glDisable (GL_DEPTH_TEST); // top glBegin(GL_TRIANGLE_STRIP); glNormal3f (0.0f, 0.0f, 1.0f); glVertex3f (pM.x(), pM.y(), volume.z()); glVertex3f (0.0f, 0.0f, volume.z()); glVertex3f (volume.x() - pM.x(), pM.y(), volume.z()); glVertex3f (volume.x(), 0.0f, volume.z()); glVertex3f (volume.x() - pM.x(), volume.y() - pM.y(), volume.z()); glVertex3f (volume.x(), volume.y(), volume.z()); glVertex3f (pM.x(), volume.y() - pM.y(), volume.z()); glVertex3f (0.0f, volume.y(), volume.z()); glVertex3f (pM.x(), pM.y(), volume.z()); glVertex3f (0.0f, 0.0f, volume.z()); glEnd(); // mark front left // glBegin(GL_TRIANGLES); // glNormal3f (0.0f, 0.0f, 1.0f); // glVertex3f (pM.x(), pM.y(), 0.0f); // glVertex3f (pM.x()+10.0f, pM.y(), 0.0f); // glVertex3f (pM.x(), pM.y()+10.0f, 0.0f); // glEnd(); glEnable (GL_DEPTH_TEST); // Draw print surface float mat_diffuse_white[] = {0.2f, 0.2f, 0.2f, 0.2f}; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_white); glBegin(GL_QUADS); glVertex3f (pM.x(), pM.y(), 0.0f); glVertex3f (volume.x() - pM.x(), pM.y(), 0.0f); glVertex3f (volume.x() - pM.x(), volume.y() - pM.y(), 0.0f); glVertex3f (pM.x(), volume.y() - pM.y(), 0.0f); glEnd(); glDisable (GL_LIGHTING); } // called from Render::on_expose_event void View::Draw (vector &selected, bool objects_only) { // Draw the grid, pushed back so it can be seen // when viewed from below. if (!objects_only) { glEnable (GL_POLYGON_OFFSET_FILL); glPolygonOffset (1.0f, 1.0f); DrawGrid(); } glPolygonOffset (-0.5f, -0.5f); glDisable (GL_POLYGON_OFFSET_FILL); // Draw GCode, which already incorporates any print offset if (!objects_only) { if (m_gcodetextview->has_focus()) { double z = m_model->gcode.currentCursorWhere.z(); m_model->GlDrawGCode(z); } else { m_model->gcode.currentCursorWhere = Vector3d::ZERO; m_model->GlDrawGCode(); } } // Draw all objects int layerdrawn = m_model->draw(selected); if (layerdrawn > -1) { Gtk::Label *layerlabel; m_builder->get_widget("layerno_label", layerlabel); if (layerlabel){ stringstream s; s << layerdrawn ; layerlabel->set_text(s.str()); } } } void View::showCurrentPrinting(unsigned long lineno) { //Glib::Mutex::Lock lock(mutex); if (lineno == 0) { m_progress->stop(_("Done")); return; } bool cont = true; cont = m_progress->update(lineno, true); if (!cont) { // stop by progress bar m_printer->Pause(); // printing_changed(); } m_model->setCurrentPrintingLine(lineno); queue_draw(); // while(Gtk::Main::events_pending()) { // Gtk::Main::iteration(); // } } repsnapper-2.3.2a5/src/ui/view.h000066400000000000000000000166201231531733200164570ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef VIEW_H #define VIEW_H #include #include #include "stdafx.h" #include "printer/printer.h" #include "filechooser.h" static bool UNUSED toggle_block = false; // blocks signals for togglebuttons etc. class View : public Gtk::Window { class TempRow; class AxisRow; class TranslationSpinRow; class ExtruderRow; friend class PrintInhibitor; friend class Render; friend class RSFilechooser; bool get_userconfirm(string maintext, string secondarytext="") const; void toggle_fullscreen(); void load_gcode(); void save_gcode(); void move_gcode_to_platform (); void convert_to_gcode(); void load_stl(); void autoarrange(); void save_stl(); void do_load(); void do_save_stl(); void do_save_gcode(); void do_save_settings_as(); void slice_svg(); void do_slice_svg(bool singlelayer=false); void send_gcode(); void printing_changed(); void power_toggled(Gtk::ToggleToolButton *button); void print_clicked(); /* void stop_clicked(); */ void pause_toggled(Gtk::ToggleToolButton *button); void reset_clicked(); /* void add_statusbar_msg(const char *name, const char *message); */ /* void add_statusbar_msg(Gtk::Widget *widget, const char *message); */ void update_scale_value(); void scale_object_x(); void scale_object_y(); void scale_object_z(); void update_rot_value(); void rot_object_from_spinbutton(); Printer *m_printer; ExtruderRow *m_extruder_row; PrefsDlg *m_settings_ui; Glib::RefPtr m_builder; Model *m_model; ViewProgress *m_progress; ConnectView *m_cnx_view; Gtk::Entry *m_gcode_entry; Render *m_renderer; RSFilechooser *m_filechooser; void on_controlnotebook_switch(GtkNotebookPage* page, guint page_num); void on_gcodebuffer_cursor_set (const Gtk::TextIter &iter, const Glib::RefPtr &refMark); Gtk::TextView * m_gcodetextview; Gtk::TextView *log_view, *err_view, *echo_view; void log_msg(Gtk::TextView *view, string s); Gtk::ToolButton *m_print_button; Gtk::ToggleToolButton *m_pause_button; void connect_button(const char *name, const sigc::slot &slot); void connect_action(const char *name, const sigc::slot &slot); void connect_toggled(const char *name, const sigc::slot &slot); void connect_tooltoggled(const char *name, const sigc::slot &slot); virtual bool on_delete_event(GdkEventAny* event); void hide_on_response(int, Gtk::Dialog *dialog); void about_dialog(); void load_settings(); void save_settings(); void save_settings_as(); void save_settings_to(Glib::RefPtr < Gio::File > file); // interactive bits void temp_monitor_enabled_toggled (Gtk::ToggleButton *button); void enable_logging_toggled (Gtk::ToggleButton *button); void fan_enabled_toggled (Gtk::ToggleButton *button); void run_extruder(); void clear_logs(); void home_all(); /* Gtk::CheckButton *m_extruder_reverse; */ Gtk::SpinButton *m_extruder_speed; Gtk::SpinButton *m_extruder_length; Gtk::SpinButton *m_extruder_speed_mult; Gtk::SpinButton *m_extruder_length_mult; Gtk::SpinButton *m_fan_voltage; AxisRow *m_axis_rows[3]; TempRow *m_temps[TEMP_LAST]; void temp_changed(); void edit_custombutton(string name="", string code="", Gtk::ToolButton *button=NULL); void new_custombutton() {edit_custombutton();}; void hide_custombutton_dlg(int code, Gtk::Dialog *dialog); void add_custombutton(string name, string gcode); void custombutton_pressed(string name, Gtk::ToolButton *button); Gtk::TreeView * extruder_treeview; Glib::RefPtr< Gtk::ListStore > extruder_liststore; Gtk::TreeModelColumn extrudername; void copy_extruder(); void remove_extruder(); void extruder_selected(); void update_extruderlist(); // rfo bits Gtk::TreeView *m_treeview; TranslationSpinRow *m_translation_row; void tree_selection_changed(); void delete_selected_objects(); void duplicate_selected_objects(); void split_selected_objects(); void merge_selected_objects(); void divide_selected_objects(); void auto_rotate(); void update_settings_gui(); void handle_ui_settings_changed(); bool key_pressed_event(GdkEventKey *event); void setModel (Model *model); void showAllWidgets(); bool saveWindowSizeAndPosition(Settings &settings) const; bool statusBarMessage(Glib::ustring message); void stop_progress(); public: void setNonPrintingMode(bool noprinting=true, string filename=""); void PrintToFile(); string printtofile_name; Model *get_model() { return m_model; } ViewProgress *get_view_progress() { return m_progress; } bool get_selected_objects(vector &objects, vector &shapes); bool get_selected_shapes(vector &shapes, vector &transforms); View(BaseObjectType* cobject, const Glib::RefPtr& builder); virtual ~View(); static View *create (Model *model); void progess_bar_start (const char *label, double max); void inhibit_print_changed(); void alert (Gtk::MessageType t, const char *message, const char *secondary); bool move_selection( float x, float y, float z=0); bool rotate_selection (Vector3d axis, double angle); void scale_selection(); void scale_selection_to(const double factor); void twist_selection (double angle); void invertnormals_selection (); void hollow_selection (); void mirror_selection (); void placeonplatform_selection (); void stl_added (Gtk::TreePath &path); void model_changed (); void gcode_changed (); void set_SliderBBox(Vector3d min, Vector3d max); void show_notebooktab (string name, string notebookname) const; void show_widget (string name, bool visible) const; void preview_file(Glib::RefPtr file); /* Matrix4d &SelectedNodeMatrix(guint objectNr = 1); */ /* void SelectedNodeMatrices(std::vector &result ); */ /* void newObject(); */ void show_dialog(const char *name); void show_preferences(); Glib::RefPtr getBuilder() const { return m_builder; }; void err_log(string s); void comm_log(string s); void echo_log(string s); sigc::connection logprint_timeout; void set_logging(bool); bool logprint_timeout_cb(); // view nasties ... void Draw (vector &selected, bool objects_only=false); void DrawGrid (); void showCurrentPrinting(unsigned long line); Glib::Mutex mutex; Glib::RefPtr iconfile; void set_icon_file(Glib::RefPtr iconfile); }; #ifdef MODEL_IMPLEMENTATION # error "The whole point is to avoid coupling the model to the view - think again" #endif #endif // VIEW_H repsnapper-2.3.2a5/src/ui/widgets.cpp000066400000000000000000000217641231531733200175130ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "widgets.h" #include "objtree.h" #include "model.h" static const char *axis_names[] = { "X", "Y", "Z" }; // apply values to objects void View::TranslationSpinRow::spin_value_changed (int axis) { if (m_inhibit_update) return; vector shapes; vector objects; if (!m_view->get_selected_objects(objects, shapes)) return; if (shapes.size()==0 && objects.size()==0) return; double val = m_xyz[axis]->get_value(); Matrix4d *mat; if (shapes.size()!=0) for (uint s=0; stransform3D.transform; double scale = (*mat)[3][3]; Vector3d trans; mat->get_translation(trans); trans[axis] = val*scale; mat->set_translation (trans); } else for (uint o=0; otransform3D.transform; double scale = (*mat)[3][3]; Vector3d trans; mat->get_translation(trans); trans[axis] = val*scale; mat->set_translation (trans); } m_view->get_model()->ModelChanged(); } // Changed STL Selection - must update translation values void View::TranslationSpinRow::selection_changed () { m_inhibit_update = true; vector shapes; vector objects; if (!m_view->get_selected_objects(objects, shapes)) return; if (shapes.size()==0 && objects.size()==0) return; Matrix4d *mat; if (shapes.size()==0) { if (objects.size()==0) { for (uint i = 0; i < 3; i++) m_xyz[i]->set_value(0.0); return; } else mat = &objects.back()->transform3D.transform; } else mat = &shapes.back()->transform3D.transform; Vector3d trans; mat->get_translation(trans); double scale = (*mat)[3][3]; for (uint i = 0; i < 3; i++) m_xyz[i]->set_value(trans[i]/scale); m_inhibit_update = false; } View::TranslationSpinRow::TranslationSpinRow(View *view, Gtk::TreeView *treeview) : m_inhibit_update(false), m_view(view) { // view->m_builder->get_widget (box_name, m_box); view->m_builder->get_widget ("translate_x", m_xyz[0]); view->m_builder->get_widget ("translate_y", m_xyz[1]); view->m_builder->get_widget ("translate_z", m_xyz[2]); for (uint i = 0; i < 3; i++) { // m_box->add (*manage(new Gtk::Label (axis_names[i]))); // m_xyz[i] = manage (new Gtk::SpinButton()); // m_xyz[i]->set_numeric(); // m_xyz[i]->set_digits (1); // m_xyz[i]->set_increments (0.5, 10); // m_xyz[i]->set_range(-5000.0, +5000.0); // m_box->add (*m_xyz[i]); m_xyz[i]->signal_value_changed().connect (sigc::bind(sigc::mem_fun(*this, &TranslationSpinRow::spin_value_changed), (int)i)); // /* Add statusbar message */ // // stringstream oss; // // oss << "Move object in " << axis_names[i] << "-direction (mm)"; // // m_view->add_statusbar_msg(m_xyz[i], oss.str().c_str()); } selection_changed(); // m_box->show_all(); treeview->get_selection()->signal_changed().connect (sigc::mem_fun(*this, &TranslationSpinRow::selection_changed)); } View::TranslationSpinRow::~TranslationSpinRow() { for (uint i = 0; i < 3; i++) delete m_xyz[i]; } View::TempRow::TempRow(Model *model, Printer *printer, TempType type) : m_model(model), m_printer(printer), m_type(type) { static const char *names[] = { _("Nozzle:"), _("Bed:") }; set_homogeneous(true); add(*manage(new Gtk::Label(names[type]))); m_temp = new Gtk::Label(_("-- °C")); add (*m_temp); // add(*manage (new Gtk::Label(_("°C")))); add(*manage(new Gtk::Label(_("Target:")))); m_target = new Gtk::SpinButton(); m_target->set_increments (1, 5); switch (type) { case TEMP_NOZZLE: default: m_target->set_range(0, 350.0); m_target->set_value(m_model->settings.get_double("Printer","NozzleTemp")); break; case TEMP_BED: m_target->set_range(0, 250.0); m_target->set_value(m_model->settings.get_double("Printer","BedTemp")); break; } add (*m_target); m_button = manage (new Gtk::ToggleButton(_("Off"))); m_button->signal_toggled().connect (sigc::mem_fun (*this, &TempRow::button_toggled)); add(*m_button); m_target->signal_value_changed().connect (sigc::mem_fun (*this, &TempRow::heat_changed)); } View::TempRow::~TempRow() { delete m_temp; delete m_target; delete m_button; } void View::TempRow::button_toggled() { if (m_button->get_active()) m_button->set_label(_("On")); else m_button->set_label(_("Off")); if (toggle_block) return; float value = 0; if (m_button->get_active()) { value = m_target->get_value(); } if (!m_printer->SetTemp(m_type, value)) { toggle_block = true; m_button->set_active(!m_button->get_active()); toggle_block = false; } } void View::TempRow::heat_changed() { float value = m_target->get_value(); switch (m_type) { case TEMP_NOZZLE: default: m_model->settings.set_double("Printer","NozzleTemp", value); break; case TEMP_BED: m_model->settings.set_double("Printer","BedTemp", value); } if (m_button->get_active()) m_printer->SetTemp(m_type, value); } void View::TempRow::update_temp (double value) { ostringstream oss; oss.precision(1); oss << fixed << value << " °C"; m_temp->set_text(oss.str()); } void View::AxisRow::home_clicked() { m_printer->Home(std::string (axis_names[m_axis])); m_target->set_value(0.0); } void View::AxisRow::spin_value_changed () { if (m_inhibit_update) return; m_printer->Goto (std::string (axis_names[m_axis]), m_target->get_value()); } void View::AxisRow::nudge_clicked (double nudge) { m_inhibit_update = true; m_target->set_value (MAX (m_target->get_value () + nudge, 0.0)); m_printer->Move (std::string (axis_names[m_axis]), nudge); m_inhibit_update = false; } void View::AxisRow::add_nudge_button (double nudge) { std::stringstream label; if (nudge > 0) label << "+"; label << nudge; Gtk::Button *button = new Gtk::Button(label.str()); add(*button); button->signal_clicked().connect (sigc::bind(sigc::mem_fun (*this, &AxisRow::nudge_clicked), nudge)); } void View::AxisRow::notify_homed() { m_inhibit_update = true; m_target->set_value(0.0); m_inhibit_update = false; } View::AxisRow::AxisRow(Model *model, Printer *printer, int axis) : m_inhibit_update(false), m_model(model), m_printer(printer), m_axis(axis) { add(*manage(new Gtk::Label(axis_names[axis]))); Gtk::Button *home = new Gtk::Button(_("Home")); home->signal_clicked().connect (sigc::mem_fun (*this, &AxisRow::home_clicked)); add (*home); add_nudge_button (-10.0); add_nudge_button (-1.0); add_nudge_button (-0.1); m_target = manage (new Gtk::SpinButton()); m_target->set_digits (1); m_target->set_increments (0.1, 1); m_target->set_range(-200.0, +200.0); m_target->set_value(0.0); add (*m_target); m_target->signal_value_changed().connect (sigc::mem_fun(*this, &AxisRow::spin_value_changed)); add_nudge_button (+0.1); add_nudge_button (+1.0); add_nudge_button (+10.0); } View::ExtruderRow::ExtruderRow(Printer *printer) : m_printer(printer) { set_homogeneous (true); } View::ExtruderRow::~ExtruderRow() { m_buttons.clear(); } void View::ExtruderRow::set_number(uint num) { vector< Widget* > ch = get_children(); for (uint i = 0; i< ch.size(); i++){ remove(*ch[i]); } m_buttons.clear(); for (uint i = 0; i< num; i++){ ostringstream o; o << i+1; // cerr << o.str() << endl; m_buttons.push_back(new Gtk::RadioButton(m_group,o.str())); m_buttons[i]->signal_toggled().connect (sigc::mem_fun(*this, &ExtruderRow::button_selected)); add(*manage(m_buttons[i])); } if (num>0) m_buttons[0]->set_active(); show_all(); check_resize(); } uint View::ExtruderRow::get_selected() const { vector< const Widget* > ch = get_children(); for (uint i = 0; i< ch.size(); i++){ const Gtk::RadioButton *but = dynamic_cast(ch[i]); if (but->get_active()) return i; } return 0; } void View::ExtruderRow::button_selected() { m_printer->SelectExtruder(get_selected()); } repsnapper-2.3.2a5/src/ui/widgets.h000066400000000000000000000043621231531733200171530ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2011 Michael Meeks This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "types.h" #include "view.h" class View::TranslationSpinRow { // apply values to objects void spin_value_changed (int axis); public: TranslationSpinRow(View *view, Gtk::TreeView *treeview); ~TranslationSpinRow(); bool m_inhibit_update; View *m_view; Gtk::Box *m_box; Gtk::SpinButton *m_xyz[3]; // Changed STL Selection - must update translation values void selection_changed (); }; class View::TempRow : public Gtk::HBox { public: TempRow(Model *model, Printer *printer, TempType type); ~TempRow(); Model *m_model; Printer *m_printer; TempType m_type; Gtk::Label *m_temp; Gtk::SpinButton *m_target; Gtk::ToggleButton *m_button; void button_toggled(); void heat_changed(); void update_temp (double value); }; class View::AxisRow : public Gtk::HBox { public: AxisRow(Model *model, Printer *printer, int axis); void home_clicked(); void notify_homed(); void spin_value_changed (); void nudge_clicked (double nudge); void add_nudge_button (double nudge); bool m_inhibit_update; Model *m_model; Printer *m_printer; Gtk::SpinButton *m_target; int m_axis; }; class View::ExtruderRow : public Gtk::HBox { public: ExtruderRow(Printer *printer); ~ExtruderRow(); Printer *m_printer; vector m_buttons; Gtk::RadioButtonGroup m_group; void set_number(uint num); uint get_selected() const; void button_selected(); }; repsnapper-2.3.2a5/src/unittest.cpp000066400000000000000000000207701231531733200173030ustar00rootroot00000000000000/* This file is a part of the RepSnapper project. Copyright (C) 2010 Kulitorum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /************************************************************************* TODO LIST: Logick: Add more Unittest :) *************************************************************************/ #include "config.h" #include "stdafx.h" #include "modelviewcontroller.h" #include "gcode.h" #include "ui.h" #if !defined(WIN32) || defined (UNITTEST) GUI *gui; #include using namespace std; #include #define BOOST_TEST_MODULE RepSnapperTest #define BOOST_TEST_MAIN 1 #define BOOST_TEST_DYN_LINK 1 #include using namespace PolyLib; //// seven ways to detect and report the same error: //BOOST_CHECK( add( 2,2 ) == 4 ); // #1 continues on error //BOOST_REQUIRE( add( 2,2 ) == 4 ); // #2 throws on error //if( add( 2,2 ) != 4 ) // BOOST_ERROR( "Ouch..." ); // #3 continues on error //if( add( 2,2 ) != 4 ) // BOOST_FAIL( "Ouch..." ); // #4 throws on error //if( add( 2,2 ) != 4 ) throw "Ouch..."; // #5 throws on error //BOOST_CHECK_MESSAGE( add( 2,2 ) == 4, // #6 continues on error // "add(..) result: " << add( 2,2 ) ); //BOOST_CHECK_EQUAL( add( 2,2 ), 4 ); // #7 continues on error BOOST_AUTO_TEST_CASE( Logick_Basic_Shrink_Test ) { Polygon2d p; p.vertices.push_back(Vector2d(10,10)); p.vertices.push_back(Vector2d(10,110)); p.vertices.push_back(Vector2d(110,110)); p.vertices.push_back(Vector2d(110,10)); list parent; list res; p.Shrink(1, parent, res); BOOST_CHECK( p.vertices.size() == res.front()->vertices.size() ); BOOST_CHECK( res.front()->vertices.front() == Vector2d(11,11) ); BOOST_CHECK( res.front()->vertices.back() == Vector2d(109,11) ); delete res.front(); } BOOST_AUTO_TEST_CASE( Logick_Advanced_Shrink_Test ) { Polygon2d p; p.vertices.push_back(Vector2d(10,10)); p.vertices.push_back(Vector2d(10,110)); p.vertices.push_back(Vector2d(110,110)); p.vertices.push_back(Vector2d(120,110)); p.vertices.push_back(Vector2d(110,109)); p.vertices.push_back(Vector2d(110,10)); list parent; list res; p.Shrink(2, parent, res); BOOST_CHECK( p.vertices.size()-2 == res.front()->vertices.size() ); BOOST_CHECK( res.front()->vertices.front() == Vector2d(12,12) ); BOOST_CHECK( res.front()->vertices.back() == Vector2d(108,12) ); delete res.front(); } BOOST_AUTO_TEST_CASE( Logick_Advanced_Polygon_Split_Tests ) { Polygon2d p; p.vertices.push_back(Vector2d(10,10)); p.vertices.push_back(Vector2d(59,60)); p.vertices.push_back(Vector2d(10,110)); p.vertices.push_back(Vector2d(110,110)); p.vertices.push_back(Vector2d(61,60)); p.vertices.push_back(Vector2d(110,10)); list parent; list res; p.Shrink(2, parent, res); BOOST_CHECK( res.size() == 2 ); for(list::iterator pIt = res.begin(); pIt != res.end(); pIt++) delete *pIt; } BOOST_AUTO_TEST_CASE( Slicing_PointHash ) { PointHash h; float x = 10.0, y = 7.0; float d = PointHash::float_epsilon / 2; BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y)) < 0); h.InsertPoint (0, Vector2d (x, y)); // look around that point BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x + d, y)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - d, y)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y + d)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y - d)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x + d, y + d)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - d, y - d)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x + d, y - d)) == 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - d, y + d)) == 0); // look nearby but not there float e = PointHash::float_epsilon * 3 / 2; BOOST_CHECK (h.IndexOfPoint (Vector2d(x + e, y)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - e, y)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y + e)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x, y - e)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x + e, y + e)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - e, y - e)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x + e, y - e)) < 0); BOOST_CHECK (h.IndexOfPoint (Vector2d(x - e, y + e)) < 0); } // Simple neat square BOOST_AUTO_TEST_CASE( Slicing_Lines_Square_Simple ) { CuttingPlane cp; // degenerate case BOOST_CHECK (cp.LinkSegments (0.1, 0.001) == true); int tl = cp.RegisterPoint (Vector2d (10, 20)); int tr = cp.RegisterPoint (Vector2d (20, 20)); int bl = cp.RegisterPoint (Vector2d (10, 10)); int br = cp.RegisterPoint (Vector2d (20, 10)); cp.AddLine (CuttingPlane::Segment (tl, tr)); cp.AddLine (CuttingPlane::Segment (bl, tl)); cp.AddLine (CuttingPlane::Segment (tr, br)); cp.AddLine (CuttingPlane::Segment (br, bl)); BOOST_CHECK (cp.LinkSegments (0.1, 0.001) == true); BOOST_CHECK (cp.GetPolygons().size() == 1); BOOST_CHECK (cp.GetPolygons()[0].points.size() == 4); } // Dis-connected square BOOST_AUTO_TEST_CASE( Slicing_Lines_Square_Nastier ) { CuttingPlane cp; float d = PointHash::float_epsilon / 2; int tl = cp.RegisterPoint (Vector2d (10, 20)); int tln = cp.RegisterPoint (Vector2d (10, 20 + 0.01)); int tr = cp.RegisterPoint (Vector2d (20, 20)); int trn = cp.RegisterPoint (Vector2d (20 + d, 20)); int bl = cp.RegisterPoint (Vector2d (10, 10)); int bln = cp.RegisterPoint (Vector2d (10 + 0.5, 10 + 0.5)); int br = cp.RegisterPoint (Vector2d (20, 10)); int brn = cp.RegisterPoint (Vector2d (20 + 0.5, 10 + d)); cp.AddLine (CuttingPlane::Segment (tl, trn)); cp.AddLine (CuttingPlane::Segment (bl, tln)); cp.AddLine (CuttingPlane::Segment (tr, brn)); cp.AddLine (CuttingPlane::Segment (br, bln)); BOOST_CHECK (cp.LinkSegments (0.1, 0.001) == true); BOOST_CHECK (cp.GetPolygons().size() == 1); // fprintf (stderr, "lines %d\n", cp.GetPolygons()[0].points.size()); // BOOST_CHECK (cp.GetPolygons()[0].points.size() == 4); } // Multi-point shape // a---b // | | // c---d---e // | | // f---g BOOST_AUTO_TEST_CASE( Slicing_Lines_Single_Co_Incident ) { CuttingPlane cp; int a = cp.RegisterPoint (Vector2d (10, 30)); int b = cp.RegisterPoint (Vector2d (20, 30)); int c = cp.RegisterPoint (Vector2d (10, 20)); int d = cp.RegisterPoint (Vector2d (20, 20)); int e = cp.RegisterPoint (Vector2d (30, 20)); int f = cp.RegisterPoint (Vector2d (20, 10)); int g = cp.RegisterPoint (Vector2d (30, 10)); cp.AddLine (CuttingPlane::Segment (a, b)); cp.AddLine (CuttingPlane::Segment (b, d)); cp.AddLine (CuttingPlane::Segment (d, c)); cp.AddLine (CuttingPlane::Segment (c, a)); cp.AddLine (CuttingPlane::Segment (d, e)); cp.AddLine (CuttingPlane::Segment (e, g)); cp.AddLine (CuttingPlane::Segment (g, f)); cp.AddLine (CuttingPlane::Segment (f, d)); BOOST_CHECK (cp.LinkSegments (0.1, 0.001) == true); BOOST_CHECK (cp.GetPolygons().size() == 2); } // Co-incident boundary // a---b // | | // c---d // | | // e---f BOOST_AUTO_TEST_CASE( Slicing_Lines_Boundary_Co_Incident ) { CuttingPlane cp; int a = cp.RegisterPoint (Vector2d (10, 30)); int b = cp.RegisterPoint (Vector2d (20, 30)); int c = cp.RegisterPoint (Vector2d (10, 20)); int d = cp.RegisterPoint (Vector2d (20, 20)); int e = cp.RegisterPoint (Vector2d (10, 10)); int f = cp.RegisterPoint (Vector2d (20, 10)); cp.AddLine (CuttingPlane::Segment (a, b)); cp.AddLine (CuttingPlane::Segment (b, d)); cp.AddLine (CuttingPlane::Segment (d, c)); cp.AddLine (CuttingPlane::Segment (c, a)); cp.AddLine (CuttingPlane::Segment (d, f)); cp.AddLine (CuttingPlane::Segment (f, e)); cp.AddLine (CuttingPlane::Segment (e, c)); cp.AddLine (CuttingPlane::Segment (c, d)); BOOST_CHECK (cp.LinkSegments (0.1, 0.001) == true); BOOST_CHECK (cp.GetPolygons().size() == 1); BOOST_CHECK (cp.GetPolygons()[0].points.size() == 4); } #endif // !defined(WIN32) || defined (UNITTEST) repsnapper-2.3.2a5/todo.txt000066400000000000000000000003311231531733200156260ustar00rootroot00000000000000Write an 'install' target in our makefile Implement a big red "Emergency Stop" button on the print tab that sends an M112 code to the printer. Libraries to be moved to /lib: - ivcon.c - AsyncSerial - FLTK stuff repsnapper-2.3.2a5/tools/000077500000000000000000000000001231531733200152635ustar00rootroot00000000000000repsnapper-2.3.2a5/tools/.gitignore000066400000000000000000000000161231531733200172500ustar00rootroot00000000000000gitversion.sh repsnapper-2.3.2a5/tools/gitversion.sh.in000077500000000000000000000025561231531733200204300ustar00rootroot00000000000000#!/bin/sh if [ "$#" -lt 2 ]; then echo "Usage: $0 " exit 1 fi VERSION_H="$1" TARBALL_VERSION_H="$2" TOPSRCDIR=`dirname "${TARBALL_VERSION_H}"`/.. # Check if building from git if [ ! -d "${TOPSRCDIR}/.git" ]; then # Not git, just ensure output file exists if [ ! -f "${TARBALL_VERSION_H}" ]; then echo "Warning: Not building from git and ${TARBALL_VERSION_H} doesn't exist" echo const string GIT_COMMIT=\"Unknown\"\; > $VERSION_H echo const string GIT_COMMIT_DATE=\"Unknown\"\; >> $VERSION_H # else # echo "Not updating ${VERSION_H} - building from tarball" fi exit 0 fi AWK=@AWK@ FSEQUAL="=" # test for BSD awk which needs a blackslash: FSERROR=$(${AWK} -v FS== '' 2>&1) if [ "X$FSERROR" != "X" ] ; then FSEQUAL="\=" fi GIT_DIR="${TOPSRCDIR}/.git" export GIT_DIR LOG=`git log -1` COMMIT=`echo "$LOG" | $AWK '/commit/{print $2; exit}'` DATE=` echo "$LOG" | $AWK -v FS="Date: " '/Date:/{print $2; exit}'` OLDCOMMIT="" if [ -e $VERSION_H ]; then OLDCOMMIT=`$AWK -v FS="$FSEQUAL" '/const string GIT_COMMIT=/{print $2}' $VERSION_H` fi if [ "x\"$COMMIT\";" != "x$OLDCOMMIT" ]; then # echo "Updating commit" echo const string GIT_COMMIT=\"$COMMIT\"\; > $VERSION_H echo const string GIT_COMMIT_DATE=\"$DATE\"\; >> $VERSION_H #else # echo "Commit has not changed" fi repsnapper-2.3.2a5/tools/win32-developer-setup.pl000077500000000000000000001477361231531733200217300ustar00rootroot00000000000000#!c:/perl/bin/perl.exe -w ############################################################################## ### =file ### win32-developer.pl ### ### =location ### http://svn.xxxx.org/svn/trunk/xxxxx/xxxx/xxxx/win32-developer.pl ### ### =description ### Tool for automating setup of Msys/Mingw builds on MS Windows XP (and compatible) ### based heavily on win32-packager from the MythTv project ### ( by the same author) ### ### =examples ### win32-developer.pl -h ### => Print usage ### win32-developer.pl ### => based on latest "tested" SVN trunk (ie a known-good win32 build) ### win32-developer.pl -r head ### => based on trunk head ### win32-developer.pl -b ### => based on release-021-fixes branch ### win32-developer.pl -b -t ### => include some patches which are not accepted, but needed for Win32 ### win32-developer.pl -b -t -k ### =>Same but package and create setup.exe at the end ### ### =revision ### $Id$ ### ### =author ### David Bussenschutt ############################################################################## use strict; use LWP::UserAgent; use IO::File; use Data::Dumper; use File::Copy qw(cp); use Getopt::Std; use Digest::MD5; $SIG{INT} = sub { die "Interrupted\n"; }; $| = 1; # autoflush stdout; # this script was last tested to work with this version, on other versions YMMV. #my $SVNRELEASE = '23137'; # Recent trunk #my $SVNRELEASE = 'HEAD'; # If you are game, go forth and test the latest! # We allow SourceForge to tell us which server to download from, # rather than assuming specific server/s my $sourceforge = 'downloads.sourceforge.net'; # auto-redirect to a # mirror of SF's choosing, # hopefully close to you # alternatively you can choose your own mirror: #my $sourceforge = 'optusnet.dl.sourceforge.net'; # Australia #my $sourceforge = 'internap.dl.sourceforge.net'; # USA,California #my $sourceforge = 'easynews.dl.sourceforge.net'; # USA,Arizona,Phoenix, #my $sourceforge = 'jaist.dl.sourceforge.net'; # Japan #my $sourceforge = 'mesh.dl.sourceforge.net'; # Germany #my $sourceforge = 'transact.dl.sourceforge.net'; # Germany # Set this to the empty string for no-proxy: my $proxy = ''; #my $proxy = 'http://enter.your.proxy.here:8080'; # Subversion proxy settings are configured in %APPDATA%\Subversion\servers my $NOISY = 1; # Set to 0 for less output to the screen my $package = 0; # Create a Win32 Distribution package? 1 for yes my $compile_type = "profile"; # compile options: debug, profile or release my $tickets = 0; # Apply specific win32 tickets - # usually those not merged into SVN my $dbconf = 0; # Configure MySQL as part of the build process. # Required only for testing my $makeclean = 0; # Flag to make clean #my $svnlocation = "trunk"; # defaults to trunk unless -b specified my $qtver = 4; # default to 4 until we can test otherwise my $continuous = 0 ; # by default the app pauses to notify you what # it's about to do, -y overrides for batch usage. my $GitUrl = "https://github.com/timschmidt/repsnapper.git"; ############################################################################## # get command line options my $opt_string = 'vhogkp:r:c:tldby'; my %opt = (); getopts( "$opt_string", \%opt ); usage() if $opt{h}; $package = 1 if defined $opt{k}; $NOISY = 1 if defined $opt{v}; $tickets = 1 if defined $opt{t}; $proxy = $opt{p} if defined $opt{p}; #$SVNRELEASE = $opt{r} if defined $opt{r}; $dbconf = 1 if defined $opt{d}; $makeclean = 1 if defined $opt{l}; $continuous = 1 if defined $opt{y}; if (defined $opt{c}) { $compile_type = $opt{c} if ($opt{c} eq "release") ; $compile_type = $opt{c} if ($opt{c} eq "profile") ; } #if (defined $opt{b}) { # my @num = split /\./, $version; #$svnlocation = "branches/release-$num[0]-$num[1]-fixes"; # # Releases like 0.23.1 are actually tags, and use a different location: #if ($version =~ m/-\d$/) { # $svnlocation = "tags/release-$num[0]-$num[1]-$num[2]"; #} #} else { # $svnlocation = "trunk"; #} # Try to use parallel make my $numCPU = $ENV{'NUMBER_OF_PROCESSORS'} or 1; my $parallelMake = 'make'; if ( $numCPU gt 1 ) { # Pre-queue one extra job to keep the pipeline full: $parallelMake = 'make -j '. ($numCPU + 1); } # "Config:\n\tQT version: $qtver\n\tDLLs will be labeled as: $version\n"; if ( $numCPU gt 1 ) { print "\tBuilding with ", $numCPU, " processors\n"; } print "\n\tWelcome to the Win32 MSYS/MINGW helper script for repsnapper!\n ". "\tWe are about to try to install everything for you! \n". "\n\tHere are the relevant paths were thing will be installed:\n\n"; #print "\tComponents to build: "; #foreach my $comp( @components ) { print "$comp " } #print "\n\nPress [enter] to continue, or [ctrl]-c to exit now....\n"; #getc() unless $continuous; # this will be used to test if we the same # basic build type/layout as previously. #my $is_same = "$compile_type-$svnlocation-$qtver.same"; #$is_same =~ s#/#-#g; # don't put dir slashes in a filename! # TODO - we should try to autodetect these paths, rather than assuming # the defaults - perhaps from environment variables like this: # die "must have env variable SOURCES pointing to your sources folder" # unless $ENV{SOURCES}; # my $sources = $ENV{SOURCES}; # TODO - although theoretically possible to change these paths, # it has NOT been tested much, # and will with HIGH PROBABILITY fail somewhere. # - Only $mingw is tested and most likely is safe to change. # Perl compatible paths. DOS style, but forward slashes, and must end in slash: # TIP: using paths with spaces in them is NOT supported, and will break. # patches welcome. my $msys = 'C:/MSys/1.0/'; my $sources = 'C:/MSys/1.0/sources/'; my $mingw = 'C:/MinGW/'; my $approot = 'C:/repsnapper/'; # this is where the entire SVN checkout lives # so c:/app/app/ is the main codebase. my $build = 'C:/repsnapper/repsnapper/src/'; # where 'make install' installs into # Where is the users home? #my $doshome = ''; #if ( ! exists $ENV{'HOMEPATH'} || $ENV{'HOMEPATH'} eq '\\' ) { # $doshome = $ENV{'USERPROFILE'}; #} else { # $doshome = $ENV{HOMEDRIVE}.$ENV{HOMEPATH}; #} #my $home = $doshome; #$home =~ s#\\#/#g; #$home =~ s/ /\\ /g; #$home .= '/'; # all paths should end in a slash # Where are program files (32-bit)? my $dosprogramfiles = ''; if ( $ENV{'ProgramFiles(x86)'} ) { $dosprogramfiles = $ENV{'ProgramFiles(x86)'}; } else { $dosprogramfiles = $ENV{'ProgramFiles'}; } my $programfiles = $dosprogramfiles; $programfiles =~ s#\\#/#g; # DOS executable CMD.exe versions of the paths (for when we shell to DOS mode): my $dosmsys = perl2dos($msys); my $dossources = perl2dos($sources); my $dosmingw = perl2dos($mingw); my $dosapp = perl2dos($approot); # Unix/MSys equiv. versions of the paths (for when we shell to MSYS/UNIX mode): my $unixmsys = '/'; # MSys root is always mounted here, # irrespective of where DOS says it really is. my $unixmingw = '/mingw/'; # MinGW is always mounted here under unix, # if you setup mingw right in msys, # so we will usually just say /mingw in the code, # not '.$unixmingw.' or similar (see /etc/fstab) my $unixsources = perl2unix($sources); my $unixapp = perl2unix($approot); #my $unixhome = perl2unix($home); my $unixprogramfiles = perl2unix($programfiles); my $unixbuild = perl2unix($build); # The installer for MinGW: my $MinGWinstaller = 'MinGW-5.1.6.exe'; my $installMinGW = $dossources.$MinGWinstaller; # Qt4 directory #my $qt4dir = 'C:/qt/4.5.3/'; #my $dosqt4dir = perl2dos($qt4dir); #my $unixqt4dir = perl2unix($qt4dir); #NOTE: IT'S IMPORTANT that the PATHS use the correct SLASH-ing method for #the type of action: # for [exec] actions, use standard DOS paths, with single BACK-SLASHES # '\' (unless in double quotes, then double the backslashes) # for [shell] actions, use standard UNIX paths, with single # FORWARD-SLASHES '/' # #NOTE: when referring to variables in paths, try to keep them out of double #quotes, or the slashing can get confused: # [exec] actions should always refer to $dosXXX path variables # [shell] actions should always refer to $unixXXX path variables # [dir],[file],[mkdirs],[archive] actions should always refer to # default perl compatible paths # NOTE: The architecture of this script is based on cause-and-event. # There are a number of "causes" (or expectations) that can trigger # an event/action. # There are a number of different actions that can be taken. # # eg: [ dir => "c:/MinGW", exec => $dossources.'MinGW-5.1.4.exe' ], # # means: expect there to be a dir called "c:/MinGW", and if there isn't # execute the file MinGW-5.1.4.exe. (clearly there needs to be a file # MinGW-5.1.4.exe on disk for that to work, so there is an earlier # declaration to 'fetch' it) #build expectations (causes) : # missing a file (given an expected path) [file] # missing folder [dir] # missing source archive (version of 'file' to fetch from the web) [archive] # apply a perl pattern match and if it DOESNT match execute action [grep] # - this 'cause' actually needs two parameters in an array # [ pattern, file]. If the file is absent, the pattern # is assumed to not match (and emits a warning). # test the file/s are totally the same (by size and mtime) [filesame] # - if first file is non-existant then that's permitted, # it causes the action to trigger. # test the first file is newer(mtime) than the second one [newer] # - if given 2 existing files, not necessarily same size/content, # and the first one isn't newer, execute the action! # If the first file is ABSENT, run the action too. # execute the action only if a file or directory exists [exists] # stop the run, useful for script debugging [stop] # pause the run, await a enter [pause] # always execute the action (try to minimise the use of this!) [always] #build actions (events) are: # fetch a file from the web (to a location) [fetch] # execute a DOS/Win32 exe/command and wait to complete [exec] # execute a MSYS/Unix script/command in bash and wait to complete [shell] # - this 'effect' actually accepts many parameters in an array # [ cmd1, cmd2, etc ] # extract a .tar .tar.gz or .tar.bz2 or ,zip file ( to a location) [extract] # - (note that .gz and .bz2 are thought equivalent) # write a small patch/config/script file directly to disk [write] # make directory tree upto the path specified [mkdirs] # copy a new version of a file, set mtime to the original [copy] #TODO: # copy a set of files (path/filespec, destination) not-yet-impl # => use exec => 'copy /Y xxx.* yyy' # apply a diff not-yet-impl # => use shell => 'patch -p0 < blah.patch' # search-replace text in a file not-yet-impl # => use grep => ['pattern',subject], # exec => shell 'patch < etc to replace it' # NOTES on specific actions: # 'extract' now requires all paths to be perl compatible (like all other # commands) If not supplied, it extracts into the folder the .tar.gz is in. # 'exec' actually runs all your commands inside a single cmd.exe # command-line. To link commands use '&&' # 'shell' actually runs all your commands inside a bash shell with -c "( # cmd;cmd;cmd )" so be careful about quoting. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # DEFINE OUR EXPECTATIONS and the related ACTIONS: # - THIS IS THE GUTS OF THE APPLICATION! # - A SET OF DECLARATIONS THAT SHOULD RESULT IN A WORKING WIN32 INSTALATION #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ my $expect; push @{$expect}, [ dir => [$sources] , mkdirs => [$sources], comment => 'We will download all the files from the web, and save them here:'], [ pause => '.... press [enter] to continue !'], [ archive => $sources.$MinGWinstaller, 'fetch' => 'http://'.$sourceforge.'/sourceforge/mingw/'.$MinGWinstaller, comment => 'Get mingw and addons first, or we cant do [shell] requests!' ], [ archive => $sources.'mingw-utils-0.3.tar.gz', 'fetch' => 'http://'.$sourceforge. '/sourceforge/mingw/mingw-utils-0.3.tar.gz' ], # ffmpeg complains if gcc < 4.2, so download a newer version # As of 20090626 MinGW gcc >= 4.3 do NOT work with ffmpeg (MinGW bug #2812588) [ archive => $sources.'gcc-4.2.4-tdm-1-core.tar.gz', 'fetch' => 'http://'.$sourceforge. '/sourceforge/tdm-gcc/gcc-4.2.4-tdm-1-core.tar.gz' ], [ archive => $sources.'gcc-4.2.4-tdm-1-g++.tar.gz', 'fetch' => 'http://'.$sourceforge. '/sourceforge/tdm-gcc/gcc-4.2.4-tdm-1-g++.tar.gz' ], [ dir => $mingw, exec => $installMinGW, comment => 'install MinGW (be sure to install g++, g77 and ming '. 'make too. Leave the default directory at c:\mingw ) '. '- it will require user interaction, '. 'but once completed, will return control to us....' ], # interactive, supposed to install g++ and ming make too, # but people forget to select them? [ file => $mingw."bin/gcc.exe", exec => $installMinGW, comment => 'unable to find a gcc.exe where expected, '. 'rerunning MinGW installer!' ], [ archive => $sources.'MSYS-1.0.11.exe', 'fetch' => 'http://'.$sourceforge.'/sourceforge/mingw/MSYS-1.0.11.exe', comment => 'Get the MSYS and addons:' ] , [ archive => $sources.'bash-3.1-MSYS-1.0.11-1.tar.bz2', 'fetch' => 'http://'.$sourceforge. '/sourceforge/mingw/bash-3.1-MSYS-1.0.11-1.tar.bz2' ] , [ archive => $sources.'zlib-1.2.3-MSYS-1.0.11.tar.bz2', 'fetch' => 'http://easynews.dl.sourceforge.net'. '/sourceforge/mingw/zlib-1.2.3-MSYS-1.0.11.tar.bz2' ] , [ archive => $sources.'coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2', 'fetch' => 'http://'.$sourceforge.'/sourceforge/mingw'. '/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2' ] , [ archive => $sources.'mktemp-1.5-MSYS.tar.bz2', 'fetch' => 'http://'.$sourceforge.'/sourceforge/mingw'. '/mktemp-1.5-MSYS.tar.bz2' ] , # install MSYS, it supplies the 'tar' executable, among others: [ file => $msys.'bin/tar.exe', exec => $dossources.'MSYS-1.0.11.exe', comment => 'Install MSYS, it supplies the tar executable, among others. You '. 'should follow prompts, AND do post-install in DOS box.' ] , # don't use the [shell] or [copy] actions here, # as neither are avail til bash is installed! [ file => $msys.'bin/sh2.exe', exec => 'copy /Y '.$dosmsys.'bin\sh.exe '.$dosmsys.'bin\sh2.exe', comment => 'make a copy of the sh.exe so that we can '. 'utilise it when we extract later stuff' ], # prior to this point you can't use the 'extract' 'copy' or 'shell' features! # if you did a default-install of MingW, then you need to try again, as we # really need g++ and mingw32-make, and g77 is needed for fftw [ file => $mingw.'bin/mingw32-make.exe', exec => $installMinGW, comment => 'Seriously? You must have done a default install of MinGW. '. 'go try again! You MUST choose the custom installed and select '. 'the mingw make, g++ and g77 optional packages.' ], [ file => $mingw.'bin/g++.exe', exec => $installMinGW, comment => 'Seriously? You must have done a default install of MinGW. '. 'go try again! You MUST choose the custom installed and select '. 'the mingw make, g++ and g77 optional packages.' ], [ file => $mingw.'bin/g77.exe', exec => $installMinGW, comment => 'Seriously? You must have done a default install of MinGW. '. 'go try again! You MUST choose the custom installed and select '. 'the mingw make, g++ and g77 optional packages.' ], #[ file => 'C:/MinGW/bin/mingw32-make.exe', extract => #$sources.'mingw32-make-3.81-2.tar',"C:/MinGW" ], - optionally we could get #mingw32-make from here # now that we have the 'extract' feature, we can finish ... [ file => $mingw.'/bin/reimp.exe', extract => [$sources.'mingw-utils-0.3.tar', $mingw], comment => 'Now we can finish all the mingw and msys addons:' ], [ file => $msys.'bin/bash.exe', extract => [$sources.'bash-3.1-MSYS-1.0.11-1.tar', $msys] ], [ file => $mingw.'bin/mingw32-gcc-4.2.4.exe', extract => [$sources.'gcc-4.2.4-tdm-1-core.tar', $mingw] ], [ file => $mingw.'include/c++/4.2.4/cstdlib', extract => [$sources.'gcc-4.2.4-tdm-1-g++.tar', $mingw] ], [ dir => $sources.'coreutils-5.97', extract => [$sources.'coreutils-5.97-MSYS-1.0.11-snapshot.tar'] ], [ file => $msys.'bin/pr.exe', shell => ["cd ".$unixsources."coreutils-5.97","cp -r * / "] ], [ file => $msys.'bin/mktemp.exe', extract => [$sources.'mktemp-1.5-MSYS.tar', $msys] ], [ dir => $msys."lib" , mkdirs => $msys.'lib' ], [ dir => $msys."include" , mkdirs => $msys.'include' ], #get gdb [ archive => $sources.'gdb-6.8-mingw-3.tar.bz2', 'fetch' => 'http://'.$sourceforge. '/sourceforge/mingw/gdb-6.8-mingw-3.tar.bz2', comment => 'Get gdb for possible debugging later' ], [ file => $msys.'bin/gdb.exe', extract => [$sources.'gdb-6.8-mingw-3.tar.bz2', $msys] ], # (alternate would be from the gnuwin32 project, # which is actually from same source) # run it into a 'unzip' folder, because it doesn't extract to a folder: [ dir => $sources."unzip", mkdirs => $sources.'unzip', comment => 'unzip.exe - Get a precompiled '. 'native Win32 version from InfoZip' ], [ archive => $sources.'unzip/unz552xN.exe', 'fetch' => 'ftp://ftp.info-zip.org/pub/infozip/win32/unz552xn.exe'], [ file => $sources.'unzip/unzip.exe', exec => 'chdir '.$dossources.'unzip && '. $dossources.'unzip/unz552xN.exe' ], # we could probably put the unzip.exe into the path... # get GIT from the msys git project [ archive => $sources.'Git-1.7.3.1-preview20101002.exe', 'fetch' => 'http://msysgit.googlecode.com/files/Git-1.7.3.1-preview20101002.exe', comment => 'Get GIT for use later.' ], # install GIT exe, to C:\Program Files\Git : [ file => 'C:/Progra~1/Git/bin/git.exe', exec => $dossources.'Git-1.7.3.1-preview20101002.exe', comment => 'Install GIT. You should follow the DEFAULT prompts ... dont change them! ...' ] , #[ pause => '.... press [enter] to continue !'], # : [ dir => $sources."zlib", mkdirs => $sources.'zlib', comment => 'the zlib download is a bit messed-up, and needs some TLC '. 'to put everything in the right place' ], [ dir => $sources."zlib/usr", extract => [$sources.'zlib-1.2.3-MSYS-1.0.11.tar', $sources."zlib"] ], # install to /usr: [ file => $msys.'lib/libz.a', exec => ["copy /Y ".$dossources.'zlib\usr\lib\* '.$dosmsys."lib"] ], [ file => $msys.'bin/msys-z.dll', exec => ["copy /Y ".$dossources.'zlib\usr\bin\* '.$dosmsys."bin"] ], [ file => $msys.'include/zlib.h', exec => ["copy /Y ".$dossources.'zlib\usr\include\* '. $dosmsys."include"] ], # make sure that /mingw is mounted in MSYS properly before trying # to use the /mingw folder. this is supposed to happen as part # of the MSYS post-install, but doesnt always work. [ file => $msys.'etc/fstab', write => [$msys.'etc/fstab', "$mingw /mingw " ], comment => 'correct a MinGW bug that prevents the /etc/fstab from existing'], # apply sspi.h patch [ file => $mingw.'include/sspi_h.patch', write => [$mingw.'include/sspi_h.patch', '*** sspi.h Sun Jan 25 17:55:57 2009 --- sspi.h.new Sun Jan 25 17:55:51 2009 *************** *** 8,13 **** --- 8,15 ---- extern "C" { #endif + #include + #define SECPKG_CRED_INBOUND 1 #define SECPKG_CRED_OUTBOUND 2 #define SECPKG_CRED_BOTH (SECPKG_CRED_OUTBOUND|SECPKG_CRED_INBOUND) ' ],comment => 'write the patch for the the sspi.h file'], # apply it!? [ grep => ['subauth.h',$mingw.'include/sspi.h'], shell => ["cd /mingw/include","patch -p0 < sspi_h.patch"], comment => 'Apply sspi.h patch file, if not already applied....' ], #[ pause => 'check patch.... press [enter] to continue !'], # apply sched.h patch [ always => $mingw.'include/sched_h.patch', write => [$mingw.'include/sched_h.patch', "--- include/sched.h.org Thu Dec 4 12:00:16 2008 +++ include/sched.h Wed Dec 3 13:42:54 2008 @@ -124,8 +124,17 @@ typedef int pid_t; #endif -/* Thread scheduling policies */ +/* pid_t again! */ +#if defined(__MINGW32__) || defined(_UWIN) +/* Define to `int' if does not define. */ +/* GCC 4.x reportedly defines pid_t. */ +#ifndef _PID_T_ +#define _PID_T_ +#define pid_t int +#endif +#endif +/* Thread scheduling policies */ enum { SCHED_OTHER = 0, SCHED_FIFO, " ],comment => 'write the patch for the the sched.h file'], # apply it!? [ grep => ['GCC 4.x reportedly defines pid_t',$mingw.'include/sched.h'], shell => ["cd /mingw/include","patch -p1 < sched_h.patch"], comment => 'Apply sched.h patch file, if not already applied....' ], #[ pause => 'check patch.... press [enter] to continue !'], ; # if packaging is selected, get innosetup if ($package == 1) { push @{$expect}, [ archive => $sources.'isetup-5.2.3.exe', fetch => 'http://files.jrsoftware.org/ispack/ispack-5.2.3.exe', comment => 'fetch inno setup setup' ], [ file => $programfiles.'/Inno Setup 5/iscc.exe', exec => $dossources.'isetup-5.2.3.exe', #/silent is broken! comment => 'Install innosetup - install ISTool, '. 'ISSP, AND encryption support.' ], # Get advanced uninstall [ archive => $sources.'UninsHs.rar', fetch => 'http://www.uninshs.com/down/UninsHs.rar', comment => 'fetch uninstall for innosetup' ], [ archive => $sources.'unrar-3.4.3-bin.zip', fetch => 'http://downloads.sourceforge.net/gnuwin32/unrar-3.4.3-bin.zip', comment => 'fetching unrar'], [ file => $sources.'bin/unrar.exe', shell => ["cd ".$sources, "unzip/unzip.exe unrar-3.4.3-bin.zip"]], [ file => $programfiles.'/Inno Setup 5/UninsHs.exe', shell => ['cd "'.$unixprogramfiles.'/inno setup 5"', $sources.'bin/unrar.exe e '.$sources.'UninsHs.rar'], comment => 'Install innosetup' ], [ archive => $sources.'istool-5.2.1.exe', fetch => 'http://downloads.sourceforge.net/sourceforge'. '/istool/istool-5.2.1.exe', comment => 'fetching istool' ], [ file => $programfiles.'/ISTool/isxdl.dll', exec => $dossources.'istool-5.2.1.exe /silent', comment => 'Install istool'], [ archive => $sources.'logo_mysql_sun.gif', fetch => 'http://www.mysql.com/common/logos/logo_mysql_sun.gif', comment => 'Download MySQL logo for an install page in the package' ], [ exists => $approot.'build/package_flag', shell => ["rm ".$unixapp."build/package_flag"], comment => '' ], ; } #---------------------------------------- # now we do each of the source library dependencies in turn: # download,extract,build/install # TODO - ( and just pray that they all work?) These should really be more # detailed, and actually check that we got it installed properly. # # Most of these look for a Makefile as a sign that the ./configure was # successful (not necessarily true, but it's a start) but this requires that # the .tar.gz didn't come with a Makefile in it. push @{$expect}, #[ archive => $sources.'freetype-2.3.5.tar.gz', # fetch => 'http://download.savannah.gnu.org'. # '/releases-noredirect/freetype/freetype-2.3.5.tar.gz'], #[ dir => $sources.'freetype-2.3.5', # extract => $sources.'freetype-2.3.5.tar' ], ## caution... freetype comes with a Makefile in the .tar.gz, so work around it! #[ file => $sources.'freetype-2.3.5/Makefile__', # shell => ["cd $unixsources/freetype-2.3.5", # "./configure --prefix=/usr", # "touch $unixsources/freetype-2.3.5/Makefile__"], # comment => 'building freetype' ], # ## here's an example of specifying the make and make install steps separately, ## for apps that can't be relied on to have the make step work! #[ file => $sources.'freetype-2.3.5/objs/.libs/libfreetype.a', # shell => ["cd $unixsources/freetype-2.3.5", # "make"], # comment => 'checking freetype' ], #[ file => $msys.'lib/libfreetype.a', # shell => ["cd $unixsources/freetype-2.3.5", # "make install"], # comment => 'installing freetype' ], #[ file => $msys.'bin/libfreetype-6.dll', # shell => ["cp $unixsources/freetype-2.3.5/objs/.libs/libfreetype-6.dll ". # "$msys/bin/"] ], # ##here's a classic "configure; make; make-install" script, but specifying the PREFIX. #[ archive => $sources.'lame-398-2.tar.gz', # fetch => 'http://'.$sourceforge.'/sourceforge/lame/lame-398-2.tar.gz'], #[ dir => $sources.'lame-398-2', # extract => $sources.'lame-398-2.tar' ], #[ file => $msys.'lib/libmp3lame.a', # shell => ["cd $unixsources/lame-398-2", # "./configure --prefix=/usr", # "make", # "make install"], # comment => 'building and installing: msys lame' ], # # get fluid binary: from http://www.muquit.com/muquit/software/fluid_hack/fluid.exe #[ archive => $sources.'fluid.exe', # 'fetch' => 'http://www.muquit.com/muquit/software/fluid_hack/fluid.exe', # comment => 'Get FLUID for use later.' ], #[ file => $msys.'bin/fluid.exe', # exec => 'copy /Y '.$dossources.'fluid.exe '.$dosmsys.'bin\fluid.exe'], # get fltk sources to compile against: # http://ftp.easysw.com/pub/fltk/1.1.10/fltk-1.1.10-source.tar.gz # install into /mingw as installing to /usr seems to not quite work right? [ archive => $sources.'fltk-1.1.10-source.tar.gz', 'fetch' => 'http://ftp.easysw.com/pub/fltk/1.1.10/fltk-1.1.10-source.tar.gz', comment => 'Get FLTK 1.1.10 for use later.' ], [ dir => $sources.'fltk-1.1.10', extract => $sources.'fltk-1.1.10-source.tar' ], [ file => $mingw.'lib/libfltk.a', shell => ["cd $unixsources/fltk-1.1.10", "./configure --prefix=/mingw", "make", "make install"], comment => 'building and installing: msys fltk-1.1.10-source' ], # get vmmlib: [ pause => 'check patch.... press [enter] to continue !'], ; #---------------------------------------- # get app sources, if we don't already have them # download all the files from the web, and save them here: #---------------------------------------- push @{$expect}, [ dir => $approot, mkdirs => $approot, comment => 'make app dir'], # if no files , pull from main GIT repo ( no support for alternative repos presently [ file => $build.'Makefile', shell => ['cd '.$approot, 'C:/Progra~1/Git/bin/git.exe clone '.$GitUrl], comment => 'CLONE git repo!'], # NOTE: if there are already files in the folder, we assume you just want to build them as-is # and we don't muck with them.! #[ pause => '.... press [enter] to continue !'], #---------------------------------------- # now we actually build app! #---------------------------------------- # [ file => $build.'repsnapper', # is the binary present?! shell => ['cd '.$unixbuild, 'make'], comment => 'Build the app! ' ], ; # make # check that the date stamp on your target dll's is newenough, or delete it and try again. # repeat for each dll ( not shown here ) #[ newer => [$approot."app/libs/libmyth/libmyth-$version.dll", # $approot.'app/last_build.txt'], # shell => ['rm '.$unixapp."app/libs/libmyth/libmyth-$version.dll", # 'source '.$unixapp.'qt'.$qtver.'_env.sh', # 'cd '.$unixapp.'app', $parallelMake], # comment => 'libs/libmyth/libmyth-$version.dll - '. # 'redo make unless all these files exist, '. # 'and are newer than the last_build.txt identifier' ], # Archive old build before we create a new one with make install: #[ exists => $approot.'build_old', # shell => ['rm -fr '.$unixapp.'build_old'], # comment => 'Deleting old build backup'], #[ exists => $build, # shell => ['mv '.$unixbuild.' '.$unixapp.'build_old'], # comment => 'Renaming build to build_old for backup....'], # re-install to /c/app/build if we have a newer app build # ready: #[ newer => [$build.'bin/mythfrontend.exe', # $approot.'app/programs/mythfrontend/mythfrontend.exe'], # shell => ['source '.$unixapp.'qt'.$qtver.'_env.sh', # 'cd '.$unixapp.'app', # 'make install'], # comment => 'was the last configure successful? then install app ' ], # ------------------------------- # Prepare Readme.txt for distribution file - temporary for now # ------------------------------- push @{$expect}, [ file => $approot.'repsnapper/readme.win32.txt', write => [$approot.'repsnapper/readme.win32.txt', 'PLACEHOLDER README for Win32 Installation of XXXX version ============================================================= The current installation very basic: - All exe and dlls will be installed to %PROGRAMFILES% - TODO ','nocheck'],comment => ''], [ file => $approot.'repsnapper/readme.win32.txt', shell => ['unix2dos '.$unixapp.'repsnapper/readme.win32.txt', 'nocheck'], comment => 'Create a WIN32 readme.txt file, if there isnt one' ], ; #if ($package == 1) { # push @{$expect}, # # Create directories # [ dir => [$approot.'setup'] , # # mkdirs => [$approot.'setup'], # comment => 'Create Packaging directory'], # [ dir => [$approot.'build/isfiles'] , # mkdirs => [$approot.'build/isfiles'], # comment => 'Create Packaging directory'], # # Move required files from inno setup to setup directory # [ file => $approot."build/isfiles/UninsHs.exe", # exec => 'copy /Y "'.$dosprogramfiles.'\Inno Setup 5\UninsHs.exe" '.# # $dosapp.'build\isfiles\UninsHs.exe', # comment => 'Copy UninsHs to setup directory' ], # [ file => $approot."build/isfiles/isxdl.dll", # exec => 'copy /Y "'.$dosprogramfiles.'\ISTool\isxdl.dll" '. # $dosapp.'build\isfiles\isxdl.dll', # comment => 'Copy isxdl.dll to setup directory' ], # [ file => $approot."build/isfiles/WizModernSmallImage-IS.bmp", # exec => 'copy /Y "'.$dosprogramfiles.'\Inno Setup 5'. # '\WizModernSmallImage-IS.bmp" '. # $dosapp.'build\isfiles\WizModernSmallImage-IS.bmp', # comment => 'Copy WizModernSmallImage-IS.bmp to setup directory' ], # # Copy required files from sources or packaging to setup directory: # [ filesame => [$approot.'build/isfiles/appsetup.iss', # $approot.'packaging/win32/build/appsetup.iss'], # copy => [''=>'', # comment => 'appsetup.iss'] ], # [ filesame => [$approot.'build/isfiles/mysql.gif', # $sources.'logo_mysql_sun.gif'], # copy => [''=>'', # comment => 'mysql.gif'] ], # # Create on-the-fly files required # [ file => $approot.'build/isfiles/configuremysql.vbs', # write => [$approot.'build/isfiles/configuremysql.vbs', #'WScript.Echo "Currently Unimplemented" #' ], # comment => 'Write a VB script to configure MySQL' ], ## [ always => [],# ## write => [$approot.'build/isfiles/versioninfo.iss', ' ##define MyAppName "MythTv" ##define MyAppVerName "MythTv '.$version.'(svn_'.$SVNRELEASE .')" ##define MyAppPublisher "Mythtv" ##define MyAppURL "http://www.app.org" ##define MyAppExeName "Win32MythTvInstall.exe" ##' ], # comment => 'write the version information for the setup'], # [ file => $approot.'genfiles.sh', # write => [$approot.'genfiles.sh',' #cd '.$unixapp.'build #find . -type f -printf "Source: '.$approot.'build/%h/%f; Destdir: {app}/%h\n" | sed "s/\.\///" | grep -v ".svn" | grep -#v "isfiles" | grep -v "include" > '.$unixapp.'/build/isfiles/files.iss #',], # comment => 'write script to generate setup files'], # [ newer => [$approot.'build/isfiles/files.iss', # $approot.'app/last_build.txt'], # shell => [$unixapp.'genfiles.sh'] ], ## Run setup ## [ newer => [$approot.'setup/MythTvSetup.exe', ## $approot.'app/last_build.txt'], ## exec => ['"'.$dosprogramfiles.'\Inno Setup 5\Compil32.exe" /cc "'. ## $dosapp.'build\isfiles\appsetup.iss"' ]], # [ newer => [$approot.'setup/MythTvSetup.exe', # $approot.'app/last_build.txt'], # exec => ['cd '.$dosapp.'build\isfiles && '. # '"'.$dosprogramfiles.'\Inno Setup 5\iscc.exe" "'. # $dosapp.'build\isfiles\appsetup.iss"' ]], # #; #} #------------------------------------------------------------------------------ ; # END OF CAUSE->ACTION DEFINITIONS #------------------------------------------------------------------------------ sub _end { # comment("This version of the Win32 Build script ". # "last was last tested on: $SVNRELEASE"); print << 'END'; # # SCRIPT TODO/NOTES: - further notes on this scripts direction.... END } #------------------------------------------------------------------------------ # this is the mainloop that iterates over the above definitions and # determines what to do: # cause: foreach my $dep ( @{$expect} ) { my @dep = @{$dep}; #print Dumper(\@dep); my $causetype = $dep[0]; my $cause = $dep[1]; my $effecttype = $dep[2]; my $effectparams = $dep[3] || ''; die "too many parameters in cause->event declaration (".join('|',@dep).")" if defined $dep[4] && $dep[4] ne 'comment'; # four pieces: cause => [blah] , effect => [blah] my $comment = $dep[5] || ''; if ( $comment && $NOISY ) { comment($comment); } my @cause; if (ref($cause) eq "ARRAY" ) { @cause = @{$cause}; } else { push @cause, $cause ; } # six pieces: cause => [blah] , effect => [blah] , comment => '' die "too many parameters in cause->event declaration (@dep)" if defined $dep[6]; my @effectparams = (); if (ref($effectparams) eq "ARRAY" ) { @effectparams = @{$effectparams}; } else { push @effectparams, $effectparams ; } # if a 'nocheck' parameter is passed through, dont pass it through to # the 'effect()', use it to NOT check if the file/dir exists at the end. my @nocheckeffectparams = grep { ! /nocheck/i } @effectparams; my $nocheck = 0; if ( $#nocheckeffectparams != $#effectparams ) { $nocheck = 1; } if ( $causetype eq 'archive' ) { die "archive only supports type fetch ($cause)($effecttype)" unless $effecttype eq 'fetch'; if ( -f $cause[0] ) {print "file exists: $cause[0]\n"; next;} # 2nd and 3rd params get squashed into # a single array on passing to effect(); effect($effecttype,$cause[0],@nocheckeffectparams); if ( ! -f $cause[0] && $nocheck == 0) { die "EFFECT FAILED ($causetype -> $effecttype): unable to ". "locate expected file ($cause[0]) that was to be ". "fetched from $nocheckeffectparams[0]\n"; } } elsif ( $causetype eq 'dir' ) { if ( -d $cause[0] ) { print "directory exists: $causetype,$cause[0]\n"; next; } effect($effecttype,@nocheckeffectparams); if ( ! -d $cause[0] && $nocheck == 0) { die "EFFECT FAILED ($causetype -> $effecttype): unable to ". "locate expected directory ($cause[0]).\n"; } } elsif ( $causetype eq 'file' ) { if ( -f $cause[0] ) {print "file already exists: $cause[0]\n"; next;} effect($effecttype,@nocheckeffectparams); if ( ! -f $cause[0] && $nocheck == 0) { die "EFFECT FAILED ($causetype -> $effecttype): unable to ". "locate expected file ($cause[0]).\n"; } } elsif ( $causetype eq 'filesame' ) { # NOTE - we check file mtime, byte size, AND MD5 of contents # as without the MD5, the script can break in some circumstances. my ( $size,$mtime,$md5)=fileinfo($cause[0]); my ( $size2,$mtime2,$md5_2)=fileinfo($cause[1]); if ( $mtime != $mtime2 || $size != $size2 || $md5 ne $md5_2 ) { if ( ! $nocheckeffectparams[0] ) { die "sorry but you can not leave the arguments list empty for ". "anything except the 'copy' action (and only when used with ". "the 'filesame' cause)" unless $effecttype eq 'copy'; print "no parameters defined, so applying effect($effecttype) as ". "( 2nd src parameter => 1st src parameter)!\n"; effect($effecttype,$cause[1],$cause[0]); } else { effect($effecttype,@nocheckeffectparams); # do something else if the files are not 100% identical? if ( $nocheck == 0 ) { # now verify the effect was successful # at matching the file contents!: undef $size; undef $size2; undef $mtime; undef $mtime2; undef $md5; undef $md5_2; ( $size,$mtime,$md5)=fileinfo($cause[0]); ( $size2,$mtime2,$md5_2)=fileinfo($cause[1]); if ( $mtime != $mtime2 || $size != $size2 || $md5 ne $md5_2 ) { die("effect failed, files NOT identical size,mtime, ". "and MD5: ($cause[0] => $cause[1]).\n"); } else { print "files ($cause[0] => $cause[1]) now ". "identical - successful! \n"; } } } }else { print "effect not required files already up-to-date/identical: ". "($cause[0] => $cause[1]).\n"; } undef $size; undef $size2; undef $mtime; undef $mtime2; undef $md5; undef $md5_2; } elsif ( $causetype eq 'newer' ) { my $mtime = 0; if ( -f $cause[0] ) { $mtime = (stat($cause[0]))[9] || warn("$cause[0] could not be stated"); } if (! ( -f $cause[1]) ) { die "cause: $causetype requires it's SECOND filename to exist ". "for comparison: $cause[1].\n"; } my $mtime2 = (stat($cause[1]))[9]; if ( $mtime < $mtime2 ) { effect($effecttype,@nocheckeffectparams); if ( $nocheck == 0 ) { # confirm it worked, mtimes should have changed now: my $mtime3 = 0; if ( -f $cause[0] ) { $mtime3 = (stat($cause[0]))[9]; } my $mtime4 = (stat($cause[1]))[9]; if ( $mtime3 < $mtime4 ) { die "EFFECT FAILED ($causetype -> $effecttype): mtime of file". " ($cause[0]) should be greater than file ($cause[1]).\n". "[$mtime3] [$mtime4]\n"; } } } else { print "file ($cause[0]) has same or newer mtime than ". "($cause[1]) already, no action taken\n"; } undef $mtime; undef $mtime2; } elsif ( $causetype eq 'grep' ) { print "grep-ing for pattern($cause[0]) in file($cause[1]):\n" if $NOISY >0; if ( ! _grep($cause[0],$cause[1]) ) { # grep actually needs two parameters on the source side of the action effect($effecttype,@nocheckeffectparams); } else { print "grep - already matched source file($cause[1]), ". "with pattern ($cause[0]) - no action reqd\n"; } if ( (! _grep($cause[0],$cause[1])) && $nocheck == 0 ) { die "EFFECT FAILED ($causetype -> $effecttype): unable to locate regex pattern ($cause[0]) in file ($cause[1])\n"; } } elsif ( $causetype eq 'exists' ) { print "testing if '$cause[0]' exists...\n" if $NOISY >0; if ( -e $cause[0] ) { effect($effecttype,@nocheckeffectparams); } } elsif ( $causetype eq 'always' ) { effect($effecttype,@nocheckeffectparams); } elsif ( $causetype eq 'stop' ){ die "Stop found \n"; } elsif ( $causetype eq 'pause' ){ comment("PAUSED! : ".$cause); my $temp = getc() unless $continuous; } else { die " unknown causetype $causetype \n"; } } print "\nwin32-developer all done\n"; _end(); #------------------------------------------------------------------------------ # each cause has an effect, this is where we do them: sub effect { my ( $effecttype, @effectparams ) = @_; if ( $effecttype eq 'fetch') { # passing two parameters that came in via the array _fetch(@effectparams); } elsif ( $effecttype eq 'extract') { my $tarfile = $effectparams[0]; my $destdir = $effectparams[1] || ''; if ($destdir eq '') { $destdir = $tarfile; # strip off everything after the final forward slash $destdir =~ s#[^/]*$##; } my $t = findtar($tarfile); print "found equivalent: ($t) -> ($tarfile)\n" if $t ne $tarfile; print "extracttar($t,$destdir);\n"; extracttar($t,$destdir); } elsif ($effecttype eq 'exec') { # execute a DOS command my $cmd = shift @effectparams; #print `$cmd`; print "exec:$cmd\n"; open F, $cmd." |" || die "err: $!"; while () { print; } } elsif ($effecttype eq 'shell') { shell(@effectparams); } elsif ($effecttype eq 'copy') { die "Can not copy non-existant file ($effectparams[0])\n" unless -f $effectparams[0]; print "copying file ($effectparams[0] => $effectparams[1]) \n"; cp($effectparams[0],$effectparams[1]); # make destn mtime the same as the original for ease of comparison: shell("touch --reference='".perl2unix($effectparams[0])."' '" .perl2unix($effectparams[1])."'"); } elsif ($effecttype eq 'mkdirs') { mkdirs(shift @effectparams); } elsif ($effecttype eq 'write') { # just dump the requested content from the array to the file. my $filename = shift @effectparams; my $fh = new IO::File ("> $filename") || die "error opening $filename for writing: $!\n"; $fh->binmode(); $fh->print(join('',@effectparams)); $fh->close(); } else { die " unknown effecttype $effecttype from cause 'dir'\n"; } return; # which ever one we actioned, # we don't want to action anything else } #------------------------------------------------------------------------------ # get info from a file for comparisons sub fileinfo { # filename passed in should be perl compatible path # using single FORWARD slashes my $filename = shift; my ( $size,$mtime,$md5)=(0,0,0); if ( -f $filename ) { $size = (stat($filename))[7]; $mtime = (stat($filename))[9]; my $md5obj = Digest::MD5->new(); my $fileh = IO::File->new($filename); binmode($fileh); $md5obj->addfile($fileh); $md5 = $md5obj->digest(); } else { warn(" invalid file name provided for testing: ($filename)\n"); $size=rand(99); $mtime=rand(999); $md5=rand(999); } #print "compared: $size,$mtime,$md5\n"; return ($size,$mtime,$md5); } #------------------------------------------------------------------------------ # kinda like a directory search for blah.tar* but faster/easier. # only finds .tar.gz, .tar.bz2, .zip sub findtar { my $t = shift; return "$t.gz" if -f "$t.gz"; return "$t.bz2" if -f "$t.bz2"; if ( -f "$t.zip" || $t =~ m/\.zip$/ ) { die "no unzip.exe found ! - yet" unless -f $sources."unzip/unzip.exe"; # TODO - a bit of a special test, should be fixed better. return "$t.zip" if -f "$t.zip"; return $t if -f $t; } return $t if -f $t; die "findtar failed to match a file from:($t)\n"; } #------------------------------------------------------------------------------ # given a ($t) .tar.gz, .tar.bz2, .zip extract it to the directory ( $d) # changes current directory to $d too sub extracttar { my ( $t, $d) = @_; # both $t and $d at this point should be perl-compatible-forward-slashed die "extracttar expected forward-slashes only in pathnames ($t,$d)" if $t =~ m#\\# || $d =~ m#\\#; unless ( $t =~ m/zip/ ) { # the unzip tool need the full DOS path, # the msys commands need that stripped off. $t =~ s#^$msys#/#i; } print "extracting to: $d\n"; # unzipping happens in DOS as it's a dos utility: if ( $t =~ /\.zip$/ ) { #$d =~ s#/#\\#g; # the chdir command MUST have paths with backslashes, # not forward slashes. $d = perl2dos($d); $t = perl2dos($t); my $cmd = 'chdir '.$d.' && '.$dossources.'unzip\unzip.exe -o '.$t; print "extracttar:$cmd\n"; open F, "$cmd |" || die "err: $!"; while () { print; } return; } $d = perl2unix($d); $t = perl2unix($t); # untarring/gzipping/bunzipping happens in unix/msys mode: die "unable to locate sh2.exe" unless -f $dosmsys.'bin/sh2.exe'; my $cmd = $dosmsys. 'bin\sh2.exe -c "( export PATH=/bin:/mingw/bin:$PATH ; '; $cmd .= "cd $d;"; if ( $t =~ /\.gz$/ ) { $cmd .= $unixmsys."bin/tar.exe -zxvpf $t"; } elsif ( $t =~ /\.bz2$/ ) { $cmd .= $unixmsys."bin/tar.exe -jxvpf $t"; } elsif ( $t =~ /\.tar$/ ) { $cmd .= $unixmsys."bin/tar.exe -xvpf $t"; } else { die "extract tar failed on ($t,$d)\n"; } $cmd .= ')"'; # end-off the brackets around the shell commands. # execute the cmd, and capture the output! # this is a glorified version of "print `$cmd`;" # except it doesn't buffer the output, if $|=1; is set. # $t should be a msys compatible path ie /sources/etc print "extracttar:$cmd\n"; open F, "$cmd |" || die "err: $!"; while () { print; } } #------------------------------------------------------------------------------ # get the $url (typically a .tar.gz or similar) , and save it to $file sub _fetch { my ( $file,$url ) = @_; #$file =~ s#/#\\\\#g; print "already exists: $file \n" if -f $file; return undef if -f $file; print "fetching $url to $file (please wait)...\n"; my $ua = LWP::UserAgent->new; $ua->proxy(['http', 'ftp'], $proxy); my $res = $ua->request(HTTP::Request->new(GET => $url), sub { if (! -f $file) { open(FILE, ">$file") || die "_fetch can't open $file: $!\n"; binmode FILE; } print FILE $_[0] or die "_fetch can't write to $file: $!\n"; } ); close(FILE) || print "_fetch can't close $file: $!\n"; if (my $mtime = $res->last_modified) { utime time, $mtime, $file; } if ($res->header("X-Died") || !$res->is_success) { unlink($file) && print "Transfer failed. File deleted.\n"; } if ( ! -s $file ) { die ('ERR: Unable to automatically fetch file!\nPerhaps manually '. 'downloading from the URL to the filename (both listed above) '. 'might work, or you might want to choose your own SF mirror '. '(edit this script for instructions), or perhaps this version'. ' of the file is no longer available.'); } } #------------------------------------------------------------------------------ # execute a sequence of commands in a bash shell. # we explicitly add the /bin and /mingw/bin to the path # because at this point they aren't likely to be there # (cause we are in the process of installing them) sub shell { my @cmds = @_; my $cmd = $dosmsys.'bin\bash.exe -c "( export PATH=/bin:/mingw/bin:$PATH;'. join(';',@cmds).') 2>&1 "'; print "shell:$cmd\n"; # execute the cmd, and capture the output! this is a glorified version # of "print `$cmd`;" except it doesn't buffer the output if $|=1; is set. open F, "$cmd |" || die "err: $!"; while () { if (! $NOISY ) { # skip known spurious messages from going to the screen unnecessarily next if /redeclared without dllimport attribute after being referenced with dllimpo/; next if /declared as dllimport: attribute ignored/; next if /warning: overriding commands for target `\.\'/; next if /warning: ignoring old commands for target `\.\'/; next if /Nothing to be done for `all\'/; next if /^cd .* \&\& \\/; next if /^make -f Makefile/; } print; } } #------------------------------------------------------------------------------ # recursively make folders, requires perl-compatible folder separators # (ie forward slashes) # sub mkdirs { my $path = shift; die "backslash in foldername not allowed in mkdirs function:($path)\n" if $path =~ m#\\#; $path = perl2dos($path); print "mkdir $path\n"; # reduce path to just windows, # incase we have a rogue unix mkdir command elsewhere! print `set PATH=C:\\WINDOWS\\system32;c:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem && mkdir $path`; } #------------------------------------------------------------------------------ # unix compatible versions of the perl paths (for when we [shell] to unix/bash mode): sub perl2unix { my $p = shift; print "perl2unix: $p\n"; $p =~ s#$msys#/#i; # remove superfluous msys folders if they are there #change c:/ into /c (or a D:) so c:/msys becomes /c/msys etc. $p =~ s#^([A-Z]):#/$1#ig; $p =~ s#//#/#ig; # reduce any double forward slashes to single ones. return $p; } #------------------------------------------------------------------------------ # DOS executable CMD.exe versions of the paths (for when we [exec] to DOS mode): sub perl2dos { my $p = shift; $p =~ s#/#\\#g; # single forward to single backward return $p; } #------------------------------------------------------------------------------ # find a pattern in a file and return if it was found or not. # Absent file assumes pattern was not found. sub _grep { my ($pattern,$file) = @_; #$pattern = qw($pattern); my $fh = IO::File->new("< $file"); unless ( $fh) { print "WARNING: Unable to read file ($file) when searching for ". "pattern:($pattern), assumed to NOT match pattern\n"; return 0; } my $found = 0; while ( my $contents = <$fh> ) { if ( $contents =~ m/$pattern/ ) { $found= 1; } } $fh->close(); return $found; } #------------------------------------------------------------------------------ # where is this script? sub scriptpath { return "" if ($0 eq ""); my @path = split /\\/, $0; pop @path; return join '\\', @path; } #------------------------------------------------------------------------------ # display stuff to the user in a manner that unclutters it from # the other compilation messages that will be scrolling past! sub comment { my $comment = shift; print "\nCOMMENTS:"; print "-"x30; print "\n"; print "COMMENTS:$comment\nCOMMENTS:"; print "-"x30; print "\n"; print "\n"; } #------------------------------------------------------------------------------ # how? what the? oh! like that! I get it now, I think. sub usage { print << 'END_USAGE'; -h This message -v Verbose output -k Package win32 distribution -p proxy:port Your proxy -c debug|release|profile END_USAGE exit; } #------------------------------------------------------------------------------ repsnapper-2.3.2a5/win32/000077500000000000000000000000001231531733200150655ustar00rootroot00000000000000repsnapper-2.3.2a5/win32/.gitignore000066400000000000000000000000451231531733200170540ustar00rootroot00000000000000/checkout.* /target.* repsnapper.nsi repsnapper-2.3.2a5/win32/common-build.sh000077500000000000000000000033731231531733200200170ustar00rootroot00000000000000#!/bin/sh if [ -z "$BUILD_FLAVOUR" ]; then exit 0; fi export TARGET=target.$BUILD_FLAVOUR export CHECKOUT=checkout.$BUILD_FLAVOUR jhbuild --file=gtk+-win32.jhbuildrc "$@" || exit 1 if [ ! -d "$TARGET/lib/gdk-pixbuf-2.0/2.10.0/" ]; then mkdir -p "$TARGET/lib/gdk-pixbuf-2.0/2.10.0/" fi # FIXME: gdk-pixbuf-query-loaders.exe needs to be run on the target, by the installer or so # if [ -f "$TARGET/bin/gdk-pixbuf-query-loaders.exe" ]; then # wine "$TARGET/bin/gdk-pixbuf-query-loaders.exe" > "$TARGET/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" # fi # Build repsnapper if [ ! -d "$CHECKOUT/repsnapper" ]; then mkdir "$CHECKOUT"/repsnapper || exit 1 fi cd "$CHECKOUT"/repsnapper CPPFLAGS=-I../../"$TARGET"/include PKG_CONFIG_PATH=../../"$TARGET"/lib/pkgconfig ../../../configure --prefix="`pwd`/../../$TARGET" --host=i686-w64-mingw32 && make -j4 && make install || exit 1 cd ../.. MINGW_CPP=i686-w64-mingw32-cpp # Copy appropriate libgcc into place #GCCPATH=`i586-mingw32msvc-gcc -print-libgcc-file-name` GCCPATH=`$MINGW_CPP -print-libgcc-file-name` GCCPATH=`dirname "$GCCPATH"` for f in $GCCPATH/libgcc*dll; do LIBGCC_FILE=`basename "$f"` done if [ -z "$LIBGCC_FILE" ]; then echo "Failed to locate shared libgcc dll in $GCCPATH. Is your GCC install correct?" exit 1 fi cp "$GCCPATH/$LIBGCC_FILE" "$TARGET/bin" #Copy libwinpthread-1.dll LIBWINPTHREAD=`$MINGW_CPP -print-file-name=libwinpthread-1.dll` cp "$LIBWINPTHREAD" "$TARGET/bin" LIBSTDCPP=`$MINGW_CPP -print-file-name=libstdc++-6.dll` cp "$LIBSTDCPP" "$TARGET/bin" if [ "$BUILD_FLAVOUR" = "rls" ]; then echo "Building installer..." # run NSIS installer script for release build makensis -DLIBGCC_FILE="$LIBGCC_FILE" -V2 -NOCD "$CHECKOUT"/repsnapper/win32/repsnapper.nsi || exit 2 fi echo "All done..." repsnapper-2.3.2a5/win32/cross-build-repsnapper-dbg000077500000000000000000000001011231531733200221400ustar00rootroot00000000000000#!/bin/sh export BUILD_FLAVOUR=dbg exec ./common-build.sh "$@" repsnapper-2.3.2a5/win32/cross-build-repsnapper-rls000077500000000000000000000001011231531733200222040ustar00rootroot00000000000000#!/bin/sh export BUILD_FLAVOUR=rls exec ./common-build.sh "$@" repsnapper-2.3.2a5/win32/glib-win32.moduleset000066400000000000000000000046701231531733200206740ustar00rootroot00000000000000 repsnapper-2.3.2a5/win32/gtk+-win32.jhbuildrc000066400000000000000000000161701231531733200205620ustar00rootroot00000000000000# -*- mode: python -*- # This code is licensed under the GPLv2 License # Derived work from the original freedesktop.org example.jhbuildrc # # This jhbuildrc file is created for the purpose of cross compile Gtk+ # with Mingw32 under Linux. # # Author: Alberto Ruiz # # modified by: Rolf Gebhardt # moduleset = os.environ['PWD']+'/gtk+-win32.moduleset' modules = ['libzip', 'gtkmm', 'libglade', 'gtkglext', 'gtkglextmm', 'libxml++' ] flavour = os.environ['BUILD_FLAVOUR'] if flavour == 'rls': flavour_ext = 'rls' flavour_opt = '--enable-debug=no' else: flavour_ext = 'dbg' flavour_opt = "--enable-debug=yes" # checkoutroot: path to download packages elsewhere # prefix: target path to install the compiled binaries checkoutroot = os.path.join (os.sep, os.environ['PWD'], 'checkout.'+flavour_ext) prefix = os.path.join (os.sep, os.environ['PWD'], 'target.'+flavour_ext) os.environ['prefix'] = prefix #The host value is obtained with the result of executing #the config.guess script on any of the packages. #This value must be valid for most linux/x86 out there os.environ['HOST'] = 'i686-pc-linux-gnu' os.environ['TARGET'] = 'i586-pc-mingw32' # Clear PKG_CONFIG_PATH os.environ['PKG_CONFIG_PATH'] = "" os.environ['PKG_CONFIG_LIBDIR'] = os.path.join(os.sep, prefix, 'lib', 'pkgconfig') addpath('PKG_CONFIG_PATH', os.path.join(os.sep, prefix, 'lib64', 'pkgconfig')) # addpath('PKG_CONFIG_PATH', os.path.join(os.sep, 'usr', 'lib', 'pkgconfig')) # addpath('PKG_CONFIG_PATH', os.path.join(os.sep, 'usr', 'share', 'pkgconfig')) #Prefix for all the tools mingw_tool_prefix = '/usr/bin/i686-w64-mingw32-' mingw_tools = {'ADDR2LINE': 'addr2line', 'AS': 'as', 'CC': 'gcc', 'CPP': 'cpp', 'Cppfilt': 'c++filt', 'CXX': 'g++', 'DLLTOOL': 'dlltool', 'DLLWRAP': 'dllwrap', 'GCOV': 'gcov', 'LD': 'ld', 'NM': 'nm', 'OBJCOPY': 'objcopy', 'OBJDUMP': 'objdump', 'READELF': 'readelf', 'SIZE': 'size', 'STRINGS': 'strings', 'WINDRES': 'windres', 'AR': 'ar', 'RANLIB': 'ranlib', 'STRIP': 'strip'} #Exporting all as enviroment variables with its prefix mingw_tools_args = str() for tool in mingw_tools.keys(): fullpath_tool = mingw_tool_prefix + mingw_tools[tool] os.environ[tool] = fullpath_tool #Added another common env var name for windres os.environ['RC'] = os.environ['WINDRES'] #Exporting tool flags enviroment variables os.environ['LDFLAGS'] = '-L'+prefix+'/lib -shared-libgcc -mthreads -fexceptions' os.environ['CFLAGS'] = '-mms-bitfields -march=i686' os.environ['CPPFLAGS'] = '-I'+prefix+'/include' os.environ['CXXFLAGS'] = '-mms-bitfields -march=i686 -fexceptions -shared-libgcc -mthreads' os.environ['ARFLAGS'] = '-ar rcs' os.environ['INSTALL'] = os.path.expanduser('~/bin/install-check') if flavour == 'dbg': os.environ['CFLAGS'] += ' -g -O0' os.environ['CXXFLAGS'] += ' -g -O0' #needed by win32/Makefile.gcc of zlib os.environ['INCLUDE_PATH'] = prefix+'/include' os.environ['LIBRARY_PATH'] = prefix+'/lib' os.environ['BINARY_PATH'] = prefix+'/bin' # always autogen because otherwise freetype will not build alwaysautogen = True # Don't pass lib64 as the libdir on 64 bit systems use_lib64 = False #Populating autogenargs autogenargs = ' --build='+os.environ['HOST'] autogenargs += ' --host='+os.environ['TARGET'] autogenargs += ' --target='+os.environ['TARGET'] autogenargs += ' --disable-docs' autogenargs += ' --enable-all-warnings --enable-maintainer-mode' autogenargs += ' --disable-static' autogenargs += ' '+flavour_opt for tool in ('AR', 'RANLIB', 'STRIP', 'AS', 'DLLTOOL', 'OBJDUMP', 'NM', 'WINDRES'): autogenargs += ' '+tool+'="'+os.environ[tool]+'" ' #Module specific configure arguments module_autogenargs['zlib'] = ' --prefix='+prefix+' --shared' module_autogenargs['gettext'] = autogenargs + """ --without-emacs \ --without-cvs \ --disable-curses \ --disable-java \ --disable-native-java \ --enable-relocatable""" module_autogenargs['glib'] = autogenargs + """ --enable-explicit-deps=no \ --disable-rebuilds \ --disable-gtk-doc""" module_autogenargs['cairo'] = autogenargs + """ --enable-explicit-deps=no \ --enable-xlib=no \ --enable-xlib-xrender=no \ --enable-win32-font=yes""" module_autogenargs['pixman'] = autogenargs + """ --enable-gtk=no""" module_autogenargs['pango'] = autogenargs + """ --disable-gtk-doc \ --enable-explicit-deps=no \ --with-included-modules \ --enable-introspection=no""" module_autogenargs['atk'] = autogenargs + """ --disable-glibtest \ --disable-scrollkeeper \ --disable-gtk-doc \ --enable-introspection=no""" module_autogenargs['gdk-pixbuf'] = autogenargs + """ --disable-glibtest \ --disable-scrollkeeper \ --disable-gtk-doc \ --with-included-loaders \ --without-libjasper \ --enable-introspection=no""" module_autogenargs['gtk+'] = autogenargs + """ --disable-glibtest \ --disable-scrollkeeper \ --disable-gtk-doc \ --disable-cups \ --enable-introspection=no""" module_autogenargs['fontconfig'] = autogenargs + """ --with-arch=i686""" module_autogenargs['freetype'] = autogenargs + """ --with-arch=i686 \ --disable-gtk-doc \ --disable-docs""" module_autogenargs['libxml2'] = autogenargs + """ --with-arch=i686 \ --with-python=no \ --with-iconv=yes""" module_autogenargs['glibmm'] = autogenargs + """ --disable-documentation """ module_autogenargs['gtkmm'] = autogenargs + """ --disable-documentation """ module_autogenargs['atkmm'] = autogenargs + """ --disable-documentation """ # Pass -j4 to make by default, override with module_makeargs where that doesn't work makeargs = "-j4" # module_makeargs['freetype'] = "" # Todo: # module_autogenargs['jasper'] = autogenargs + """ --enable-shared --disable-static""" repsnapper-2.3.2a5/win32/gtk+-win32.moduleset000066400000000000000000000162361231531733200206200ustar00rootroot00000000000000 repsnapper-2.3.2a5/win32/imglibs-win32.moduleset000066400000000000000000000025241231531733200214010ustar00rootroot00000000000000 repsnapper-2.3.2a5/win32/include/000077500000000000000000000000001231531733200165105ustar00rootroot00000000000000repsnapper-2.3.2a5/win32/include/uninstall-log.nsh000066400000000000000000000045101231531733200220120ustar00rootroot00000000000000;AddItem macro !macro AddItem Path FileWrite $UninstLog "${Path}$\r$\n" !macroend ;File macro !macro File FilePath FileName IfFileExists "$OUTDIR\${FileName}" +2 FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n" File "${FilePath}\${FileName}" !macroend ;FileAs macro !macro FileAs FileName InFile IfFileExists "$OUTDIR\${FileName}" +2 FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n" File "/oname=${FileName}" "${InFile}" !macroend ;CreateShortcut macro !macro CreateShortcut FilePath FilePointer FileWrite $UninstLog "${FilePath}$\r$\n" CreateShortcut "${FilePath}" "${FilePointer}" !macroend ;CreateShortcutFull macro !macro CreateShortcutFull FilePath FilePointer Parameters Icon IconIndex FileWrite $UninstLog "${FilePath}$\r$\n" CreateShortcut "${FilePath}" "${FilePointer}" "${Parameters}" "${Icon}" "${IconIndex}" !macroend ;Copy files macro !macro CopyFiles SourcePath DestPath IfFileExists "${DestPath}" +2 FileWrite $UninstLog "${DestPath}$\r$\n" CopyFiles "${SourcePath}" "${DestPath}" !macroend ;Rename macro !macro Rename SourcePath DestPath IfFileExists "${DestPath}" +2 FileWrite $UninstLog "${DestPath}$\r$\n" Rename "${SourcePath}" "${DestPath}" !macroend ;CreateDirectory macro !macro CreateDirectory Path CreateDirectory "${Path}" FileWrite $UninstLog "${Path}$\r$\n" !macroend ;SetOutPath macro !macro SetOutPath Path SetOutPath "${Path}" FileWrite $UninstLog "${Path}$\r$\n" !macroend ;WriteUninstaller macro !macro WriteUninstaller Path WriteUninstaller "${Path}" FileWrite $UninstLog "${Path}$\r$\n" !macroend ;WriteIniStr macro !macro WriteIniStr IniFile SectionName EntryName NewValue IfFileExists "${IniFile}" +2 FileWrite $UninstLog "${IniFile}$\r$\n" WriteIniStr "${IniFile}" "${SectionName}" "${EntryName}" "${NewValue}" !macroend ;WriteRegStr macro !macro WriteRegStr RegRoot UnInstallPath Key Value FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n" WriteRegStr "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}" !macroend ;WriteRegDWORD macro !macro WriteRegDWORD RegRoot UnInstallPath Key Value FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n" WriteRegDWORD "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}" !macroend repsnapper-2.3.2a5/win32/patches/000077500000000000000000000000001231531733200165145ustar00rootroot00000000000000repsnapper-2.3.2a5/win32/patches/atk-export-minimum-inc.patch000066400000000000000000000004721231531733200240560ustar00rootroot00000000000000--- atk/atk.symbols 2012-03-13 14:42:48.179678138 +1100 +++ atk/atk.symbols.mininc 2012-03-13 14:42:33.311677419 +1100 @@ -239,5 +239,6 @@ atk_value_get_current_value atk_value_get_maximum_value atk_value_get_minimum_value + atk_value_get_minimum_increment atk_value_get_type atk_value_set_current_value repsnapper-2.3.2a5/win32/patches/cairo_1_10_2_mingw_ffs_func.patch000066400000000000000000000005031231531733200246430ustar00rootroot00000000000000--- cairo-1.10.2/src/cairo.c.orig 2012-03-14 23:19:12.077359190 +1100 +++ cairo-1.10.2/src/cairo.c 2012-03-14 23:20:34.117363162 +1100 @@ -43,6 +43,10 @@ #include "cairo-error-private.h" #include "cairo-path-private.h" +#ifdef __MINGW32__ +#define ffs __builtin_ffs +#endif + /** * SECTION:cairo * @Title: cairo_t repsnapper-2.3.2a5/win32/patches/fontconfig-cross-compile.patch000066400000000000000000000061361231531733200244540ustar00rootroot00000000000000diff -ur fontconfig-2.8.0.orig/configure.in fontconfig-2.8.0/configure.in --- fontconfig-2.8.0.orig/configure.in 2009-11-19 10:49:23.000000000 +1100 +++ fontconfig-2.8.0/configure.in 2012-03-14 22:08:39.725154354 +1100 @@ -103,9 +103,13 @@ AC_MSG_CHECKING([for a C compiler for build tools]) if test $cross_compiling = yes; then AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc) + CFLAGS_FOR_BUILD= else CC_FOR_BUILD=$CC + CFLAGS_FOR_BUILD=$CFLAGS fi AC_MSG_RESULT([$CC_FOR_BUILD]) + AC_MSG_RESULT([flags = $CFLAGS_FOR_BUILD]) AC_SUBST(CC_FOR_BUILD) + AC_SUBST(CFLAGS_FOR_BUILD) AC_MSG_CHECKING([for suffix of executable build tools]) if test $cross_compiling = yes; then diff -ur fontconfig-2.8.0.orig/doc/Makefile.am fontconfig-2.8.0/doc/Makefile.am --- fontconfig-2.8.0.orig/doc/Makefile.am 2009-11-17 04:24:52.000000000 +1100 +++ fontconfig-2.8.0/doc/Makefile.am 2012-03-14 22:07:47.749151839 +1100 @@ -22,6 +22,8 @@ # PERFORMANCE OF THIS SOFTWARE. CC = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS_FOR_BUILD@ +LDFLAGS = @CFLAGS_FOR_BUILD@ EXEEXT = @EXEEXT_FOR_BUILD@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ diff -ur fontconfig-2.8.0.orig/fc-arch/Makefile.am fontconfig-2.8.0/fc-arch/Makefile.am --- fontconfig-2.8.0.orig/fc-arch/Makefile.am 2009-11-19 01:31:09.000000000 +1100 +++ fontconfig-2.8.0/fc-arch/Makefile.am 2012-03-14 22:07:35.629151253 +1100 @@ -23,6 +23,8 @@ # CC = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS_FOR_BUILD@ +LDFLAGS = @CFLAGS_FOR_BUILD@ EXEEXT = @EXEEXT_FOR_BUILD@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ diff -ur fontconfig-2.8.0.orig/fc-case/Makefile.am fontconfig-2.8.0/fc-case/Makefile.am --- fontconfig-2.8.0.orig/fc-case/Makefile.am 2012-03-14 22:06:35.157148325 +1100 +++ fontconfig-2.8.0/fc-case/Makefile.am 2012-03-14 22:06:54.425149259 +1100 @@ -23,6 +23,8 @@ # CC = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS_FOR_BUILD@ +LDFLAGS = @CFLAGS_FOR_BUILD@ EXEEXT = @EXEEXT_FOR_BUILD@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ diff -ur fontconfig-2.8.0.orig/fc-glyphname/Makefile.am fontconfig-2.8.0/fc-glyphname/Makefile.am --- fontconfig-2.8.0.orig/fc-glyphname/Makefile.am 2009-11-19 01:27:57.000000000 +1100 +++ fontconfig-2.8.0/fc-glyphname/Makefile.am 2012-03-14 22:07:54.281152155 +1100 @@ -23,6 +23,8 @@ # CC = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS_FOR_BUILD@ +LDFLAGS = @CFLAGS_FOR_BUILD@ EXEEXT = @EXEEXT_FOR_BUILD@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ diff -ur fontconfig-2.8.0.orig/fc-lang/Makefile.am fontconfig-2.8.0/fc-lang/Makefile.am --- fontconfig-2.8.0.orig/fc-lang/Makefile.am 2009-11-19 01:27:43.000000000 +1100 +++ fontconfig-2.8.0/fc-lang/Makefile.am 2012-03-14 22:07:43.845151650 +1100 @@ -23,6 +23,8 @@ # CC = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS_FOR_BUILD@ +LDFLAGS = @CFLAGS_FOR_BUILD@ EXEEXT = @EXEEXT_FOR_BUILD@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ --- fontconfig-2.8.0.orig/autogen.sh 1970-01-01 10:00:00.000000000 +1000 +++ fontconfig-2.8.0/autogen.sh 2012-03-13 23:45:49.705254993 +1100 @@ -0,0 +1,4 @@ +#!/bin/sh + +autoreconf -i +./configure "$@" repsnapper-2.3.2a5/win32/patches/gdk_pixbuf_2_24_1_io_gdip_fix.patch000066400000000000000000000010341231531733200251630ustar00rootroot00000000000000--- gdk-pixbuf-2.24.1.orig/gdk-pixbuf/io-gdip-animation.c 2011-12-17 08:43:53.000000000 +1100 +++ gdk-pixbuf-2.24.1/gdk-pixbuf/io-gdip-animation.c 2012-03-13 14:02:16.787560466 +1100 @@ -165,6 +165,11 @@ G_DEFINE_TYPE (GdkPixbufGdipAnimIter, gdk_pixbuf_gdip_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER); static void +gdk_pixbuf_gdip_anim_iter_init (GdkPixbufGdipAnimIter *iter) +{ +} + +static void gdk_pixbuf_gdip_anim_iter_class_init (GdkPixbufGdipAnimIterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); repsnapper-2.3.2a5/win32/patches/gdkspanfunc.patch000066400000000000000000000010311231531733200220330ustar00rootroot00000000000000# fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621976 # reference: http://www.mail-archive.com/pld-cvs-commit@lists.pld-linux.org/msg250570.html --- gtkglextmm-1.2.0-orig/gtkglext/gtkmm/gl/widget.cc 2004-05-18 03:01:50.000000000 -0300 +++ gtkglextmm-1.2.0/gtkglext/gtkmm/gl/widget.cc 2011-06-12 17:57:13.075541070 -0300 @@ -17,9 +17,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include - #include "widget.h" +#include namespace Gtk { repsnapper-2.3.2a5/win32/patches/gettext_0_18_crossbuild_override_tools_fix.patch000066400000000000000000000005221231531733200301650ustar00rootroot00000000000000--- Makefile.in.orig 2010-05-09 20:59:19.000000000 +0200 +++ Makefile.in 2010-10-02 00:59:46.000000000 +0200 @@ -211,7 +211,7 @@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = 1.5 gnu no-dependencies ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = gnulib-local gettext-runtime gettext-tools +SUBDIRS = gnulib-local gettext-runtime # DJGPP port. repsnapper-2.3.2a5/win32/patches/gtk_2_24_10_schar_marshal.patch000066400000000000000000000010371231531733200242400ustar00rootroot00000000000000--- gtk/gtkmarshal.c.schar 2012-03-13 14:14:13.495595154 +1100 +++ gtk/gtkmarshal.c 2012-03-13 14:14:25.771595747 +1100 @@ -6,7 +6,7 @@ #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) repsnapper-2.3.2a5/win32/patches/gtkglext-fixups.patch000066400000000000000000000072301231531733200227040ustar00rootroot00000000000000--- gtkglext-1.2.0.orig/gdk/gdkglwindow.c 2004-02-20 20:38:12.000000000 +1100 +++ gtkglext-1.2.0/gdk/gdkglwindow.c 2012-03-13 23:53:22.033276885 +1100 @@ -740,15 +740,19 @@ * Set a background of "None" on window to avoid AIX X server crash */ +#ifndef G_OS_WIN32 GDK_GL_NOTE (MISC, g_message (" - window->bg_pixmap = %p", ((GdkWindowObject *) window)->bg_pixmap)); +#endif gdk_window_set_back_pixmap (window, NULL, FALSE); +#ifndef G_OS_WIN32 GDK_GL_NOTE (MISC, g_message (" - window->bg_pixmap = %p", ((GdkWindowObject *) window)->bg_pixmap)); +#endif return glwindow; } --- gtkglext-1.2.0.orig/gtk/gtkglwidget.c 2004-02-20 20:38:36.000000000 +1100 +++ gtkglext-1.2.0/gtk/gtkglwidget.c 2012-03-13 23:56:48.997286901 +1100 @@ -127,7 +127,7 @@ * Synchronize OpenGL and window resizing request streams. */ - if (GTK_WIDGET_REALIZED (widget) && private->is_realized) + if (gtk_widget_get_realized (widget) && private->is_realized) { gldrawable = gdk_window_get_gl_drawable (widget->window); gdk_gl_drawable_wait_gdk (gldrawable); @@ -154,7 +154,7 @@ * Remove OpenGL-capability from widget->window. */ - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) gdk_window_unset_gl_capability (widget->window); private->is_realized = FALSE; @@ -174,7 +174,7 @@ */ toplevel = gtk_widget_get_toplevel (widget); - if (GTK_WIDGET_TOPLEVEL (toplevel) && !GTK_WIDGET_REALIZED (toplevel)) + if (gtk_widget_is_toplevel (toplevel) && !gtk_widget_get_realized (toplevel)) { GTK_GL_NOTE (MISC, g_message (" - Install colormap to the top-level window.")); @@ -194,17 +194,21 @@ * Set a background of "None" on window to avoid AIX X server crash. */ - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) { +#ifndef G_OS_WIN32 GTK_GL_NOTE (MISC, g_message (" - window->bg_pixmap = %p", ((GdkWindowObject *) (widget->window))->bg_pixmap)); +#endif gdk_window_set_back_pixmap (widget->window, NULL, FALSE); +#ifndef G_OS_WIN32 GTK_GL_NOTE (MISC, g_message (" - window->bg_pixmap = %p", ((GdkWindowObject *) (widget->window))->bg_pixmap)); +#endif } } @@ -250,8 +254,8 @@ GTK_GL_NOTE_FUNC (); g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); - g_return_val_if_fail (!GTK_WIDGET_NO_WINDOW (widget), FALSE); - g_return_val_if_fail (!GTK_WIDGET_REALIZED (widget), FALSE); + g_return_val_if_fail (gtk_widget_get_has_window (widget), FALSE); + g_return_val_if_fail (!gtk_widget_get_realized (widget), FALSE); g_return_val_if_fail (GDK_IS_GL_CONFIG (glconfig), FALSE); /* @@ -432,7 +436,7 @@ GTK_GL_NOTE_FUNC (); g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); + g_return_val_if_fail (gtk_widget_get_realized (widget), NULL); gldrawable = gdk_window_get_gl_drawable (widget->window); if (gldrawable == NULL) @@ -474,7 +478,7 @@ GLWidgetPrivate *private; g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); + g_return_val_if_fail (gtk_widget_get_realized (widget), NULL); private = g_object_get_qdata (G_OBJECT (widget), quark_gl_private); if (private == NULL) @@ -501,7 +505,7 @@ gtk_widget_get_gl_window (GtkWidget *widget) { g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); + g_return_val_if_fail (gtk_widget_get_realized (widget), NULL); return gdk_window_get_gl_window (widget->window); } repsnapper-2.3.2a5/win32/patches/gtkglext-pangox-configure.patch000066400000000000000000000024311231531733200246370ustar00rootroot00000000000000--- gtkglext-1.2.0.orig/configure.in 2006-02-05 14:17:19.000000000 +1100 +++ gtkglext-1.2.0/configure.in 2012-03-13 23:19:12.041177670 +1100 @@ -345,11 +345,16 @@ ## calls. Oh, also the later pkg-config calls don't include ## the version requirements since those make the module lists ## annoying to construct +if test "x$os_win32" != "xyes"; then + PANGOX="pangox_pkg >= pangox_required_version" + PANGOX_PKG="pangox_pkg" +fi + PKG_CHECK_MODULES([BASE_DEPENDENCIES], [\ gtk_pkg >= gtk_required_version \ gdk_pkg >= gdk_required_version \ pango_pkg >= pango_required_version \ -pangox_pkg >= pangox_required_version \ +$PANGOX gmodule_pkg >= gmodule_required_version \ ]) @@ -794,7 +799,7 @@ # CFLAGS and LIBS ################################################## -GDKGLEXT_PACKAGES="gdk_pkg pango_pkg pangox_pkg gmodule_pkg" +GDKGLEXT_PACKAGES="gdk_pkg pango_pkg $PANGOX_PKG gmodule_pkg" GDKGLEXT_EXTRA_CFLAGS="$GL_CFLAGS $GDKGLEXT_WIN_CFLAGS" GDKGLEXT_EXTRA_LIBS="$GL_LIBS $GDKGLEXT_WIN_LIBS" GDKGLEXT_DEP_CFLAGS="$GDKGLEXT_EXTRA_CFLAGS `$PKG_CONFIG --cflags $GDKGLEXT_PACKAGES`" --- gtkglext-1.2.0.orig/autogen.sh 1970-01-01 10:00:00.000000000 +1000 +++ gtkglext-1.2.0/autogen.sh 2012-03-13 23:45:49.705254993 +1100 @@ -0,0 +1,4 @@ +#!/bin/sh + +autoreconf -i +./configure "$@" repsnapper-2.3.2a5/win32/patches/libxml-mingw-dllexports.patch000066400000000000000000000010601231531733200243360ustar00rootroot00000000000000diff -ur include/libxml/xmlexports.h libxml2-2.7.8/include/libxml/xmlexports.h --- include/libxml/xmlexports.h 2010-10-12 17:25:32.000000000 +1100 +++ include/libxml/xmlexports.h 2012-03-13 11:01:35.495035778 +1100 @@ -113,7 +113,7 @@ * _imp__xmlFree listed as missing. Try to workaround the problem * by also making that declaration when compiling client code. */ - #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #if !defined(LIBXML_STATIC) #define XMLPUBFUN __declspec(dllexport) #define XMLPUBVAR __declspec(dllexport) #else repsnapper-2.3.2a5/win32/patches/zlib-1.2.6-mingw-Makefile.patch000066400000000000000000000040611231531733200237720ustar00rootroot00000000000000--- win32/Makefile.gcc 2012-01-30 03:53:53.000000000 +1100 +++ win32/Makefile.gcc.new 2013-02-17 16:49:02.732054937 +1100 @@ -23,14 +23,14 @@ # If the platform is *not* MinGW (e.g. it is Cygwin or UWIN), # the DLL name should be changed from "zlib1.dll". -STATICLIB = libz.a +STATICLIB = libz.dll.a SHAREDLIB = zlib1.dll -IMPLIB = libz.dll.a +IMPLIB = libz.a # # Set to 1 if shared object needs to be installed # -SHARED_MODE=0 +SHARED_MODE=1 #LOC = -DASMV #LOC = -DDEBUG -g @@ -60,7 +60,7 @@ RM = rm -f prefix ?= /usr/local -exec_prefix = $(prefix) +exec_prefix ?= $(prefix) OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o @@ -127,16 +127,16 @@ echo INCLUDE_PATH, LIBRARY_PATH, and BINARY_PATH must be specified; \ exit 1; \ fi - -@mkdir -p $(INCLUDE_PATH) - -@mkdir -p $(LIBRARY_PATH) $(LIBRARY_PATH)/pkgconfig + -@mkdir -p $(DESTDIR)/$(INCLUDE_PATH) + -@mkdir -p $(DESTDIR)/$(LIBRARY_PATH) $(DESTDIR)/$(LIBRARY_PATH)/pkgconfig -if [ "$(SHARED_MODE)" = "1" ]; then \ - mkdir -p $(BINARY_PATH); \ - $(INSTALL) $(SHAREDLIB) $(BINARY_PATH); \ - $(INSTALL) $(IMPLIB) $(LIBRARY_PATH); \ + mkdir -p $(DESTDIR)/$(BINARY_PATH); \ + $(INSTALL) $(SHAREDLIB) $(DESTDIR)/$(BINARY_PATH); \ + $(INSTALL) $(IMPLIB) $(DESTDIR)/$(LIBRARY_PATH); \ fi - -$(INSTALL) zlib.h $(INCLUDE_PATH) - -$(INSTALL) zconf.h $(INCLUDE_PATH) - -$(INSTALL) $(STATICLIB) $(LIBRARY_PATH) + -$(INSTALL) zlib.h $(DESTDIR)/$(INCLUDE_PATH) + -$(INSTALL) zconf.h $(DESTDIR)/$(INCLUDE_PATH) + -$(INSTALL) $(STATICLIB) $(DESTDIR)/$(LIBRARY_PATH) sed \ -e 's|@prefix@|${prefix}|g' \ -e 's|@exec_prefix@|${exec_prefix}|g' \ @@ -144,7 +144,7 @@ -e 's|@sharedlibdir@|$(LIBRARY_PATH)|g' \ -e 's|@includedir@|$(INCLUDE_PATH)|g' \ -e 's|@VERSION@|'`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' zlib.h`'|g' \ - zlib.pc.in > $(LIBRARY_PATH)/pkgconfig/zlib.pc + zlib.pc.in > $(DESTDIR)/$(LIBRARY_PATH)/pkgconfig/zlib.pc uninstall: -if [ "$(SHARED_MODE)" = "1" ]; then \ repsnapper-2.3.2a5/win32/repsnapper.nsi.in000066400000000000000000002032051231531733200203660ustar00rootroot00000000000000!define PRODUCT_NAME "@PACKAGE_NAME@" !define PRODUCT_VERSION "@PACKAGE_VERSION@" !define PRODUCT_PUBLISHER "repsnapper" !define PRODUCT_WEB_SITE "@PACKAGE_URL@" !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\repsnapper.exe" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" !define BUILD_OUTPUT_DIR "@prefix_win@" !addincludedir ".\include" !include "uninstall-log.nsh" SetCompressor lzma ; MUI 1.67 compatible ------ !include "MUI.nsh" ; MUI Settings !define MUI_ABORTWARNING !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" ; Welcome page !insertmacro MUI_PAGE_WELCOME ; License page !insertmacro MUI_PAGE_LICENSE "${BUILD_OUTPUT_DIR}\GPL-2.0.txt" ; Directory page !insertmacro MUI_PAGE_DIRECTORY ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page !define MUI_FINISHPAGE_RUN "$INSTDIR\bin\repsnapper.exe" !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\Readme.txt" !insertmacro MUI_PAGE_FINISH ; Uninstaller pages !insertmacro MUI_UNPAGE_INSTFILES ; Language files !insertmacro MUI_LANGUAGE "English" ; Reserve files !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "repsnapper-${PRODUCT_VERSION}.exe" InstallDir "$PROGRAMFILES\Repsnapper" InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" ShowInstDetails show ShowUnInstDetails show RequestExecutionLevel admin ; Need Admin rights on Vista/Win7 !macro VerifyUserIsAdmin UserInfo::GetAccountType pop $0 ${If} $0 != "admin" ;Require admin rights on NT4+ messageBox mb_iconstop "Administrator rights required!" setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED quit ${EndIf} !macroend function .onInit setShellVarContext all !insertmacro VerifyUserIsAdmin functionEnd !define UninstLog "uninstall.log" Var UninstLog LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!" !define AddItem "!insertmacro AddItem" !define File "!insertmacro File" !define FileAs "!insertmacro FileAs" !define CreateShortcut "!insertmacro CreateShortcut" !define CreateShortcutFull "!insertmacro CreateShortcutFull" !define CopyFiles "!insertmacro CopyFiles" !define Rename "!insertmacro Rename" !define CreateDirectory "!insertmacro CreateDirectory" !define SetOutPath "!insertmacro SetOutPath" !define WriteUninstaller "!insertmacro WriteUninstaller" !define WriteIniStr "!insertmacro WriteIniStr" !define WriteRegStr "!insertmacro WriteRegStr" !define WriteRegDWORD "!insertmacro WriteRegDWORD" Section -openlogfile CreateDirectory "$INSTDIR" IfFileExists "$INSTDIR\${UninstLog}" +3 FileOpen $UninstLog "$INSTDIR\${UninstLog}" w Goto +4 SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL FileOpen $UninstLog "$INSTDIR\${UninstLog}" a FileSeek $UninstLog 0 END SectionEnd Section "MainSection" SEC01 ${SetOutPath} "$INSTDIR" SetOverwrite ifnewer ${FileAs} "Readme.txt" "${BUILD_OUTPUT_DIR}\README.win32" ${SetOutPath} "$INSTDIR\bin" SetOverwrite ifnewer ${File} "${BUILD_OUTPUT_DIR}\bin\" "repsnapper.exe" ${CreateDirectory} "$SMPROGRAMS\Repsnapper" ${CreateShortCut} "$SMPROGRAMS\Repsnapper\Repsnapper.lnk" "$INSTDIR\bin\repsnapper.exe" ${CreateShortCut} "$DESKTOP\Repsnapper.lnk" "$INSTDIR\bin\repsnapper.exe" ${AddItem} "$INSTDIR\etc" ${AddItem} "$INSTDIR\etc\xdg" ${SetOutPath} "$INSTDIR\etc\xdg\repsnapper" ${File} "${BUILD_OUTPUT_DIR}\etc\xdg\repsnapper\" "repsnapper.conf" ${AddItem} "$INSTDIR\lib" ${AddItem} "$INSTDIR\lib\gtk-2.0" ${AddItem} "$INSTDIR\lib\gtk-2.0\2.10.0" ${SetOutPath} "$INSTDIR\lib\gtk-2.0\2.10.0\engines" SetOverwrite try ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\engines\" "libpixmap.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\engines\" "libwimp.dll" ${SetOutPath} "$INSTDIR\lib\gtk-2.0\2.10.0\immodules" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-thai.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-viqr.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-ime.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-ipa.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-cyrillic-translit.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-am-et.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-ti-er.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-cedilla.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-ti-et.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-multipress.dll" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\2.10.0\immodules\" "im-inuktitut.dll" ${SetOutPath} "$INSTDIR\lib\gtk-2.0\modules" ${File} "${BUILD_OUTPUT_DIR}\lib\gtk-2.0\modules\" "libgail.dll" ${AddItem} "$INSTDIR\@DATADIRNAME@\locale" ${AddItem} "$INSTDIR\@DATADIRNAME@\locale\de_DE" ${AddItem} "$INSTDIR\@DATADIRNAME@\locale\en_GB" ${SetOutPath} "$INSTDIR\@DATADIRNAME@\locale\de_DE\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\@DATADIRNAME@\locale\de_DE\LC_MESSAGES\" "repsnapper.mo" ${SetOutPath} "$INSTDIR\@DATADIRNAME@\locale\en_GB\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\@DATADIRNAME@\locale\en_GB\LC_MESSAGES\" "repsnapper.mo" ${SetOutPath} "$INSTDIR\etc\gtk-2.0" ${File} "${BUILD_OUTPUT_DIR}\etc\gtk-2.0\" "im-multipress.conf" ${SetOutPath} "$INSTDIR\etc\fonts" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\" "fonts.dtd" ${SetOutPath} "$INSTDIR\etc\fonts\conf.d" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "69-unifont.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "40-nonlatin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "80-delicious.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "20-fix-globaladvance.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "README" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "65-fonts-persian.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "65-nonlatin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "51-local.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "45-latin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "90-synthetic.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "49-sansserif.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "50-user.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "30-metric-aliases.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "30-urw-aliases.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "60-latin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.d\" "20-unhint-small-vera.conf" ${SetOutPath} "$INSTDIR\etc\fonts\conf.avail" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "69-unifont.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-sub-pixel-rgb.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "40-nonlatin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-sub-pixel-vrgb.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "80-delicious.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "20-fix-globaladvance.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "65-khmer.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-sub-pixel-vbgr.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "65-fonts-persian.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "65-nonlatin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "51-local.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-unhinted.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "45-latin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "90-synthetic.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "49-sansserif.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-sub-pixel-bgr.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "25-unhint-nonlatin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "70-yes-bitmaps.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-no-sub-pixel.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "50-user.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "70-no-bitmaps.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "30-metric-aliases.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "10-autohint.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "30-urw-aliases.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "60-latin.conf" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\conf.avail\" "20-unhint-small-vera.conf" ${SetOutPath} "$INSTDIR\etc\fonts" ${File} "${BUILD_OUTPUT_DIR}\etc\fonts\" "fonts.conf" ${AddItem} "$INSTDIR\share" ${AddItem} "$INSTDIR\share\themes" ${AddItem} "$INSTDIR\share\themes\Emacs" ${SetOutPath} "$INSTDIR\share\themes\Emacs\gtk-2.0-key" ${File} "${BUILD_OUTPUT_DIR}\share\themes\Emacs\gtk-2.0-key\" "gtkrc" ${AddItem} "$INSTDIR\share\themes\MS-Windows" ${SetOutPath} "$INSTDIR\share\themes\MS-Windows\gtk-2.0" ${File} "${BUILD_OUTPUT_DIR}\share\themes\MS-Windows\gtk-2.0\" "gtkrc" ${AddItem} "$INSTDIR\share\themes\Default" ${SetOutPath} "$INSTDIR\share\themes\Default\gtk-2.0-key" ${File} "${BUILD_OUTPUT_DIR}\share\themes\Default\gtk-2.0-key\" "gtkrc" ${AddItem} "$INSTDIR\share\themes\Raleigh" ${SetOutPath} "$INSTDIR\share\themes\Raleigh\gtk-2.0" ${File} "${BUILD_OUTPUT_DIR}\share\themes\Raleigh\gtk-2.0\" "gtkrc" ${SetOutPath} "$INSTDIR\share\repsnapper" ${File} "${BUILD_OUTPUT_DIR}\share\repsnapper\" "repsnapper.ui" ${SetOutPath} "$INSTDIR\share\locale" ${File} "${BUILD_OUTPUT_DIR}\share\locale\" "locale.alias" ${AddItem} "$INSTDIR\share\locale\gu" ${SetOutPath} "$INSTDIR\share\locale\gu\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gu\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gu\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gu\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gu\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gu\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\zh_CN" ${SetOutPath} "$INSTDIR\share\locale\zh_CN\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_CN\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sr@ije" ${SetOutPath} "$INSTDIR\share\locale\sr@ije\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@ije\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@ije\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@ije\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@ije\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@ije\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sq" ${SetOutPath} "$INSTDIR\share\locale\sq\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sq\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sq\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sq\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sq\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sq\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\eu" ${SetOutPath} "$INSTDIR\share\locale\eu\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eu\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eu\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eu\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eu\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eu\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\eo" ${SetOutPath} "$INSTDIR\share\locale\eo\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\eo\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sv" ${SetOutPath} "$INSTDIR\share\locale\sv\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sv\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\bs" ${SetOutPath} "$INSTDIR\share\locale\bs\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bs\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bs\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bs\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bs\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bs\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\kk" ${SetOutPath} "$INSTDIR\share\locale\kk\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kk\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kk\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kk\LC_MESSAGES\" "gtk20-properties.mo" ${AddItem} "$INSTDIR\share\locale\mai" ${SetOutPath} "$INSTDIR\share\locale\mai\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mai\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mai\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mai\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mai\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mai\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ur" ${SetOutPath} "$INSTDIR\share\locale\ur\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ur\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ur\LC_MESSAGES\" "gtk20-properties.mo" ${AddItem} "$INSTDIR\share\locale\te" ${SetOutPath} "$INSTDIR\share\locale\te\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\te\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\te\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\te\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\te\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\te\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\es" ${SetOutPath} "$INSTDIR\share\locale\es\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\es\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\vi" ${SetOutPath} "$INSTDIR\share\locale\vi\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\vi\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\hi" ${SetOutPath} "$INSTDIR\share\locale\hi\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hi\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hi\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hi\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hi\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hi\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\xh" ${SetOutPath} "$INSTDIR\share\locale\xh\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\xh\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\xh\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\xh\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\xh\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\xh\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\wa" ${SetOutPath} "$INSTDIR\share\locale\wa\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\wa\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\wa\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\wa\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\wa\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\wa\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\de" ${SetOutPath} "$INSTDIR\share\locale\de\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\de\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\bn" ${SetOutPath} "$INSTDIR\share\locale\bn\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\si" ${SetOutPath} "$INSTDIR\share\locale\si\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\si\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\si\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\si\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\si\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\si\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\cs" ${SetOutPath} "$INSTDIR\share\locale\cs\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cs\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ug" ${SetOutPath} "$INSTDIR\share\locale\ug\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ug\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ug\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ug\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ug\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ug\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\uz@cyrillic" ${SetOutPath} "$INSTDIR\share\locale\uz@cyrillic\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz@cyrillic\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz@cyrillic\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz@cyrillic\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ast" ${SetOutPath} "$INSTDIR\share\locale\ast\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ast\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ast\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ast\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ast\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ast\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ca" ${SetOutPath} "$INSTDIR\share\locale\ca\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\uz" ${SetOutPath} "$INSTDIR\share\locale\uz\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uz\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ms" ${SetOutPath} "$INSTDIR\share\locale\ms\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ms\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ms\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ms\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ms\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ms\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ka" ${SetOutPath} "$INSTDIR\share\locale\ka\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ka\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ka\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ka\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ka\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ka\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\az_IR" ${SetOutPath} "$INSTDIR\share\locale\az_IR\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az_IR\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az_IR\LC_MESSAGES\" "gtk20-properties.mo" ${AddItem} "$INSTDIR\share\locale\nso" ${SetOutPath} "$INSTDIR\share\locale\nso\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nso\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nso\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nso\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\uk" ${SetOutPath} "$INSTDIR\share\locale\uk\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\uk\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\fi" ${SetOutPath} "$INSTDIR\share\locale\fi\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fi\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\be@latin" ${SetOutPath} "$INSTDIR\share\locale\be@latin\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be@latin\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be@latin\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be@latin\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be@latin\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be@latin\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\pt_BR" ${SetOutPath} "$INSTDIR\share\locale\pt_BR\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt_BR\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\mr" ${SetOutPath} "$INSTDIR\share\locale\mr\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mr\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mr\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mr\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mr\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mr\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ru" ${SetOutPath} "$INSTDIR\share\locale\ru\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ru\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\id" ${SetOutPath} "$INSTDIR\share\locale\id\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\id\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\fr" ${SetOutPath} "$INSTDIR\share\locale\fr\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fr\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\be" ${SetOutPath} "$INSTDIR\share\locale\be\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\be\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\crh" ${SetOutPath} "$INSTDIR\share\locale\crh\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\crh\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\crh\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\crh\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\nn" ${SetOutPath} "$INSTDIR\share\locale\nn\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nn\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\nl" ${SetOutPath} "$INSTDIR\share\locale\nl\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nl\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sk" ${SetOutPath} "$INSTDIR\share\locale\sk\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sk\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\dz" ${SetOutPath} "$INSTDIR\share\locale\dz\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\dz\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\dz\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\dz\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\dz\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\dz\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\as" ${SetOutPath} "$INSTDIR\share\locale\as\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\as\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\as\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\as\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\as\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\as\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\en@boldquot" ${SetOutPath} "$INSTDIR\share\locale\en@boldquot\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en@boldquot\LC_MESSAGES\" "gettext-runtime.mo" ${AddItem} "$INSTDIR\share\locale\da" ${SetOutPath} "$INSTDIR\share\locale\da\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\da\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\el" ${SetOutPath} "$INSTDIR\share\locale\el\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\el\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\kn" ${SetOutPath} "$INSTDIR\share\locale\kn\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kn\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kn\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kn\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kn\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\kn\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\en@quot" ${SetOutPath} "$INSTDIR\share\locale\en@quot\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en@quot\LC_MESSAGES\" "gettext-runtime.mo" ${AddItem} "$INSTDIR\share\locale\et" ${SetOutPath} "$INSTDIR\share\locale\et\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\et\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\hu" ${SetOutPath} "$INSTDIR\share\locale\hu\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hu\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hu\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hu\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hu\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hu\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\yi" ${SetOutPath} "$INSTDIR\share\locale\yi\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\yi\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\yi\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\yi\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\yi\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\yi\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\zh_HK" ${SetOutPath} "$INSTDIR\share\locale\zh_HK\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_HK\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ca@valencia" ${SetOutPath} "$INSTDIR\share\locale\ca@valencia\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca@valencia\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca@valencia\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca@valencia\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca@valencia\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ca@valencia\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\io" ${SetOutPath} "$INSTDIR\share\locale\io\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\io\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\io\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\io\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\is" ${SetOutPath} "$INSTDIR\share\locale\is\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\is\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\is\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\is\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\is\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\is\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\li" ${SetOutPath} "$INSTDIR\share\locale\li\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\li\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\li\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\li\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\li\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\pt" ${SetOutPath} "$INSTDIR\share\locale\pt\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pt\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\mg" ${SetOutPath} "$INSTDIR\share\locale\mg\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mg\LC_MESSAGES\" "glib20.mo" ${AddItem} "$INSTDIR\share\locale\en_CA" ${SetOutPath} "$INSTDIR\share\locale\en_CA\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_CA\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_CA\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_CA\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_CA\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_CA\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\oc" ${SetOutPath} "$INSTDIR\share\locale\oc\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\oc\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\oc\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\oc\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\oc\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\oc\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\it" ${SetOutPath} "$INSTDIR\share\locale\it\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\it\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ar" ${SetOutPath} "$INSTDIR\share\locale\ar\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ar\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ar\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ar\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ar\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ar\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\cy" ${SetOutPath} "$INSTDIR\share\locale\cy\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cy\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cy\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cy\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cy\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\cy\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\br" ${SetOutPath} "$INSTDIR\share\locale\br\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\br\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\br\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\br\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\az" ${SetOutPath} "$INSTDIR\share\locale\az\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\az\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\tt" ${SetOutPath} "$INSTDIR\share\locale\tt\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tt\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tt\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tt\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tt\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tt\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\hr" ${SetOutPath} "$INSTDIR\share\locale\hr\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hr\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hr\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hr\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hr\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hr\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sr@latin" ${SetOutPath} "$INSTDIR\share\locale\sr@latin\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@latin\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@latin\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@latin\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@latin\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr@latin\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ro" ${SetOutPath} "$INSTDIR\share\locale\ro\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ro\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\mn" ${SetOutPath} "$INSTDIR\share\locale\mn\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mn\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mn\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mn\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mn\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mn\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\lv" ${SetOutPath} "$INSTDIR\share\locale\lv\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lv\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lv\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lv\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lv\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lv\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\pl" ${SetOutPath} "$INSTDIR\share\locale\pl\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pl\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\mk" ${SetOutPath} "$INSTDIR\share\locale\mk\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mk\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mk\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mk\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mk\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mk\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\fa" ${SetOutPath} "$INSTDIR\share\locale\fa\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fa\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fa\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fa\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fa\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\fa\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\pa" ${SetOutPath} "$INSTDIR\share\locale\pa\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pa\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pa\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pa\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pa\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\pa\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sl" ${SetOutPath} "$INSTDIR\share\locale\sl\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sl\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ne" ${SetOutPath} "$INSTDIR\share\locale\ne\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ne\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ne\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ne\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ne\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ne\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\en_GB" ${SetOutPath} "$INSTDIR\share\locale\en_GB\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_GB\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_GB\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_GB\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_GB\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en_GB\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ia" ${SetOutPath} "$INSTDIR\share\locale\ia\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ia\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ia\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ia\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\tk" ${SetOutPath} "$INSTDIR\share\locale\tk\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tk\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tk\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tk\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tk\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ku" ${SetOutPath} "$INSTDIR\share\locale\ku\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ku\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ku\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ku\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ku\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ku\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\af" ${SetOutPath} "$INSTDIR\share\locale\af\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\af\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\af\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\af\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\af\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\af\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ang" ${SetOutPath} "$INSTDIR\share\locale\ang\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ang\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ang\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ang\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ta" ${SetOutPath} "$INSTDIR\share\locale\ta\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ta\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ta\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ta\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ta\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ta\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\he" ${SetOutPath} "$INSTDIR\share\locale\he\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\he\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\he\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\he\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\he\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\he\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ga" ${SetOutPath} "$INSTDIR\share\locale\ga\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ga\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\nb" ${SetOutPath} "$INSTDIR\share\locale\nb\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nb\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ko" ${SetOutPath} "$INSTDIR\share\locale\ko\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ko\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\mi" ${SetOutPath} "$INSTDIR\share\locale\mi\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mi\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mi\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\mi\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\am" ${SetOutPath} "$INSTDIR\share\locale\am\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\am\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\am\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\am\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\am\LC_MESSAGES\" "gtk20-properties.mo" ${AddItem} "$INSTDIR\share\locale\ja" ${SetOutPath} "$INSTDIR\share\locale\ja\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ja\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\zh_TW" ${SetOutPath} "$INSTDIR\share\locale\zh_TW\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\zh_TW\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\tl" ${SetOutPath} "$INSTDIR\share\locale\tl\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tl\LC_MESSAGES\" "glib20.mo" ${AddItem} "$INSTDIR\share\locale\th" ${SetOutPath} "$INSTDIR\share\locale\th\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\th\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\th\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\th\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\th\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\th\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\en@shaw" ${SetOutPath} "$INSTDIR\share\locale\en@shaw\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en@shaw\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en@shaw\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\en@shaw\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\bn_IN" ${SetOutPath} "$INSTDIR\share\locale\bn_IN\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn_IN\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn_IN\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn_IN\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn_IN\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bn_IN\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ps" ${SetOutPath} "$INSTDIR\share\locale\ps\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ps\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ps\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ps\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ps\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ps\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\ml" ${SetOutPath} "$INSTDIR\share\locale\ml\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ml\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ml\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ml\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ml\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\ml\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\nds" ${SetOutPath} "$INSTDIR\share\locale\nds\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nds\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nds\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nds\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\nds\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\lt" ${SetOutPath} "$INSTDIR\share\locale\lt\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lt\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lt\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lt\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lt\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\lt\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\hy" ${SetOutPath} "$INSTDIR\share\locale\hy\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hy\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hy\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hy\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\hy\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\rw" ${SetOutPath} "$INSTDIR\share\locale\rw\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\rw\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\rw\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\rw\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\rw\LC_MESSAGES\" "gtk20-properties.mo" ${AddItem} "$INSTDIR\share\locale\or" ${SetOutPath} "$INSTDIR\share\locale\or\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\or\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\or\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\or\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\or\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\or\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\bg" ${SetOutPath} "$INSTDIR\share\locale\bg\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\bg\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\my" ${SetOutPath} "$INSTDIR\share\locale\my\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\my\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\my\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\my\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\gl" ${SetOutPath} "$INSTDIR\share\locale\gl\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\gl\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\tr" ${SetOutPath} "$INSTDIR\share\locale\tr\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\tr\LC_MESSAGES\" "gdk-pixbuf.mo" ${AddItem} "$INSTDIR\share\locale\sr" ${SetOutPath} "$INSTDIR\share\locale\sr\LC_MESSAGES" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "gettext-runtime.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "atk10.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "gtk20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "glib20.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "gtk20-properties.mo" ${File} "${BUILD_OUTPUT_DIR}\share\locale\sr\LC_MESSAGES\" "gdk-pixbuf.mo" ${SetOutPath} "$INSTDIR\bin" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgtkglext-win32-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgtkglextmm-win32-1.2-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpixman-1-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgiomm-2.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgdk_pixbuf-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgdk-win32-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libcharset-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libcairo-gobject-2.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libfontconfig-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgio-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgthread-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpango-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "gspawn-win32-helper-console.exe" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libglade-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpangowin32-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgdkmm-2.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpng-3.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libtiff-3.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libiconv-2.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libfreetype-6.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libsigc-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libtiffxx-3.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "gspawn-win32-helper.exe" ${File} "${BUILD_OUTPUT_DIR}\bin\" "zlib1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpangocairo-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgmodule-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libglibmm_generate_extra_defs-2.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libcairo-script-interpreter-2.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libglib-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libglibmm-2.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "${LIBGCC_FILE}" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libwinpthread-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libstdc++-6.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgailutil-18.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgdkglext-win32-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgdkglextmm-win32-1.2-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpangomm-1.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libjpeg-8.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libatkmm-1.6-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libatk-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libcairomm-1.0-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libintl-8.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgtk-win32-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgobject-2.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libcairo-2.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libgtkmm-2.4-1.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libxml2-2.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libasprintf-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpangoft2-1.0-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libpng12-0.dll" ${File} "${BUILD_OUTPUT_DIR}\bin\" "libxml++-2.6-2.dll" SectionEnd Section -AdditionalIcons ${SetOutPath} $INSTDIR ${WriteIniStr} "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" ${CreateShortCut} "$SMPROGRAMS\Repsnapper\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" ${CreateShortCut} "$SMPROGRAMS\Repsnapper\Uninstall.lnk" "$INSTDIR\uninst.exe" SectionEnd Section -Post ${WriteUninstaller} "$INSTDIR\uninst.exe" ${WriteRegStr} HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\repsnapper.exe" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" ${WriteRegStr} ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" SectionEnd Function un.onUninstSuccess HideWindow MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." FunctionEnd Function un.onInit SetShellVarContext all MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2 Abort !insertmacro VerifyUserIsAdmin FunctionEnd Section Uninstall ;Can't uninstall if uninstall log is missing! IfFileExists "$INSTDIR\${UninstLog}" +3 MessageBox MB_OK|MB_ICONSTOP "$(UninstLogMissing)" Abort Push $R0 Push $R1 Push $R2 SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL FileOpen $UninstLog "$INSTDIR\${UninstLog}" r StrCpy $R1 -1 GetLineCount: ClearErrors FileRead $UninstLog $R0 IntOp $R1 $R1 + 1 StrCpy $R0 $R0 -2 Push $R0 IfErrors 0 GetLineCount Pop $R0 LoopRead: StrCmp $R1 0 LoopDone Pop $R0 IfFileExists "$R0\*.*" 0 +3 RMDir $R0 #is dir Goto +9 IfFileExists $R0 0 +3 Delete $R0 #is file Goto +6 StrCmp $R0 "HKLM ${PRODUCT_DIR_REGKEY}" 0 +3 DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" #is Reg Element Goto +3 StrCmp $R0 "${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY}" 0 +2 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" #is Reg Element IntOp $R1 $R1 - 1 Goto LoopRead LoopDone: FileClose $UninstLog Delete "$INSTDIR\${UninstLog}" RMDir "$INSTDIR" Pop $R2 Pop $R1 Pop $R0 ;Remove registry keys ;DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" ;DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" SetAutoClose true SectionEnd