[SCM] 3depict branch, master, updated. debian/0.0.13-1_exp1-6-g87852b3

D Haley mycae at gmx.com
Sat Jul 20 17:11:48 UTC 2013


The following commit has been merged in the master branch:
commit ffb1a5775e66eda17a83e26f6491d94269211665
Author: D Haley <mycae at gmx.com>
Date:   Sat Jul 20 18:31:29 2013 +0200

    * Fix git-import-orig not actually importing files

diff --git a/AUTHORS b/AUTHORS
index e55b7aa..2817a29 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,5 @@
 Programming:
-  D Haley mycae % yahoo com
+  D Haley mycae % gmx com
   annacegu annacegu % users sourceforge net
 
 Translations:
diff --git a/ChangeLog b/ChangeLog
index 05992af..c61a060 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+* 20 Jul 2013 : 0.0.14
+	Features:
+	- 2D slice render mode for voxels. Can now visualise voxel data
+	  using colourised planes - show voxel values on a given slice
+	- Animated spin-progress icon to show refresh status
+	- Automatic, but optional, limiting of point count in 3D display 
+		- Improved responsiveness of program to user when
+		  working with large datasets. Enabled by default.
+		- Downsampling no longer added when loading datasets
+	- New "double-ORNL rng" rangefile support
+
+	User Visible Bugfixes/Changes:
+	- Fix "blinking"/flicker problems in 3D scene when changing properties
+	- Improved tracking of changes to state
+		- Current filename
+		- Current directory
+		- Changes to state (eg, for asking to save at exit)
+	- Fix state load/save bugs
+		- Orthogonal camera scaling
+		- stash handling
+	- Add new tree warnings
+		- Composition biasing warning for rangefile->composition pairs
+		- Missing required parent filter (eg clustering)
+	- More caching in voxel filter, for better performance
+	- Better axis handling for plot window
+	- Better handling of cylinder objects during interaction
+	- Improved performance in some cases when ranging
+	- On Mac OSX, manual now stored locally
+	- New "quick start" section in documentation
+	- Ranged ions/volume now reported correctly by ion info filter
+
+	Technical Bugfixes/Features:
+	- Split viscontrol and analysis state into separate modules
+	- Minor improvements to rangefile loading
+	- Improved assertion checking for selection bindings
+	- Remove needless templating of selection devices
+	- Continuous Integration script for cppcheck
+	- Minor opengl enhancement (performance & error reporting)
+
 * 12 Apr 2013 : 0.0.13
 	Features:
 	- Spherical composition profile support
diff --git a/TODO b/TODO
index 39a1f44..a1e5a77 100644
--- a/TODO
+++ b/TODO
@@ -1,15 +1,17 @@
 TODO List - worlds simplest bugtracking system 
 
 --Packaging--
-	* Fix linker order (?) for mingw-cross compile
 
 --Main app--
 	To Implement:
 		== Next version ==
 		* Range editor
-		* Plot overlays
-		* Ruler annotation could use "enable" and control sphere size setting
+		* Unit tests for statefile with stashes
+		* Improved filter tree visibility behaviour 
+		* Unit testing of text data loading routines
+
 		== Eventually == 
+		* Plot overlays
 		* Support for XY scatter plots
 		* Status bar message queue
 		* Voxel export dialog 
@@ -58,9 +60,6 @@ TODO List - worlds simplest bugtracking system
 		* Cluster filter wont save state correctly if parent
 		  rangefile has disabled ions. It will output incorrect
 		  number of enabled ions, and get wiped during next ::initFilter
-		* Don't appear to be able to move ranges in plot
-		  below/above upper and lower bound of data, regardless
-		  of plot zoom status
 		
 		Windows:
 		* Drawing updates for resolution dialog are wonk
@@ -91,10 +90,10 @@ TODO List - worlds simplest bugtracking system
 			* drag drop not working?
 			* icon on dock bounces very fast during some refreshes
 
+		== Needs reproducing ==
+
 	Auditing:
 		== Next release ==
-		* Set keynames for property groupings
-		* Unit testing of text data loading routines
 
 	Performance:
 		* Scene is sometimes continuously refreshed during post effects, causing CPU usage
@@ -107,17 +106,16 @@ TODO List - worlds simplest bugtracking system
 		  cluster BB interactions.
 		* Examine performance characteristics of HULL_GRAB in ioninfo
 		* Conversion of double axis-angle rotations to single axis angle rotations - any value here?
+		* Ranging does two full passes, one to estimate output size, and one to actually range
+			- why not simply sample the input to estimate output size??
 	
 	Misc:
 
 
 -- Refactor/cleanup --
-	* Interaction code needs to be cleaned up. Currently it is a substatiative hack.
-		- Viscontrol should store a copy of the original tree,
-		  then periodicially compare it to the current tree. if it
-		  is different, then it should invalidate the caches for
-		  the different bits, and then force a refresh. This would allow for removal 
-		  of the callback mechanism that is currently in use
+	* updateFilterPropertyGrid is in a bad location, need new
+	  file that knows about filters and wx at the same time,
+	  but is not viscontrol ;)
 	* Plotting code is a nightmare. Data model for plot.h is not
 	   very well thought out, leading to large duplication, and elaborate special-case-ing
 		- Plots need log/non-log axes
@@ -129,3 +127,10 @@ TODO List - worlds simplest bugtracking system
 	* I have multiple colour classes floating about. might be an idea to unify them.
 	* K3DTree currently requires public access to members of boundcube
 
+-- Deprecate --
+	* On Minor version change:
+		- DataLoadFilter::readState(...) -> doSample test for statefiles without doSample.
+			- 3Depict versions prior to 1207:2a01b7e83d75
+		- VoxeliseFilter::readState(...) -> axial slice read will be silently skipped if it is missing
+			- 3Depict versions <= 1628:ffa0b851e966 don't know about this element 
+		- Annotation XML element "sphereanglesize" name doesn't match its purpose, and needs to be renamed "spheremarkersize"
diff --git a/configure b/configure
index a42bd54..eb63ac8 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for 3Depict 0.0.13.
+# Generated by GNU Autoconf 2.69 for 3Depict 0.0.14.
 #
 # Report bugs to <mycae at yahoo.com>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='3Depict'
 PACKAGE_TARNAME='3depict'
-PACKAGE_VERSION='0.0.13'
-PACKAGE_STRING='3Depict 0.0.13'
+PACKAGE_VERSION='0.0.14'
+PACKAGE_STRING='3Depict 0.0.14'
 PACKAGE_BUGREPORT='mycae at yahoo.com'
 PACKAGE_URL=''
 
@@ -1349,7 +1349,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures 3Depict 0.0.13 to adapt to many kinds of systems.
+\`configure' configures 3Depict 0.0.14 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1419,7 +1419,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of 3Depict 0.0.13:";;
+     short | recursive ) echo "Configuration of 3Depict 0.0.14:";;
    esac
   cat <<\_ACEOF
 
@@ -1546,7 +1546,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-3Depict configure 0.0.13
+3Depict configure 0.0.14
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2103,6 +2103,143 @@ fi
 
 } # ac_fn_cxx_try_cpp
 
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ------------------------------ ##
+## Report this to mycae at yahoo.com ##
+## ------------------------------ ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES
 # -------------------------------------------
 # Tests whether TYPE exists after having included INCLUDES, setting cache
@@ -2227,7 +2364,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by 3Depict $as_me 0.0.13, which was
+It was created by 3Depict $as_me 0.0.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3042,7 +3179,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='3depict'
- VERSION='0.0.13'
+ VERSION='0.0.14'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -6436,8 +6573,10 @@ LIBS="$LIBS_ORIG"
 #Try linking against gluSphere windows usese -lglu32; mac?? ; linux -lGLU
 case "${host_os}" in
 	mingw*|windows*|winnt)
-		#FTGL_CHECK_GL # Not working for some reason?
-		GL_LIBS="-lglu32 -lopengl32 "
+		#win32 opengl names
+		GL_LIBS="-lglu32 -lopengl32"
+		#Add GLEW dependency for opengl > 1.1
+		GL_LIBS="$GL_LIBS -lglew32"
 
 	    ;;
 	darwin*)
@@ -6564,9 +6703,16 @@ $as_echo "\"mathgl check: assuming mathgl 1.x\"" >&6; }
 		;;
 esac
 
+
 #mgl2 is installed into different path (at least under debian)
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
 as_ac_Header=`$as_echo "ac_cv_header_${MGL_HEADER_TESTFILE}" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "${MGL_HEADER_TESTFILE}" "$as_ac_Header" "$ac_includes_default"
+ac_fn_cxx_check_header_mongrel "$LINENO" "${MGL_HEADER_TESTFILE}" "$as_ac_Header" "$ac_includes_default"
 if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
 
 $as_echo "#define HAVE_MGL_H /**/" >>confdefs.h
@@ -6601,7 +6747,7 @@ return mgl_set_def_param ();
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"; then :
   ac_cv_lib_mgl_mgl_set_def_param=yes
 else
   ac_cv_lib_mgl_mgl_set_def_param=no
@@ -6620,6 +6766,13 @@ else
   as_fn_error $? "Required MathGL libraries not found" "$LINENO" 5
 fi
 
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
 
 CFLAGS="$CFLAGS_ORIG"
 LDFLAGS="$LDFLAGS_ORIG"
@@ -7774,7 +7927,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by 3Depict $as_me 0.0.13, which was
+This file was extended by 3Depict $as_me 0.0.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7840,7 +7993,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-3Depict config.status 0.0.13
+3Depict config.status 0.0.14
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index eaa24d8..a482567 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([3Depict], [0.0.13], [mycae at yahoo.com])
+AC_INIT([3Depict], [0.0.14], [mycae at yahoo.com])
 AM_INIT_AUTOMAKE([foreign])
 AC_PROG_CXX
 AC_PROG_CC
@@ -253,8 +253,10 @@ dnl--------------
 #Try linking against gluSphere windows usese -lglu32; mac?? ; linux -lGLU
 case "${host_os}" in 
 	mingw*|windows*|winnt)
-		#FTGL_CHECK_GL # Not working for some reason?
-		GL_LIBS="-lglu32 -lopengl32 "
+		#win32 opengl names
+		GL_LIBS="-lglu32 -lopengl32"
+		#Add GLEW dependency for opengl > 1.1
+		GL_LIBS="$GL_LIBS -lglew32"
 		AC_SUBST(GL_LIBS)
 	    ;;
 	darwin*)
@@ -327,10 +329,14 @@ case "${host_os}" in
 		;;
 esac
 
+
 #mgl2 is installed into different path (at least under debian)
+AC_LANG_PUSH([C++])
 AC_CHECK_HEADER([${MGL_HEADER_TESTFILE}],[AC_DEFINE(HAVE_MGL_H,[],[Have got mathgl headers])],
 	[AC_MSG_ERROR([Required MathGL headers not found (looking for ${MGL_HEADER_TESTFILE}) - is mathgl development code installed?])])
 AC_CHECK_LIB(mgl, mgl_set_def_param, [AC_DEFINE(HAVE_MGL,[],[MathGL compilation OK])] , AC_MSG_ERROR([Required MathGL libraries not found]), -lmgl)
+AC_LANG_POP([C++])
+
 
 CFLAGS="$CFLAGS_ORIG"
 LDFLAGS="$LDFLAGS_ORIG"
diff --git a/data/textures/animProgress0.png b/data/textures/animProgress0.png
new file mode 100644
index 0000000..92760e5
Binary files /dev/null and b/data/textures/animProgress0.png differ
diff --git a/data/textures/animProgress1.png b/data/textures/animProgress1.png
new file mode 100644
index 0000000..351c829
Binary files /dev/null and b/data/textures/animProgress1.png differ
diff --git a/data/textures/animProgress2.png b/data/textures/animProgress2.png
new file mode 100644
index 0000000..9f87048
Binary files /dev/null and b/data/textures/animProgress2.png differ
diff --git a/data/textures/tex-source/3Depict-icon-anim.svg b/data/textures/tex-source/3Depict-icon-anim.svg
new file mode 100644
index 0000000..f299627
--- /dev/null
+++ b/data/textures/tex-source/3Depict-icon-anim.svg
@@ -0,0 +1,2114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   inkscape:export-ydpi="60.43671"
+   inkscape:export-xdpi="60.43671"
+   inkscape:export-filename="/home/pcuser/code/3Depict/data/textures/animProgress3.png"
+   sodipodi:docname="3Depict-icon-anim.svg"
+   inkscape:version="0.47 r22583"
+   id="svg2"
+   height="190"
+   width="190"
+   version="1.0">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1168"
+     inkscape:window-height="928"
+     id="namedview21"
+     showgrid="false"
+     inkscape:zoom="2.1078947"
+     inkscape:cx="54.090149"
+     inkscape:cy="53.751237"
+     inkscape:window-x="751"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g5582"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <sodipodi:guide
+       id="guide3731"
+       position="291.01817,-36.781987"
+       orientation="1,0" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata23">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5">
+    <inkscape:perspective
+       id="perspective25"
+       inkscape:persp3d-origin="64 : 42.666667 : 1"
+       inkscape:vp_z="128 : 64 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 64 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <linearGradient
+       id="linearGradient2816">
+      <stop
+         id="stop2818"
+         offset="0"
+         style="stop-color:#00b000;stop-opacity:1" />
+      <stop
+         id="stop2820"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2794">
+      <stop
+         id="stop2796"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2760">
+      <stop
+         id="stop2762"
+         offset="0"
+         style="stop-color:#00ff00;stop-opacity:1" />
+      <stop
+         id="stop2768"
+         offset="0.61160713"
+         style="stop-color:#00a200;stop-opacity:1" />
+      <stop
+         id="stop2764"
+         offset="1"
+         style="stop-color:#66ff66;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(-6.9292336,37.951483)"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2760"
+       id="linearGradient2766"
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336" />
+    <radialGradient
+       gradientTransform="translate(-2.8974896,41.983227)"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2794"
+       id="radialGradient2812"
+       fy="65.015877"
+       fx="62.984127"
+       r="54.179893"
+       cy="65.015877"
+       cx="62.984127" />
+    <linearGradient
+       gradientTransform="translate(-7.6223536,39.951483)"
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2816"
+       id="linearGradient2822"
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective2949" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2794-4"
+       id="radialGradient2812-8"
+       fy="65.015877"
+       fx="62.984127"
+       r="54.179893"
+       cy="65.015877"
+       cx="62.984127" />
+    <linearGradient
+       id="linearGradient2794-4">
+      <stop
+         id="stop2796-5"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804-0"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798-3"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2760-1"
+       id="linearGradient2766-6"
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(31.937501,26.651513)" />
+    <linearGradient
+       id="linearGradient2760-1">
+      <stop
+         id="stop2762-0"
+         offset="0"
+         style="stop-color:#0000ff;stop-opacity:1" />
+      <stop
+         id="stop2768-6"
+         offset="0.61160713"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2764-3"
+         offset="1"
+         style="stop-color:#6666ff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2816-0"
+       id="linearGradient2822-2"
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(31.244381,28.651513)" />
+    <linearGradient
+       id="linearGradient2816-0">
+      <stop
+         id="stop2818-6"
+         offset="0"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2820-1"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective3035" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2794-0"
+       id="radialGradient2812-3"
+       fy="65.015877"
+       fx="62.984127"
+       r="54.179893"
+       cy="65.015877"
+       cx="62.984127" />
+    <linearGradient
+       id="linearGradient2794-0">
+      <stop
+         id="stop2796-7"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804-8"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798-6"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3015">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3017" />
+    </filter>
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2760-8"
+       id="linearGradient2766-8"
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)" />
+    <linearGradient
+       id="linearGradient2760-8">
+      <stop
+         id="stop2762-4"
+         offset="0"
+         style="stop-color:#0000ff;stop-opacity:1" />
+      <stop
+         id="stop2768-3"
+         offset="0.61160713"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2764-1"
+         offset="1"
+         style="stop-color:#6666ff;stop-opacity:1" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3019">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3021" />
+    </filter>
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       xlink:href="#linearGradient2816-9"
+       id="linearGradient2822-4"
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)" />
+    <linearGradient
+       id="linearGradient2816-9">
+      <stop
+         id="stop2818-2"
+         offset="0"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2820-0"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3023">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3025" />
+    </filter>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0"
+       id="radialGradient3062"
+       gradientUnits="userSpaceOnUse"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893"
+       gradientTransform="translate(73.448584,25.244909)" />
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(35.969245,30.683257)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3133"
+       xlink:href="#linearGradient2794-4"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(31.937501,26.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3135"
+       xlink:href="#linearGradient2760-1"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(31.244381,28.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3137"
+       xlink:href="#linearGradient2816-0"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248"
+       xlink:href="#linearGradient2760-8"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250"
+       xlink:href="#linearGradient2816-9"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250-460"
+       xlink:href="#linearGradient2816-9-422"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422">
+      <stop
+         id="stop2956"
+         offset="0"
+         style="stop-color:#0030a2;stop-opacity:1" />
+      <stop
+         id="stop2958"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250-460-52"
+       xlink:href="#linearGradient2816-9-422-867"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867">
+      <stop
+         id="stop3128"
+         offset="0"
+         style="stop-color:#0060a2;stop-opacity:1" />
+      <stop
+         id="stop3130"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78"
+       xlink:href="#linearGradient2760-8-456"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456">
+      <stop
+         id="stop3308"
+         offset="0"
+         style="stop-color:#004cff;stop-opacity:1" />
+      <stop
+         id="stop3310"
+         offset="0.61160713"
+         style="stop-color:#0030a2;stop-opacity:1" />
+      <stop
+         id="stop3312"
+         offset="1"
+         style="stop-color:#6593ff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78-173"
+       xlink:href="#linearGradient2760-8-456-365"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365">
+      <stop
+         id="stop3500"
+         offset="0"
+         style="stop-color:#0098ff;stop-opacity:1" />
+      <stop
+         id="stop3502"
+         offset="0.61160713"
+         style="stop-color:#0060a2;stop-opacity:1" />
+      <stop
+         id="stop3504"
+         offset="1"
+         style="stop-color:#64c1ff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250-460-52-832"
+       xlink:href="#linearGradient2816-9-422-867-939"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867-939">
+      <stop
+         id="stop3702"
+         offset="0"
+         style="stop-color:#0090a2;stop-opacity:1" />
+      <stop
+         id="stop3704"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78-173-154"
+       xlink:href="#linearGradient2760-8-456-365-365"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365">
+      <stop
+         id="stop3910"
+         offset="0"
+         style="stop-color:#00e4ff;stop-opacity:1" />
+      <stop
+         id="stop3912"
+         offset="0.61160713"
+         style="stop-color:#0090a2;stop-opacity:1" />
+      <stop
+         id="stop3914"
+         offset="1"
+         style="stop-color:#63efff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250-460-52-832-209"
+       xlink:href="#linearGradient2816-9-422-867-939-292"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867-939-292">
+      <stop
+         id="stop4373"
+         offset="0"
+         style="stop-color:#008292;stop-opacity:1" />
+      <stop
+         id="stop4375"
+         offset="1"
+         style="stop-color:#e6e6e6;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78-173-154-735"
+       xlink:href="#linearGradient2760-8-456-365-365-148"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148">
+      <stop
+         id="stop4379"
+         offset="0"
+         style="stop-color:#00cde6;stop-opacity:1" />
+      <stop
+         id="stop4381"
+         offset="0.61160713"
+         style="stop-color:#008292;stop-opacity:1" />
+      <stop
+         id="stop4383"
+         offset="1"
+         style="stop-color:#59d7e6;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2816-9-422-867-939-292-243">
+      <stop
+         id="stop4617"
+         offset="0"
+         style="stop-color:#007583;stop-opacity:1" />
+      <stop
+         id="stop4619"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78-173-154-735-205"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762">
+      <stop
+         id="stop4623"
+         offset="0"
+         style="stop-color:#00b9cf;stop-opacity:1" />
+      <stop
+         id="stop4625"
+         offset="0.61160713"
+         style="stop-color:#007583;stop-opacity:1" />
+      <stop
+         id="stop4627"
+         offset="1"
+         style="stop-color:#50c2cf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3248-78-173-154-735-205-739"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762-822">
+      <stop
+         id="stop4879"
+         offset="0"
+         style="stop-color:#00a7ba;stop-opacity:1" />
+      <stop
+         id="stop4881"
+         offset="0.61160713"
+         style="stop-color:#006976;stop-opacity:1" />
+      <stop
+         id="stop4883"
+         offset="1"
+         style="stop-color:#48afba;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762-822-337">
+      <stop
+         id="stop5145"
+         offset="0"
+         style="stop-color:#0090a0;stop-opacity:1" />
+      <stop
+         id="stop5147"
+         offset="0.61160713"
+         style="stop-color:#00525c;stop-opacity:1" />
+      <stop
+         id="stop5149"
+         offset="1"
+         style="stop-color:#3f9ea8;stop-opacity:1" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective2974" />
+    <linearGradient
+       id="linearGradient2794-8">
+      <stop
+         id="stop2796-8"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804-7"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798-7"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2760-10">
+      <stop
+         id="stop2762-6"
+         offset="0"
+         style="stop-color:#00ff00;stop-opacity:1" />
+      <stop
+         id="stop2768-2"
+         offset="0.61160713"
+         style="stop-color:#00a200;stop-opacity:1" />
+      <stop
+         id="stop2764-7"
+         offset="1"
+         style="stop-color:#66ff66;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2816-95">
+      <stop
+         id="stop2818-8"
+         offset="0"
+         style="stop-color:#00b000;stop-opacity:1" />
+      <stop
+         id="stop2820-02"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2794-4-9">
+      <stop
+         id="stop2796-5-2"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804-0-1"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798-3-8"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2760-1-6">
+      <stop
+         id="stop2762-0-0"
+         offset="0"
+         style="stop-color:#0000ff;stop-opacity:1" />
+      <stop
+         id="stop2768-6-1"
+         offset="0.61160713"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2764-3-3"
+         offset="1"
+         style="stop-color:#6666ff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2816-0-7">
+      <stop
+         id="stop2818-6-2"
+         offset="0"
+         style="stop-color:#0000a2;stop-opacity:1" />
+      <stop
+         id="stop2820-1-3"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2794-0-3">
+      <stop
+         id="stop2796-7-4"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2804-8-0"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop2798-6-0"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3015-6">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3017-3" />
+    </filter>
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762-822-337-5">
+      <stop
+         id="stop5145-5"
+         offset="0"
+         style="stop-color:#0090a0;stop-opacity:1" />
+      <stop
+         id="stop5147-9"
+         offset="0.61160713"
+         style="stop-color:#00525c;stop-opacity:1" />
+      <stop
+         id="stop5149-9"
+         offset="1"
+         style="stop-color:#3f9ea8;stop-opacity:1" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3019-7">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3021-4" />
+    </filter>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3250-460-52-832-209-821-8"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243-7"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867-939-292-243-7">
+      <stop
+         id="stop4617-8"
+         offset="0"
+         style="stop-color:#007583;stop-opacity:1" />
+      <stop
+         id="stop4619-2"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       width="1"
+       height="1"
+       x="0"
+       y="0"
+       inkscape:menu-tooltip="Invert hue, or rotate it"
+       inkscape:menu="Color"
+       inkscape:label="Invert hue"
+       id="filter3023-8">
+      <feColorMatrix
+         result="result1"
+         values="180"
+         type="hueRotate"
+         id="feColorMatrix3025-2" />
+    </filter>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(73.448584,25.244909)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3656"
+       xlink:href="#linearGradient2794-0"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3658"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3660"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243"
+       inkscape:collect="always" />
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3662"
+       xlink:href="#linearGradient2794"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3664"
+       xlink:href="#linearGradient2760"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3666"
+       xlink:href="#linearGradient2816"
+       inkscape:collect="always" />
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(35.969245,30.683257)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3668"
+       xlink:href="#linearGradient2794-4"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(31.937501,26.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3670"
+       xlink:href="#linearGradient2760-1"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(31.244381,28.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3672"
+       xlink:href="#linearGradient2816-0"
+       inkscape:collect="always" />
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(35.969245,30.683257)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3668-667"
+       xlink:href="#linearGradient2794-4-114"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-4-114">
+      <stop
+         id="stop4014"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop4016"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop4018"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(31.937501,26.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3670-471"
+       xlink:href="#linearGradient2760-1-620"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-1-620">
+      <stop
+         id="stop4022"
+         offset="0"
+         style="stop-color:#1d1d1d;stop-opacity:1" />
+      <stop
+         id="stop4024"
+         offset="0.61160713"
+         style="stop-color:#121212;stop-opacity:1" />
+      <stop
+         id="stop4026"
+         offset="1"
+         style="stop-color:#777777;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(31.244381,28.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3672-27"
+       xlink:href="#linearGradient2816-0-909"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-0-909">
+      <stop
+         id="stop4030"
+         offset="0"
+         style="stop-color:#121212;stop-opacity:1" />
+      <stop
+         id="stop4032"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(73.448584,25.244909)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3656-220"
+       xlink:href="#linearGradient2794-0-725"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-0-725">
+      <stop
+         id="stop4036"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop4038"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop4040"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3658-965"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337-149"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762-822-337-149">
+      <stop
+         id="stop4044"
+         offset="0"
+         style="stop-color:#676767;stop-opacity:1" />
+      <stop
+         id="stop4046"
+         offset="0.61160713"
+         style="stop-color:#3b3b3b;stop-opacity:1" />
+      <stop
+         id="stop4048"
+         offset="1"
+         style="stop-color:#838383;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3660-732"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243-371"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867-939-292-243-371">
+      <stop
+         id="stop4052"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop4054"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3662-331"
+       xlink:href="#linearGradient2794-109"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-109">
+      <stop
+         id="stop5198"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5200"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5202"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3664-849"
+       xlink:href="#linearGradient2760-829"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-829">
+      <stop
+         id="stop5206"
+         offset="0"
+         style="stop-color:#969696;stop-opacity:1" />
+      <stop
+         id="stop5208"
+         offset="0.61160713"
+         style="stop-color:#5f5f5f;stop-opacity:1" />
+      <stop
+         id="stop5210"
+         offset="1"
+         style="stop-color:#c0c0c0;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3666-65"
+       xlink:href="#linearGradient2816-504"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-504">
+      <stop
+         id="stop5214"
+         offset="0"
+         style="stop-color:#676767;stop-opacity:1" />
+      <stop
+         id="stop5216"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(35.969245,30.683257)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3668-811"
+       xlink:href="#linearGradient2794-4-759"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-4-759">
+      <stop
+         id="stop5220"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5222"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5224"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(31.937501,26.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3670-865"
+       xlink:href="#linearGradient2760-1-497"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-1-497">
+      <stop
+         id="stop5228"
+         offset="0"
+         style="stop-color:#1d1d1d;stop-opacity:1" />
+      <stop
+         id="stop5230"
+         offset="0.61160713"
+         style="stop-color:#121212;stop-opacity:1" />
+      <stop
+         id="stop5232"
+         offset="1"
+         style="stop-color:#777777;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(31.244381,28.651513)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3672-385"
+       xlink:href="#linearGradient2816-0-184"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-0-184">
+      <stop
+         id="stop5236"
+         offset="0"
+         style="stop-color:#121212;stop-opacity:1" />
+      <stop
+         id="stop5238"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3662-283"
+       xlink:href="#linearGradient2794-350"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-350">
+      <stop
+         id="stop5864"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5866"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5868"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3664-838"
+       xlink:href="#linearGradient2760-528"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-528">
+      <stop
+         id="stop5872"
+         offset="0"
+         style="stop-color:#969696;stop-opacity:1" />
+      <stop
+         id="stop5874"
+         offset="0.61160713"
+         style="stop-color:#5f5f5f;stop-opacity:1" />
+      <stop
+         id="stop5876"
+         offset="1"
+         style="stop-color:#c0c0c0;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3666-869"
+       xlink:href="#linearGradient2816-302"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-302">
+      <stop
+         id="stop5880"
+         offset="0"
+         style="stop-color:#676767;stop-opacity:1" />
+      <stop
+         id="stop5882"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       r="54.179893"
+       fy="65.015877"
+       fx="62.984127"
+       cy="65.015877"
+       cx="62.984127"
+       gradientTransform="translate(73.448584,25.244909)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3656-793"
+       xlink:href="#linearGradient2794-0-605"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2794-0-605">
+      <stop
+         id="stop5886"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5888"
+         offset="0.9464286"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5890"
+         offset="1"
+         style="stop-color:#c5c5c5;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       y2="8.9609833"
+       x2="6.9292336"
+       y1="121.07077"
+       x1="6.9292336"
+       gradientTransform="translate(69.41684,21.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3658-960"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337-281"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2760-8-456-365-365-148-762-822-337-281">
+      <stop
+         id="stop5894"
+         offset="0"
+         style="stop-color:#676767;stop-opacity:1" />
+      <stop
+         id="stop5896"
+         offset="0.61160713"
+         style="stop-color:#3b3b3b;stop-opacity:1" />
+      <stop
+         id="stop5898"
+         offset="1"
+         style="stop-color:#838383;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       y2="12"
+       x2="31.5"
+       y1="63"
+       x1="31.5"
+       gradientTransform="translate(68.72372,23.213165)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3660-35"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243-958"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient2816-9-422-867-939-292-243-958">
+      <stop
+         id="stop5902"
+         offset="0"
+         style="stop-color:#545454;stop-opacity:1" />
+      <stop
+         id="stop5904"
+         offset="1"
+         style="stop-color:#cfcfcf;stop-opacity:1" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794"
+       id="radialGradient6329"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760"
+       id="linearGradient6331"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816"
+       id="linearGradient6333"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0"
+       id="radialGradient6335"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(73.448584,25.244909)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337"
+       id="linearGradient6337"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(69.41684,21.213165)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243"
+       id="linearGradient6339"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(68.72372,23.213165)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-4"
+       id="radialGradient6341"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(35.969245,30.683257)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-1"
+       id="linearGradient6343"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.937501,26.651513)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-0"
+       id="linearGradient6345"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.244381,28.651513)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-350"
+       id="radialGradient6364"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-528"
+       id="linearGradient6366"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-302"
+       id="linearGradient6368"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0-605"
+       id="radialGradient6370"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(73.448584,25.244909)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337-281"
+       id="linearGradient6372"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(69.41684,21.213165)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243-958"
+       id="linearGradient6374"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(68.72372,23.213165)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-4"
+       id="radialGradient6376"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(35.969245,30.683257)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-1"
+       id="linearGradient6378"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.937501,26.651513)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-0"
+       id="linearGradient6380"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.244381,28.651513)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-109"
+       id="radialGradient6399"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-829"
+       id="linearGradient6401"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-504"
+       id="linearGradient6403"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0"
+       id="radialGradient6405"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(73.448584,25.244909)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337"
+       id="linearGradient6407"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(69.41684,21.213165)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243"
+       id="linearGradient6409"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(68.72372,23.213165)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-4-759"
+       id="radialGradient6411"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(35.969245,30.683257)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-1-497"
+       id="linearGradient6413"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.937501,26.651513)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-0-184"
+       id="linearGradient6415"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.244381,28.651513)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794"
+       id="radialGradient6434"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760"
+       id="linearGradient6436"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816"
+       id="linearGradient6438"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0-725"
+       id="radialGradient6440"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(73.448584,25.244909)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337-149"
+       id="linearGradient6442"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(69.41684,21.213165)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243-371"
+       id="linearGradient6444"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(68.72372,23.213165)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-4-114"
+       id="radialGradient6446"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(35.969245,30.683257)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-1-620"
+       id="linearGradient6448"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.937501,26.651513)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-0-909"
+       id="linearGradient6450"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.244381,28.651513)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794"
+       id="radialGradient6469"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-2.8974896,41.983227)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760"
+       id="linearGradient6471"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-6.9292336,37.951483)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816"
+       id="linearGradient6473"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-7.6223536,39.951483)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-0"
+       id="radialGradient6475"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(73.448584,25.244909)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-8-456-365-365-148-762-822-337"
+       id="linearGradient6477"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(69.41684,21.213165)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-9-422-867-939-292-243"
+       id="linearGradient6479"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(68.72372,23.213165)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2794-4"
+       id="radialGradient6481"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(35.969245,30.683257)"
+       cx="62.984127"
+       cy="65.015877"
+       fx="62.984127"
+       fy="65.015877"
+       r="54.179893" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2760-1"
+       id="linearGradient6483"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.937501,26.651513)"
+       x1="6.9292336"
+       y1="121.07077"
+       x2="6.9292336"
+       y2="8.9609833" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2816-0"
+       id="linearGradient6485"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(31.244381,28.651513)"
+       x1="31.5"
+       y1="63"
+       x2="31.5"
+       y2="12" />
+  </defs>
+  <g
+     style="display:none"
+     inkscape:label="Orig"
+     id="layer5"
+     inkscape:groupmode="layer"
+     transform="translate(0.30631,15.087074)">
+    <g
+       id="g6452"
+       transform="translate(0,-15.087075)">
+      <g
+         id="g2941"
+         transform="translate(-0.30631,-15.087076)">
+        <path
+           id="path2790"
+           style="fill:url(#radialGradient6469);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           d="m 114.26653,106.9991 c 0,29.92273 -24.257164,54.1799 -54.179893,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922725 24.257164,-54.179889 54.179893,-54.179889 29.922729,0 54.179893,24.257164 54.179893,54.179889 z" />
+        <path
+           id="path1873"
+           style="fill:url(#linearGradient6471);fill-opacity:1;fill-rule:nonzero;stroke:#007400;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           d="m 110.23479,102.96736 c 0,29.92273 -24.257168,54.17989 -54.179897,54.17989 -29.922729,0 -54.179893,-24.25716 -54.179893,-54.17989 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922729,0 54.179897,24.257164 54.179897,54.179893 z" />
+        <path
+           id="path2814"
+           style="fill:url(#linearGradient6473);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           d="m 87.877646,77.451483 c 0,14.083261 -14.326888,25.499997 -32,25.499997 -17.673112,0 -32,-11.416736 -32,-25.499997 0,-14.083261 14.326888,-25.5 32,-25.5 17.673112,0 32,11.416739 32,25.5 z" />
+      </g>
+      <g
+         id="g2946"
+         transform="translate(-0.30631,-15.087076)">
+        <path
+           id="path2790-6"
+           style="fill:url(#radialGradient6475);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3015)"
+           d="m 190.61262,90.260786 c 0,29.922724 -24.25717,54.179884 -54.1799,54.179884 -29.92274,0 -54.179902,-24.25716 -54.179902,-54.179884 0,-29.922729 24.257162,-54.179893 54.179902,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z" />
+        <path
+           id="path1873-8"
+           style="fill:url(#linearGradient6477);fill-opacity:1;fill-rule:nonzero;stroke:#00343b;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3019)"
+           d="m 186.58088,86.229042 c 0,29.922728 -24.25717,54.179888 -54.1799,54.179888 -29.92274,0 -54.179906,-24.25716 -54.179906,-54.179888 0,-29.922729 24.257166,-54.179893 54.179906,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z" />
+        <path
+           id="path2814-9"
+           style="fill:url(#linearGradient6479);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3023)"
+           d="m 164.22373,60.713165 c 0,14.083261 -14.32689,25.5 -32,25.5 -17.67311,0 -32.00001,-11.416739 -32.00001,-25.5 0,-14.083261 14.3269,-25.5 32.00001,-25.5 17.67311,0 32,11.416739 32,25.5 z" />
+      </g>
+      <g
+         id="g2958"
+         transform="translate(-0.30631,-15.087076)">
+        <g
+           id="g2951">
+          <g
+             id="g3127"
+             transform="translate(19.581036,40.120974)">
+            <path
+               id="path2790-5"
+               style="fill:url(#radialGradient6481);fill-opacity:1;fill-rule:nonzero;stroke:none"
+               d="m 153.13327,95.699138 c 0,29.922732 -24.25717,54.179892 -54.179902,54.179892 -29.922725,0 -54.179889,-24.25716 -54.179889,-54.179892 0,-29.922733 24.257164,-54.179897 54.179889,-54.179897 29.922732,0 54.179902,24.257164 54.179902,54.179897 z" />
+            <g
+               id="g3119">
+              <path
+                 d="m 149.10153,91.66739 c 0,29.92273 -24.25717,54.1799 -54.179902,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922732,0 54.179902,24.257164 54.179902,54.179893 z"
+                 style="fill:url(#linearGradient6483);fill-opacity:1;fill-rule:nonzero;stroke:#000074;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+                 id="path1873-5" />
+              <path
+                 d="m 126.74438,66.151513 c 0,14.083261 -14.32689,25.5 -32.000002,25.5 -17.673109,0 -31.999997,-11.416739 -31.999997,-25.5 0,-14.083261 14.326888,-25.5 31.999997,-25.5 17.673112,0 32.000002,11.416739 32.000002,25.5 z"
+                 style="fill:url(#linearGradient6485);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path2814-4" />
+            </g>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="g3788"
+     inkscape:label="Green"
+     style="display:none"
+     transform="translate(0.30631,15.087074)">
+    <g
+       id="g6417"
+       transform="translate(0,-15.087075)">
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g3790">
+        <path
+           d="m 114.26653,106.9991 c 0,29.92273 -24.257164,54.1799 -54.179893,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922725 24.257164,-54.179889 54.179893,-54.179889 29.922729,0 54.179893,24.257164 54.179893,54.179889 z"
+           style="fill:url(#radialGradient6434);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path3792" />
+        <path
+           d="m 110.23479,102.96736 c 0,29.92273 -24.257168,54.17989 -54.179897,54.17989 -29.922729,0 -54.179893,-24.25716 -54.179893,-54.17989 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922729,0 54.179897,24.257164 54.179897,54.179893 z"
+           style="fill:url(#linearGradient6436);fill-opacity:1;fill-rule:nonzero;stroke:#007400;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           id="path3794" />
+        <path
+           d="m 87.877646,77.451483 c 0,14.083261 -14.326888,25.499997 -32,25.499997 -17.673112,0 -32,-11.416736 -32,-25.499997 0,-14.083261 14.326888,-25.5 32,-25.5 17.673112,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6438);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path3796" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g3798">
+        <path
+           d="m 190.61262,90.260786 c 0,29.922724 -24.25717,54.179884 -54.1799,54.179884 -29.92274,0 -54.179902,-24.25716 -54.179902,-54.179884 0,-29.922729 24.257162,-54.179893 54.179902,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#radialGradient6440);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3015)"
+           id="path3800" />
+        <path
+           d="m 186.58088,86.229042 c 0,29.922728 -24.25717,54.179888 -54.1799,54.179888 -29.92274,0 -54.179906,-24.25716 -54.179906,-54.179888 0,-29.922729 24.257166,-54.179893 54.179906,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#linearGradient6442);fill-opacity:1;fill-rule:nonzero;stroke:#252525;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3019)"
+           id="path3802" />
+        <path
+           d="m 164.22373,60.713165 c 0,14.083261 -14.32689,25.5 -32,25.5 -17.67311,0 -32.00001,-11.416739 -32.00001,-25.5 0,-14.083261 14.3269,-25.5 32.00001,-25.5 17.67311,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6444);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3023)"
+           id="path3804" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g3806">
+        <g
+           id="g3808">
+          <g
+             transform="translate(19.581036,40.120974)"
+             id="g3810">
+            <path
+               d="m 153.13327,95.699138 c 0,29.922732 -24.25717,54.179892 -54.179902,54.179892 -29.922725,0 -54.179889,-24.25716 -54.179889,-54.179892 0,-29.922733 24.257164,-54.179897 54.179889,-54.179897 29.922732,0 54.179902,24.257164 54.179902,54.179897 z"
+               style="fill:url(#radialGradient6446);fill-opacity:1;fill-rule:nonzero;stroke:none"
+               id="path3812" />
+            <g
+               id="g3814">
+              <path
+                 id="path3816"
+                 style="fill:url(#linearGradient6448);fill-opacity:1;fill-rule:nonzero;stroke:#0d0d0d;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+                 d="m 149.10153,91.66739 c 0,29.92273 -24.25717,54.1799 -54.179902,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922732,0 54.179902,24.257164 54.179902,54.179893 z" />
+              <path
+                 id="path3818"
+                 style="fill:url(#linearGradient6450);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 d="m 126.74438,66.151513 c 0,14.083261 -14.32689,25.5 -32.000002,25.5 -17.673109,0 -31.999997,-11.416739 -31.999997,-25.5 0,-14.083261 14.326888,-25.5 31.999997,-25.5 17.673112,0 32.000002,11.416739 32.000002,25.5 z" />
+            </g>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="g4338"
+     inkscape:label="Red"
+     style="display:none"
+     transform="translate(0.30631,15.087074)">
+    <g
+       id="g6382"
+       transform="translate(0,-15.087075)">
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g4340">
+        <path
+           d="m 114.26653,106.9991 c 0,29.92273 -24.257164,54.1799 -54.179893,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922725 24.257164,-54.179889 54.179893,-54.179889 29.922729,0 54.179893,24.257164 54.179893,54.179889 z"
+           style="fill:url(#radialGradient6399);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path4342" />
+        <path
+           d="m 110.23479,102.96736 c 0,29.92273 -24.257168,54.17989 -54.179897,54.17989 -29.922729,0 -54.179893,-24.25716 -54.179893,-54.17989 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922729,0 54.179897,24.257164 54.179897,54.179893 z"
+           style="fill:url(#linearGradient6401);fill-opacity:1;fill-rule:nonzero;stroke:#444444;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           id="path4344" />
+        <path
+           d="m 87.877646,77.451483 c 0,14.083261 -14.326888,25.499997 -32,25.499997 -17.673112,0 -32,-11.416736 -32,-25.499997 0,-14.083261 14.326888,-25.5 32,-25.5 17.673112,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6403);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path4346" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g4348">
+        <path
+           d="m 190.61262,90.260786 c 0,29.922724 -24.25717,54.179884 -54.1799,54.179884 -29.92274,0 -54.179902,-24.25716 -54.179902,-54.179884 0,-29.922729 24.257162,-54.179893 54.179902,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#radialGradient6405);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3015)"
+           id="path4350" />
+        <path
+           d="m 186.58088,86.229042 c 0,29.922728 -24.25717,54.179888 -54.1799,54.179888 -29.92274,0 -54.179906,-24.25716 -54.179906,-54.179888 0,-29.922729 24.257166,-54.179893 54.179906,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#linearGradient6407);fill-opacity:1;fill-rule:nonzero;stroke:#00343b;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3019)"
+           id="path4352" />
+        <path
+           d="m 164.22373,60.713165 c 0,14.083261 -14.32689,25.5 -32,25.5 -17.67311,0 -32.00001,-11.416739 -32.00001,-25.5 0,-14.083261 14.3269,-25.5 32.00001,-25.5 17.67311,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6409);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3023)"
+           id="path4354" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g4356">
+        <g
+           id="g4358">
+          <g
+             transform="translate(19.581036,40.120974)"
+             id="g4360">
+            <path
+               d="m 153.13327,95.699138 c 0,29.922732 -24.25717,54.179892 -54.179902,54.179892 -29.922725,0 -54.179889,-24.25716 -54.179889,-54.179892 0,-29.922733 24.257164,-54.179897 54.179889,-54.179897 29.922732,0 54.179902,24.257164 54.179902,54.179897 z"
+               style="fill:url(#radialGradient6411);fill-opacity:1;fill-rule:nonzero;stroke:none"
+               id="path4362" />
+            <g
+               id="g4364">
+              <path
+                 id="path4366"
+                 style="fill:url(#linearGradient6413);fill-opacity:1;fill-rule:nonzero;stroke:#0d0d0d;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+                 d="m 149.10153,91.66739 c 0,29.92273 -24.25717,54.1799 -54.179902,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922732,0 54.179902,24.257164 54.179902,54.179893 z" />
+              <path
+                 id="path4368"
+                 style="fill:url(#linearGradient6415);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 d="m 126.74438,66.151513 c 0,14.083261 -14.32689,25.5 -32.000002,25.5 -17.673109,0 -31.999997,-11.416739 -31.999997,-25.5 0,-14.083261 14.326888,-25.5 31.999997,-25.5 17.673112,0 32.000002,11.416739 32.000002,25.5 z" />
+            </g>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="g5582"
+     inkscape:label="Blue"
+     style="display:inline"
+     transform="translate(0.30631,15.087074)">
+    <g
+       id="g6347"
+       transform="translate(0,-15.087075)">
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g5584">
+        <path
+           d="m 114.26653,106.9991 c 0,29.92273 -24.257164,54.1799 -54.179893,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922725 24.257164,-54.179889 54.179893,-54.179889 29.922729,0 54.179893,24.257164 54.179893,54.179889 z"
+           style="fill:url(#radialGradient6364);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path5586" />
+        <path
+           d="m 110.23479,102.96736 c 0,29.92273 -24.257168,54.17989 -54.179897,54.17989 -29.922729,0 -54.179893,-24.25716 -54.179893,-54.17989 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922729,0 54.179897,24.257164 54.179897,54.179893 z"
+           style="fill:url(#linearGradient6366);fill-opacity:1;fill-rule:nonzero;stroke:#444444;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           id="path5588" />
+        <path
+           d="m 87.877646,77.451483 c 0,14.083261 -14.326888,25.499997 -32,25.499997 -17.673112,0 -32,-11.416736 -32,-25.499997 0,-14.083261 14.326888,-25.5 32,-25.5 17.673112,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6368);fill-opacity:1;fill-rule:nonzero;stroke:none"
+           id="path5590" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g5592">
+        <path
+           d="m 190.61262,90.260786 c 0,29.922724 -24.25717,54.179884 -54.1799,54.179884 -29.92274,0 -54.179902,-24.25716 -54.179902,-54.179884 0,-29.922729 24.257162,-54.179893 54.179902,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#radialGradient6370);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3015)"
+           id="path5594" />
+        <path
+           d="m 186.58088,86.229042 c 0,29.922728 -24.25717,54.179888 -54.1799,54.179888 -29.92274,0 -54.179906,-24.25716 -54.179906,-54.179888 0,-29.922729 24.257166,-54.179893 54.179906,-54.179893 29.92273,0 54.1799,24.257164 54.1799,54.179893 z"
+           style="fill:url(#linearGradient6372);fill-opacity:1;fill-rule:nonzero;stroke:#252525;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3019)"
+           id="path5596" />
+        <path
+           d="m 164.22373,60.713165 c 0,14.083261 -14.32689,25.5 -32,25.5 -17.67311,0 -32.00001,-11.416739 -32.00001,-25.5 0,-14.083261 14.3269,-25.5 32.00001,-25.5 17.67311,0 32,11.416739 32,25.5 z"
+           style="fill:url(#linearGradient6374);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3023)"
+           id="path5598" />
+      </g>
+      <g
+         transform="translate(-0.30631,-15.087076)"
+         id="g5600">
+        <g
+           id="g5602">
+          <g
+             transform="translate(19.581036,40.120974)"
+             id="g5604">
+            <path
+               d="m 153.13327,95.699138 c 0,29.922732 -24.25717,54.179892 -54.179902,54.179892 -29.922725,0 -54.179889,-24.25716 -54.179889,-54.179892 0,-29.922733 24.257164,-54.179897 54.179889,-54.179897 29.922732,0 54.179902,24.257164 54.179902,54.179897 z"
+               style="fill:url(#radialGradient6376);fill-opacity:1;fill-rule:nonzero;stroke:none"
+               id="path5606" />
+            <g
+               id="g5608">
+              <path
+                 id="path5610"
+                 style="fill:url(#linearGradient6378);fill-opacity:1;fill-rule:nonzero;stroke:#000074;stroke-width:3.75;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+                 d="m 149.10153,91.66739 c 0,29.92273 -24.25717,54.1799 -54.179902,54.1799 -29.922729,0 -54.179893,-24.25717 -54.179893,-54.1799 0,-29.922729 24.257164,-54.179893 54.179893,-54.179893 29.922732,0 54.179902,24.257164 54.179902,54.179893 z" />
+              <path
+                 id="path5612"
+                 style="fill:url(#linearGradient6380);fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 d="m 126.74438,66.151513 c 0,14.083261 -14.32689,25.5 -32.000002,25.5 -17.673109,0 -31.999997,-11.416739 -31.999997,-25.5 0,-14.083261 14.326888,-25.5 31.999997,-25.5 17.673112,0 32.000002,11.416739 32.000002,25.5 z" />
+            </g>
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/debian/changelog b/debian/changelog
index 1f7c919..d1d6c47 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+3depict (0.0.14-1) unstable; urgency=low
+
+  * Update to upstream
+
+ -- D Haley <mycae at gmx.com>  Sat, 20 Jul 2013 18:31:32 +0200
+
 3depict (0.0.13-2) unstable; urgency=low
 
   * Enable mathgl2.x configure option
diff --git a/debian/patches/debian-desktop-naming.patch b/debian/patches/debian-desktop-naming.patch
index aaacf1d..fce3ae7 100644
--- a/debian/patches/debian-desktop-naming.patch
+++ b/debian/patches/debian-desktop-naming.patch
@@ -4,8 +4,8 @@ Forwarded: not-needed
 Author: D Haley <mycae - gmx - com>
 Index: 3depict-0.0.14/packaging/3Depict.desktop
 ===================================================================
---- 3depict-0.0.14.orig/packaging/3Depict.desktop	2013-07-20 18:09:35.000000000 +0200
-+++ 3depict-0.0.14/packaging/3Depict.desktop	2013-07-20 18:29:34.000000000 +0200
+--- 3depict-0.0.14.orig/packaging/3Depict.desktop	2013-03-22 19:31:39.000000000 +0100
++++ 3depict-0.0.14/packaging/3Depict.desktop	2013-07-20 18:36:33.000000000 +0200
 @@ -2,8 +2,8 @@
  Version=1.0
  Type=Application
diff --git a/debian/patches/lowercase-textdomain.patch b/debian/patches/lowercase-textdomain.patch
index b735d73..7b59388 100644
--- a/debian/patches/lowercase-textdomain.patch
+++ b/debian/patches/lowercase-textdomain.patch
@@ -3,9 +3,9 @@ Forwarded: not-needed
 Author: D Haley <mycae - gmx - com>
 Index: 3depict-0.0.14/src/3Depict.cpp
 ===================================================================
---- 3depict-0.0.14.orig/src/3Depict.cpp	2013-07-20 18:26:53.000000000 +0200
-+++ 3depict-0.0.14/src/3Depict.cpp	2013-07-20 18:29:34.000000000 +0200
-@@ -164,7 +164,7 @@
+--- 3depict-0.0.14.orig/src/3Depict.cpp	2013-07-20 14:41:45.000000000 +0200
++++ 3depict-0.0.14/src/3Depict.cpp	2013-07-20 18:36:33.000000000 +0200
+@@ -165,7 +165,7 @@
  		else
  		{
  			//Set the gettext language
@@ -14,7 +14,7 @@ Index: 3depict-0.0.14/src/3Depict.cpp
  			setlocale (LC_ALL, "");
  #ifdef __WXMAC__
  			bindtextdomain( PROGRAM_NAME, paths->GetResourcesDir().mb_str(wxConvUTF8) );
-@@ -196,8 +196,8 @@
+@@ -197,8 +197,8 @@
  					break;
  			}			
  #else
diff --git a/debian/rules b/debian/rules
index 431c180..bea47f7 100755
--- a/debian/rules
+++ b/debian/rules
@@ -4,7 +4,6 @@
 	dh $@ --parallel
 
 override_dh_auto_configure: 
-	dh_autoreconf
 	dh_auto_configure -- --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-openmp-parallel --disable-debug-checks --with-libpng-link="-lpng" --with-libpng-flags="-L/lib" --with-ftgl-prefix="/usr" --enable-mgl2
 
 
diff --git a/docs/manual-latex/3depictusermanual.kilepr b/docs/manual-latex/3depictusermanual.kilepr
index 3e19177..4616df8 100644
--- a/docs/manual-latex/3depictusermanual.kilepr
+++ b/docs/manual-latex/3depictusermanual.kilepr
@@ -3,7 +3,7 @@ def_graphic_ext=
 img_extIsRegExp=false
 img_extensions=.eps .jpg .jpeg .png .pdf .ps .fig .gif
 kileprversion=2
-kileversion=2.1.0
+kileversion=2.1.3
 lastDocument=manual.tex
 masterDocument=
 name=3Depict User Manual
@@ -17,7 +17,7 @@ MakeIndex=
 QuickBuild=
 
 [document-settings,item:manual.tex]
-Bookmarks=903,349
+Bookmarks=957,403
 Encoding=UTF-8
 FoldedColumns=
 FoldedLines=
@@ -71,13 +71,13 @@ archive=true
 column=0
 encoding=UTF-8
 highlight=LaTeX
-line=2
+line=356
 mode=LaTeX
 open=true
 order=0
 
 [view-settings,view=0,item:manual.tex]
 CursorColumn=0
-CursorLine=2
+CursorLine=356
 JumpList=
-ViMarks=a,349,0,b,903,0
+ViMarks=a,403,0,b,957,0
diff --git a/docs/manual-latex/figures/quickStartConcLayout.png b/docs/manual-latex/figures/quickStartConcLayout.png
new file mode 100644
index 0000000..f65462a
Binary files /dev/null and b/docs/manual-latex/figures/quickStartConcLayout.png differ
diff --git a/docs/manual-latex/figures/quickStartIonInfoLayout.png b/docs/manual-latex/figures/quickStartIonInfoLayout.png
new file mode 100644
index 0000000..ddc9fca
Binary files /dev/null and b/docs/manual-latex/figures/quickStartIonInfoLayout.png differ
diff --git a/docs/manual-latex/figures/rangeDropdown.png b/docs/manual-latex/figures/rangeDropdown.png
new file mode 100644
index 0000000..68cfaec
Binary files /dev/null and b/docs/manual-latex/figures/rangeDropdown.png differ
diff --git a/docs/manual-latex/figures/rangedSpectrum.png b/docs/manual-latex/figures/rangedSpectrum.png
new file mode 100644
index 0000000..7e0479c
Binary files /dev/null and b/docs/manual-latex/figures/rangedSpectrum.png differ
diff --git a/docs/manual-latex/figures/rangedSpectrumCloud.png b/docs/manual-latex/figures/rangedSpectrumCloud.png
new file mode 100644
index 0000000..d29a4cf
Binary files /dev/null and b/docs/manual-latex/figures/rangedSpectrumCloud.png differ
diff --git a/docs/manual-latex/figures/voxel-representations.png b/docs/manual-latex/figures/voxel-representations.png
new file mode 100644
index 0000000..db4a452
Binary files /dev/null and b/docs/manual-latex/figures/voxel-representations.png differ
diff --git a/docs/manual-latex/manual.aux b/docs/manual-latex/manual.aux
new file mode 100644
index 0000000..edcbcb1
--- /dev/null
+++ b/docs/manual-latex/manual.aux
@@ -0,0 +1,191 @@
+\relax 
+\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
+\HyperFirstAtBeginDocument{\ifx\hyper at anchor\@undefined
+\global\let\oldcontentsline\contentsline
+\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
+\global\let\oldnewlabel\newlabel
+\gdef\newlabel#1#2{\newlabelxx{#1}#2}
+\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
+\AtEndDocument{\ifx\hyper at anchor\@undefined
+\let\contentsline\oldcontentsline
+\let\newlabel\oldnewlabel
+\fi}
+\fi}
+\global\let\hyper at last\relax 
+\gdef\HyperFirstAtBeginDocument#1{#1}
+\providecommand\HyField at AuxAddToFields[1]{}
+\@writefile{toc}{\contentsline {section}{\numberline {1}Foreword}{1}{section.1}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Introduction}{1}{subsection.1.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {1.1.1}Background}{1}{subsubsection.1.1.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {1.1.2}What is Open Source?}{1}{subsubsection.1.1.2}}
+\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Closed-source programs only provide the final application, are neither human readable nor modifiable, and will only work on a specific platform. By contrast open source programs distribute the source-code as well as the application. The source code is the core logic which can be made to work on many platforms due to the invariance of the program logic.}}{1}{figure.1}}
+\newlabel{fig:compilation}{{1}{1}{Closed-source programs only provide the final application, are neither human readable nor modifiable, and will only work on a specific platform. By contrast open source programs distribute the source-code as well as the application. The source code is the core logic which can be made to work on many platforms due to the invariance of the program logic}{figure.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.2}Requirements}{2}{subsection.1.2}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.3}Platform specific notes}{2}{subsection.1.3}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.4}Getting help}{3}{subsection.1.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.5}Who wrote this program?}{3}{subsection.1.5}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.6}Alternate documentation}{3}{subsection.1.6}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {1.7}Helping out}{3}{subsection.1.7}}
+\@writefile{toc}{\contentsline {section}{\numberline {2}Basics}{3}{section.2}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Getting started}{3}{subsection.2.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.1.1}Licence}{3}{subsubsection.2.1.1}}
+\newlabel{sec:licence}{{2.1.1}{3}{Licence\relax }{subsubsection.2.1.1}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.1.2}Installing the program}{4}{subsubsection.2.1.2}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Understanding the interface}{4}{subsection.2.2}}
+\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Interface layout. The 3D view, plot panel and filter tree are labelled.}}{4}{figure.2}}
+\newlabel{fig:interfaceLayout}{{2}{4}{Interface layout. The 3D view, plot panel and filter tree are labelled}{figure.2}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.1}The 3D View}{5}{subsubsection.2.2.1}}
+\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Basic camera layout. Each camera has a position, an up direction and a target. The 3D view is as seen by the camera. Cameras may be saved and recalled to return to specific views. Try to realise it is not the object that moves, but rather yourself.}}{5}{figure.3}}
+\newlabel{fig:camera-basics}{{3}{5}{Basic camera layout. Each camera has a position, an up direction and a target. The 3D view is as seen by the camera. Cameras may be saved and recalled to return to specific views. Try to realise it is not the object that moves, but rather yourself}{figure.3}{}}
+\@writefile{toc}{\contentsline {paragraph}{Basic movement}{5}{figure.3}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.2}Plot area}{6}{subsubsection.2.2.2}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces Raw data pane, with associated spectrum displayed. Data can be selected, and saved for external manipulation as desired.}}{6}{figure.4}}
+\newlabel{fig:raw-basics}{{4}{6}{Raw data pane, with associated spectrum displayed. Data can be selected, and saved for external manipulation as desired}{figure.4}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.3}Console}{6}{subsubsection.2.2.3}}
+\@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces Console tab, with sample console messages. The inset shows how the tab will appear if messages are pending whilst the console itself is hidden.}}{7}{figure.5}}
+\newlabel{fig:console-basics}{{5}{7}{Console tab, with sample console messages. The inset shows how the tab will appear if messages are pending whilst the console itself is hidden}{figure.5}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {2.2.4}Tools panel}{7}{subsubsection.2.2.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Usage fundamentals}{8}{subsection.2.3}}
+\@writefile{toc}{\contentsline {section}{\numberline {3}Quick start}{9}{section.3}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Loading data}{9}{subsection.3.1}}
+\newlabel{sec:quickStartLoadData}{{3.1}{9}{Loading data\relax }{subsection.3.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Loading an analysis}{9}{subsection.3.2}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Ranging}{9}{subsection.3.3}}
+\newlabel{sec:quickStartRangedData}{{3.3}{9}{Ranging\relax }{subsection.3.3}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {6}{\ignorespaces Opening a range file can be done from either the filter drop down, or by dropping a rangefile onto the program. You must first have data loaded (as shown by the red points).}}{10}{figure.6}}
+\newlabel{fig:rangeDropdown}{{6}{10}{Opening a range file can be done from either the filter drop down, or by dropping a rangefile onto the program. You must first have data loaded (as shown by the red points)}{figure.6}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Spectrum}{10}{subsection.3.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.5}Composition profiles}{10}{subsection.3.5}}
+\@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces Ranged spectrum shown only the data that is within the selected ranging windows. The ``Drop unranged'' option can be used to show all the data, and thus the complete spectrum.}}{11}{figure.7}}
+\newlabel{fig:rangedSpectrum}{{7}{11}{Ranged spectrum shown only the data that is within the selected ranging windows. The ``Drop unranged'' option can be used to show all the data, and thus the complete spectrum}{figure.7}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.6}Counting Points and measuring volume}{11}{subsection.3.6}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {3.7}Concentration surface and slices}{11}{subsection.3.7}}
+\@writefile{lof}{\contentsline {figure}{\numberline {8}{\ignorespaces This layout can be used to simultaneously display both the point cloud and the ranged spectrum.}}{12}{figure.8}}
+\newlabel{fig:rangedSpectrumWithCloud}{{8}{12}{This layout can be used to simultaneously display both the point cloud and the ranged spectrum}{figure.8}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {9}{\ignorespaces This layout can be used to show both point data and a concentration profile simultaneously.}}{12}{figure.9}}
+\newlabel{fig:quickStartConcLayout}{{9}{12}{This layout can be used to show both point data and a concentration profile simultaneously}{figure.9}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {10}{\ignorespaces Ion count and volume data can be displayed from the ion information filter. The output is displayed in the console window.}}{13}{figure.10}}
+\newlabel{fig:quickStartIonInfoLayout}{{10}{13}{Ion count and volume data can be displayed from the ion information filter. The output is displayed in the console window}{figure.10}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4}Understanding the program}{14}{section.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Filters}{14}{subsection.4.1}}
+\@writefile{lof}{\contentsline {figure}{\numberline {11}{\ignorespaces Basic concept of a filter. Data goes in, data comes out. The filter may perform any operation on the data coming in or out as it chooses. The data streams coming in are restricted to certain types of data, as shown. }}{14}{figure.11}}
+\newlabel{fig:basic-filter}{{11}{14}{Basic concept of a filter. Data goes in, data comes out. The filter may perform any operation on the data coming in or out as it chooses. The data streams coming in are restricted to certain types of data, as shown}{figure.11}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Trees}{14}{subsection.4.2}}
+\newlabel{sec:treebehaviour}{{4.2}{14}{Trees\relax }{subsection.4.2}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {12}{\ignorespaces Data propagation in a tree for a particular arrangement of filters. Data is propagated from a parent filter to its children.}}{15}{figure.12}}
+\newlabel{fig:datapropagate}{{12}{15}{Data propagation in a tree for a particular arrangement of filters. Data is propagated from a parent filter to its children}{figure.12}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Stashes}{15}{subsection.4.3}}
+\@writefile{lof}{\contentsline {figure}{\numberline {13}{\ignorespaces Creating a stash from the filter tree. New stashes will appear in the dropdown and can be selected to recall subtrees to insert into the filter tree.}}{16}{figure.13}}
+\newlabel{fig:stash-creation}{{13}{16}{Creating a stash from the filter tree. New stashes will appear in the dropdown and can be selected to recall subtrees to insert into the filter tree}{figure.13}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.4}Plots}{16}{subsection.4.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.5}Cameras}{16}{subsection.4.5}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.6}Effects}{17}{subsection.4.6}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {4.7}Program actions}{17}{subsection.4.7}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.1}Save}{17}{subsubsection.4.7.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.2}Undo}{17}{subsubsection.4.7.2}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.3}Raw Data}{17}{subsubsection.4.7.3}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.4}Export Menu}{17}{subsubsection.4.7.4}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.5}Autosave}{18}{subsubsection.4.7.5}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.7.6}Export Animation}{18}{subsubsection.4.7.6}}
+\newlabel{sec:animationExport}{{4.7.6}{18}{Export Animation\relax }{subsubsection.4.7.6}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {14}{\ignorespaces Overview of animation dialog with ``filter view'' active; left hand area of the window shows standard tree view, right hand window shows properties that are to be animated.}}{19}{figure.14}}
+\newlabel{fig:animateFilterView}{{14}{19}{Overview of animation dialog with ``filter view'' active; left hand area of the window shows standard tree view, right hand window shows properties that are to be animated}{figure.14}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {15}{\ignorespaces Numerical input window for setting parameters for animation}}{19}{figure.15}}
+\newlabel{fig:animateParamDialog}{{15}{19}{Numerical input window for setting parameters for animation\relax }{figure.15}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {16}{\ignorespaces Conflicting filter properties shown, highlighted to show the conflicting values in the animation property grid.}}{20}{figure.16}}
+\newlabel{fig:animateParamConflict}{{16}{20}{Conflicting filter properties shown, highlighted to show the conflicting values in the animation property grid}{figure.16}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {17}{\ignorespaces Setting string properties using the string input dialog, via manual entry.}}{21}{figure.17}}
+\newlabel{fig:animatePropString}{{17}{21}{Setting string properties using the string input dialog, via manual entry}{figure.17}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {18}{\ignorespaces Overview of animation dialog with ``frame view'' active; right hand region of the window shows the values of the animation for each frame, on the left hand side are the outputs that the user wishes to obtain.}}{21}{figure.18}}
+\newlabel{fig:animateFrameView}{{18}{21}{Overview of animation dialog with ``frame view'' active; right hand region of the window shows the values of the animation for each frame, on the left hand side are the outputs that the user wishes to obtain}{figure.18}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {5}Detailed Reference}{22}{section.5}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.1}Data types}{22}{subsection.5.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.1}Ions}{22}{subsubsection.5.1.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.2}Plots}{22}{subsubsection.5.1.2}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.3}Range}{22}{subsubsection.5.1.3}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.4}Voxels}{22}{subsubsection.5.1.4}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.1.5}Drawables}{22}{subsubsection.5.1.5}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.2}Filters}{22}{subsection.5.2}}
+\newlabel{sec:filter}{{5.2}{23}{Filters\relax }{subsection.5.2}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.1}Data load}{23}{subsubsection.5.2.1}}
+\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Propagation matrix for Data load.}}{24}{table.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.2}Downsampling}{24}{subsubsection.5.2.2}}
+\@writefile{lot}{\contentsline {table}{\numberline {2}{\ignorespaces Propagation matrix for Downsampling.}}{24}{table.2}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.3}Ion Information}{24}{subsubsection.5.2.3}}
+\newlabel{sec:FilterIonInformation}{{5.2.3}{24}{Ion Information\relax }{subsubsection.5.2.3}{}}
+\@writefile{lot}{\contentsline {table}{\numberline {3}{\ignorespaces Propagation matrix for Ion Information.}}{25}{table.3}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.4}Ranging}{25}{subsubsection.5.2.4}}
+\newlabel{sec:rangeFilter}{{5.2.4}{25}{Ranging\relax }{subsubsection.5.2.4}{}}
+\@writefile{lot}{\contentsline {table}{\numberline {4}{\ignorespaces Propagation matrix for Ranging.}}{25}{table.4}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.5}Bounding Box}{26}{subsubsection.5.2.5}}
+\@writefile{lot}{\contentsline {table}{\numberline {5}{\ignorespaces Propagation matrix for Bounding Box.}}{26}{table.5}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.6}Clipping}{26}{subsubsection.5.2.6}}
+\@writefile{lot}{\contentsline {table}{\numberline {6}{\ignorespaces Propagation matrix for Clipping.}}{26}{table.6}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.7}Spectrum}{26}{subsubsection.5.2.7}}
+\@writefile{lot}{\contentsline {table}{\numberline {7}{\ignorespaces Propagation matrix for Spectrum.}}{27}{table.7}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.8}Profile}{27}{subsubsection.5.2.8}}
+\@writefile{lot}{\contentsline {table}{\numberline {8}{\ignorespaces Propagation matrix for Profile.}}{27}{table.8}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.9}Spatial Analysis}{27}{subsubsection.5.2.9}}
+\@writefile{toc}{\contentsline {paragraph}{Algorithms}{27}{section*.3}}
+\citation{Stephenson07}
+\citation{Hyde10}
+\citation{Vaumousse03}
+\@writefile{lot}{\contentsline {table}{\numberline {9}{\ignorespaces Propagation matrix for Spatial Analysis.}}{28}{table.9}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.10}Clustering analysis}{28}{subsubsection.5.2.10}}
+\@writefile{lot}{\contentsline {table}{\numberline {10}{\ignorespaces Propagation matrix for Clustering Analysis.}}{29}{table.10}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.11}External Program}{29}{subsubsection.5.2.11}}
+\@writefile{toc}{\contentsline {paragraph}{Command syntax: }{29}{section*.4}}
+\@writefile{toc}{\contentsline {paragraph}{Prior to program execution:}{30}{section*.5}}
+\@writefile{toc}{\contentsline {paragraph}{After program execution:}{30}{section*.6}}
+\@writefile{lot}{\contentsline {table}{\numberline {11}{\ignorespaces Propagation matrix for External Program.}}{30}{table.11}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.12}Annotation}{30}{subsubsection.5.2.12}}
+\@writefile{toc}{\contentsline {paragraph}{Text}{30}{section*.7}}
+\@writefile{toc}{\contentsline {paragraph}{Arrow, Arrow with Text}{31}{section*.8}}
+\@writefile{toc}{\contentsline {paragraph}{Angle Measurement}{31}{section*.9}}
+\@writefile{lot}{\contentsline {table}{\numberline {12}{\ignorespaces Propagation matrix for Annotation.}}{31}{table.12}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {5.2.13}Voxels}{31}{subsubsection.5.2.13}}
+\@writefile{lof}{\contentsline {figure}{\numberline {19}{\ignorespaces Voxelisation filter, showing different representations. Left to right shows point cloud, axial slice and isosurface mode on the same dataset}}{32}{figure.19}}
+\newlabel{fig:voxeliseDisplayType}{{19}{32}{Voxelisation filter, showing different representations. Left to right shows point cloud, axial slice and isosurface mode on the same dataset\relax }{figure.19}{}}
+\@writefile{lot}{\contentsline {table}{\numberline {13}{\ignorespaces Propagation matrix for Voxels.}}{32}{table.13}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.3}Ion Colour}{32}{subsection.5.3}}
+\@writefile{lot}{\contentsline {table}{\numberline {14}{\ignorespaces Propagation matrix for Ion Colour.}}{33}{table.14}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4}Ion Transform}{33}{subsection.5.4}}
+\@writefile{lot}{\contentsline {table}{\numberline {15}{\ignorespaces Propagation matrix for Ion Transform.}}{33}{table.15}}
+\@writefile{toc}{\contentsline {section}{\numberline {6}Attributions}{33}{section.6}}
+\@writefile{toc}{\contentsline {section}{\numberline {7}Licence}{34}{section.7}}
+\@writefile{toc}{\contentsline {section}{\numberline {8}Appendices}{34}{section.8}}
+\newlabel{sec:appendix}{{8}{34}{Appendices\relax }{section.8}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {8.1}Paths}{34}{subsection.8.1}}
+\newlabel{sec:3DepictPaths}{{8.1}{34}{Paths\relax }{subsection.8.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {8.2}File formats}{34}{subsection.8.2}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.2.1}State file}{34}{subsubsection.8.2.1}}
+\newlabel{sec:xmlstatefile}{{8.2.1}{34}{State file\relax }{subsubsection.8.2.1}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.2.2}Range files}{35}{subsubsection.8.2.2}}
+\newlabel{sec:rangeFormat}{{8.2.2}{35}{Range files\relax }{subsubsection.8.2.2}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.2.3}POS files}{36}{subsubsection.8.2.3}}
+\newlabel{sec:posformat}{{8.2.3}{36}{POS files\relax }{subsubsection.8.2.3}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.2.4}Text files}{36}{subsubsection.8.2.4}}
+\newlabel{sec:textformat}{{8.2.4}{36}{Text files\relax }{subsubsection.8.2.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {8.3}External Program Examples}{37}{subsection.8.3}}
+\newlabel{sec:externalProgExample}{{8.3}{37}{External Program Examples\relax }{subsection.8.3}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.3.1}Scilab}{37}{subsubsection.8.3.1}}
+\@writefile{lof}{\contentsline {figure}{\numberline {20}{\ignorespaces Example program screenshot using the \emph  {Scilab} sample script. The \%i value in the command line instructs \emph  {3Depict} to take the first (and only the first) ion stream, and save it as an input file for the external program. }}{38}{figure.20}}
+\newlabel{fig:externalProgScilabSample}{{20}{38}{Example program screenshot using the \emph {Scilab} sample script. The \%i value in the command line instructs \emph {3Depict} to take the first (and only the first) ion stream, and save it as an input file for the external program}{figure.20}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.3.2}Python}{41}{subsubsection.8.3.2}}
+\@writefile{lof}{\contentsline {figure}{\numberline {21}{\ignorespaces Example program screenshot without and with the Python test example present. Note that the program merges ion streams into a single pos file, which is re-loaded as a single ion stream, as marked by the arrows.}}{42}{figure.21}}
+\newlabel{fig:externalProgPythonSample}{{21}{42}{Example program screenshot without and with the Python test example present. Note that the program merges ion streams into a single pos file, which is re-loaded as a single ion stream, as marked by the arrows}{figure.21}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.3.3}Bash}{43}{subsubsection.8.3.3}}
+\@writefile{lof}{\contentsline {figure}{\numberline {22}{\ignorespaces Example program screenshot when using the BASH test example.}}{44}{figure.22}}
+\newlabel{fig:externalProgBashSample}{{22}{44}{Example program screenshot when using the BASH test example}{figure.22}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {23}{\ignorespaces Example program screenshot without and with the C++ test example present..}}{45}{figure.23}}
+\newlabel{fig:externalProgCppSample}{{23}{45}{Example program screenshot without and with the C++ test example present.}{figure.23}{}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.3.4}C/C++}{45}{subsubsection.8.3.4}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {8.4}Modifying the program}{49}{subsection.8.4}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.4.1}Development tools}{49}{subsubsection.8.4.1}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.4.2}Getting yourself set up}{50}{subsubsection.8.4.2}}
+\@writefile{toc}{\contentsline {subsubsection}{\numberline {8.4.3}Changing stuff}{50}{subsubsection.8.4.3}}
+\bibstyle{unsrt}
+\bibdata{manual}
+\bibcite{Stephenson07}{1}
+\bibcite{Hyde10}{2}
+\bibcite{Vaumousse03}{3}
diff --git a/docs/manual-latex/manual.bbl b/docs/manual-latex/manual.bbl
new file mode 100644
index 0000000..9846081
--- /dev/null
+++ b/docs/manual-latex/manual.bbl
@@ -0,0 +1,21 @@
+\begin{thebibliography}{1}
+
+\bibitem{Stephenson07}
+Leigh~T. Stephenson, Michael~P. Moody, Peter~V. Liddicoat, and Simon~P. Ringer.
+\newblock {New Techniques for the Analysis of Fine-Scaled Clustering Phenomena
+  within Atom Probe Tomography (APT) Data}.
+\newblock {\em Microscopy and Microanalysis}, 13(06):448--463, 2007.
+
+\bibitem{Hyde10}
+J.M. Hyde, E.A. Marquis, K.B. Wilford, and T.J. Williams.
+\newblock A sensitivity analysis of the maximum separation method for the
+  characterisation of solute clusters.
+\newblock {\em Ultramicroscopy}, 111(6):440--447, 2011.
+
+\bibitem{Vaumousse03}
+D.~Vaumousse, A.~Cerezo, and P.J. Warren.
+\newblock A procedure for quantification of precipitates microstructures from
+  three-dimensional atom probe data.
+\newblock {\em Ultramicroscopy}, 95:215--221, 2003.
+
+\end{thebibliography}
diff --git a/docs/manual-latex/manual.blg b/docs/manual-latex/manual.blg
new file mode 100644
index 0000000..5776488
--- /dev/null
+++ b/docs/manual-latex/manual.blg
@@ -0,0 +1,46 @@
+This is BibTeX, Version 0.99d (TeX Live 2012/Debian)
+Capacity: max_strings=35307, hash_size=35307, hash_prime=30011
+The top-level auxiliary file: manual.aux
+The style file: unsrt.bst
+Database file #1: manual.bib
+You've used 3 entries,
+            1791 wiz_defined-function locations,
+            468 strings with 4144 characters,
+and the built_in function-call counts, 780 in all, are:
+= -- 66
+> -- 39
+< -- 0
++ -- 14
+- -- 11
+* -- 67
+:= -- 133
+add.period$ -- 9
+call.type$ -- 3
+change.case$ -- 3
+chr.to.int$ -- 0
+cite$ -- 3
+duplicate$ -- 27
+empty$ -- 72
+format.name$ -- 11
+if$ -- 166
+int.to.chr$ -- 0
+int.to.str$ -- 3
+missing$ -- 3
+newline$ -- 18
+num.names$ -- 3
+pop$ -- 3
+preamble$ -- 1
+purify$ -- 0
+quote$ -- 0
+skip$ -- 9
+stack$ -- 0
+substring$ -- 67
+swap$ -- 3
+text.length$ -- 0
+text.prefix$ -- 0
+top$ -- 0
+type$ -- 0
+warning$ -- 0
+while$ -- 7
+width$ -- 4
+write$ -- 35
diff --git a/docs/manual-latex/manual.log b/docs/manual-latex/manual.log
new file mode 100644
index 0000000..44e67df
--- /dev/null
+++ b/docs/manual-latex/manual.log
@@ -0,0 +1,569 @@
+This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2012.11.24)  15 JUL 2013 00:17
+entering extended mode
+ restricted \write18 enabled.
+ %&-line parsing enabled.
+**manual.tex
+(./manual.tex
+LaTeX2e <2011/06/27>
+Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, lo
+aded.
+(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
+(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2007/10/19 v1.4h Standard LaTeX file (size option)
+)
+\c at part=\count79
+\c at section=\count80
+\c at subsection=\count81
+\c at subsubsection=\count82
+\c at paragraph=\count83
+\c at subparagraph=\count84
+\c at figure=\count85
+\c at table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/usr/share/texlive/texmf-dist/tex/latex/preprint/fullpage.sty
+Package: fullpage 1999/02/23 1.1 (PWD)
+\FP at margin=\skip43
+)
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
+Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty
+Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
+\KV at toks@=\toks14
+)
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty
+Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty
+Package: trig 1999/03/16 v1.09 sin cos tan (DPC)
+)
+(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/graphics.cfg
+File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live
+)
+Package graphics Info: Driver file: pdftex.def on input line 91.
+
+(/usr/share/texlive/texmf-dist/tex/latex/pdftex-def/pdftex.def
+File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty
+Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO)
+)
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty
+Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO)
+)
+\Gread at gobject=\count87
+))
+\Gin at req@height=\dimen103
+\Gin at req@width=\dimen104
+)
+(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty
+\Urlmuskip=\muskip10
+Package: url 2006/04/12  ver 3.3  Verb mode for urls, etc.
+)
+(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty
+Package: hyperref 2012/05/13 v6.82q Hypertext links for LaTeX
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty
+Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO)
+
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty
+Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO)
+Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO)
+Package hobsub Info: Skipping package `infwarerr' (already loaded).
+Package hobsub Info: Skipping package `ltxcmds' (already loaded).
+Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO)
+Package ifluatex Info: LuaTeX not detected.
+Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO)
+Package ifvtex Info: VTeX not detected.
+Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO)
+Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO)
+Package ifpdf Info: pdfTeX in PDF mode is detected.
+Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO)
+Package etexcmds Info: Could not find \expanded.
+(etexcmds)             That can mean that you are not using pdfTeX 1.50 or
+(etexcmds)             that some package has redefined \expanded.
+(etexcmds)             In the latter case, load this package earlier.
+Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO)
+Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO)
+Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO
+)
+Package pdftexcmds Info: LuaTeX not detected.
+Package pdftexcmds Info: \pdf at primitive is available.
+Package pdftexcmds Info: \pdf at ifprimitive is available.
+Package pdftexcmds Info: \pdfdraftmode found.
+Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO)
+Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO
+)
+Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO)
+Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO)
+)
+Package hobsub Info: Skipping package `hobsub' (already loaded).
+Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO)
+Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO)
+Package: xcolor-patch 2011/01/30 xcolor patch
+Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO)
+Package atveryend Info: \enddocument detected (standard20110627).
+Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO)
+Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO)
+Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO)
+)
+(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty
+Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional
+)
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
+Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO)
+)
+\@linkdim=\dimen105
+\Hy at linkcounter=\count88
+\Hy at pagecounter=\count89
+
+(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def
+File: pd1enc.def 2012/05/13 v6.82q Hyperref: PDFDocEncoding definition (HO)
+)
+\Hy at SavedSpaceFactor=\count90
+
+(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg
+File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive
+)
+Package hyperref Info: Hyper figures OFF on input line 4062.
+Package hyperref Info: Link nesting OFF on input line 4067.
+Package hyperref Info: Hyper index ON on input line 4070.
+Package hyperref Info: Plain pages OFF on input line 4077.
+Package hyperref Info: Backreferencing OFF on input line 4082.
+Package hyperref Info: Implicit mode ON; LaTeX internals redefined.
+Package hyperref Info: Bookmarks ON on input line 4300.
+\c at Hy@tempcnt=\count91
+LaTeX Info: Redefining \url on input line 4653.
+\Fld at menulength=\count92
+\Field at Width=\dimen106
+\Fld at charsize=\dimen107
+Package hyperref Info: Hyper figures OFF on input line 5773.
+Package hyperref Info: Link nesting OFF on input line 5778.
+Package hyperref Info: Hyper index ON on input line 5781.
+Package hyperref Info: backreferencing OFF on input line 5788.
+Package hyperref Info: Link coloring OFF on input line 5793.
+Package hyperref Info: Link coloring with OCG OFF on input line 5798.
+Package hyperref Info: PDF/A mode OFF on input line 5803.
+LaTeX Info: Redefining \ref on input line 5843.
+LaTeX Info: Redefining \pageref on input line 5847.
+\Hy at abspage=\count93
+\c at Item=\count94
+\c at Hfootnote=\count95
+)
+
+Package hyperref Message: Driver (autodetected): hpdftex.
+
+(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def
+File: hpdftex.def 2012/05/13 v6.82q Hyperref driver for pdfTeX
+\Fld at listcount=\count96
+\c at bookmark@seq at number=\count97
+
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty
+Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO)
+Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2
+82.
+)
+\Hy at SectionHShift=\skip44
+)
+(/usr/share/texlive/texmf-dist/tex/latex/placeins/placeins.sty
+Package: placeins 2005/04/18  v 2.2
+)
+(/usr/share/texlive/texmf-dist/tex/latex/wrapfig/wrapfig.sty
+\wrapoverhang=\dimen108
+\WF at size=\dimen109
+\c at WF@wrappedlines=\count98
+\WF at box=\box26
+\WF at everypar=\toks15
+Package: wrapfig 2003/01/31  v 3.6
+) (./manual.aux)
+\openout1 = `manual.aux'.
+
+LaTeX Font Info:    Checking defaults for OML/cmm/m/it on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for T1/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OT1/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OMS/cmsy/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OMX/cmex/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for U/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for PD1/pdf/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+
+(/usr/share/texlive/texmf-dist/tex/context/base/supp-pdf.mkii
+[Loading MPS to PDF converter (version 2006.09.02).]
+\scratchcounter=\count99
+\scratchdimen=\dimen110
+\scratchbox=\box27
+\nofMPsegments=\count100
+\nofMParguments=\count101
+\everyMPshowfont=\toks16
+\MPscratchCnt=\count102
+\MPscratchDim=\dimen111
+\MPnumerator=\count103
+\makeMPintoPDFobject=\count104
+\everyMPtoPDFconversion=\toks17
+) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
+Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf
+
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty
+Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO)
+)
+Package grfext Info: Graphics extension search list:
+(grfext)             [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE
+G,.JBIG2,.JB2,.eps]
+(grfext)             \AppendGraphicsExtensions on input line 452.
+
+(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
+File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
+e
+))
+\AtBeginShipoutBox=\box28
+Package hyperref Info: Link coloring OFF on input line 14.
+
+(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty
+Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty
+Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO)
+)
+\c at section@level=\count105
+)
+LaTeX Info: Redefining \ref on input line 14.
+LaTeX Info: Redefining \pageref on input line 14.
+LaTeX Info: Redefining \nameref on input line 14.
+
+(./manual.out) (./manual.out)
+\@outlinefile=\write3
+\openout3 = `manual.out'.
+
+
+<./figures/CoverImage.png, id=337, 1312.905pt x 974.64125pt>
+File: ./figures/CoverImage.png Graphic file (type png)
+
+<use ./figures/CoverImage.png>
+Package pdftex.def Info: ./figures/CoverImage.png used on input line 25.
+(pdftex.def)             Requested size: 469.75502pt x 348.72903pt.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <12> on input line 38.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <8> on input line 38.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <6> on input line 38.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <24.88> on input line 39.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <20.74> on input line 39.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <17.28> on input line 39.
+ [1
+
+{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map} <./figures/CoverImage.png>]
+ (./manual.toc
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <7> on input line 2.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <5> on input line 2.
+ [1
+
+] [2])
+\tf at toc=\write4
+\openout4 = `manual.toc'.
+
+ [3]
+<./figures/compilation.pdf, id=450, 489.83pt x 262.58101pt>
+File: ./figures/compilation.pdf Graphic file (type pdf)
+
+<use ./figures/compilation.pdf>
+Package pdftex.def Info: ./figures/compilation.pdf used on input line 77.
+(pdftex.def)             Requested size: 328.82707pt x 176.27693pt.
+
+Underfull \hbox (badness 3260) in paragraph at lines 82--83
+[]\OT1/cmr/m/n/10 Open source pro-grams are
+ []
+
+
+Underfull \hbox (badness 6477) in paragraph at lines 82--83
+\OT1/cmr/m/n/10 only the ex-e-cutable code,
+ []
+
+pdfTeX warning (ext4): destination with the same identifier (name{page.1}) has 
+been already used, duplicate ignored
+<to be read again> 
+                   \relax 
+l.88 N
+      ote that there are restrictions on what may be done with the program, ...
+[1
+
+ <./figures/compilation.pdf>]
+LaTeX Font Info:    Try loading font information for OMS+cmr on input line 104.
+
+
+(/usr/share/texlive/texmf-dist/tex/latex/base/omscmr.fd
+File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions
+)
+LaTeX Font Info:    Font shape `OMS/cmr/m/n' in size <10> not available
+(Font)              Font shape `OMS/cmsy/m/n' tried instead on input line 104.
+
+Overfull \hbox (3.63295pt too wide) in paragraph at lines 115--116
+\OT1/cmr/m/n/10 Assistance with this pro-gram may be freely ob-tained over the 
+In-ter-net at []$\OT1/cmtt/m/n/10 http : / / threedepict . sourceforge .
+ []
+
+[2] [3] <./figures/interface.png, id=767, 1026.83624pt x 682.55pt>
+File: ./figures/interface.png Graphic file (type png)
+
+<use ./figures/interface.png>
+Package pdftex.def Info: ./figures/interface.png used on input line 148.
+(pdftex.def)             Requested size: 399.29463pt x 265.41231pt.
+ [4 <./figures/interface.png>]
+<./figures/camera.pdf, id=774, 579.76598pt x 383.834pt>
+File: ./figures/camera.pdf Graphic file (type pdf)
+
+<use ./figures/camera.pdf>
+Package pdftex.def Info: ./figures/camera.pdf used on input line 171.
+(pdftex.def)             Requested size: 328.82707pt x 217.70413pt.
+ [5 <./figures/camera.pdf>]
+<./figures/spectrum-raw.png, id=859, 1199.48125pt x 848.16875pt>
+File: ./figures/spectrum-raw.png Graphic file (type png)
+
+<use ./figures/spectrum-raw.png>
+Package pdftex.def Info: ./figures/spectrum-raw.png used on input line 201.
+(pdftex.def)             Requested size: 399.29463pt x 282.34259pt.
+
+<./figures/console.png, id=862, 1199.48125pt x 848.16875pt>
+File: ./figures/console.png Graphic file (type png)
+
+<use ./figures/console.png>
+Package pdftex.def Info: ./figures/console.png used on input line 218.
+(pdftex.def)             Requested size: 399.29463pt x 282.34259pt.
+ [6 <./figures/spectrum-raw.png>] [7 <./figures/console.png>] [8] <./figures/ra
+ngeDropdown.png, id=886, 954.56625pt x 804.00375pt>
+File: ./figures/rangeDropdown.png Graphic file (type png)
+
+<use ./figures/rangeDropdown.png>
+Package pdftex.def Info: ./figures/rangeDropdown.png used on input line 284.
+(pdftex.def)             Requested size: 399.29463pt x 336.30525pt.
+
+
+LaTeX Warning: `h' float specifier changed to `ht'.
+
+[9] <./figures/rangedSpectrum.png, id=896, 1087.06125pt x 625.33624pt>
+File: ./figures/rangedSpectrum.png Graphic file (type png)
+
+<use ./figures/rangedSpectrum.png>
+Package pdftex.def Info: ./figures/rangedSpectrum.png used on input line 303.
+(pdftex.def)             Requested size: 399.29463pt x 229.70096pt.
+
+
+LaTeX Warning: `h' float specifier changed to `ht'.
+
+<./figures/rangedSpectrumCloud.png, id=899, 1087.06125pt x 625.33624pt>
+File: ./figures/rangedSpectrumCloud.png Graphic file (type png)
+
+<use ./figures/rangedSpectrumCloud.png>
+Package pdftex.def Info: ./figures/rangedSpectrumCloud.png used on input line 3
+14.
+(pdftex.def)             Requested size: 399.29463pt x 229.70096pt.
+
+
+LaTeX Warning: `h' float specifier changed to `ht'.
+
+<./figures/quickStartConcLayout.png, id=902, 1373.13pt x 905.3825pt>
+File: ./figures/quickStartConcLayout.png Graphic file (type png)
+
+<use ./figures/quickStartConcLayout.png>
+Package pdftex.def Info: ./figures/quickStartConcLayout.png used on input line 
+326.
+(pdftex.def)             Requested size: 399.29463pt x 263.27258pt.
+ [10 <./figures/rangeDropdown.png (PNG copy)>]
+
+LaTeX Warning: `h' float specifier changed to `ht'.
+
+<./figures/quickStartIonInfoLayout.png, id=912, 869.2475pt x 629.35126pt>
+File: ./figures/quickStartIonInfoLayout.png Graphic file (type png)
+
+<use ./figures/quickStartIonInfoLayout.png>
+Package pdftex.def Info: ./figures/quickStartIonInfoLayout.png used on input li
+ne 340.
+(pdftex.def)             Requested size: 399.29463pt x 289.10176pt.
+
+
+LaTeX Warning: `h' float specifier changed to `ht'.
+
+[11 <./figures/rangedSpectrum.png>] [12 <./figures/rangedSpectrumCloud.png> <./
+figures/quickStartConcLayout.png>] [13 <./figures/quickStartIonInfoLayout.png>]
+<./figures/generic-filter.png, id=932, 4353.20471pt x 2563.45941pt>
+File: ./figures/generic-filter.png Graphic file (type png)
+
+<use ./figures/generic-filter.png>
+Package pdftex.def Info: ./figures/generic-filter.png used on input line 365.
+(pdftex.def)             Requested size: 399.29463pt x 235.12141pt.
+ [14
+
+ <./figures/generic-filter.png>]
+<./figures/tree-propagate.pdf, id=942, 1518.55293pt x 800.81699pt>
+File: ./figures/tree-propagate.pdf Graphic file (type pdf)
+
+<use ./figures/tree-propagate.pdf>
+Package pdftex.def Info: ./figures/tree-propagate.pdf used on input line 384.
+(pdftex.def)             Requested size: 399.29463pt x 210.56586pt.
+
+<./figures/Stash-operation.png, id=944, 1068.99374pt x 608.2725pt>
+File: ./figures/Stash-operation.png Graphic file (type png)
+
+<use ./figures/Stash-operation.png>
+Package pdftex.def Info: ./figures/Stash-operation.png used on input line 406.
+(pdftex.def)             Requested size: 399.29463pt x 227.20132pt.
+ [15 <./figures/tree-propagate.pdf>]
+[16 <./figures/Stash-operation.png>] [17]
+<./figures/exportanimDialogFilterView.png, id=1271, 1380.15625pt x 800.9925pt>
+File: ./figures/exportanimDialogFilterView.png Graphic file (type png)
+
+<use ./figures/exportanimDialogFilterView.png>
+Package pdftex.def Info: ./figures/exportanimDialogFilterView.png used on input
+ line 470.
+(pdftex.def)             Requested size: 422.77664pt x 245.35957pt.
+
+<./figures/exportanimParamDialog.png, id=1272, 1376.14125pt x 801.99625pt>
+File: ./figures/exportanimParamDialog.png Graphic file (type png)
+
+<use ./figures/exportanimParamDialog.png>
+Package pdftex.def Info: ./figures/exportanimParamDialog.png used on input line
+ 480.
+(pdftex.def)             Requested size: 422.77664pt x 246.38904pt.
+
+<./figures/exportanimDialogConflict.png, id=1274, 1382.16376pt x 801.99625pt>
+File: ./figures/exportanimDialogConflict.png Graphic file (type png)
+
+<use ./figures/exportanimDialogConflict.png>
+Package pdftex.def Info: ./figures/exportanimDialogConflict.png used on input l
+ine 490.
+(pdftex.def)             Requested size: 422.77664pt x 245.31215pt.
+ [18] [19 <./figures/exportanimDialogFilterView.png (PNG copy)> <./figures/expo
+rtanimParamDialog.png (PNG copy)>]
+<./figures/exportanimDialogPropString.png, id=1286, 1237.62375pt x 763.85374pt>
+File: ./figures/exportanimDialogPropString.png Graphic file (type png)
+<use ./figures/exportanimDialogPropString.png>
+Package pdftex.def Info: ./figures/exportanimDialogPropString.png used on input
+ line 502.
+(pdftex.def)             Requested size: 422.77664pt x 260.93065pt.
+
+<./figures/exportanimDialogFrameView.png, id=1287, 1237.62375pt x 763.85374pt>
+File: ./figures/exportanimDialogFrameView.png Graphic file (type png)
+
+<use ./figures/exportanimDialogFrameView.png>
+Package pdftex.def Info: ./figures/exportanimDialogFrameView.png used on input 
+line 516.
+(pdftex.def)             Requested size: 422.77664pt x 260.93065pt.
+ [20 <./figures/exportanimDialogConflict.png (PNG copy)>] [21 <./figures/export
+animDialogPropString.png (PNG copy)> <./figures/exportanimDialogFrameView.png (
+PNG copy)>] [22] [23] [24]
+[25] [26] [27] [28] [29] [30]
+<./figures/voxel-representations.png, id=1371, 1615.03375pt x 1027.84pt>
+File: ./figures/voxel-representations.png Graphic file (type png)
+
+<use ./figures/voxel-representations.png>
+Package pdftex.def Info: ./figures/voxel-representations.png used on input line
+ 1036.
+(pdftex.def)             Requested size: 422.77664pt x 269.06708pt.
+ [31]
+
+LaTeX Warning: `!h' float specifier changed to `!ht'.
+
+[32 <./figures/voxel-representations.png>] [33] [34] [35] [36]
+<./figures/externalProgScilab.png, id=1423, 1686.3pt x 847.165pt>
+File: ./figures/externalProgScilab.png Graphic file (type png)
+
+<use ./figures/externalProgScilab.png>
+Package pdftex.def Info: ./figures/externalProgScilab.png used on input line 12
+82.
+(pdftex.def)             Requested size: 422.77664pt x 212.38535pt.
+ [37] [38 <./figures/externalProgScilab.png>] [39] [40]
+<./figures/externalProgPython.png, id=1444, 1465.475pt x 856.19875pt>
+File: ./figures/externalProgPython.png Graphic file (type png)
+
+<use ./figures/externalProgPython.png>
+Package pdftex.def Info: ./figures/externalProgPython.png used on input line 14
+63.
+(pdftex.def)             Requested size: 399.29463pt x 233.28014pt.
+ [41] [42 <./figures/externalProgPython.png>] <./figures/externalProgBash.png, 
+id=1457, 1385.175pt x 876.27374pt>
+File: ./figures/externalProgBash.png Graphic file (type png)
+
+<use ./figures/externalProgBash.png>
+Package pdftex.def Info: ./figures/externalProgBash.png used on input line 1537
+.
+(pdftex.def)             Requested size: 399.29463pt x 252.5886pt.
+ [43] [44 <./figures/externalProgBash.png>]
+LaTeX Font Info:    Try loading font information for OMS+cmtt on input line 159
+4.
+LaTeX Font Info:    No file OMScmtt.fd. on input line 1594.
+
+LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined
+(Font)              using `OMS/cmsy/m/n' instead
+(Font)              for symbol `textbraceleft' on input line 1594.
+
+<./figures/externalProgCpp.png, id=1468, 2123.935pt x 839.135pt>
+File: ./figures/externalProgCpp.png Graphic file (type png)
+
+<use ./figures/externalProgCpp.png>
+Package pdftex.def Info: ./figures/externalProgCpp.png used on input line 1602.
+
+(pdftex.def)             Requested size: 399.29463pt x 157.74715pt.
+ [45 <./figures/externalProgCpp.png>]
+[46] [47] [48] [49] [50] (./manual.bbl)
+Package atveryend Info: Empty hook `BeforeClearDocument' on input line 1847.
+ [51]
+Package atveryend Info: Empty hook `AfterLastShipout' on input line 1847.
+ (./manual.aux)
+Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 1847.
+Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 1847.
+
+Package rerunfilecheck Info: File `manual.out' has not changed.
+(rerunfilecheck)             Checksum: 2391597B6536F7B9377565452E4D63E0;5463.
+
+
+LaTeX Font Warning: Some font shapes were not available, defaults substituted.
+
+Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 1847.
+ ) 
+Here is how much of TeX's memory you used:
+ 5553 strings out of 495059
+ 84276 string characters out of 3182029
+ 165875 words of memory out of 3000000
+ 8475 multiletter control sequences out of 15000+200000
+ 12804 words of font info for 45 fonts, out of 3000000 for 9000
+ 14 hyphenation exceptions out of 8191
+ 29i,11n,28p,1037b,445s stack positions out of 5000i,500n,10000p,200000b,50000s
+</usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></us
+r/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb></usr/shar
+e/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbxti10.pfb></usr/share/te
+xlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/share/texlive
+/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texlive/texmf
+-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/share/texlive/texmf-dist/f
+onts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texlive/texmf-dist/fonts/ty
+pe1/public/amsfonts/cm/cmr12.pfb></usr/share/texlive/texmf-dist/fonts/type1/pub
+lic/amsfonts/cm/cmr6.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsf
+onts/cm/cmr7.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/
+cmr8.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.p
+fb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb></u
+sr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmti12.pfb></usr/sha
+re/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt10.pfb></usr/share/tex
+live/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt12.pfb></usr/share/texlive/t
+exmf-dist/fonts/type1/public/amsfonts/cm/cmtt8.pfb>
+Output written on manual.pdf (55 pages, 4248400 bytes).
+PDF statistics:
+ 1611 PDF objects out of 1728 (max. 8388607)
+ 1243 compressed objects within 13 object streams
+ 195 named destinations out of 1000 (max. 500000)
+ 785 words of extra memory for PDF output out of 10000 (max. 10000000)
+
diff --git a/docs/manual-latex/manual.out b/docs/manual-latex/manual.out
new file mode 100644
index 0000000..ae19109
--- /dev/null
+++ b/docs/manual-latex/manual.out
@@ -0,0 +1,83 @@
+\BOOKMARK [1][-]{section.1}{Foreword}{}% 1
+\BOOKMARK [2][-]{subsection.1.1}{Introduction}{section.1}% 2
+\BOOKMARK [3][-]{subsubsection.1.1.1}{Background}{subsection.1.1}% 3
+\BOOKMARK [3][-]{subsubsection.1.1.2}{What is Open Source?}{subsection.1.1}% 4
+\BOOKMARK [2][-]{subsection.1.2}{Requirements}{section.1}% 5
+\BOOKMARK [2][-]{subsection.1.3}{Platform specific notes}{section.1}% 6
+\BOOKMARK [2][-]{subsection.1.4}{Getting help}{section.1}% 7
+\BOOKMARK [2][-]{subsection.1.5}{Who wrote this program?}{section.1}% 8
+\BOOKMARK [2][-]{subsection.1.6}{Alternate documentation}{section.1}% 9
+\BOOKMARK [2][-]{subsection.1.7}{Helping out}{section.1}% 10
+\BOOKMARK [1][-]{section.2}{Basics}{}% 11
+\BOOKMARK [2][-]{subsection.2.1}{Getting started}{section.2}% 12
+\BOOKMARK [3][-]{subsubsection.2.1.1}{Licence}{subsection.2.1}% 13
+\BOOKMARK [3][-]{subsubsection.2.1.2}{Installing the program}{subsection.2.1}% 14
+\BOOKMARK [2][-]{subsection.2.2}{Understanding the interface}{section.2}% 15
+\BOOKMARK [3][-]{subsubsection.2.2.1}{The 3D View}{subsection.2.2}% 16
+\BOOKMARK [3][-]{subsubsection.2.2.2}{Plot area}{subsection.2.2}% 17
+\BOOKMARK [3][-]{subsubsection.2.2.3}{Console}{subsection.2.2}% 18
+\BOOKMARK [3][-]{subsubsection.2.2.4}{Tools panel}{subsection.2.2}% 19
+\BOOKMARK [2][-]{subsection.2.3}{Usage fundamentals}{section.2}% 20
+\BOOKMARK [1][-]{section.3}{Quick start}{}% 21
+\BOOKMARK [2][-]{subsection.3.1}{Loading data}{section.3}% 22
+\BOOKMARK [2][-]{subsection.3.2}{Loading an analysis}{section.3}% 23
+\BOOKMARK [2][-]{subsection.3.3}{Ranging}{section.3}% 24
+\BOOKMARK [2][-]{subsection.3.4}{Spectrum}{section.3}% 25
+\BOOKMARK [2][-]{subsection.3.5}{Composition profiles}{section.3}% 26
+\BOOKMARK [2][-]{subsection.3.6}{Counting Points and measuring volume}{section.3}% 27
+\BOOKMARK [2][-]{subsection.3.7}{Concentration surface and slices}{section.3}% 28
+\BOOKMARK [1][-]{section.4}{Understanding the program}{}% 29
+\BOOKMARK [2][-]{subsection.4.1}{Filters}{section.4}% 30
+\BOOKMARK [2][-]{subsection.4.2}{Trees}{section.4}% 31
+\BOOKMARK [2][-]{subsection.4.3}{Stashes}{section.4}% 32
+\BOOKMARK [2][-]{subsection.4.4}{Plots}{section.4}% 33
+\BOOKMARK [2][-]{subsection.4.5}{Cameras}{section.4}% 34
+\BOOKMARK [2][-]{subsection.4.6}{Effects}{section.4}% 35
+\BOOKMARK [2][-]{subsection.4.7}{Program actions}{section.4}% 36
+\BOOKMARK [3][-]{subsubsection.4.7.1}{Save}{subsection.4.7}% 37
+\BOOKMARK [3][-]{subsubsection.4.7.2}{Undo}{subsection.4.7}% 38
+\BOOKMARK [3][-]{subsubsection.4.7.3}{Raw Data}{subsection.4.7}% 39
+\BOOKMARK [3][-]{subsubsection.4.7.4}{Export Menu}{subsection.4.7}% 40
+\BOOKMARK [3][-]{subsubsection.4.7.5}{Autosave}{subsection.4.7}% 41
+\BOOKMARK [3][-]{subsubsection.4.7.6}{Export Animation}{subsection.4.7}% 42
+\BOOKMARK [1][-]{section.5}{Detailed Reference}{}% 43
+\BOOKMARK [2][-]{subsection.5.1}{Data types}{section.5}% 44
+\BOOKMARK [3][-]{subsubsection.5.1.1}{Ions}{subsection.5.1}% 45
+\BOOKMARK [3][-]{subsubsection.5.1.2}{Plots}{subsection.5.1}% 46
+\BOOKMARK [3][-]{subsubsection.5.1.3}{Range}{subsection.5.1}% 47
+\BOOKMARK [3][-]{subsubsection.5.1.4}{Voxels}{subsection.5.1}% 48
+\BOOKMARK [3][-]{subsubsection.5.1.5}{Drawables}{subsection.5.1}% 49
+\BOOKMARK [2][-]{subsection.5.2}{Filters}{section.5}% 50
+\BOOKMARK [3][-]{subsubsection.5.2.1}{Data load}{subsection.5.2}% 51
+\BOOKMARK [3][-]{subsubsection.5.2.2}{Downsampling}{subsection.5.2}% 52
+\BOOKMARK [3][-]{subsubsection.5.2.3}{Ion Information}{subsection.5.2}% 53
+\BOOKMARK [3][-]{subsubsection.5.2.4}{Ranging}{subsection.5.2}% 54
+\BOOKMARK [3][-]{subsubsection.5.2.5}{Bounding Box}{subsection.5.2}% 55
+\BOOKMARK [3][-]{subsubsection.5.2.6}{Clipping}{subsection.5.2}% 56
+\BOOKMARK [3][-]{subsubsection.5.2.7}{Spectrum}{subsection.5.2}% 57
+\BOOKMARK [3][-]{subsubsection.5.2.8}{Profile}{subsection.5.2}% 58
+\BOOKMARK [3][-]{subsubsection.5.2.9}{Spatial Analysis}{subsection.5.2}% 59
+\BOOKMARK [3][-]{subsubsection.5.2.10}{Clustering analysis}{subsection.5.2}% 60
+\BOOKMARK [3][-]{subsubsection.5.2.11}{External Program}{subsection.5.2}% 61
+\BOOKMARK [3][-]{subsubsection.5.2.12}{Annotation}{subsection.5.2}% 62
+\BOOKMARK [3][-]{subsubsection.5.2.13}{Voxels}{subsection.5.2}% 63
+\BOOKMARK [2][-]{subsection.5.3}{Ion Colour}{section.5}% 64
+\BOOKMARK [2][-]{subsection.5.4}{Ion Transform}{section.5}% 65
+\BOOKMARK [1][-]{section.6}{Attributions}{}% 66
+\BOOKMARK [1][-]{section.7}{Licence}{}% 67
+\BOOKMARK [1][-]{section.8}{Appendices}{}% 68
+\BOOKMARK [2][-]{subsection.8.1}{Paths}{section.8}% 69
+\BOOKMARK [2][-]{subsection.8.2}{File formats}{section.8}% 70
+\BOOKMARK [3][-]{subsubsection.8.2.1}{State file}{subsection.8.2}% 71
+\BOOKMARK [3][-]{subsubsection.8.2.2}{Range files}{subsection.8.2}% 72
+\BOOKMARK [3][-]{subsubsection.8.2.3}{POS files}{subsection.8.2}% 73
+\BOOKMARK [3][-]{subsubsection.8.2.4}{Text files}{subsection.8.2}% 74
+\BOOKMARK [2][-]{subsection.8.3}{External Program Examples}{section.8}% 75
+\BOOKMARK [3][-]{subsubsection.8.3.1}{Scilab}{subsection.8.3}% 76
+\BOOKMARK [3][-]{subsubsection.8.3.2}{Python}{subsection.8.3}% 77
+\BOOKMARK [3][-]{subsubsection.8.3.3}{Bash}{subsection.8.3}% 78
+\BOOKMARK [3][-]{subsubsection.8.3.4}{C/C++}{subsection.8.3}% 79
+\BOOKMARK [2][-]{subsection.8.4}{Modifying the program}{section.8}% 80
+\BOOKMARK [3][-]{subsubsection.8.4.1}{Development tools}{subsection.8.4}% 81
+\BOOKMARK [3][-]{subsubsection.8.4.2}{Getting yourself set up}{subsection.8.4}% 82
+\BOOKMARK [3][-]{subsubsection.8.4.3}{Changing stuff}{subsection.8.4}% 83
diff --git a/docs/manual-latex/manual.pdf b/docs/manual-latex/manual.pdf
index 385841b..b0e8788 100644
Binary files a/docs/manual-latex/manual.pdf and b/docs/manual-latex/manual.pdf differ
diff --git a/docs/manual-latex/manual.tex b/docs/manual-latex/manual.tex
index 05b64c2..7c0e5c6 100644
--- a/docs/manual-latex/manual.tex
+++ b/docs/manual-latex/manual.tex
@@ -40,7 +40,7 @@
 \begin{minipage}{0.3\textwidth}
 \begin{flushright} \large
 \emph{Version:} \\
- 0.0.13, Apr 2012\end{flushright}
+ 0.0.14, Aug 2013\end{flushright}
 \end{minipage}
 
 \vfill
@@ -94,7 +94,7 @@ Due to the design of the program, the program should run under Linux, Mac, BSD a
 
 The minimum requirements for running \emph{3Depict} are not known. The author wrote a substantial portion of the program on a machine with only 4 and 12~GB drives, and a 1.6~GHz processor, which normally runs at 800~MHz and has 1~GB of RAM. There is no clear reason that it would not run on even lower-spec machines. Whilst a higher spec machine may run the program faster, intelligent use of the programs ``filter'' system may allow for complex analyses even on low-end machines. 
 
-If you are experiencing 3D graphics problems, first ensure that other 3D programs do not experience the same problems. Otherwise, please contact the authors for assistance -- there should be no requirement for vendor-specific hardware. Note however that the exact appearance of the 3D view is dependant upon your hardware, and may have small changes between different platforms. 
+If you are experiencing 3D graphics problems, first ensure that other 3D programs do not experience the same problems. Otherwise, please contact the authors for assistance -- there should be no requirement for vendor-specific hardware. Note however that the exact appearance of the 3D view is dependent upon your hardware, and may have small changes between different platforms. 
 
 \subsection{Platform specific notes}
 Note that whilst every effort is made to ensure that the program will run on a variety of systems, small system-specific quirks may be evident, particularly on platforms to which the authors do not use regularly (\emph{e.g.}\ windows). Secondly, due to slight differences between platforms some functions may be remapped to other mouse/key combinations.  
@@ -229,11 +229,17 @@ The tools panel offers several options on changes to the way the program operate
 \begin{itemize}
 \item  \textbf{Smooth and Translucent objects}: This enables so-called ``alpha blending'' in the 3D scene, where appropriate which allows for non-opaque objects, and anti-aliased objects. This mode alters the way in which objects are rendered in the 3D scene and is in effect a quality-appearance tradeoff. Most of the time you will probably want it set to ON. The program may render the 3D scene slightly faster if this is disabled.
  
-\item  \textbf{Enable lighting}: 3D objects do not look very 3D if you are only seeing them on a 2D screen. Computer graphics works around this by simulating the effect of having a 3D lighting source. This might provide minor performance improvements if disabled, at the cost of clarity of rendering.
+\item  \textbf{3D lighting}: 3D objects do not look very 3D if you are only seeing them on a 2D screen. Computer graphics works around this by simulating the effect of having a 3D lighting source. This might provide minor performance improvements if disabled, at the cost of clarity of rendering.
+
+\item \textbf{Fast and weak random}: This setting is a program wide setting that switches the strength of the random number generator. However, for more robust statistical results, it is recommended that this be disabled when computing final values. When enabled, the program will use a Linear Shift Feedback Register using a maximal length Galois polynomial to generate numbers required for random sampling. This has the advantageous property of being a somewhat random entirely non-repeating sequence that is fast to generate, but having sufficient decorrelative strength against most inputs to provide the appearance of random sampling. 
+
+\item \textbf{Limit Output Points}: This setting controls the maximum number of points that will be drawn in the 3D display. The internal calculations will perform the same computations, regardless of this value. This value allows for drawing performance tuning. Higher numbers will show more points, and will slow down the computation. Lower numbers will speed up the computation at the cost of visual inaccuracy.
+
+
  
 \item \textbf{Enable filter caching}: This alters the way in which the program processes the filter tree. Normally, the program performs what is known as a depth-first search, and propagates data generated by the program from one filter to the other. Intermediate copies are kept by the filters themselves to speed up recomputation. However, this strategy has a large downside, which is memory consumption. Disabling this will reduce memory consumption by filters, but will mean that any change to the filter tree, no matter how small, will cause the entire tree to be recomputed, including data loading.
 
-\item \textbf{Weak and fast random}: This setting is a program wide setting that switches the strength of the random number generator. However, for more robust statistical results, it is recommended that this be disabled when computing final values. When enabled, the program will use a Linear Shift Feedback Register using a maximal length Galois polynomial to generate numbers required for random sampling. This has the advantageous property of being a somewhat random entirely non-repeating sequence that is fast to generate, but having sufficient decorrelative strength against most inputs to provide the appearance of random sampling. 
+
 \end{itemize}
 
 
@@ -255,8 +261,99 @@ New items can be added to the tree by selecting the filter to add from the dropd
 Once an item is added, the filter tree is thus modified and a recomputation of the scene will occur. Approximate progress on the filter update is visible in the status bar. During an update, only limited interaction with the program is permitted. An update may be cancelled at any time with the \texttt{escape} key. 
 
 
+\section{Quick start}
+Several quick notes are provided here as examples of how to perform specific measurements/calcuations. Whilst this is not an exhaustive list of measurements that can be made in \emph{3Depict}, this section is targeted towards new users who wish to use the program to perform quick or common measurments.
+
+\subsection{Loading data}
+\label{sec:quickStartLoadData}
+To load data, one must first have data to load in the form of either a "POS" formatted file (see Section~\ref{sec:posformat}), or as a text file (using english notation, four columns - see Section~\ref{sec:textformat}). To load the data, use the Open command in the File menu. Alternatively, one can drag and drop the file onto the program.
+
+\subsection{Loading an analysis}
+You may have an existing analysis file, which you can use to load both the data, and any associated analysis information (plots, clustering, clipping, etc.), which for example may have been undertaken by a separate user. 
+
+To load it, you require a ``package'' from the previous user, which will be a folder containing a XML file, and any data files that are required. As for loading data, you can either directly open the analysis with File$\rightarrow$Open, or by dropping it onto the program. 
+
+Note that by default, the program will not load all the data in the file - a sampling will be performed. Careful use of data sampling will allow for a much more rapid and interactive analysis of large datasets - many of the algorithms running times do not scale directly with the size of the dataset. Reducing the number of ions can, in some cases, result in a signfificant reduction in run time (eg halving number of ions for some algoritms can result in a run time of a quarter required for the full dataset).
+
+\subsection{Ranging}
+\label{sec:quickStartRangedData}
+The program can be used to mark particular sections of the spectrum as belonging to a particular ``range'' of values. Each value can be tagged with a specific name for the range, and an associated colour, which will be used to mark the points in the 3D display.
+
+\begin{figure}[h]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangeDropdown.png}
+
+ \caption{Opening a range file can be done from either the filter drop down, or by dropping a rangefile onto the program. You must first have data loaded (as shown by the red points).}
+\label{fig:rangeDropdown}
+\end{figure}
+
+
+To perform ranging, you must first have a valid rangefile. As of time of writing, (July, 2013 - 0.0.14), the program is unable to generate these. It is possible to write the file by hand, or using a separate program - details on manually writing the file can be found in Section~\ref{sec:rangeFormat}.
+
+To perform ranging, the data must be first loaded into the program. The range information can be loaded in two ways, by dropping a valid rangefile onto the program, or by using the filter dropdown (Figure~\ref{fig:rangeDropdown}), whereby a window will open that will allow for the selection of a valid range file. 
+
+Once loaded, you can select the ranging filter and enable/disable ions and ranges you do not wish to see. By default unranged ions are not emitted from a range filter, so will not be seen unless ``Drop Unranged'' is unselected.
+
+
+\subsection{Spectrum}
+To see the mass spectrum for a selected data, the ``spectrum'' filter must be used. First load the required data (as per Section~\ref{sec:quickStartLoadData}), then select the data filter in the tree, and select ``Spectrum'' from the filter drop-down. This will display the spectrum without any overlaid ranges. To get the desired signal/noise level, you may wish to either alter the sampling level in the Pos Data (Load Limit value), or disable sampling. Changing the spectrum bin width until the spectrum appears as desired is also recommended.
+
+\begin{figure}[h]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangedSpectrum.png}
+
+ \caption{Ranged spectrum shown only the data that is within the selected ranging windows. The ``Drop unranged'' option can be used to show all the data, and thus the complete spectrum.}
+\label{fig:rangedSpectrum}
+\end{figure}
+
+
+To display the ranged spectrum, simply use the sequence \texttt{Data$\rightarrow$Ranging$\rightarrow$Spectrum}, as shown in Figure~\ref{fig:rangedSpectrum}. To see the ions outside existing ranges, untick ``drop unranged`` from the range filter. Note that as the data is converted into a spectrum, the 3D view will disappear. To see both the spectrum and the point data at the same time, use the configuration shown in Figure~\ref{fig:rangedSpectrumWithCloud}.
+
+\begin{figure}[h]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangedSpectrumCloud.png}
+
+ \caption{This layout can be used to simultaneously display both the point cloud and the ranged spectrum.}
+\label{fig:rangedSpectrumWithCloud}
+\end{figure}
+
+
+\subsection{Composition profiles}
+To display a composition profile, you first require a ranged dataset (see Section~\ref{sec:quickStartRangedData}). Once done, first select the range filter, then choose a concentration profile from the drop down. Note that as the data has now been converted into a concentration profile, the point cloud will disappear (although the concentration profile cylinder is visible, and is computing the correct result). To see both the data and the concentration profile at the same time, use the configuration shown in Figure~\ref{fig:quickStartConcLayout}.
+
+\begin{figure}[h]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/quickStartConcLayout.png}
+
+ \caption{This layout can be used to show both point data and a concentration profile simultaneously.}
+\label{fig:quickStartConcLayout}
+\end{figure}
+
+
+
+\subsection{Counting Points and measuring volume}
+
+To compute the absolute counts of the number of ions that are visible in the dataset, use the ``Ion information'' filter, as shown in Figure~\ref{fig:quickStartIonInfoLayout}. To compute the ion count, check the ``count'' box. To compute the dataset volume, select the ''volume'' checkbox, and the desired algorithm (For algorithm details see Section~\ref{sec:FilterIonInformation}). The results are displayed in the console window (Figure~\ref{fig:quickStartIonInfoLayout}).
+
+\begin{figure}[h]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/quickStartIonInfoLayout.png}
+
+ \caption{Ion count and volume data can be displayed from the ion information filter. The output is displayed in the console window.}
+\label{fig:quickStartIonInfoLayout}
+\end{figure}
+
 
 
+\subsection{Concentration surface and slices}
+
+To generate iso-concentration surfaces, or to create 2D slices in your data for visualising information such as concentration fields, a voxelisation must first be conducted.
+
+Load some ranged data (Section~\ref{sec:quickStartRangedData}), and then select the range filter and choose ``Voxelisation''. This will cause the dataset to disappear until you configure the voxelisation parameters appropriately. To compute a concentration field, change the normalisation mode to ``All ions (Conc)'', then select the ions that are to be included.  To visualise the result, change the ``representation'' mode to either isosurface or 2D slice. The upper and lower bounds of the 2D slice are auto computed. 
+
+However, for the isosurface one must choose the value that the isosurface is spanning. For non-concentration modes, after computation of the voxel field, the upper and lower bounds of the field are shown in the console window, and can aid in selecting the desired isosurface value.
+
+\FloatBarrier
 
 \section{Understanding the program}
 \subsection{Filters}
@@ -422,7 +519,8 @@ In this case either each string must be individually specified, as shown in the
 \end{center}
 \end{figure}
 
-Once the desired properties have been set in the filter view, then one proceeds to the frame view in order to review the animation by examining the properties that will be obtained in each filter, frame-by-frame. If you are familiar with this dialog, then it is easy to simply examine this quickly to ensure that the properties that were intended have been obtained. Now, having ensured that this is the case, it can be seen that the "OK" button cannot be pressed at this time. Firstly, the desired outputs, and the directory that they will be sent to during the animation process must be specified. Once the output directory is set, the desired outputs, normally either images, or points are to be selected as required. The checkbox `` '',  if set, will cause only the changes that actually alter the computation internal computation to be saved. As an example, if one was to animate the ``Load Limit'' property of the ``Pos Data'' filter, and the file to be opened was only 1~MB, but the animation proceeded as 0.5, 0.6...,
+Once the desired properties have been set in the filter view, then one proceeds to the frame view in order to review the animation by examining the properties that will be obtained in each filter, frame-by-frame. If you are familiar with this dialog, then it is easy to simply examine this quickly to ensure that the properties that were intended have been obtained. Now, having ensured that this is the case, it can be seen that the "OK" button cannot be pressed at this time. Firstly, the desired outputs, and the directory that they will be sent to during the animation process must be specified. Once the output directory is set, the desired outputs, normally either images, or points are to be selected as required. The checkbox `` '',  if set, will cause only the changes that actually alter the computation internal computation to be saved. As an example, if one was to animate the ``Load Limit'' property of the ``Pos Data'' filter, and the file to be opened was only 1~MB, but the animation proceeded as 0.5, 0.6...
+,
  1.0,1.1... , when the sampling value exceeds 1~MB, there is no effect on the computation, thus the program will not save data on frames that do not alter the output.
 
 \section{Detailed Reference}
@@ -543,7 +641,7 @@ Voxel & No & No & No \\
 
 \FloatBarrier
 \subsubsection{Ion Information}
-
+\label{sec:FilterIonInformation}
 This filter allows for the computation of ion counts in any input streams, as well as volume estimation. If a range stream is present in its input, (\emph{i.e.}\ a Ranging is a parent of this filter) then the filter will perform per-species computation of the value.
 
 \begin{itemize}
@@ -924,9 +1022,23 @@ Voxel & No & No & No \\
 
 This filter discretises space into a series of 3D cubed regions, known as ``Voxels'' (Volume Pixels). Voxels can be used to alter a point cloud into a discrete volume of counts associated with each region. For example, the number of points inside each cube can be used as the counting metric, the number of points of a certain ion type, or the ratio of the number of points within a given region.
 
-At this time, there are two representations for Voxels -- Point cloud and Isosurface modes. Point cloud mode uses a colour value to display the value stored in the voxel, with the point based at the centre of the voxel. Point clouds can be used to visualise the entire volume at once (\emph{e.g}\ by using large translucent points), or to provide a quick-to-compute representation. Isosurfaces can be used to visually segment regions of high and low intensity within the data volume, by construction of an interpolated surface between your data volumes. 
+At this time, there are three representations for Voxels:
+\begin{itemize}
+ \item Point Cloud - usses a colour value to display the value stored in the voxel, with a grid of points based at the centre of each voxel.
+ \item Axial Slice - 
+ \item Isosurface - Visually segment regions of high and low intensity within the data volume, by building a dividing surface between these two regions
+\end{itemize}
+
+If a range file is present in the input, this can be used to perform per-range computations, such as ratio voxelisation specific to particular species. Figure~\ref{fig:voxeliseDisplayType} shows the different representations on the same input data.
+
+\begin{figure}
+ \centering
+  \includegraphics[keepaspectratio=true,width=0.9 \textwidth]{./figures/voxel-representations.png}
+
+ \caption{Voxelisation filter, showing different representations. Left to right shows point cloud, axial slice and isosurface mode on the same dataset}
+ \label{fig:voxeliseDisplayType}
+\end{figure}
 
-If a range file is present in the input, this can be used to perform per-range computations, such as ratio voxelisation specific to particular species.
 
 Note that the limits of the values associated with the voxels will be printed on the console after the filter has refreshed -- this can be used, for example, to set the limits for isosurface representation.
 
@@ -1033,9 +1145,9 @@ This document is licenced under the Creative Commons 3.0 ShareAlike licence. \ur
 \label{sec:3DepictPaths}
 \emph{3Depict} uses one of several different paths for storing configuration and autosave information, depending upon your host operating system. 
 \begin{itemize}
- \item Linux-like : your home directory, in th .3Depict folder. \emph{e.g.} \texttt{/home/someuser/.3Depict/}
- \item Mac OSX :\texttt{ /Users/someuser/Documents/.3Depict/}
- \item Windows : usually \texttt{C:\\Documents and settings\\someuser\\Documents\\.3Depict\\}
+ \item Linux-like : your home directory, in th .3Depict folder. \emph{e.g.} \path{/home/someuser/.3Depict/}
+ \item Mac OSX :\path{/Users/someuser/Documents/.3Depict/}
+ \item Windows : usually \path{C:\Documents} \path{and} \path{settings\someuser\Documents\.3Depict\} %Sigh - path macro doesn't work with whitespace!
 \end{itemize}
 
 \subsection{File formats}
@@ -1477,7 +1589,7 @@ appended file to output.pos
 \end{verbatim}
 
 \subsubsection{C/C++}
-For \emph{C/C++}, an example is given. The example here is somewhat more complex than the rest, as in this case, we do not simply treate the data as a series of bytes, bt we additionally perform the data transformation steps required to get it into a usable form (ie as a list of correctly ordered bytes in memory, in a useful variable). This was not done for the previous examples.
+For \emph{C/C++}, an example is given. The example here is somewhat more complex than the rest, as in this case, we do not simply treat the data as a series of bytes, bt we additionally perform the data transformation steps required to get it into a usable form (ie as a list of correctly ordered bytes in memory, in a useful variable). This was not done for the previous examples.
 
 Note that as C/C++ are compiled languages, it is necessary to be able to be able to generate a binary (executable) version of the program - this procedure is not described here, but users are encouraged to be comfortable with this process before attempting to implement the following examples for themselves. The exact procedure for doing this is outside of the scope for this document - you will require a compiler, such as \emph{gcc}'s \emph{g++} compiler, which you will most likely want to install from some form of package management system, such as the \emph{APT}, \emph{yum} or \emph{zypper} systems on linux, \emph{Xcode} or \emph{Macports} on Mac OSX, or \emph{Cygwin} or \emph{tdm-gcc/msys} under windows. Being able to compile a program file to produce an executable binary (under windows `EXE') that consists only of \texttt{int main() \{\} } is a definite prerequisite.
 
@@ -1716,7 +1828,8 @@ If you are running a Debian or Debian derived distribution, all you need to do i
 Once this is done, you can download the latest source code from the website, unzip it, and then run \texttt{./configure \&\& make}. This builds the program. You can now modify any of the files, then recompile it simply running \texttt{make}. By examining the options listed by \texttt{./configure --help}, the configuration of the program can be altered to some extent (\emph{e.g.}, enable/disable debug checks, or computational parallelism).
 
 \subsubsection{Changing stuff}
-As \emph{3Depict} is open source, it can be modified in the case any error fixes, extentions or other alterations to the program are  desired. However, a certain level of prerequisite knowledge is necessary to effectively alter the program. If altering code in \emph{3Depict}, You should be familiar with C++, as well as compiling multi-file programs. Depending upon the modification, you may need to have some familiarity with the mathematical problems you need to solve and with libraries used by \emph{3Depict}, such as OpenGL or wxWidgets. 
+As \emph{3Depict} is open source, it can be modified in the case any error fixes, extentions or other alterations to the program are  desired. However, a certain level of prerequisite knowledge is necessary to effectively alter the program. If altering code in \emph{3Depict}, You should be familiar with C++, as well as compiling multi-file programs. Depending upon the modification, you may need to have some familiarity with the mathematical problems you need to solve and with libraries used by \emph{3Depict}, such as OpenGL or wxWidgets. Instructions on how to compile for the various platforms is given on the website. However, due to the changing nature of these platforms, no guarantees that compilation will be successful can be given, when following these instructions -- some debugging of the process may be required.
+
 
 The internal structure of the program can be more easily seen from the Doxygen documentation, which is listed online, or can be generated from the source files themselves via the Doxygen tool. If you want to have a play around with the code, try getting it to compile first, before trying to change anything. Feel free to drop us a line on the website to ask about the change you want to make, and how it could be most easily achieved in the code.
 
diff --git a/docs/manual-latex/manual.tex b/docs/manual-latex/manual.tex.backup
similarity index 91%
copy from docs/manual-latex/manual.tex
copy to docs/manual-latex/manual.tex.backup
index 05b64c2..d2685bc 100644
--- a/docs/manual-latex/manual.tex
+++ b/docs/manual-latex/manual.tex.backup
@@ -40,7 +40,7 @@
 \begin{minipage}{0.3\textwidth}
 \begin{flushright} \large
 \emph{Version:} \\
- 0.0.13, Apr 2012\end{flushright}
+ 0.0.14, Aug 2013\end{flushright}
 \end{minipage}
 
 \vfill
@@ -94,7 +94,7 @@ Due to the design of the program, the program should run under Linux, Mac, BSD a
 
 The minimum requirements for running \emph{3Depict} are not known. The author wrote a substantial portion of the program on a machine with only 4 and 12~GB drives, and a 1.6~GHz processor, which normally runs at 800~MHz and has 1~GB of RAM. There is no clear reason that it would not run on even lower-spec machines. Whilst a higher spec machine may run the program faster, intelligent use of the programs ``filter'' system may allow for complex analyses even on low-end machines. 
 
-If you are experiencing 3D graphics problems, first ensure that other 3D programs do not experience the same problems. Otherwise, please contact the authors for assistance -- there should be no requirement for vendor-specific hardware. Note however that the exact appearance of the 3D view is dependant upon your hardware, and may have small changes between different platforms. 
+If you are experiencing 3D graphics problems, first ensure that other 3D programs do not experience the same problems. Otherwise, please contact the authors for assistance -- there should be no requirement for vendor-specific hardware. Note however that the exact appearance of the 3D view is dependent upon your hardware, and may have small changes between different platforms. 
 
 \subsection{Platform specific notes}
 Note that whilst every effort is made to ensure that the program will run on a variety of systems, small system-specific quirks may be evident, particularly on platforms to which the authors do not use regularly (\emph{e.g.}\ windows). Secondly, due to slight differences between platforms some functions may be remapped to other mouse/key combinations.  
@@ -255,7 +255,97 @@ New items can be added to the tree by selecting the filter to add from the dropd
 Once an item is added, the filter tree is thus modified and a recomputation of the scene will occur. Approximate progress on the filter update is visible in the status bar. During an update, only limited interaction with the program is permitted. An update may be cancelled at any time with the \texttt{escape} key. 
 
 
+\section{Quick start}
+Several quick notes are provided here as examples of how to perform specific measurements/calcuations. Whilst this is not an exhaustive list of measurements that can be made in \emph{3Depict}, this section is targeted towards new users who wish to use the program to perform quick or common measurments.
 
+\subsection{Loading data}
+\label{sec:quickStartLoadData}
+To load data, one must first have data to load in the form of either a "POS" formatted file (see Section~\ref{sec:posformat}), or as a text file (using english notation, four columns - see Section~\ref{sec:textformat}). To load the data, use the Open command in the File menu. Alternatively, one can drag and drop the file onto the program.
+
+\subsection{Loading an analysis}
+You may have an existing analysis file, which you can use to load both the data, and any associated analysis information (plots, clustering, clipping, etc.), which for example may have been undertaken by a separate user. 
+
+To load it, you require a ``package'' from the previous user, which will be a folder containing a XML file, and any data files that are required. As for loading data, you can either directly open the analysis with File$\rightarrow$Open, or by dropping it onto the program. 
+
+Note that by default, the program will not load all the data in the file - a sampling will be performed. Careful use of data sampling will allow for a much more rapid and interactive analysis of large datasets - many of the algorithms running times do not scale directly with the size of the dataset. Reducing the number of ions can, in some cases, result in a signfificant reduction in run time (eg halving number of ions for some algoritms can result in a run time of a quarter required for the full dataset).
+
+\subsection{Ranging}
+\label{sec:quickStartRangedData}
+The program can be used to mark particular sections of the spectrum as belonging to a particular ``range'' of values. Each value can be tagged with a specific name for the range, and an associated colour, which will be used to mark the points in the 3D display.
+
+\begin{figure}[ht]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangeDropdown.png}
+
+ \caption{Opening a range file can be done from either the filter drop down, or by dropping a rangefile onto the program. You must first have data loaded (as shown by the red points).}
+\label{fig:rangeDropdown}
+\end{figure}
+
+
+To perform ranging, you must first have a valid rangefile. As of time of writing, (July, 2013 - 0.0.14), the program is unable to generate these. It is possible to write the file by hand, or using a separate program - details on manually writing the file can be found in Section~\ref{sec:rangeFormat}.
+
+To perform ranging, the data must be first loaded into the program. The range information can be loaded in two ways, by dropping a valid rangefile onto the program, or by using the filter dropdown (Figure~\ref{fig:rangeDropdown}), whereby a window will open that will allow for the selection of a valid range file. 
+
+Once loaded, you can select the ranging filter and enable/disable ions and ranges you do not wish to see. By default unranged ions are not emitted from a range filter, so will not be seen unless ``Drop Unranged'' is unselected.
+
+
+\subsection{Spectrum}
+To see the mass spectrum for a selected data, the ``spectrum'' filter must be used. First load the required data (as per Section~\ref{sec:quickStartLoadData}), then select the data filter in the tree, and select ``Spectrum'' from the filter drop-down. This will display the spectrum without any overlaid ranges. To get the desired signal/noise level, you may wish to either alter the sampling level in the Pos Data (Load Limit value), or disable sampling. Changing the spectrum bin width until the spectrum appears as desired is also recommended.
+
+\begin{figure}[ht]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangedSpectrum.png}
+
+ \caption{Ranged spectrum shown only the data that is within the selected ranging windows. The ``Drop unranged'' option can be used to show all the data, and thus the complete spectrum.}
+\label{fig:rangedSpectrum}
+\end{figure}
+
+
+To display the ranged spectrum, simply use the sequence \texttt{Data$rightarrow$Ranging$rightarrow$Spectrum}, as shown in Figure~\ref{fig:rangedSpectrum}. To see the ions outside existing ranges, untick ``drop unranged`` from the range filter. Note that as the data is converted into a spectrum, the 3D view will disappear. To see both the spectrum and the point data at the same time, use the configuration shown in Figure~\ref{fig:rangedSpectrumWithCloud}.
+
+\begin{figure}[ht]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/rangedSpectrumCloud.png}
+
+ \caption{This layout can be used to simultaneously display both the point cloud and the ranged spectrum.}
+\label{fig:rangedSpectrumWithCloud}
+\end{figure}
+
+
+\subsection{Composition profiles}
+To display a composition profile, you first require a ranged dataset (see Section~\ref{sec:quickStartRangedData}). Once done, first select the range filter, then choose a concentration profile from the drop down. Note that as the data has now been converted into a concentration profile, the point cloud will disappear (although the concentration profile cylinder is visible, and is computing the correct result). To see both the data and the concentration profile at the same time, use the configuration shown in Figure~\ref{fig:quickStartConcLayout}.
+
+\begin{figure}[ht]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/quickStartConcLayout.png}
+
+ \caption{This layout can be used to show both point data and a concentration profile simultaneously.}
+\label{fig:quickStartConcLayout}
+\end{figure}
+
+
+
+\subsection{Counting Points and measuring volume}
+
+To compute the absolute counts of the number of ions that are visible in the dataset, use the ``Ion information'' filter, as shown in Figure~\ref{fig:quickStartIonInfoLayout}. To compute the ion count, check the ``count'' box. To compute the dataset volume, select the ''volume'' checkbox, and the desired algorithm (For algorithm details see Section~\ref{sec:FilterIonInformation}). The results are displayed in the console window (Figure~\ref{fig:quickStartIonInfoLayout}).
+
+\begin{figure}[ht]
+\centering
+ \includegraphics[width=0.85 \textwidth,keepaspectratio=true]{./figures/quickStartIonInfoLayout.png}
+
+ \caption{Ion count and volume data can be displayed from the ion information filter. The output is displayed in the console window.}
+\label{fig:quickStartIonInfoLayout}
+\end{figure}
+
+
+
+\subsection{Concentration surface and slices}
+
+To generate iso-concentration surfaces, or to create 2D slices in your data for visualising information such as concentration fields, a voxelisation must first be conducted.
+
+Load some ranged data (Section~\ref{sec:quickStartRangedData}), and then select the range filter and choose ``Voxelisation''. This will cause the dataset to disappear until you configure the voxelisation parameters appropriately. To compute a concentration field, change the normalisation mode to ``All ions (Conc)'', then select the ions that are to be included.  To visualise the result, change the ``representation'' mode to either isosurface or 2D slice. The upper and lower bounds of the 2D slice are auto computed. 
+
+However, for the isosurface one must choose the value that the isosurface is spanning. For non-concentration modes, after computation of the voxel field, the upper and lower bounds of the field are shown in the console window, and can aid in selecting the desired isosurface value.
 
 
 \section{Understanding the program}
@@ -422,7 +512,8 @@ In this case either each string must be individually specified, as shown in the
 \end{center}
 \end{figure}
 
-Once the desired properties have been set in the filter view, then one proceeds to the frame view in order to review the animation by examining the properties that will be obtained in each filter, frame-by-frame. If you are familiar with this dialog, then it is easy to simply examine this quickly to ensure that the properties that were intended have been obtained. Now, having ensured that this is the case, it can be seen that the "OK" button cannot be pressed at this time. Firstly, the desired outputs, and the directory that they will be sent to during the animation process must be specified. Once the output directory is set, the desired outputs, normally either images, or points are to be selected as required. The checkbox `` '',  if set, will cause only the changes that actually alter the computation internal computation to be saved. As an example, if one was to animate the ``Load Limit'' property of the ``Pos Data'' filter, and the file to be opened was only 1~MB, but the animation proceeded as 0.5, 0.6...,
+Once the desired properties have been set in the filter view, then one proceeds to the frame view in order to review the animation by examining the properties that will be obtained in each filter, frame-by-frame. If you are familiar with this dialog, then it is easy to simply examine this quickly to ensure that the properties that were intended have been obtained. Now, having ensured that this is the case, it can be seen that the "OK" button cannot be pressed at this time. Firstly, the desired outputs, and the directory that they will be sent to during the animation process must be specified. Once the output directory is set, the desired outputs, normally either images, or points are to be selected as required. The checkbox `` '',  if set, will cause only the changes that actually alter the computation internal computation to be saved. As an example, if one was to animate the ``Load Limit'' property of the ``Pos Data'' filter, and the file to be opened was only 1~MB, but the animation proceeded as 0.5, 0.6...
+,
  1.0,1.1... , when the sampling value exceeds 1~MB, there is no effect on the computation, thus the program will not save data on frames that do not alter the output.
 
 \section{Detailed Reference}
@@ -543,7 +634,7 @@ Voxel & No & No & No \\
 
 \FloatBarrier
 \subsubsection{Ion Information}
-
+\label{sec:FilterIonInformation}
 This filter allows for the computation of ion counts in any input streams, as well as volume estimation. If a range stream is present in its input, (\emph{i.e.}\ a Ranging is a parent of this filter) then the filter will perform per-species computation of the value.
 
 \begin{itemize}
@@ -924,9 +1015,23 @@ Voxel & No & No & No \\
 
 This filter discretises space into a series of 3D cubed regions, known as ``Voxels'' (Volume Pixels). Voxels can be used to alter a point cloud into a discrete volume of counts associated with each region. For example, the number of points inside each cube can be used as the counting metric, the number of points of a certain ion type, or the ratio of the number of points within a given region.
 
-At this time, there are two representations for Voxels -- Point cloud and Isosurface modes. Point cloud mode uses a colour value to display the value stored in the voxel, with the point based at the centre of the voxel. Point clouds can be used to visualise the entire volume at once (\emph{e.g}\ by using large translucent points), or to provide a quick-to-compute representation. Isosurfaces can be used to visually segment regions of high and low intensity within the data volume, by construction of an interpolated surface between your data volumes. 
+At this time, there are three representations for Voxels:
+\begin{itemize}
+ \item Point Cloud - usses a colour value to display the value stored in the voxel, with a grid of points based at the centre of each voxel.
+ \item Axial Slice - 
+ \item Isosurface - Visually segment regions of high and low intensity within the data volume, by building a dividing surface between these two regions
+\end{itemize}
+
+If a range file is present in the input, this can be used to perform per-range computations, such as ratio voxelisation specific to particular species. Figure~\ref{fig:voxeliseDisplayType} shows the different representations on the same input data.
+
+\begin{figure}
+ \centering
+  \includegraphics[keepaspectratio=true,width=0.9 \textwidth]{./figures/voxel-representations.png}
+
+ \caption{Voxelisation filter, showing different representations. Left to right shows point cloud, axial slice and isosurface mode on the same dataset}
+ \label{fig:voxeliseDisplayType}
+\end{figure}
 
-If a range file is present in the input, this can be used to perform per-range computations, such as ratio voxelisation specific to particular species.
 
 Note that the limits of the values associated with the voxels will be printed on the console after the filter has refreshed -- this can be used, for example, to set the limits for isosurface representation.
 
@@ -1033,9 +1138,9 @@ This document is licenced under the Creative Commons 3.0 ShareAlike licence. \ur
 \label{sec:3DepictPaths}
 \emph{3Depict} uses one of several different paths for storing configuration and autosave information, depending upon your host operating system. 
 \begin{itemize}
- \item Linux-like : your home directory, in th .3Depict folder. \emph{e.g.} \texttt{/home/someuser/.3Depict/}
- \item Mac OSX :\texttt{ /Users/someuser/Documents/.3Depict/}
- \item Windows : usually \texttt{C:\\Documents and settings\\someuser\\Documents\\.3Depict\\}
+ \item Linux-like : your home directory, in th .3Depict folder. \emph{e.g.} \path{/home/someuser/.3Depict/}
+ \item Mac OSX :\path{/Users/someuser/Documents/.3Depict/}
+ \item Windows : usually \path{C:\Documents} \path{and} \path{settings\someuser\Documents\.3Depict\} %Sigh - path macro doesn't work with whitespace!
 \end{itemize}
 
 \subsection{File formats}
@@ -1477,7 +1582,7 @@ appended file to output.pos
 \end{verbatim}
 
 \subsubsection{C/C++}
-For \emph{C/C++}, an example is given. The example here is somewhat more complex than the rest, as in this case, we do not simply treate the data as a series of bytes, bt we additionally perform the data transformation steps required to get it into a usable form (ie as a list of correctly ordered bytes in memory, in a useful variable). This was not done for the previous examples.
+For \emph{C/C++}, an example is given. The example here is somewhat more complex than the rest, as in this case, we do not simply treat the data as a series of bytes, bt we additionally perform the data transformation steps required to get it into a usable form (ie as a list of correctly ordered bytes in memory, in a useful variable). This was not done for the previous examples.
 
 Note that as C/C++ are compiled languages, it is necessary to be able to be able to generate a binary (executable) version of the program - this procedure is not described here, but users are encouraged to be comfortable with this process before attempting to implement the following examples for themselves. The exact procedure for doing this is outside of the scope for this document - you will require a compiler, such as \emph{gcc}'s \emph{g++} compiler, which you will most likely want to install from some form of package management system, such as the \emph{APT}, \emph{yum} or \emph{zypper} systems on linux, \emph{Xcode} or \emph{Macports} on Mac OSX, or \emph{Cygwin} or \emph{tdm-gcc/msys} under windows. Being able to compile a program file to produce an executable binary (under windows `EXE') that consists only of \texttt{int main() \{\} } is a definite prerequisite.
 
@@ -1716,7 +1821,8 @@ If you are running a Debian or Debian derived distribution, all you need to do i
 Once this is done, you can download the latest source code from the website, unzip it, and then run \texttt{./configure \&\& make}. This builds the program. You can now modify any of the files, then recompile it simply running \texttt{make}. By examining the options listed by \texttt{./configure --help}, the configuration of the program can be altered to some extent (\emph{e.g.}, enable/disable debug checks, or computational parallelism).
 
 \subsubsection{Changing stuff}
-As \emph{3Depict} is open source, it can be modified in the case any error fixes, extentions or other alterations to the program are  desired. However, a certain level of prerequisite knowledge is necessary to effectively alter the program. If altering code in \emph{3Depict}, You should be familiar with C++, as well as compiling multi-file programs. Depending upon the modification, you may need to have some familiarity with the mathematical problems you need to solve and with libraries used by \emph{3Depict}, such as OpenGL or wxWidgets. 
+As \emph{3Depict} is open source, it can be modified in the case any error fixes, extentions or other alterations to the program are  desired. However, a certain level of prerequisite knowledge is necessary to effectively alter the program. If altering code in \emph{3Depict}, You should be familiar with C++, as well as compiling multi-file programs. Depending upon the modification, you may need to have some familiarity with the mathematical problems you need to solve and with libraries used by \emph{3Depict}, such as OpenGL or wxWidgets. Instructions on how to compile for the various platforms is given on the website. However, due to the changing nature of these platforms, no guarantees that compilation will be successful can be given, when following these instructions -- some debugging of the process may be required.
+
 
 The internal structure of the program can be more easily seen from the Doxygen documentation, which is listed online, or can be generated from the source files themselves via the Doxygen tool. If you want to have a play around with the code, try getting it to compile first, before trying to change anything. Feel free to drop us a line on the website to ask about the change you want to make, and how it could be most easily achieved in the code.
 
diff --git a/docs/manual-latex/manual.toc b/docs/manual-latex/manual.toc
new file mode 100644
index 0000000..f9780b0
--- /dev/null
+++ b/docs/manual-latex/manual.toc
@@ -0,0 +1,91 @@
+\contentsline {section}{\numberline {1}Foreword}{1}{section.1}
+\contentsline {subsection}{\numberline {1.1}Introduction}{1}{subsection.1.1}
+\contentsline {subsubsection}{\numberline {1.1.1}Background}{1}{subsubsection.1.1.1}
+\contentsline {subsubsection}{\numberline {1.1.2}What is Open Source?}{1}{subsubsection.1.1.2}
+\contentsline {subsection}{\numberline {1.2}Requirements}{2}{subsection.1.2}
+\contentsline {subsection}{\numberline {1.3}Platform specific notes}{2}{subsection.1.3}
+\contentsline {subsection}{\numberline {1.4}Getting help}{3}{subsection.1.4}
+\contentsline {subsection}{\numberline {1.5}Who wrote this program?}{3}{subsection.1.5}
+\contentsline {subsection}{\numberline {1.6}Alternate documentation}{3}{subsection.1.6}
+\contentsline {subsection}{\numberline {1.7}Helping out}{3}{subsection.1.7}
+\contentsline {section}{\numberline {2}Basics}{3}{section.2}
+\contentsline {subsection}{\numberline {2.1}Getting started}{3}{subsection.2.1}
+\contentsline {subsubsection}{\numberline {2.1.1}Licence}{3}{subsubsection.2.1.1}
+\contentsline {subsubsection}{\numberline {2.1.2}Installing the program}{4}{subsubsection.2.1.2}
+\contentsline {subsection}{\numberline {2.2}Understanding the interface}{4}{subsection.2.2}
+\contentsline {subsubsection}{\numberline {2.2.1}The 3D View}{5}{subsubsection.2.2.1}
+\contentsline {paragraph}{Basic movement}{5}{figure.3}
+\contentsline {subsubsection}{\numberline {2.2.2}Plot area}{6}{subsubsection.2.2.2}
+\contentsline {subsubsection}{\numberline {2.2.3}Console}{6}{subsubsection.2.2.3}
+\contentsline {subsubsection}{\numberline {2.2.4}Tools panel}{7}{subsubsection.2.2.4}
+\contentsline {subsection}{\numberline {2.3}Usage fundamentals}{8}{subsection.2.3}
+\contentsline {section}{\numberline {3}Quick start}{9}{section.3}
+\contentsline {subsection}{\numberline {3.1}Loading data}{9}{subsection.3.1}
+\contentsline {subsection}{\numberline {3.2}Loading an analysis}{9}{subsection.3.2}
+\contentsline {subsection}{\numberline {3.3}Ranging}{9}{subsection.3.3}
+\contentsline {subsection}{\numberline {3.4}Spectrum}{10}{subsection.3.4}
+\contentsline {subsection}{\numberline {3.5}Composition profiles}{10}{subsection.3.5}
+\contentsline {subsection}{\numberline {3.6}Counting Points and measuring volume}{11}{subsection.3.6}
+\contentsline {subsection}{\numberline {3.7}Concentration surface and slices}{11}{subsection.3.7}
+\contentsline {section}{\numberline {4}Understanding the program}{14}{section.4}
+\contentsline {subsection}{\numberline {4.1}Filters}{14}{subsection.4.1}
+\contentsline {subsection}{\numberline {4.2}Trees}{14}{subsection.4.2}
+\contentsline {subsection}{\numberline {4.3}Stashes}{15}{subsection.4.3}
+\contentsline {subsection}{\numberline {4.4}Plots}{16}{subsection.4.4}
+\contentsline {subsection}{\numberline {4.5}Cameras}{16}{subsection.4.5}
+\contentsline {subsection}{\numberline {4.6}Effects}{17}{subsection.4.6}
+\contentsline {subsection}{\numberline {4.7}Program actions}{17}{subsection.4.7}
+\contentsline {subsubsection}{\numberline {4.7.1}Save}{17}{subsubsection.4.7.1}
+\contentsline {subsubsection}{\numberline {4.7.2}Undo}{17}{subsubsection.4.7.2}
+\contentsline {subsubsection}{\numberline {4.7.3}Raw Data}{17}{subsubsection.4.7.3}
+\contentsline {subsubsection}{\numberline {4.7.4}Export Menu}{17}{subsubsection.4.7.4}
+\contentsline {subsubsection}{\numberline {4.7.5}Autosave}{18}{subsubsection.4.7.5}
+\contentsline {subsubsection}{\numberline {4.7.6}Export Animation}{18}{subsubsection.4.7.6}
+\contentsline {section}{\numberline {5}Detailed Reference}{22}{section.5}
+\contentsline {subsection}{\numberline {5.1}Data types}{22}{subsection.5.1}
+\contentsline {subsubsection}{\numberline {5.1.1}Ions}{22}{subsubsection.5.1.1}
+\contentsline {subsubsection}{\numberline {5.1.2}Plots}{22}{subsubsection.5.1.2}
+\contentsline {subsubsection}{\numberline {5.1.3}Range}{22}{subsubsection.5.1.3}
+\contentsline {subsubsection}{\numberline {5.1.4}Voxels}{22}{subsubsection.5.1.4}
+\contentsline {subsubsection}{\numberline {5.1.5}Drawables}{22}{subsubsection.5.1.5}
+\contentsline {subsection}{\numberline {5.2}Filters}{22}{subsection.5.2}
+\contentsline {subsubsection}{\numberline {5.2.1}Data load}{23}{subsubsection.5.2.1}
+\contentsline {subsubsection}{\numberline {5.2.2}Downsampling}{24}{subsubsection.5.2.2}
+\contentsline {subsubsection}{\numberline {5.2.3}Ion Information}{24}{subsubsection.5.2.3}
+\contentsline {subsubsection}{\numberline {5.2.4}Ranging}{25}{subsubsection.5.2.4}
+\contentsline {subsubsection}{\numberline {5.2.5}Bounding Box}{26}{subsubsection.5.2.5}
+\contentsline {subsubsection}{\numberline {5.2.6}Clipping}{26}{subsubsection.5.2.6}
+\contentsline {subsubsection}{\numberline {5.2.7}Spectrum}{26}{subsubsection.5.2.7}
+\contentsline {subsubsection}{\numberline {5.2.8}Profile}{27}{subsubsection.5.2.8}
+\contentsline {subsubsection}{\numberline {5.2.9}Spatial Analysis}{27}{subsubsection.5.2.9}
+\contentsline {paragraph}{Algorithms}{27}{section*.3}
+\contentsline {subsubsection}{\numberline {5.2.10}Clustering analysis}{28}{subsubsection.5.2.10}
+\contentsline {subsubsection}{\numberline {5.2.11}External Program}{29}{subsubsection.5.2.11}
+\contentsline {paragraph}{Command syntax: }{29}{section*.4}
+\contentsline {paragraph}{Prior to program execution:}{30}{section*.5}
+\contentsline {paragraph}{After program execution:}{30}{section*.6}
+\contentsline {subsubsection}{\numberline {5.2.12}Annotation}{30}{subsubsection.5.2.12}
+\contentsline {paragraph}{Text}{30}{section*.7}
+\contentsline {paragraph}{Arrow, Arrow with Text}{31}{section*.8}
+\contentsline {paragraph}{Angle Measurement}{31}{section*.9}
+\contentsline {subsubsection}{\numberline {5.2.13}Voxels}{31}{subsubsection.5.2.13}
+\contentsline {subsection}{\numberline {5.3}Ion Colour}{32}{subsection.5.3}
+\contentsline {subsection}{\numberline {5.4}Ion Transform}{33}{subsection.5.4}
+\contentsline {section}{\numberline {6}Attributions}{33}{section.6}
+\contentsline {section}{\numberline {7}Licence}{34}{section.7}
+\contentsline {section}{\numberline {8}Appendices}{34}{section.8}
+\contentsline {subsection}{\numberline {8.1}Paths}{34}{subsection.8.1}
+\contentsline {subsection}{\numberline {8.2}File formats}{34}{subsection.8.2}
+\contentsline {subsubsection}{\numberline {8.2.1}State file}{34}{subsubsection.8.2.1}
+\contentsline {subsubsection}{\numberline {8.2.2}Range files}{35}{subsubsection.8.2.2}
+\contentsline {subsubsection}{\numberline {8.2.3}POS files}{36}{subsubsection.8.2.3}
+\contentsline {subsubsection}{\numberline {8.2.4}Text files}{36}{subsubsection.8.2.4}
+\contentsline {subsection}{\numberline {8.3}External Program Examples}{37}{subsection.8.3}
+\contentsline {subsubsection}{\numberline {8.3.1}Scilab}{37}{subsubsection.8.3.1}
+\contentsline {subsubsection}{\numberline {8.3.2}Python}{41}{subsubsection.8.3.2}
+\contentsline {subsubsection}{\numberline {8.3.3}Bash}{43}{subsubsection.8.3.3}
+\contentsline {subsubsection}{\numberline {8.3.4}C/C++}{45}{subsubsection.8.3.4}
+\contentsline {subsection}{\numberline {8.4}Modifying the program}{49}{subsection.8.4}
+\contentsline {subsubsection}{\numberline {8.4.1}Development tools}{49}{subsubsection.8.4.1}
+\contentsline {subsubsection}{\numberline {8.4.2}Getting yourself set up}{50}{subsubsection.8.4.2}
+\contentsline {subsubsection}{\numberline {8.4.3}Changing stuff}{50}{subsubsection.8.4.3}
diff --git a/docs/web/about.html b/docs/web/about.html
index 27bccfe..5bbb4a1 100644
--- a/docs/web/about.html
+++ b/docs/web/about.html
@@ -61,20 +61,24 @@ creation of this program. Without their work, this program could never
 have got beyond the concept stage.<br/>
 <h3>Thanking:</h3>
 <ul>
-  <li>The wxWidgets team</li>
+  <li>The <a href="http://wxwidgets.org">wxWidgets</a> team</li>
   <li>Alexy Balakin (<a href="http://mathgl.sourceforge.net/">MathGL</a>), <br/>
   </li>
   <li><a href="http://ftgl.sourceforge.net">FTGL</a> and <a href="http://freetype.org">freetype</a> people, <br/>
   </li>
   <li>The <a href="http://tree.phi-sci.com/">tree.h</a> guy (Kasper Peeters)  </li>
-  <li>The <a href="http://www.sintef.no/Projectweb/Heterogeneous-Computing/Research-Topics/Marching-Cubes-using-Histogram-Pyramids/">HPMC </a>researchers</li>
+  <li><a href="http://www.gnu.org/software/gsl/">GNU Scientific Library</a> developers. </li>
+  <li><a href="http://www.cppcheck.sourceforge.net">Cppcheck</a> and <a href="http://www.valgrind.org">Valgrind</a> developers, for great debugging tools</li>
+
   <li>Minimalistic design whose <a href="style.css">CSS</a> I modifed (GPLv3) for the website template.<br/>
   </li>
-
   <li>The random internet postings that help me debug weird and confusing problems<br/>
   </li>
+
 </ul>
 
+And anyone else I missed!
+
 </div>
 </div>
 
diff --git a/docs/web/compiling.html b/docs/web/compiling.html
index 06473e5..822623d 100644
--- a/docs/web/compiling.html
+++ b/docs/web/compiling.html
@@ -20,7 +20,7 @@
 
 <div id="left">
 <div class="box">
-<h2> Latest version: 0.0.6</h2>
+<h2> Latest version: 0.0.13</h2>
 <p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform</p>
 </div>
 <div class="box">
@@ -67,7 +67,13 @@ windows is highly complicated, and more thoroughly documented <a href="#windows"
 Direct <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Software_library">Dependencies</a>: <br/>
 
 <ul>
-<li>ftgl</li><li>freetype2</li><li>libxml2</li><li>mathgl</li><li>wxwidgets</li>
+<li><a href="http://sourceforge.net/projects/ftgl/">ftgl</a></li>
+<li><a href="http://freetype.org/">freetype2</a></li>
+<li><a href="http://www.xmlsoft.org/">libxml2</a></li>
+<li><a href="http://mathgl.sourceforge.net/">mathgl</a></li>
+<li><a href="http://wxwidgets.org/">wxwidgets</a></li>
+<li><a href="http://www.gnu.org/software/gettext/">gettext</a></li>
+<li><a href="http://www.qhull.org/">qhull</a></li>
 </ul>
 
 
@@ -99,7 +105,7 @@ You should then install the following packages (this requires administrative rig
 <h2>Setting up</h2>
 <h3>Debian/Ubuntu:</h3>
 <ul>
-<li>build-essential</li><li>libwxgtk2.8-dev</li><li>libmgl-dev</li><li>libxml2-dev</li><li>libftgl-dev</li>
+<li>build-essential</li><li>libwxgtk2.8-dev</li><li>libmgl-dev</li><li>libxml2-dev</li><li>libftgl-dev</li><li>libqhull-dev</li>
 </ul>
 
 
@@ -107,13 +113,13 @@ This can be done through the command line (below), or using the gui (synaptic pa
 
 <br/>
 
-<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> sudo aptitude install build-essential libwxgtk2.8-dev libmgl-dev libxml2-dev libftgl-dev) </span><br/>
+<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> sudo apt-get build-dep 3depict </span><br/>
 
 
 <h3>Fedora/RedHat:</h3>
 
 <ul>
-<li>"Development Tools"  group package</li><li>mathgl-devel</li><li>libxml2-devel</li><li>ftgl-devel</li><li>wxgtk-devel</li>
+<li>"Development Tools"  group package</li><li>mathgl-devel</li><li>libxml2-devel</li><li>ftgl-devel</li><li>wxgtk-devel</li><li>qhull-devel</li>
 </ul>
 
 
@@ -124,13 +130,13 @@ This can be done through either the command line, or through the GUI <br/>
 
 <span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum groupinstall "Development Tools"</span><br/>
 
-<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum install mathgl-devel libxml2-devel ftgl-devel wxgtk-devel</span><br/>
+<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum install mathgl-devel libxml2-devel ftgl-devel wxgtk-devel qhull-devel</span><br/>
 <br/>
 
 <h3>OpenSuse:</h3>
 
 <ul>
-<li>wxGTK-devel</li><li>libxml2-devel</li><li>ftgl-devel</li>
+<li>wxGTK-devel</li><li>libxml2-devel</li><li>ftgl-devel</li><li>qhull-devel</li>
 </ul>
 
 
@@ -142,7 +148,7 @@ This can be done either through the graphical interface (YaST) or at the command
 
 <span style="font-family: monospace;">    $ zypper install -t devel_C_C++</span><br/>
 
-<span style="font-family: monospace;">    $ zypper install wxGTK-devel libxml2-devel ftgl-devel</span><br/>
+<span style="font-family: monospace;">    $ zypper install wxGTK-devel libxml2-devel ftgl-devel qhull-devel</span><br/>
 
     <br/>
 
@@ -154,11 +160,16 @@ website:<br/>
 <li><a href="http://mathgl.sourceforge.net/">http://mathgl.sourceforge.net/</a></li>
 </ul>
 
+<h4> Cross compiling</h4>
+There is a cross compilation script available (0.0.13) in the packaging/mingw-debian-cross/ folder of the <a href="http://threedepict.hg.sourceforge.net/hgweb/threedepict/threedepict/summary">code repository</a>. This can be used to build 3Depict for windows platforms using a Debian or Debian-like host. The cross-compilation script is experimental, but will get you most of the way to a cross compiled version.  The script will download, patch and build all the neccessary dependencies automatically.
+
+<br/>
+
 
 <h3>Mac OS X</h3>
 
-Mac OS does not have a proper package management system. You need XCode installed (<a href="http://developer.apple.com/mac/library/documentation/Xcode/Conceptual/XcodeCoexistence/Contents/Resources/en.lproj/Basics/Basics.html">here</a>). For the latest version of Snow Leopard for some reason this is not free, and you now have to pay to download this or build gcc yourself (somehow) it appears. Considering GCC (the bit we need) is completely free, it is unclear what the deal is here.
-Note that at time of writing the wxWidgets version provided with XCode are several years out of date and cannot be guaranteed function correctly (though it may). There are some <a href="#Extra_notes_for_Mac_OSX">post-compile notes</a>, which <span style="font-weight: bold; font-style: italic;">must</span>  be followed to build a usable program.<br/>
+Mac OS does not have a proper package management system. You need XCode installed (<a href="http://developer.apple.com/mac/library/documentation/Xcode/Conceptual/XcodeCoexistence/Contents/Resources/en.lproj/Basics/Basics.html">here</a>). For the latest version of Snow Leopard for some reason this is not free, and you now are required to use the app store or something to get this or build gcc yourself (somehow) it appears. Considering GCC (the bit we need) is completely free (GPL), it is unclear what the deal is here.
+Note that at time of writing the wxWidgets version provided with XCode is several years out-of-date and probably won't work. Please don't try to use any of the built-in libraries provided with XCode - you cannot mix and match library linkage, it simply won't work (crashes). There are some <a href="#Extra_notes_for_Mac_OSX">post-compile notes</a>, which <span style="font-weight: bold; font-style: italic;">must</span>  be followed to build a usable program.<br/>
 
 <br/>
 
@@ -205,7 +216,7 @@ MinGW/MSYS or TDM-GCC/MSYS (unless you know better), some instructions are <a hr
 
 
 
-<br/>
+
 
 <h4>wxWidgets<br/>
 </h4>
@@ -331,8 +342,12 @@ You can even move this ".app" package to other computers (with the same OSX vers
 <br/>
 
 <h2><a href="windows"></a> Compile notes for windows </h2>
-<p>
-Before I post the full notes, this is very, very detailed and technical. But it means I have this working, and down to a fine art. Its a rough ride.</p>
+<p><i>
+THese notes are a little outdated as of April 2013 - you may find some of the program versions have changed. Most of the notes should still be valid.  However, this is not how 3Depict is built for windows - we use the cross-compile method instead. This has been scripted and is much easier, but requires a Debian or Debian-like installation (we recommend using VirtualBox). If you still want to compile under normal windows, then read on.
+</i>
+</p>
+
+<p> Before I post the full notes, this is very, very detailed and technical. But it means I have this working, and down to a fine art. Its a rough ride.</p>
 <p>
 You will need the 7zip file manager program or winrar to be able to open tar/gz files, as windows does not support this filetype, nor recognises it in the "web search" facility. (Its a standard gzip + archive file, note to windows devs : see <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Tgz">wikipedia on tar-gz</a>)</p>
 <p>
@@ -524,7 +539,7 @@ ran <span style="font-family: monospace;">make</span>. This will take a long tim
   Ran Make
 	<ul>
 	<li>
-	-- This failed in the utils dir. libpng is unable to see libz for whatever reason. Does not bode well,  but it was  in the utils section, which I don't need, so I ignored it.
+	This failed in the utils dir. libpng is unable to see libz for whatever reason. Does not bode well,  but it was  in the utils section, which I don't need, so I ignored it.
 		</li>
 	</ul>
 </li>
@@ -537,16 +552,14 @@ ran <span style="font-family: monospace;">make</span>. This will take a long tim
 </ul>
 <h4>3Depict</h4>
 <ul>
+
 <li>
- Had to override glu (gluSphere) check (this appears to be broken? (Note to self: Is this fixed now?) )
-</li>
-<li>
- Ran <span style="font-family: monospace;">export CFLAGS="-I/c/msys/1.0/local/include" && LDFLAGS="-L/c/msys/1.0/local/lib" && ./configure </span>
+ Ran <span style="font-family: monospace;"> export CFLAGS="-I/c/msys/1.0/local/include" && export LDFLAGS="-L/c/msys/1.0/local/lib" && ./configure --with-libqhull-link="-L/c/msys/1.0/local/lib/ -lqhull"  --with-libpng-link="-lpng -lz" </span>
 	<ul>
 	<li>
-		-- For an explanation for why this "export" businessis needed, see <a href="http://www.mingw.org/wiki/IncludePathHOWTO">this mingw faq</a>.	</li><li>
-		-- This wont build with parallelism; you have to add <span style="font-family: monospace;">--enable-openmp-parallel </span> , however some versions of GCC do not like this, so I left it off by default.  If you get errors about <span style="font-family: monospace;">undefined __sync_compare_and_swap_4  </span>(or similar) you can either 1) Alter your optimisation level 2) rebuild with -march=i686 3) modify the files it complains from, and build only those files without paralellism (modify cflags and remove -D_GLIBCXX... and -fopenmp , or 4) just build the whole thing without parallelism (the default).</li><li>
-		-- This will enable slow debug checking. To turn off debug checking add  <span style="font-family: monospace;">--enable-no-debug-checks</span> after configure, as in <span style="font-family: monospace;">./configure --enable-no-debug-checks</span>. Full information is available in <span style="font-family: monospace;">./configure --help</span>.
+		 For an explanation as to why this "export" business is needed, see <a href="http://www.mingw.org/wiki/IncludePathHOWTO">this mingw faq</a>.	</li><li>
+		-- This won't build with parallelism; you have to add <span style="font-family: monospace;">--enable-openmp-parallel </span> , however some versions of GCC do not like this, so I left it off by default.  If you get errors about <span style="font-family: monospace;">undefined __sync_compare_and_swap_4  </span>(or similar) you can either 1) Alter your optimisation level 2) rebuild with -march=i686 3) modify the files it complains from, and build only those files without paralellism (modify cflags and remove -D_GLIBCXX... and -fopenmp , or 4) just build the whole thing without parallelism (the default).</li><li>
+		 These settings will enable slow debug checking. To turn off debug checking add  <span style="font-family: monospace;">--enable-no-debug-checks</span> after configure, as in <span style="font-family: monospace;">./configure --enable-no-debug-checks</span>. Full information is available in <span style="font-family: monospace;">./configure --help</span>.
 	</li>
 	</ul>
 </li>
diff --git a/docs/web/contact.html b/docs/web/contact.html
index 9b504c8..cbd3254 100644
--- a/docs/web/contact.html
+++ b/docs/web/contact.html
@@ -45,7 +45,9 @@ You can post messages to the <a href="https://sourceforge.net/apps/phpbb/threede
 
 <h2>Email</h2>
 <form id="emf-form" enctype="multipart/form-data" method="post" action="http://www.emailmeform.com/builder/form/ff3Jr0WI55h54"><table style="text-align:left;" cellpadding="2" cellspacing="0" border="0" bgcolor="transparent"><tr><td style="" colspan="2"></td></tr><tr valign="top"><td style="" ><font face="Verdana" size="2" color="#000000"><b>Name</b></font><span style="color:red;"><small>*</small></span></td></tr><tr><td style=""><input id="element_0" name="element_0" value="" size="30" class="validate[required]" type="text" /><div style="padding-bottom:8px;color:#000000;"><small><font face="Verdana"></font></small></div></td></tr><tr valign="top"><td style="" ><font face="Verdana" size="2" color="#000000"><b>Your Email</b></font><span style="color:red;"><small>*</small></span></td></tr><tr><td style=""><input id="element_1" name="element_1" class="validate[required,custom[email]]" value="" size="30" type="text" /><div style="padding-bottom:8px;color:#000000;"><small><font face="Verdana"></font></small></div></td></tr><tr valign="top"><td style="" ><font face="Verdana" size="2" color="#000000"><b>Subject</b></font><span style="color:red;"><small>*</small></span></td></tr><tr><td style=""><input id="element_2" name="element_2" value="" size="30" class="validate[required]" type="text" /><div style="padding-bottom:8px;color:#000000;"><small><font face="Verdana"></font></small></div></td></tr><tr valign="top"><td style=""><font face="Verdana" size="2" color="#000000"><b>Message</b></font><span style="color:red;"><small>*</small></span></td></tr><tr><td style=""><textarea id="element_3" name="element_3" cols="60" rows="10" class="validate[required] "></textarea><div style="padding-bottom:8px;color:#000000;"><small><font face="Verdana"></font></small></div></td></tr><tr><td colspan="2"><table cellpadding="5" cellspacing="0" bgcolor="#E4F8E4" width="100%"><tr bgcolor="#AAD6AA"><td colspan="2"><font color="#FFFFFF" face="Verdana" size="2"><b>Image Verification</b></font></td></tr><tr><td style="padding:2px; width:100px;"><img id="captcha_image" src="http://www.emailmeform.com/builder/captcha/index/f78b3c73409d202f11a480f040354efb" alt="captcha"/></td><td valign="top"><div><font color="#000000">Please enter the text from the image</font>:<br/><input type="text" id="captcha_code" name="captcha_code" maxlength="10" size="10" class="validate[required,funcCall[valid_captcha]]"  />[<a id="captcha_code_refresh" href="javascript:void(0);" onclick="document.getElementById('captcha_image').src = 'http://www.emailmeform.com/builder/captcha/index/'+Math.random();get_valid_captcha();return false;">Refresh Image</a>][<a id="captcha_code_about" href="javascript:void(0);" onclick="window.open('http://www.emailmeform.com/captcha-instruction.html','_blank','width=400, height=500, left=' + (screen.width-450) + ', top=100');return false;">What's This?</a>]</div></td></tr></table></td></tr><tr><td colspan="2" align="right"><input name="element_counts" value="4" type="hidden" /><input  value="Send email" type="submit" /><input  value="Clear" type="reset" /></td></tr></table></form><div><font face="Verdana" size="2" color="#000000">Powered by</font><span style="position: relative; padding-left: 3px; bottom: -5px;"><img src="http://www.emailmeform.com/builder/images/footer-logo.png" alt="footer logo"/></span><font face="Verdana" size="2" color="#000000">EMF </font><a style="text-decoration:none;" href="http://www.emailmeform.com" target="_blank"><font face="Verdana" size="2" color="#000000">HTML Form</font></a></div>
-
+<p>
+If you need to attach an image, you can do so using an image upload service, such as <a href="http://imagepaste.nullnetwork.net/">Nullnetwork's image paste bin</a>, provided the images are < 1MB in size.
+</p>
 </div>
 </div>
 
diff --git a/docs/web/documentation.html b/docs/web/documentation.html
index 5017ece..bb29cc4 100644
--- a/docs/web/documentation.html
+++ b/docs/web/documentation.html
@@ -23,7 +23,7 @@
 <div id="left">
 <div class="box">
 <h2>Want to help out?</h2>
-You can help, even without programming. If you know how to program <a href="compiling.html">download the source</a> and get a build up and running.
+You can help, even without programming; (<a href="http://transifex.net/projects/p/3depict">translation</a>, web page maintenance, etc) — Just <a href="contact.html"/>get in touch</a>. <br/><br/> If you do program, try <a href="compiling.html">downloading the source</a> and get a build up and running, or just ask.
 <br>
  
 </div>
@@ -37,32 +37,26 @@ You can help, even without programming. If you know how to program <a href="comp
 <h1>Documentation</h1>
 
 
-<h2>User's reference</h2>
+<h2>User's Reference</h2>
 PDF Manual <a href="manual.pdf">here</a>. There is an <a href="manual/manual.html">HTML version</a>, automatically generated from the PDF.
 
 
 <h2>Screencasts</h2>
 <p>
-New in 0.0.4 (Jan, 2011) :<br>
+Animation and composition profiles in 3Depict 0.0.13  (Apr, 2013):<br>
 <center>
-<video src="3Depict-0.0.4-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br>
-<small><a href="3Depict-0.0.4-screencast.ogg">download video</a></small>
+<video src="3Depict-0.0.13-sphere_comp_and_animate-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br></small>
+<small><a href="33Depict-0.0.13-sphere_comp_and_animate-screencast.ogg">download video</a></small>
 </center>
 
-
-
-New in 0.0.3 (Nov, 2010) :<br>
+A short demo of 3Depict 0.0.8 (Oct, 2011):<br>
 <center>
-<video src="3Depict-0.0.3-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br>
-<small><a href="3Depict-0.0.3-screencast.ogg">download video</a></small>
+<video src="3Depict-0.0.8-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br></small>
+<small><a href="3Depict-0.0.8-screencast.ogg">download video</a></small>
 </center>
 
 
-
-A short demo of 3Depict 0.0.1 (Aug, 2010):<br>
 <center>
-<video src="3Depict-0.0.1-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br><small>
-<a href="3Depict-0.0.1-screencast.ogg">download video</a>
 <br>
 <br>
 Can't see the videos above? You can download the video using the links above, we recommend the <a href="http://www.videolan.org/vlc/">VideoLan Client</a> player for playing the downloaded files. <br> If you want in-browser playback, you might need to install <a href="http://xiph.org/quicktime/">XiphQT</a> (mac, safari) or <a href="http://xiph.org/dshow/">Xiph Directshow</a> (windows, IE). Alternately, you should be able to view this without downloading any plugins  under the <a href="http://www.mozilla.com/en-US/firefox/">Firefox</a>, or <a href="http://www.opera.com">Opera</a> browsers.</small>
@@ -74,16 +68,24 @@ You can view <a href="videos.html">more videos</a> from different program versio
 
 
 
-<h2> Sample datasets </h2>
-
-Some sample datasets are listed below, and whilst not very interesting can be used to understand the program's capabilites. If you have better looking datasets that you are willing to provide, please <a href="contact.html">let me know</a>.
+<h2> Sample Datasets </h2>
+<p>
+Some sample datasets are listed below, and whilst not very interesting can be used to understand the program's capabilities. If you have better looking datasets that you are willing to provide, please <a href="contact.html">let us know</a>.
 
 <!-- firefox tries to render the data as a page. Force the mime-type to override this.-->
 <ul>
-<li> <a href="sample-data/bcc-0.288-sim.pos" type="application/octet-stream">Simulated BCC crystal </a></li>
-<li> <a href="sample-data/BCT theta Al-Cu crystal-sim.pos" type="application/octet-stream">Simulated Al-Cu theta' crystal </a> (with <a href="sample-data/BCT theta Al-Cu crystal-sim.rng" type="application/octet-stream">range file</a>)</li>
-<li> <a href="sample-data/spatially-random.pos" type="application/octet-stream">Some spatially random data</a></li>
+
+<li> <a href="samples/bcc-0.288-sim.pos" type="application/octet-stream">Simulated BCC crystal </a></li>
+<li> <a href="samples/BCT theta Al-Cu crystal-sim.pos" type="application/octet-stream">Simulated Al-Cu theta' crystal </a> (with <a href="samples/BCT theta Al-Cu crystal-sim.rng" type="application/octet-stream">range file</a>)</li>
+<li> <a href="samples/spatially-random.pos" type="application/octet-stream">Some spatially random data</a></li>
+<li> <a href="https://cosmicweb.mse.iastate.edu/wiki/display/experiments/RHIT9990">Blast-resistant martensitic steel dataset R06_09990- .pos and .rrng files</a> External website.</li>
 </ul>
+</p>
+
+<h2> Programmer's Reference</h2>
+<p> 
+3Depict has <a href="doxygen/main.html">documentation</a> regarding the program structure available. This is automatically generated using the <a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a> "Doxyfile" in the source tarball. The documentation provides data such as call and inheritance diagrams, hyperlinked function declarations and descriptions, and provides a useful "first glance"  reference for working with the code. For a full program overview, try looking at the <a href="doxygen/classMainWindowFrame.html">MainWindowFrame class</a>.
+</p>
 
 
 <small>
diff --git a/docs/web/download.html b/docs/web/download.html
index 80d6bf6..e04aae3 100644
--- a/docs/web/download.html
+++ b/docs/web/download.html
@@ -20,7 +20,7 @@
 
 <div id="left">
 <div class="box">
-	<h2> Latest version: 0.0.6</h2>
+	<h2> Latest version: 0.0.13</h2>
 </div>
 
 <div class="box">
@@ -50,40 +50,48 @@ how</p>
 </ul>
 <h3><a name="Ubuntu"></a>Ubuntu </h3>
 <ul>
-  <li><a href="apt://3depict">Click to install</a> (Ubuntu 10.10 "Maverick" or later).  The application installs the <code>3depict</code> package securely from your <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Synaptic_%28software%29">package manager</a>. <br>
+  <li><a href="apt://3depict">Click to install</a> 
+	<ul>
+	<li>If you want a newer version, you can visit our <a href="https://launchpad.net/~tehuser/+archive/ppa">PPA</a>, or read more about PPAs <a href="https://help.ubuntu.com/community/PPA">here</a>  </li>
+	</ul>
   </li>
   
 </ul>
 <h3><a name="Fedoraredhat"></a>Fedora/redhat<br>
 </h3>
 <ul>
-  <li> Fedora 12 or later: Package can be installed securely using "Add/remove programs", or by entering the following command in the terminal: <code>yum install 3Depict</code></li></ul>
+  <li>  Package can be installed securely using "Add/remove programs", or by entering the following command in the terminal: <code>yum install 3Depict</code></li></ul>
 <h3><a name="Debian"></a>Debian</h3>
 <ul>
-  <li>Packages exist in <a href="http://packages.debian.org/sid/3depict">debian testing & unstable</a>. Use your package manger to install, either using a <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Synaptic_%28software%29">Graphical method</a>, or entering the command: <code>aptitude install 3depict</code> as administrator.</li>
+  <li>Use your package manger to install, either using a <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Synaptic_%28software%29">Graphical method</a>, or entering the command: <code>aptitude install 3depict</code> as an administrator.</li>
   
 </ul>
 <h3><a name="Mac_OS_X"></a>Mac OS X  </h3>
 <ul>
-  <li>10.6 "Snow Leopard" </li>
+      <li>10.7 "Lion" </li>
+      <ul>
+      <li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.13-mac10.7.5.pkg/download">64 bit Intel</a> <br>
+      </ul>
+    
+    </li>
+  <li>10.6 "Snow Leopard" (0.0.10) </li>
 	<ul>
-		<li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.6.dmg/download">32 bit Intel</a> <br>
+		<li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.10-mac10.6.dmg/download">32 bit Intel</a> <br>
 	</ul>
 
   </li>
-  <li>10.5 "Leopard"   : We lack the hardware to build for this platform, sorry.
-  </li>
   
 </ul>
-<h3><a name="Windows"></a>Windows</h3>
+<h3><a name="Windows"></a>Windows (0.0.11)</h3>
 <ul>
-  <li><a href="http://sourceforge.net/projects/threedepict/files/3Depict-0.0.6-win32.exe/download">32 Bit version</a> (works on 64 bit too, just slower)
+  <li><a href="http://sourceforge.net/projects/threedepict/files/3Depict-0.0.11-win32.exe/download">32 Bit version</a> (works on 64 bit too, just slower, and can't use as much RAM). XP Users - <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=13">Note</a>
   </li>
 </ul>
 <h3><a name="Other_systems"></a>Other systems</h3>
 <ul>
   <li>Binaries (executables) not available for your system, sorry. You
-will have to <a href="compiling.html">compile from source</a>. The current compressed source archive is <a href="http://sourceforge.net/projects/threedepict/files/0.0.6/3Depict-0.0.6.tar.gz/download">here</a>.</li>
+will have to <a href="compiling.html">compile from source</a>. The current compressed source archive is <a href="http://sourceforge.net/projects/threedepict/files/0.0.12/3Depict-0.0.12.tar.gz/download">3Depict 0.0.12</a>.</li> 
+   <li>Older releases are avaialable in both source and binary (excecutable) form from our <a href="https://sourceforge.net/projects/threedepict/files/">sourceforge files page</a>. </li>
 </ul>
 <br>
 </div>
diff --git a/docs/web/images/Screenshot.png b/docs/web/images/Screenshot.png
index e113b0c..4fda14a 100644
Binary files a/docs/web/images/Screenshot.png and b/docs/web/images/Screenshot.png differ
diff --git a/docs/web/index.html b/docs/web/index.html
index 3256484..adebc5b 100644
--- a/docs/web/index.html
+++ b/docs/web/index.html
@@ -26,7 +26,7 @@
 
 <div id="left">
 <div class="box">
-<h2> Latest version: 0.0.6</h2>
+<h2> Latest version: 0.0.13</h2>
 <p><a href="download.html">Download</a> the latest version of 3Depict for your platform</p>
 </div>
 <div class="box">
@@ -60,25 +60,21 @@ News:
 </h3>
 
 <ul>
-	<li><i>21st May. 2011: </i> 3Depict 0.0.6 <a href="download.html">released</a>.</li>
-	<li><i>12th May. 2011: </i> Please note that the clustering filter in 0.0.5 (latest) should not be used for quantitative purposes, due to errors in implementation. These errors have been resolved in the source, but will only appear in 0.0.6. <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=6">Read more</a> </a></li>
-	<li><i>11th Apr. 2011: </i> 3Depict 0.0.5 Mac OSX build has been re-uploaded to fix <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=5&p=13">performance and installer bugs</a></li>
-	<li><i>27th Mar. 2011: </i> 3Depict 0.0.5 <a href="download.html">released</a>.</li>	
-
+	<li><i>15th Apr. 2013: </i> 3Depict 0.0.13 windows installers <a href="download.html">uploaded</a>.</li>
+	<li><i>13th Apr. 2013: </i> 3Depict 0.0.13 mac OSX 10.7 ("Lion") <a href="download.html">uploaded</a>.</li>
+	<li><i>12th Apr. 2013: </i> 3Depict 0.0.13 source code uploaded</li>
+	
 	<li>Older news <a href="news.html">here</a>
 </ul>
 
 <h3>
-Changes in 0.0.6:
+New features in 0.0.13: 
 </h3>
 
 <ul>
-	<li>Text data file loading (experimental).</li>
-	<li>Rewritten refresh routines -- more advanced type-based topology analysis to determine minimum refresh set for significantly faster refreshes where caching is limited</li>
-	<li>Corrected cluster filter routines. Better scalability to large or dense cluster queries.</li>
-	<li>Noise transform</li>
-	<li>Camera locking</li>
-	<li>64 bit build for windows platform (currently pending)</li>
+	<li>Spherical composition profiles</li>
+	<li>1D "axial" distribution functions, for measuring inter-atomic distance profiles</li>
+	
 
 	<li> and more. Full details in the <a href="changelog.txt">Changelog</a></li>
 </ul>
@@ -143,7 +139,7 @@ RAM's worth of data at any time;
 <li>32 bit versions: <br/>
 	<ul>
 		<li>General: You can only access files up to 4GB in size.<br/></li>
-		<li>Windows:  You can only access up to 4GB of system RAM in
+		<li>Windows :  You can only access up to 4GB of system RAM in
 the application, <a href="http://msdn.microsoft.com/en-us/library/aa366778%28VS.85%29.aspx">regardless
 of how much you have </a><br/> 
 		</li>
diff --git a/docs/web/news.html b/docs/web/news.html
index eb73f1b..e016dff 100644
--- a/docs/web/news.html
+++ b/docs/web/news.html
@@ -30,12 +30,46 @@
 <div id="right">
 <h2> News Archive </h2>
 <p>
+<h3> 2012</h3>
 <ul>
+	<li><i>24 Nov. 2012: 0.0.12 released - the source code has been uploaded, with various platform builds to follow shortly. This release focussed on a new feature - filter animation, as well as improved stability and decreased resource consumption. As usual, check the <a href="changelog.txt">Changelog</a> for more info!</i></li>
+	<li><i>29 Oct. 2012: We are finalising the current code for release of 0.0.12 in ~6 weeks. We need people to test the program, do translation and provide feedback - if you can help out, please <a href="contact.html">contact us</a>!</i></li>
+	<li><i>20 Jul. 2012: We have received unconfirmed reports that some users on Windows XP may experience startup problems with 3Depict. If this affects you, please <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=13">report it</a>.</i></li>
+	<li><i>17th Jul. 2012: Windows and Mac 10.7 installers uploaded for 3Depict 0.0.11.</i></li>
+	<li><i>16th Jul. 2012: 3Depict 0.0.11 source code uploaded. Installers for various platforms (linux,mac,windows) to follow soon.</i></li>
+	<li><i>28th Jun. 2012: 3Depict 0.0.10 mac 10.6 (snow leopard) installer uploaded.</i></li>
+	<li><i>10th Apr. 2012: 3Depict 0.0.10 mac 10.7 (lion) installer uploaded.</i></li>
+	<li><i>1st Apr. 2012:</i> 3Depict 0.0.10 windows installer uploaded.</li>
+	<li><i>31st Mar. 2012:</i> 3Depict 0.0.10 source code uploaded. Builds for various platforms to follow. This version mostly is directed at bug fixes and improved program structure.</li>
+	<li><i>25th Mar. 2012:</i> We are close to releasing 0.0.10, and we would like to have better native language support - we have added French and Spanish using <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Translation_memory">translation memory</a>, but it still needs human review. If you can check translations in these languages - please consider doing so <a href="https://www.transifex.net/projects/p/3depict/">here</a>.</li>
+	<li><i>22nd Jan. 2012: </i> 0.0.9 Mac OS X 10.7 (Lion) installer <a href="download.html">uploaded</a>. </li>
+</ul>
+<h3> 2011</h3>
+<ul>
+	<li><i>21st Dec. 2011: </i> 0.0.9 Mac OS X 10.6 (Snow Leopard) installer <a href="download.html">uploaded</a>. For Ubuntu users, a <a href="https://help.ubuntu.com/community/PPA">PPA</a> is now <a href="https://launchpad.net/~tehuser/+archive/ppa">available</a>. </li>
+	<li><i>18th Dec. 2011: </i> 0.0.9 windows installer <a href="download.html">uploaded</a>.</li>
+	<li><i>18th Dec. 2011: </i> 3Depict 0.0.9 source <a href="download.html">uploaded</a> -- installers to follow shortly.</li>
+	<li><i>23th Oct. 2011: </i> Windows installer for 0.0.8 <a href="download.html">uploaded.</a></li>
+
+	<li><i>13th Oct. 2011: </i> Mac OS X 10.7 installer and source code for 0.0.8 <a href="download.html">uploaded.</a></li>
+	
+	<li><i>31st Jul. 2011: </i> Windows installer for 0.0.7 <a href="download.html">uploaded.</a></li>
+
+	<li><i>30th Jul. 2011: </i> 3Depict 0.0.7 source uploaded -- installers to be distributed shortly. We have added foreign translation support, so if you would like to <a href="https://www.transifex.net/projects/p/3depict/">translate the program</a> to your local language, please <a href="contact.html">contact us</a>.</li>
+	<li><i>17th Jun. 2011: </i> Problem with win32 installer fixed. If you use windows regularly, and would like to help out, we would appreciate testers.</li>
+	<li><i>21st May. 2011: </i> 3Depict 0.0.6 <a href="download.html">released</a>.</li>
+
+	<li><i>12th May. 2011: </i> Please note that the clustering filter in 0.0.5 (latest) should not be used for quantitative purposes, due to errors in implementation. These errors have been resolved in the source, but will only appear in 0.0.6. <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=6">Read more</a> </a></li>
+	<li><i>11th Apr. 2011: </i> 3Depict 0.0.5 Mac OSX build has been re-uploaded to fix <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=5&p=13">performance and installer bugs</a></li>
+	<li><i>27th Mar. 2011: </i> 3Depict 0.0.5 <a href="download.html">released</a>.</li>	
 	<li><i>20th Mar. 2011: </i> 3Depict 0.0.5 preview has been uploaded to the <a href="http://sourceforge.net/projects/threedepict/develop">mercurial repository</a> .</li>	
 	<li><i>2nd Feb. 2011: </i> 3Depict 0.0.4 for Mac OSX 10.6 (Snow leopard) uploaded.</li>
 	<li><i>24th Jan. 2011: </i> 3Depict 0.0.4 installers uploaded to the files section. Hop over to the <a href="download.html">downloads page</a> to grab a copy.</li>
 
 	<li><i>16th Jan. 2011: </i> 3Depict 0.0.4 preview has been uploaded to the <a href="http://sourceforge.net/projects/threedepict/develop">sourceforge mercurial repository</a>. If you are keen, you can <a href="compiling.html">compile</a> the new version from source to give it a test drive. If you find any bugs, please <a href="contact.html">report them</a></li>
+</ul>
+<h3> 2010</h3>
+<ul>
 	<li><i>29th Nov. 2010: </i> 3Depict 0.0.3 has been released, so why not <a href="download.html">download it</a>.  Note that state files are not compatible between the 0.0.x series.</li>
 </ul>
 </p>
diff --git a/docs/web/questions.html b/docs/web/questions.html
index 44cae61..d3c105b 100644
--- a/docs/web/questions.html
+++ b/docs/web/questions.html
@@ -40,16 +40,6 @@ You can help, even without programming; Alternately, if you know how to program
 <h1>Questions (and answers)
 </h1>
 <ul>
-  <li>Why did you write this program?</li>
-  <ul>
-    <li>I needed it to fill some needs that I could not find existing
-software to suit. I couldn't find a flexible point cloud + value
-analysis
-program that fitted my needs, so I built one. Seeing as I needed to do
-it quickly, free components were the order of the day.</li>
-  </ul>
-</ul>
-<ul>
   <li>Are there any instruction manuals?</li>
   <ul>
     <li>Yes, you can download one from the <a href="documentation.html">documentation
@@ -58,21 +48,40 @@ page.</a>
   </ul>
 </ul>
 <ul>
-  <li>Are there any screencasts</li>
+  <li>Are there any screencasts?</li>
   <ul>
     <li>Yes, you can also find them on the documentation page.</li>
   </ul>
 </ul>
 <ul>
+  <li>How do I pronounce the name, and where does it come from?</li>
+  <ul>
+	<li>We get this one more than we expected. It's pronounced separately as two words, "three", then the word "depict" (to draw or display), strung together. The name originated from "3D PoInt Cloud Tool". If you have a US accent, it sounds like <a href="questions/En-us-threedepict.ogg">this</a>.</li>
+	</ul>
+  </ul>
+</ul>
+<ul>
+  <li>I'm running Debian/Mint/Ubuntu, and getting a crash on startup: "Floating point exception"</li>
+  <ul>
+    <li>We left some strict debugging in for some of the deb packages, which converts a minor problem into a major one, but only on some machines (we are not sure why). To solve this, you need to update to 0.0.8 or later. We have <a href="https://launchpad.net/~tehuser/+archive/ppa">set up a PPA</a> for Ubuntu users.</li>
+  </ul>
+</ul>
+<ul>
+  <li>I'm running Mac OSX, and when trying to update to the new version, I get the error "A newer version of this software already exists on this disk"</li>
+  <ul>
+    <li>This was due to us not specifying a version number in some early releases. Go to spotlight, then type "terminal", and open Terminal.app. Now cut and paste the following command into the terminal to remove the old version data. <p><span style="font-family: monospace;">sudo rm /private/var/db/receipts/net.sourceforge.threedepict.3Depict.pkg.plist /private/var/db/receipts/net.sourceforge.3Depict.pkg.plist
+</span></p> don't forget to press enter. You will be prompted for your password for this action.</li>
+  </ul>
+</ul>
+
+<ul>
   <li>This project is terrible, it doesn't work! What can I do?</li>
   <ul>
-    <li>Try asking for support; it might be fixable.</li>
-    <li>Report a bug (complain). These will be prioritised to be fixed,
-if I can reproduce them. Remember that to solve the problem, I need to
-make the same problem happen on my computer, and if I can't then I
-might not be able to fix it.</li>
+    <li>Try <a href="contact.html">asking for support</a>; it might be fixable.</li>
+    <li>Report a bug (complain). These will be prioritised to be fixed, if I can reproduce them (get the same problem as you by trying to follow your report). Remember that to solve the problem, I need to make the same problem happen on my computer, and if I can't then I might not be able to fix it.</li>
   </ul>
 </ul>
+
 <ul>
   <li>This project is great, can I donate?</li>
   <ul>
@@ -86,12 +95,16 @@ motivation to keep working on it.</li>
     <ul>
       <li><a href="contact.html">Email the author</a> to say how this has helped you. If you are
 from an academic background, doing this in a formal manner is helpful
-too. </li>
+too.</li>
+
+    </ul>
+    <ul>
+      <li><a href="http://imagepaste.nullnetwork.net/">Upload a nice screenshot online</a>, then send us a link. </li>
       <li>Report bugs, or </li>
     </ul>
     <ul>
       <li>Work on something that the program needs, such as documentation, artwork,
-foreign language translation, web design or programming.</li>
+<a href="https://www.transifex.net/projects/p/3depict/">language translation</a>, web design or programming.</li>
       <li>If you need a particular feature, you could fund a project to
 develop it, either independantly, or by contacting the author. This
 could be quite expensive though, and would require some level of
@@ -102,41 +115,45 @@ computational skill and more importantly, familiarity with the code.</li>
 <ul>
   <li>This program doesn't do what I need -- can you still help me?</li>
   <ul>
-    <li>Maybe. </li>
+    <li>Maybe.</li>
     <ul>
-      <li>You can request a feature. I do not promise to get these
-things done, but you might find that it is quite easy to create a
-change.</li>
+      <li>You can request a feature through the forum or contact form. I do not promise to get these things done, but you might find that it is quite easy to create a change. Worst case scenario is that you lose a few minutes asking.</li>
     </ul>
     <ul>
-      <li>I might be able to propose a work around, or suggest
-alternate, or combinations of tools that can help. </li>
-      <li>If there are modules that might benefit the community, or you
-are using this for a specific academic need, it might be possible to
-construct a problem-specific solution</li>
+      <li>I might be able to propose a work around, or suggest alternate, or combinations of tools that can help. </li>
+      <li>If there are modules that might benefit the community, or you are using this for a specific academic need, it might be possible to construct a problem-specific solution</li>
     </ul>
-    <li>Just remember that there are many, many analysis tools out
-there. <br/>
+    <li>Just remember that there are many, many analysis tools out there. <br/>
     </li>
   </ul>
 </ul>
 <ul>
-  <li>How much does this program cost? How much did this program cost?</li>
+  <li>How much does this program cost? </li>
   <ul>
-    <li>Nothing. </li>
-    <li>Well, at 8 months development, 2 days a week that comes to about 50 days work, roughly 10 working weeks. At US$50k/year, that comes to about USD$12,800 equivalent cost. Software development is cheaper than you think, it is just that few people are willing to do it, and experience is only gained by trying. But no-one was paid for this work anyway, so the number is somewhat academic.<br/>
-</li>
+    <li>Nothing. If you paid for it, ask for your money back, and contact us.</li>
   </ul>
 </ul>
 <ul>
-</ul>
-<ul>
   <li>Is the program any good?</li>
   <ul>
     <li>I don't know. I'd like to think so. That's not for me to decide.</li>
   </ul>
 </ul>
 <ul>
+  <li>Why did you write this program?</li>
+  <ul>
+    <li>I needed it to fill some needs that I could not find existing software to suit. I couldn't find a flexible point cloud + value analysis program that fitted my needs, so I built one. Seeing as I needed to do it quickly, free components were the order of the day.</li>
+  </ul>
+</ul>
+
+<ul>
+  <li>I'm keen on doing programming and all that sort of stuff. How can I get started?</li>
+  <ul>
+	<li>Firstly, make sure you are familiar with C++ and compiling projects with multiple source files. Then, the best thing to do is to <a href="compiling.html">compile</a> the latest source code (.tar.gz file). This is by far the easiest under Linux, then Mac, and most difficult under windows, due to dependencies. If needed, you can run a <a href="http://www.virtualbox.org">virtual machine</a>. Now, once done, you can make your changes as you like - there is a section in the manual describing some of this process. Also, you can check out the generated <a href="doxygen/main.html">code documentation</a>, which has some nice graphical representations of the program structure. Also, feel free to drop a line in the forums, or via a contact form, so we can give you a help.</li>
+  </ul>
+</ul>
+
+<ul>
   <li>My question is not listed here.</li>
   <ul>
     <li>Can you put that in the form of a question? </li>
@@ -146,7 +163,7 @@ there. <br/>
   <li>What if my question is not listed here?</li>
   <ul>
     <li>Well,
-try to <a href="contact.html">contact the author</a>. These questions were written in a
+try to <a href="contact.html">contact the authors</a>. These questions were written in a
 speculative fashion, and are not technically "frequently asked".</li>
   </ul>
 </ul>
diff --git a/docs/web/rss.xml b/docs/web/rss.xml
index ec5dfd6..9c0d622 100644
--- a/docs/web/rss.xml
+++ b/docs/web/rss.xml
@@ -6,12 +6,93 @@
 	<title>3Depict releases</title>
 	<description>3Depict release data</description>
 	<link>http://threedepict.sourceforge.net/</link>
-	<lastBuildDate>Sat, 21 May 2011 00:00:00 +0000 </lastBuildDate>
-	<pubDate>Sat, 21 May 2011 00:00:00 +0000  </pubDate>
+	<lastBuildDate>Sat, 24 Nov 2012 00:00:00 +0000 </lastBuildDate>
+	<pubDate>Fri, 12 Apr 2013 00:00:00 +0000 </pubDate>
 
 	<item>
-		<title>3Depict 0.0.6</title>
-			<description>Tarball release notification for 3Depict 0.0.6</description>
+		<title>0.0.13</title>
+		<description>macosx10.7,source</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.13/3Depict-0.0.13.tar.gz/download</guid>
+		
+		<pubDate>Fri, 12 Apr 2013 00:00:00 +0000 </pubDate>
+	</item>
+
+
+	<item>
+		<title>0.0.12</title>
+		<description>macosx10.7,source</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.12/3Depict-0.0.12.tar.gz/download</guid>
+		
+		<pubDate>Sat, 24 Nov 2012 00:00:00 +0000 </pubDate>
+	</item>
+
+	<item>
+		<title>0.0.11</title>
+		<description>win32,macosx10.7,source</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.11/3Depict-0.0.11.tar.gz/download</guid>
+		
+		<pubDate>Wed, 18 Jul 2012 00:00:00 +0000 </pubDate>
+	</item>
+
+
+	<item>
+		<title>0.0.10</title>
+		<description>win32,source,macosx10.7,macosx10.6</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.10/3Depict-0.0.10.tar.gz/download</guid>
+		
+		<pubDate>Thu, 28 Jun 2012 00:00:00 +0000 </pubDate>
+	</item>
+
+
+	<item>
+		<title>0.0.9</title>
+		<description>win32,source,macosx10.7,macosx10.6</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.9/3Depict-0.0.9.tar.gz/download</guid>
+		
+		<pubDate>Sun, 18 Dec 2011 00:00:00 +0000 </pubDate>
+	</item>
+
+
+	<item>
+		<title>0.0.8</title>
+		<description>win32,macosx10.7,macosx10.6,source</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.8/3Depict-0.0.8.tar.gz/download</guid>
+		
+		<pubDate>Thu, 13 Oct 2011 00:00:00 +0000 </pubDate>
+	</item>
+
+	<item>
+		<title>0.0.7</title>
+			<description>win32,macosx10.6,source</description>
+
+
+			<link>http://threedepict.sourceforge.net/changelog.txt</link>
+			<guid>http://sourceforge.net/projects/threedepict/files/0.0.7/3Depict-0.0.7.tar.gz/download</guid>
+
+			<pubDate>Sat, 21 May 2011 00:00:00 +0000 </pubDate>
+	</item>
+
+	<item>
+		<title>0.0.6</title>
+			<description>win32,macosx10.6,source</description>
 
 
 			<link>http://threedepict.sourceforge.net/changelog.txt</link>
@@ -19,6 +100,7 @@
 
 			<pubDate>Sat, 21 May 2011 00:00:00 +0000 </pubDate>
 	</item>
+
 </channel>
 </rss>
 
diff --git a/locales/de_DE/LC_MESSAGES/3Depict.mo b/locales/de_DE/LC_MESSAGES/3Depict.mo
index 6a08e10..e9ff0b8 100644
Binary files a/locales/de_DE/LC_MESSAGES/3Depict.mo and b/locales/de_DE/LC_MESSAGES/3Depict.mo differ
diff --git a/packaging/RPM/3Depict-0.0.13-font-path.patch b/packaging/RPM/3Depict-0.0.14-font-path.patch
similarity index 100%
rename from packaging/RPM/3Depict-0.0.13-font-path.patch
rename to packaging/RPM/3Depict-0.0.14-font-path.patch
diff --git a/packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch b/packaging/RPM/3Depict-0.0.14-manual-pdf-loc.patch
similarity index 100%
rename from packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch
rename to packaging/RPM/3Depict-0.0.14-manual-pdf-loc.patch
diff --git a/packaging/RPM/3Depict.spec b/packaging/RPM/3Depict.spec
index 5c93838..0b4993b 100644
--- a/packaging/RPM/3Depict.spec
+++ b/packaging/RPM/3Depict.spec
@@ -1,5 +1,5 @@
 Name:		3Depict
-Version:	0.0.13
+Version:	0.0.14
 Release:	1%{?dist}
 Summary:	Valued 3D point cloud visualization and analysis
 Group:		Applications/Engineering
@@ -51,7 +51,7 @@ useful for general scalar valued point data purposes.
 %patch1
 
 %build
-%configure --disable-debug-checks --enable-openmp-parallel
+%configure --disable-debug-checks --enable-openmp-parallel --enable-mgl2
 make %{?_smp_mflags}
 
 %install
@@ -109,10 +109,16 @@ rm -rf %{buildroot}
 
 
 %changelog
-* Sun Mar 23 2013 D Haley <mycae(a!t)gmx.com> - 0.0.13-1
+* Sat Jul 6 2013 D Haley <mycae(a!t)gmx.com> - 0.0.14-1
+- Update to 0.0.14
+
+* Tue Jun 25 2013 D Haley <mycae(a!t)gmx.com> - 0.0.13-2
+- Enable mathgl2
+
+* Fri Apr 12 2013 D Haley <mycae(a!t)gmx.com> - 0.0.13-1
 - Update to 0.0.13
 
-* Sun Mar 23 2013 D Haley <mycae(a!t)gmx.com> - 0.0.12-4
+* Sat Mar 23 2013 D Haley <mycae(a!t)gmx.com> - 0.0.12-4
 - Add aarch 64 patch for bug 924960, until next version
 
 * Wed Feb 13 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.0.12-3
diff --git a/debian/3depict.install b/packaging/debian/3depict.install
similarity index 100%
copy from debian/3depict.install
copy to packaging/debian/3depict.install
diff --git a/packaging/debian/README.source b/packaging/debian/README.source
deleted file mode 100644
index 82fdda7..0000000
--- a/packaging/debian/README.source
+++ /dev/null
@@ -1,2 +0,0 @@
-Package uses quilt
-/usr/share/doc/quilt/README.source
diff --git a/packaging/debian/changelog b/packaging/debian/changelog
index e91f6a5..c0a216d 100644
--- a/packaging/debian/changelog
+++ b/packaging/debian/changelog
@@ -1,13 +1,43 @@
+3depict (0.0.14-1) UNRELEASED; urgency=low
+
+  * Update to upstream
+
+ -- D Haley <mycae at gmx.com>  Sat, 06 Jul 2013 11:13:02 +0200
+
+3depict (0.0.13-2) unstable; urgency=low
+
+  * Enable mathgl2.x configure option
+  * Modify build-depends, libmgl-dev >= 2.1.32
+
+ -- D Haley <mycae at gmx.com>  Sat, 15 Jun 2013 20:44:01 +0200
+
 3depict (0.0.13-1) unstable; urgency=low
 
+  * Upload to unstable 
+
+ -- D Haley <mycae at gmx.com>  Fri, 17 May 2013 00:52:39 +0200
+
+3depict (0.0.13-1~exp1) experimental; urgency=low
+
   * New upstream release
+  * Update maintainer email
+  * Remove README.source
+  * Update to compat level 9
+  * Set standards version to 3.9.4
+  * Drop DM-Upload-Allowed
+  * Update debian copyright to DEP5
+  * Drop debian/dirs
+  * Convert rules to use dh override_
+  * Add DEP3-headers to patches
+
 
- -- D Haley <mycae at yahoo.com>  Sat, 23 Mar 2013 16:06:15 +0100
+ -- D Haley <mycae at gmx.com>  Sat, 13 Apr 2013 02:06:15 +0200
 
 3depict (0.0.12-1) experimental; urgency=low
 
   [ D Haley ]
   * New upstream release
+  * upstream-post-0.0.12-fixes.patch: new patch taken from upstream
 
   [ Sylvestre Ledru ]
   * Standards-Version updated to version 3.9.3
diff --git a/packaging/debian/compat b/packaging/debian/compat
index 7f8f011..ec63514 100644
--- a/packaging/debian/compat
+++ b/packaging/debian/compat
@@ -1 +1 @@
-7
+9
diff --git a/packaging/debian/control b/packaging/debian/control
index cc57d68..8f5a643 100644
--- a/packaging/debian/control
+++ b/packaging/debian/control
@@ -2,13 +2,14 @@ Source: 3depict
 Section: science
 Priority: optional
 Maintainer: Debian Science Maintainers <debian-science-maintainers at lists.alioth.debian.org>
-Uploaders: D Haley <mycae at yahoo.com>
-DM-Upload-Allowed: yes
-Build-Depends: debhelper (>= 7), dpkg-dev (>= 1.16.1~), libgl1-mesa-dev | libgl-dev, libpng-dev | libpng15-dev, libqhull-dev, libwxgtk2.8-dev, libftgl-dev, autoconf, libxml2-dev, libmgl-dev, autotools-dev 
-Standards-Version: 3.9.3
+Uploaders: D Haley <mycae at gmx.com>
+Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), dh-autoreconf, libgl1-mesa-dev | libgl-dev, libpng-dev | libpng15-dev, libqhull-dev, libwxgtk2.8-dev, libftgl-dev, autoconf, libxml2-dev, libmgl-dev (>= 2.1.3.1), autotools-dev 
+Standards-Version: 3.9.4
 Homepage: http://threedepict.sourceforge.net/index.html
 Vcs-Git: git://git.debian.org/debian-science/packages/3depict.git
 Vcs-Browser: http://git.debian.org/?p=debian-science/packages/3depict.git
+XS-Testsuite: autopkgtest
+
 
 Package: 3depict
 Architecture: any
diff --git a/packaging/debian/copyright b/packaging/debian/copyright
index 2590f3e..1b4e28a 100644
--- a/packaging/debian/copyright
+++ b/packaging/debian/copyright
@@ -1,42 +1,58 @@
-This package was debianized by D Haley <mycae at yahoo.com> on
-Sat, 24 Jul 2010 23:23:50 +0100.
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: 3Depict
+Upstream: http://threedepict.sourceforge.net
+
+Files: *
+Copyright: 3Depict is Copyright (C) 2013 by D Haley.
+License: GPL-3+
+ On Debian systems the full text of the GNU General Public License v3 
+ can be found in the `/usr/share/common-licenses/GPL-3' file.
+
+Files: docs/manual-latex/manual.tex
+Copyright: Copyright (C) 2013 by D Haley.
+License: CC-BY-SA 3.0 
+ The work (as defined below) is provided under the terms of this creative
+ commons public license ("CCPL"; or "license"). The work is protected by
+ copyright and/or other applicable law. any use of the work other than as
+ authorized under this license or copyright law is prohibited.
+ By exercising any rights to the work provided here, you accept and agree
+ to be bound by the terms of this license. to the extent this license may
+ be considered to be a contract, the licensor grants you the rights
+ contained here in consideration of your acceptance of such terms and
+ conditions.
+
+Files: debian/*
+Copyright: Copyright 2013, D Haley <mycae gmx com>
+License: GPL-3+
+ On Debian systems the full text of the GNU General Public License v3 
+ can be found in the `/usr/share/common-licenses/GPL-3' file.
+
+Files:data/textures/*rrow*png data/textures/*rrow*svg data/textures/tex-source/*rrow*svg data/textures/*enlarge*png data/textures/tex-source/*enlarge.svg
+Copyright: Copyright 2006, Everaldo Coelho
+Source: https://commons.wikimedia.org/wiki/Crystal_clear
+License: LGPL-2+
+ On Debian systems the full text of the Lesser GNU General Public License
+ v2 can be found in the `/usr/share/common-licenses/LGPL-2' file.
+
+Files: data/textures/tex-source/*mouse.svg data/textures/*mouse*png
+Copyright: Copyright 2007, User:Darklama
+Source: https://commons.wikimedia.org/wiki/File:Left_clicked_mouse.svg
+License: GFDL-1.2
+ On Debian systems the full text of the GNU Free Documentation License
+ v1.2 can be found in the `/usr/share/common-licenses/GFDL-1.2' file.
+
+Files: data/textures/tex-source/*phere.svg data/textures/tex-source/*phere.png
+Copyright: Copyright 2003-2004, David Vignoni
+Source: www.icon-king.com/projects/nuvola//
+License: LGPL-2+
+ On Debian systems the full text of the Lesser GNU General Public License
+ v2 can be found in the `/usr/share/common-licenses/LGPL-2' file.
+
+Files: docs/web/style.css
+Copyright: Copyright 2006, Minamalistic-design
+Source: http://www.minimalistic-design.com/minimalistic.zip
+License: GPL-2+
+ On Debian systems the full text of the Lesser GNU General Public License
+ v2 can be found in the `/usr/share/common-licenses/LGPL-2' file.
 
-It was downloaded from <http://threedepict.sourceforge.net>
 
-Upstream Author(s):
-
-    D Haley <mycae at yahoo.com>
-
-Copyright:
-
-    Copyright (C) 2012 D. Haley
-
-License:
-
-    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 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
-    Library 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 St, Fifth Floor, Boston, MA 02110-1301,
-    USA.
-
-    On your Debian GNU/Linux system, a copy of the GNU GPLv3 can be found in
-    /usr/share/common-licenses/GPL-3
-
-The Debian packaging is:
-
-    Copyright (C) 2012 D Haley <mycae at yahoo.com>
-
-and is licensed under the GPL version 3 or any later version, 
-see `/usr/share/common-licenses/GPL-3'.
-
-Icons are covered by the GNU Free Documentation Licence, GFDL. For this
-licence, please see '/usr/share/common-licencses/GFDL'
diff --git a/packaging/debian/dirs b/packaging/debian/dirs
deleted file mode 100644
index 5673a50..0000000
--- a/packaging/debian/dirs
+++ /dev/null
@@ -1,4 +0,0 @@
-usr/bin
-usr/sbin
-usr/share/applications
-usr/share/3depict
diff --git a/packaging/debian/docs b/packaging/debian/docs
index ecd03c5..c17f037 100644
--- a/packaging/debian/docs
+++ b/packaging/debian/docs
@@ -2,4 +2,3 @@ AUTHORS
 NEWS
 README
 TODO
-COPYING
diff --git a/packaging/debian/patches/FTGL-lowercase.patch b/packaging/debian/patches/FTGL-lowercase.patch
index d515b67..2a92db1 100644
--- a/packaging/debian/patches/FTGL-lowercase.patch
+++ b/packaging/debian/patches/FTGL-lowercase.patch
@@ -1,13 +1,16 @@
-Index: 3depict-0.0.13/configure
+Description: Debian uses lowercase lib names.
+Forwarded: not-needed
+Author: D Haley <mycae - gmx - com>
+Index: 3depict-0.0.14/configure
 ===================================================================
---- 3depict-0.0.13.orig/configure	2013-03-23 17:54:40.000000000 +0100
-+++ 3depict-0.0.13/configure	2013-03-23 17:55:05.000000000 +0100
-@@ -5828,7 +5828,7 @@
+--- 3depict-0.0.14.orig/configure	2013-07-06 11:08:16.000000000 +0200
++++ 3depict-0.0.14/configure	2013-07-06 11:08:28.000000000 +0200
+@@ -5964,7 +5964,7 @@
  if test "x$ftgl_prefix" != "x" ; then
  	#use the supplied CFLAGS. assume LIBS
  	FTGL_CFLAGS="-I$ftgl_prefix/include/ -L$ftgl_prefix/lib/"
 -	FTGL_LIBS="-lFTGL"
 +	FTGL_LIBS="-lftgl"
  else
- 	if test "x$with_ftgl_no_pkg" = "xyes" ; then
  
+ 	HAVE_PKG=$(basename $(which pkg-config))
diff --git a/packaging/debian/patches/debian-desktop-naming.patch b/packaging/debian/patches/debian-desktop-naming.patch
index cd3e031..da1906d 100644
--- a/packaging/debian/patches/debian-desktop-naming.patch
+++ b/packaging/debian/patches/debian-desktop-naming.patch
@@ -1,4 +1,7 @@
-Debian packages are lowercase, but upstream uses uppercase "D"
+Description: Debian packages are lowercase, but upstream uses uppercase
+ "D"
+Forwarded: not-needed
+Author: D Haley <mycae - gmx - com>
 Index: 3depict-0.0.8/packaging/3Depict.desktop
 ===================================================================
 --- 3depict-0.0.8.orig/packaging/3Depict.desktop	2011-10-23 16:32:14.000000000 +0100
diff --git a/packaging/debian/patches/lowercase-textdomain.patch b/packaging/debian/patches/lowercase-textdomain.patch
index 7cac462..636eb24 100644
--- a/packaging/debian/patches/lowercase-textdomain.patch
+++ b/packaging/debian/patches/lowercase-textdomain.patch
@@ -1,9 +1,11 @@
-Debian uses different text domain for the lang files
-Index: 3depict-0.0.13/src/3Depict.cpp
+Description: Debian uses different text domain for the lang files
+Forwarded: not-needed
+Author: D Haley <mycae - gmx - com>
+Index: 3depict-0.0.14/src/3Depict.cpp
 ===================================================================
---- 3depict-0.0.13.orig/src/3Depict.cpp	2013-03-23 16:07:50.000000000 +0100
-+++ 3depict-0.0.13/src/3Depict.cpp	2013-03-23 16:08:54.000000000 +0100
-@@ -164,7 +164,7 @@
+--- 3depict-0.0.14.orig/src/3Depict.cpp	2013-07-06 11:08:20.000000000 +0200
++++ 3depict-0.0.14/src/3Depict.cpp	2013-07-06 11:08:25.000000000 +0200
+@@ -165,7 +165,7 @@
  		else
  		{
  			//Set the gettext language
@@ -12,7 +14,7 @@ Index: 3depict-0.0.13/src/3Depict.cpp
  			setlocale (LC_ALL, "");
  #ifdef __WXMAC__
  			bindtextdomain( PROGRAM_NAME, paths->GetResourcesDir().mb_str(wxConvUTF8) );
-@@ -196,8 +196,8 @@
+@@ -197,8 +197,8 @@
  					break;
  			}			
  #else
diff --git a/packaging/debian/rules b/packaging/debian/rules
index 503ff2d..bea47f7 100755
--- a/packaging/debian/rules
+++ b/packaging/debian/rules
@@ -1,130 +1,54 @@
 #!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
 
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
+%:
+	dh $@ --parallel
 
+override_dh_auto_configure: 
+	dh_auto_configure -- --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-openmp-parallel --disable-debug-checks --with-libpng-link="-lpng" --with-libpng-flags="-L/lib" --with-ftgl-prefix="/usr" --enable-mgl2
 
-# These are used for cross-compiling and for saving the configure script
-# from having to guess our platform (since we know it already)
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
-CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
-else
-CROSS= --build $(DEB_BUILD_GNU_TYPE)
-endif
 
-#Hardening
-DPKG_EXPORT_BUILDFLAGS = 1
-include /usr/share/dpkg/buildflags.mk
-
-
-config.status: configure
-	dh_testdir
-	#Compile package, disabling internal debug checking and enabling parallelism
-	./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-openmp-parallel --disable-debug-checks --with-libpng-link="-lpng" --with-libpng-flags="-L/lib" --with-ftgl-prefix="/usr"
-
-
-build: build-arch 
-
-build-arch: build-stamp
-
-build-stamp:  config.status 
-	dh_testdir
-
-	$(MAKE)
-
-	touch $@
-
-clean: 
+override_dh_clean:
 	dh_testdir
 	dh_testroot
 	rm -f build-stamp 
 
-	# Add here commands to clean up after the build process.
 	[ ! -f Makefile ] || $(MAKE) distclean
 	rm -f config.status config.cache
-	#Prevent quilt 3.0 from annoyingly convoluting config.log with a patch
+	#Prevent quilt 3.0 from annoyingly convoluting config.log with
+	#a patch
 	rm -f config.log
 
 	dh_clean 
 
-install: build
-	dh_testdir
-	dh_testroot
-	dh_prep  
-	dh_installdirs
-
-	# Add here commands to install the package into debian/3depict.
-	$(MAKE) DESTDIR=$(CURDIR)/debian/3depict install
-
-	#Install the textures
-	mkdir -p $(CURDIR)/debian/3depict/usr/share/3depict/textures/
-	cp -p data/textures/*png $(CURDIR)/debian/3depict/usr/share/3depict/textures/
 
+override_dh_auto_install: 
+	dh_auto_install
+	
 	#rename 3Depict (real program name) to debian-friendly 3depict
 	mv $(CURDIR)/debian/3depict/usr/bin/3Depict $(CURDIR)/debian/3depict/usr/bin/3depict
 
 	mkdir -p $(CURDIR)/debian/3depict/usr/share/doc/3depict/
-	echo "Copyright 2011 D Haley <mycae at yahoo.com>" > $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
+	echo "Copyright 2013 D Haley <mycae at yahoo.com>" > $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
 	echo "See /usr/share/common-licenses/GPL-1 for copyright info" >> $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
 
+	#Install files that cannot be handled by .install due to rename
+	#---
 	#Install .desktop file (for XFCE)
 	install -Dp -m 644 $(CURDIR)/packaging/3Depict.desktop $(CURDIR)/debian/3depict/usr/share/applications/3depict.desktop
 	#install icon (both SVG and XPM) into pixmaps
 	install -Dp -m 644 $(CURDIR)/data/3Depict.xpm $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.xpm
 	install -Dp -m 644 $(CURDIR)/data/textures/tex-source/3Depict-icon.svg $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.svg
+	#---
 	
 	#Install the pre-built locale files that are shipped with the tarball.
 	#translation sources (.po) files are in the translations/ folder.
-	
-	#remap a few locale names
+	#remap a few locale names as needed
+	#--
 	sh -c "mv locales/de_DE/ locales/de/"
 	mkdir -p $(CURDIR)/debian/3depict/usr/share/locale/
 	cp -R locales/* $(CURDIR)/debian/3depict/usr/share/locale/
 	#undo locale renaming
 	sh -c "mv locales/de/ locales/de_DE/"
-	
 	# convert installed 3Depict.mo files to lowercase	
 	find $(CURDIR)/debian/3depict/usr/share/locale/ -name 3Depict.mo | xargs rename 's/3Depict.mo/3depict.mo/'
-
-	#Install manual to 3depict dir
-	cp $(CURDIR)/docs/manual-latex/manual.pdf $(CURDIR)/debian/3depict/usr/share/3depict/
-
-	#delete some dirs that are generated.
-	rmdir $(CURDIR)/debian/3depict/usr/sbin
-
-
-# Build architecture-independent files here.
-binary-indep: install
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: install
-	dh_testdir
-	dh_testroot
-	dh_installchangelogs 
-	dh_install
-	dh_installmenu
-	dh_installman
-	dh_link
-	dh_strip
-	dh_compress
-	dh_fixperms
-	dh_installdeb
-	dh_shlibdeps
-	dh_gencontrol
-	dh_md5sums
-	dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 
-
-build-indep:
-
+	#--
diff --git a/packaging/debian/source/include-binaries b/packaging/debian/source/include-binaries
new file mode 100644
index 0000000..bb32417
--- /dev/null
+++ b/packaging/debian/source/include-binaries
@@ -0,0 +1 @@
+docs/manual-latex/manual.pdf 
diff --git a/packaging/debian/tests/control b/packaging/debian/tests/control
new file mode 100644
index 0000000..4a7d9b2
--- /dev/null
+++ b/packaging/debian/tests/control
@@ -0,0 +1,2 @@
+Tests: unittests
+
diff --git a/packaging/debian/tests/unittests b/packaging/debian/tests/unittests
new file mode 100755
index 0000000..4016e55
--- /dev/null
+++ b/packaging/debian/tests/unittests
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+CONFIGURE_PARAMS="--enable-mgl2"
+
+#apply all quilt patches, recording current status
+QUILT_APPLIED=`quilt applied`
+quilt push -a 
+
+#If manually running outside autopkgtest, then
+# just use /tmp
+if [ x"$ADTDMP" == x"" ] ; then
+	if [ x"$TMP" == x"" ] ; then
+		ADTDMP=/tmp/
+	else
+		ADTDMP=/tmp/
+	fi
+fi
+
+REBUILD_DIR=$ADTDMP/3depict-debug/
+
+#Go to top level dir
+#---
+TOP_LEVEL=` git rev-parse --show-toplevel`
+if [ $? -ne 0 ] ; then
+	$TOP_LEVEL=""
+else
+	pushd $TOP_LEVEL
+fi
+
+
+
+rm -rf $REBUILD_DIR || exit 1;
+mkdir  $REBUILD_DIR || exit 1;
+cp -R ./ $REBUILD_DIR 
+
+pushd $REBUILD_DIR
+
+#Rebuild program with debugging enabled.
+# Run tests in both single and multithreaded modes
+#----
+make clean ||  exit 1;
+./configure  $CONFIGURE_PARAMS ||  exit 1;   
+make -j2  ||  exit 1;
+./src/3Depict -t || exit 1; 
+
+make clean || exit 1;
+./configure $CONFIGURE_PARAMS --enable-openmp-parallel
+make -j2
+./src/3Depict -t || exit 1;
+make clean
+#----
+
+rm -rf $REBUILD_DIR/
+
+popd 
+
+#Restore patches to previous state
+quilt pop -a
+for i in $QUILT_APPLIED
+do
+	quilt push
+done
+
+if [ x"$TOP_LEVEL" != x"" ] ; then
+	popd
+fi
+
+
diff --git a/packaging/mac/3package.sh b/packaging/mac/3package.sh
index 89661f8..2e6c292 100755
--- a/packaging/mac/3package.sh
+++ b/packaging/mac/3package.sh
@@ -5,6 +5,7 @@ PROGRAM_NAME=3Depict
 cp makeMacOSXApp ../..
 cp -R ${PROGRAM_NAME}.app ../..
 cd ../..
+make distclean > out.txt 2>&1
 
 #Pull version number out of configure
 VERSION=`cat ./configure.ac | grep '^\s*AC_INIT(' | awk -F, '{ print $2 } ' | sed 's/\s*\[//' | sed 's/\]\s*//' | sed 's/\ //g'`
diff --git a/packaging/mac/makeMacOSXApp b/packaging/mac/makeMacOSXApp
index 938d0a1..69b58c2 100755
--- a/packaging/mac/makeMacOSXApp
+++ b/packaging/mac/makeMacOSXApp
@@ -38,14 +38,14 @@ fi
 
 echo "Updating .app bundle..."
 mkdir -p ./3Depict.app/Contents/MacOS/
-mkdir -p ./3Depict.app/Contents/Resources/
+mkdir -p ./3Depict.app/Contents/Resources/textures/
 mkdir -p ./3Depict.app/Contents/libs/
 cp ./src/3Depict ./3Depict.app/Contents/MacOS/3Depict
 cp data/textures/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources/3Depict-icon.icns
 touch ./3Depict.app/Contents/PkgInfo
 touch ./3Depict.app/Contents/info.plist
 #copy textures
-cp ./data/textures/* ./3Depict.app/Contents/Resources
+cp ./data/textures/* ./3Depict.app/Contents/Resources/textures/
 cp ./data/textures/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources
 
 
diff --git a/packaging/mingw-debian-cross/bootstrap.sh b/packaging/mingw-debian-cross/bootstrap.sh
index 0f20331..2088cd1 100755
--- a/packaging/mingw-debian-cross/bootstrap.sh
+++ b/packaging/mingw-debian-cross/bootstrap.sh
@@ -3,15 +3,52 @@
 #Script to bootstrap 3Depict cross-compilation under debian
 # and debian-like systems	
 # Note that building wx requires ~8GB of ram (or swap)
-BASE=`pwd`
-#HOST_VAL=x86_64-w64-mingw32 #For mingw64
-#HOST_VAL=i686-w64-mingw32
 
-if [ x$HOST_VAL = x"" ] ; then
-	echo "Please uncomment the right HOST_VAL for your system"
+#--- Determine which system we wish to build for
+#HOST_VAL=x86_64-w64-mingw32 #For mingw64 (windows 64 bit)
+#HOST_VAL=i686-w64-mingw32 #For mingw32 (Windows 32 bit)
+
+if [ ! -f host_val ] ; then
+	echo "Please select 32 or 64 bit by typing \"32\" or \"64\" (32/64)"
+	read HOST_VAL
+	
+	case $HOST_VAL in
+		32)
+			HOST_VAL="i686-w64-mingw32"
+			;;
+		64)
+			HOST_VAL="x86_64-w64-mingw32"
+			;;
+		
+		*) 
+			echo "Didn't understand HOST_VAL. You can override this by editing the script"
+			exit 1
+		;;
+	esac
+
+	#Save for next run
+	echo $HOST_VAL > host_val
+else
+	HOST_VAL=`cat host_val`
+fi
+
+
+if [ $HOST_VAL != "x86_64-w64-mingw32" ] && [ $HOST_VAL != i686-w64-mingw32 ] ; then
+	echo "Unknown HOST_VAL"
+	exit 1
+fi
+
+#----
+
+if [ ! -d code/3Depict ] || [ ! -f code/3Depict/src/3Depict.cpp ] ; then
+	echo "3Depict code dir, \"code/3Depict\", appears to be missing. Please place 3Depict source code in this location"
+	echo "Aborting"
 	exit 1
 fi
 
+
+DIST_NAME=""
+BASE=`pwd`
 PREFIX=/
 NUM_PROCS=4
 
@@ -24,13 +61,16 @@ if [ `id -u` -eq 0 ]; then
 fi
 #1) Filezilla wxwidgets patch for 64 bit support under mingw
 #2) own patch for fixing wx-config's lack of sysroot support
-PATCHES_WXWIDGETS_PRE="wxWidgets-2.8.12-mingw64-1.patch"
-PATCHES_WXWIDGETS_POST="wx-config-sysroot.patch"
+PATCHES_WXWIDGETS_PRE="wxwidgets2.8-2.8.12-mingw64-1.patch"
+PATCHES_WXWIDGETS_POST="wxwidgets2.8-wx-config-sysroot.patch"
+
+
+#Only required for 2.7.8
+PATCHES_LIBXML="libxml-impfree.patch"
 #1) Zlib no longer needs to explicitly link libc, and will fail if it tries
 PATCHES_ZLIB="zlib-no-lc.patch"
 #1) Override some configure patches to bypass false positive failures
-#2) mingw32 specific patch - mingw32 won't link with overridden prototypes
-PATCHES_FTGL="ftgl-override-configure ftgl-mingw32-prototype"
+PATCHES_FTGL="ftgl-override-configure"
 
 #1) gettext-tools fails in various places, but we don't actually need it, so turn it off
 #2) gettext fails to correctly determine windows function call prefix.
@@ -38,7 +78,9 @@ PATCHES_FTGL="ftgl-override-configure ftgl-mingw32-prototype"
 #   https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00071.html
 PATCHES_GETTEXT="gettext-disable-tools gettext-win32-prefix"
 
-PATCH_LIST="$PATCHES_WXWIDGETS_PRE $PATCHES_WXWIDGETS_POST $PATCHES_GSL $PATCHES_ZLIB $PATCHES_LIBPNG $PATCHES_GETTEXT $PATCHES_FTGL"
+PATCHES_GLEW="glew-makefile"
+
+PATCH_LIST="$PATCHES_WXWIDGETS_PRE $PATCHES_WXWIDGETS_POST $PATCHES_GSL $PATCHES_ZLIB $PATCHES_LIBPNG $PATCHES_GETTEXT $PATCHES_FTGL $PATCHES_GLEW $PATCHES_LIBXML"
 
 BUILD_STATUS_FILE="$BASE/build-status"
 PATCH_STATUS_FILE="$BASE/patch-status"
@@ -57,7 +99,7 @@ function applyPatches()
 {
 	for i in $APPLY_PATCH_ARG
 	do
-		if [ x`cat $PATCH_STATUS_FILE | grep "$i"` != x"" ] ; then
+		if [ x"`cat $PATCH_STATUS_FILE | grep "$i"`" != x"" ] ; then
 			echo "Patch already applied :" $i
 			continue
 		fi
@@ -76,41 +118,138 @@ function applyPatches()
 
 function install_mingw()
 {
-	echo "Requesting install of mingw :" $MINGW_PACKAGES
 
+	echo "Checking mingw install"
 	#install mingw and libtool (we will need it...)
-	sudo apt-get install $MINGW_PACKAGES libtool
 
-	if [ $? -ne 0] ; then
-		echo "Mingw installation failed".
-		exit 1
+	GET_PACKAGES="";
+	for i in $MINGW_PACKAGES
+	do
+		APT_RESULT=`LANG=C apt-cache policy $i | grep Installed | awk '{print $2}'`
+		if [ x"$APT_RESULT" == x"" ] ; then
+			echo "couldn't find package $i in sources, but we need it..." 
+			exit 1;
+		fi
+
+		if [ x"${APT_RESULT}" == x"(none)" ] ; then
+			GET_PACKAGES="$GET_PACKAGES $i";
+		fi
+	done
+
+	if [ x"$GET_PACKAGES" != x"" ] ; then
+		echo "Requesting install of mingw :" $GET_PACKAGES
+		sudo apt-get install $GET_PACKAGES libtool || { echo "Mingw install failed";  exit 1 ; }
 	fi
+
 }
 
 function grabDeps()
 {
 	pushd deps 2>/dev/null
-	DEB_PACKAGES="expat freetype ftgl gettext gsl libjpeg8 libpng libxml2 mathgl qhull tiff3 wxwidgets2.8 zlib nsis"
-	apt-get source $DEB_PACKAGES
 
-	if [ $? -ne 0 ] ; then
-		echo "apt-get source failed... Maybe check internet connection, then try updating package database, then re-run?"
-		exit 1
+	DEB_PACKAGES="expat freetype ftgl gettext gsl libpng libxml2 mathgl qhull tiff wxwidgets2.8 zlib glew"
+	if [ x$DIST_NAME == x"Ubuntu" ] || [ x$DIST_NAME == x"LinuxMint" ] ; then 
+		LIBJPEGNAME="libjpeg6b"
+	else
+		LIBJPEGNAME="libjpeg"
+	
 	fi
+	DEB_PACKAGES="$DEB_PACKAGES $LIBJPEGNAME"
+
+	GET_PACKAGES=""
+	for i in $DEB_PACKAGES
+	do
+		FNAME=`ls packages/${i}_*.orig.* 2> /dev/null`
+		#If filename is empty, we will need to retreive it from
+		# interwebs
+		if [ x"$FNAME" == x"" ] ; then
+			GET_PACKAGES="${GET_PACKAGES} $i"
+		fi
+	done
 
-	mv *.orig.* *.debian.* *.dsc *.diff.* packages 
+	#grab packages if they are not already on-disk
+	if [ x"$GET_PACKAGES" != x"" ] ; then
+		apt-get source $GET_PACKAGES
 
-	if [ ! -f libiconv-1.14.tar.gz ] ; then
-		wget "ftp://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz" || { echo "Libiconv download failed "; exit 1; }
-	else
-		if [ x`sha1sum libiconv-1.14.tar.gz | awk '{print $1}'` != x"be7d67e50d72ff067b2c0291311bc283add36965" ] ; then
-			echo "SHA1 sum mismatch for libiconv"
+		for i in $GET_PACKAGES
+		do
+			grep -v $i ../build-status > tmp
+			mv tmp ../build-status
+			
+			grep -v $i ../patch-status > tmp
+			mv tmp ../patch-status
+
+
+		done
+
+		if [ $? -ne 0 ] ; then
+			echo "apt-get source failed... Maybe check internet connection, then try updating package database, then re-run?"
 			exit 1
 		fi
 	fi
+
+	#Move debian stuff into packages folder
+	if [ x"$GET_PACKAGES" != x"" ] ; then
+		mv *.orig.* *.debian.* *.dsc *.diff.* packages 
+	fi
+
+	#Check that we have untarred all the required packages
+	# (eg we downloaded one, and wiped it at some stage)
+	# if not, pull the package out, and re-build it
+	GET_PACKAGES=""
+	for i in $DEB_PACKAGES
+	do
+		#if we have a package file (dsc), and no folder, add it to the list of packages
+		FNAME=`ls packages/$i*dsc 2> /dev/null` 
+		DNAME=`ls -ld $i* | grep ^d | awk '{print $NF}'`
+		if [ x"$FNAME" != x"" ] && [ x"$DNAME" == x""  ] ; then
+			GET_PACKAGES="${GET_PACKAGES} $i"
+		fi
+	done
+	
+	#Unpack pre-existing package
+	for i in $GET_PACKAGES
+	do
+		mv packages/$i*.* . || { echo "existing package extraction failed "; exit 1; } 
+		dpkg-source -x $i*dsc
+		#move package back
+		mv ${i}_*.* packages/
+		
+		#wipe record of any patches for this package
+		grep -v $i ../patch-status  > tmp
+		mv tmp ../patch-status
+		
+		#wipe record of build
+		grep -v $i ../build-status  > tmp
+		mv tmp ../build-status
+	done
+	
+	#extract libiconv if needed
+	#--
+	LIBICONV=libiconv-1.14
+	if [ ! -f packages/${LIBICONV}.tar.gz ] ; then
+		wget "http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz" || { echo "Libiconv download failed "; exit 1; }
+		mv ${LIBICONV}.tar.gz packages/
+	fi
+
+	#Check for SHA1 goodness
+	if [ x`sha1sum packages/${LIBICONV}.tar.gz | awk '{print $1}'` != x"be7d67e50d72ff067b2c0291311bc283add36965" ] ; then
+		echo "SHA1 sum mismatch for libiconv"
+		exit 1
+	fi
 	
-	tar -zxf libiconv-1.14.tar.gz || { echo "failed extracting iconv "; exit 1; }
+	#Extract
+	if [ ! -d ${LIBICONV} ] ; then
+		tar -zxf packages/${LIBICONV}.tar.gz || { echo "failed extracting iconv "; exit 1; }
+	fi	
 
+	#---
+	#We also need to install nsis, though it is not a strict "dependency" per-se.
+	if [ x`which makensis` == x"" ] ; then
+		echo "Installing nsis via apt-get";
+		sudo apt-get install nsis || { echo "Failed installation"; exit 1; }
+	fi
+	
 	
 	popd 2> /dev/null
 
@@ -135,7 +274,7 @@ function createBaseBinaries()
 	for i in g++ cpp gcc c++
 	do
 		#Skip existing links
-		if [ -f ${HOST_VAL}-$i ] ; then
+		if [ -f ${HOST_VAL}-$i ] || [ -L ${HOST_VAL}-$i ] ; then
 			continue;
 		fi
 
@@ -203,12 +342,50 @@ function build_zlib()
 
 	#Remove the static zlib. We don't want it
 	rm $BASE/lib/libz.a
+
 	popd >/dev/null
 	popd >/dev/null
 
 	echo "zlib" >> $BUILD_STATUS_FILE
 }
 
+function build_glew()
+{
+	ISBUILT_ARG="glew"
+	isBuilt
+	if [ $ISBUILT -eq 1 ] ; then
+		return;
+	fi
+
+	#Perform dynamic modification of patch
+	sed -i "s at HOST_VAL@$HOST_VAL@" patches/glew-makefile
+	sed -i "s at BASEDIR@$BASE@" patches/glew-makefile
+	
+	pushd deps >/dev/null
+	pushd glew-* >/dev/null
+
+
+	if [ $? -ne 0 ] ; then
+		echo "glew dir missing, or duplicated?"
+		exit 1
+	fi
+	
+	make clean
+	rm -f configure.log
+
+	APPLY_PATCH_ARG="$PATCHES_GLEW"
+	applyPatches
+
+	LD=$CC make -j $NUM_PROCS || { echo "glew build failed"; exit 1; } 
+
+	make install DESTDIR="$BASE"|| { echo "glew install failed"; exit 1; } 
+
+	popd >/dev/null
+	popd >/dev/null
+
+	echo "glew" >> $BUILD_STATUS_FILE
+}
+
 function build_libpng()
 {
 	ISBUILT_ARG="libpng"
@@ -284,15 +461,29 @@ function build_libxml2()
 	fi
 
 	pushd deps >/dev/null
+	LIBXMLVER=`ls -d libxml2-* | sed 's/libxml2-//'`
 	pushd libxml2-* >/dev/null
 	
 	if [ $? -ne 0 ] ; then
 		echo "libxml2 dir missing, or duplicated?"
 		exit 1
 	fi
+
+	#Libxml 2.8 and up doesn't need patching.
+	# note that --compare-versions returns 0 on truth, and 1 on false
+	dpkg --compare-versions  $LIBXMLVER lt 2.8
+	if [ $? -eq 0 ] ; then
+		echo "WARNING : Previous attempts to use libxml2 < 2.8 have failed."
+		echo " it is recommended to manually obtain the .dsc,.orig.tar.gz and .debian.tar.gz from"
+		echo " http://packages.debian.org/source/wheezy/libxml2 . download these, then replace the .dsc,.orig.tar.gz and .debian.tar.gz in deps/packages/"
+		exit 1
+	fi
+
 	make clean
 
-	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libxml2 configure failed"; exit 1; } 
+	#Modifications
+	#	Disable python, because sys/select.h is not in mingw
+	./configure --host=$HOST_VAL --without-python --without-html --without-http --without-ftp --without-push --without-writer --without-push --without-legacy --without-xpath --without-iconv  --enable-shared=yes --enable-static=no --prefix=/ || { echo "Libxml2 configure failed"; exit 1; } 
 
 	make -j $NUM_PROCS || { echo "libxml2 build failed"; exit 1; } 
 	
@@ -320,27 +511,28 @@ function build_libxml2()
 
 function build_libjpeg()
 {
-	NAME="libjpeg"
+		
+	NAME=$LIBJPEGNAME
 	ISBUILT_ARG=${NAME}
 	isBuilt
 	if [ $ISBUILT -eq 1 ] ; then
 		return;
 	fi
 	pushd deps >/dev/null
-	pushd libjpeg[0-9]*-* >/dev/null
+	pushd ${NAME}*[0-9]* >/dev/null
 	
 	if [ $? -ne 0 ] ; then
-		echo "libjpeg dir missing, or duplicated?"
+		echo "${NAME} dir missing, or duplicated?"
 		exit 1
 	fi
 
 	make clean
 
-	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libjpeg configure failed"; exit 1; } 
+	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "$NAME configure failed"; exit 1; } 
 
-	make -j $NUM_PROCS || { echo "libjpeg build failed"; exit 1; } 
+	make -j $NUM_PROCS || { echo "$NAME build failed"; exit 1; } 
 	
-	make install DESTDIR="$BASE"|| { echo "libjpeg install failed"; exit 1; } 
+	make install DESTDIR="$BASE"|| { echo "$NAME install failed"; exit 1; } 
 	
 	#DLL needs to be copied into lib manually
 	cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ 
@@ -348,7 +540,7 @@ function build_libjpeg()
 	popd >/dev/null
 	popd >/dev/null
 
-	FIX_LA_FILE_ARG=libjpeg
+	FIX_LA_FILE_ARG=$NAME
 	fix_la_file
 	echo ${NAME}  >> $BUILD_STATUS_FILE
 }
@@ -362,7 +554,7 @@ function build_libtiff()
 		return;
 	fi
 	pushd deps >/dev/null
-	pushd tiff[0-9]*-* >/dev/null
+	pushd tiff*[0-9]* >/dev/null
 	
 	if [ $? -ne 0 ] ; then
 		echo "libtiff dir missing, or duplicated?"
@@ -541,13 +733,13 @@ function build_wx()
 	PATCH_LEVEL=0
 	applyPatches
 	PATCH_LEVEL=1
+	sed -i "s at REPLACE_BASENAME@${BASE}@" wx-config || { echo "Failed to update wx-config with build root,. Aborting";  exit 1; }
 	popd
 
 	pushd ./lib/
 	ln -s wx-2.8/wx/ wx
 	popd
 
-	sed -i "s at REPLACE_BASENAME@${BASE}@" wx-config
 
 	echo ${NAME} >> $BUILD_STATUS_FILE
 
@@ -652,7 +844,7 @@ function build_gettext()
 	applyPatches
 	automake
 
-	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "gettext configure failed"; exit 1; } 
+	./configure --host=$HOST_VAL --disable-threads --enable-shared --disable-static --prefix=/ || { echo "gettext configure failed"; exit 1; } 
 
 	make -j $NUM_PROCS || { echo "gettext build failed"; exit 1; } 
 	
@@ -737,8 +929,8 @@ function build_ftgl()
 	sed -i s/'\-lGLU'/-lglu32/ configure
 	sed -i s/'\-lGL'/-lopengl32/ configure
 
-#	APPLY_PATCH_ARG="$PATCHES_FTGL"
-#	applyPatches
+	APPLY_PATCH_ARG="$PATCHES_FTGL"
+	applyPatches
 
 	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "ftgl configure failed"; exit 1; } 
 
@@ -822,22 +1014,86 @@ function checkHost()
 	done
 	
 	if [ x`which lsb_release` != x"" ] ; then
-		
+		#Possible results
+		# Debian, LinuxMint,Ubuntu,(others)
 		DIST_NAME=`lsb_release -i | awk -F: '{print $2}' | sed 's/\s//g'`
 		if [ x$DIST_NAME != x"Debian" ] ; then
 			echo "This is meant to target debian. I'm not sure if it will work on your system. You'll need to work that out."
+			echo "Sleeping for 4 seconds."
+			sleep 4
 		fi
 	fi
 	
 	echo "done"
 }
 
+#Build 3Depict
+function build_3Depict()
+{
+	pushd code/3Depict
+	make distclean
+
+
+	CONF_FLAG="--host=$HOST_VAL"
+	if [ $IS_RELEASE -ne 0 ] ; then
+		CONF_FLAG="$CONF_FLAG --disable-debug-checks"
+	fi
+
+	CFLAGS="$CFLAGS -DUNICODE" CPPFLAGS="${CPPFLAGS} -DUNICODE" ./configure  $CONF_FLAG
+
+	if [ $? -ne 0 ] ; then
+		echo "Failed 3Depict configure"
+		exit 1
+	fi
+
+	#HACK - strip all makefiles of -D_GLIBCXX_DEBUG
+	find ./ -name Makefile -exec sed -i 's/-D_GLIBCXX_DEBUG//g' {} \;
+
+	make -j$NUM_PROCS
+	if [ $? -ne 0 ] ; then
+		echo "Failed 3Depict build"
+		exit 1
+	fi
+
+	if [ $IS_RELEASE -ne 0 ] ; then
+		#Sanity check that we are actually in debug mode
+		TEST_FLAG=`./3Depict --help  2>&1 | grep "\-\-test"`
+		if [ x"$TEST_FLAG" != x"" ] ; then
+			echo "3Depict\'s Unit tests available, but should not be, when in release mode" 
+			exit 1
+		fi
+	fi
+
+
+	#if the locales are missing, try to rebuild them
+	if [ x`find locales/ -name \*.mo` = x""  ] ; then
+		
+		if [ x`which msgmerge` == x"" ] ; then
+			echo "Translations do not appear to be built for 3depict. Need to install translation builder, gettext."
+			sudo apt-get install gettext
+		fi
+		pushd translations
+		./makeTranslations || { echo "Translation build failed."; exit 1; }
+
+		mkdir -p ../locales/
+		for i in *.mo
+		do
+			TARGDIR=../locales/`echo $i | sed ' s/\.mo//' | sed 's/3Depict_//'`  
+			mkdir -p $TARGDIR
+			cp $i $TARGDIR/
+		done
+		popd
+	fi
+
+	popd > /dev/null
+}
+
 #Build the nsis package
 function make_package()
 {
 	pushd ./code/3Depict 2> /dev/null
 
-	NSI_FILE=./packaging/windows-installer/windows-installer.nsi
+	NSI_FILE=./packaging/mingw-debian-cross/windows-installer.nsi
 	if [ ! -f $NSI_FILE ] ; then
 		echo "NSI file missing whilst trying to build package"
 		exit 1;
@@ -847,7 +1103,7 @@ function make_package()
 	# Due to debian bug : #704828, makensis cannot correctly handle symlinks,
 	# so don't use symlinks
 	if [ ! -f `basename $NSI_FILE`  ] ; then
-		cp ./packaging/windows-installer/windows-installer.nsi .
+		cp ./packaging/mingw-debian-cross/windows-installer.nsi .
 	fi
 
 
@@ -881,45 +1137,25 @@ function make_package()
 
 	
 	if [ $IS_RELEASE -ne 0 ] ; then
-		pushd src/ 2> /dev/null
+		#Strip debugging information
+		pushd src/ > /dev/null
 		strip *.dll *.exe
-		popd 2> /dev/null
+		popd > /dev/null
 	fi
 
 
 	makensis `basename $NSI_FILE` ||  { echo "makensis failed" ; exit 1; }
-	
-	
-	popd
-}
-
-function make_3depict()
-{
-	cd code/3Depict
-	make distclean
-
-	if [ $IS_RELEASE -eq 1 ] ;  then
-		CONFIGURE_ARGS="--disable-debug-checks"
-	fi
-
-	CFLAGS="$CFLAGS -DUNICODE" CPPFLAGS="${CPPFLAGS} -DUNICODE" ./configure --host=$HOST_VAL $CONFIGURE_ARGS
-
-	if [ $? -ne 0 ] ; then
-		echo "Failed 3Depict configure"
-		exit 1
-	fi
-
-	#HACK - strip all makefiles of -D_GLIBCXX_DEBUG, even when not in release mode
-	# as a workaround for broken configure not handling debian bug 703935
-	if [ $IS_RELEASE -ne 1 ] ;  then
-		find ./ -name Makefile -exec sed -i 's/-D_GLIBCXX_DEBUG//g' {} \;
-	fi
 
-	make -j$NUM_PROCS
-	if [ $? -ne 0 ] ; then
-		echo "Failed 3Depict build"
-		exit 1
+	if [ $IS_RELEASE -ne 0 ] ; then
+		VERSION=`cat $NSI_FILE | grep "define PRODUCT_VERSION " | awk '{print $3}' | sed s/\"//g | sed s/.$//`
+		TARGET_FILE=3Depict-$VERSION-$HOST_EXT.exe
+		mv Setup.exe  $TARGET_FILE
+		echo "-------------------"
+		echo "File written to : `pwd`/$TARGET_FILE"
+		echo "-------------------"
 	fi
+	
+	popd > /dev/null
 }
 
 #Check that we have a suitable host system
@@ -931,28 +1167,39 @@ checkPatchesExist
 #build the dirs we need
 createDirLayout
 
-#Create the binaries we need
-createBaseBinaries
-
-#Obtain the needed dependencies
-grabDeps
 
 #Install cross compiler
-case echo ${HOST_VAL} 
-	
+#---
+case ${HOST_VAL}  in
 	x86_64-w64-mingw32)
-		MINGW_PACKAGES="gcc-mingw32"
+		if [ $DIST_NAME == "Ubuntu" ] || [ $DIST_NAME == "LinuxMint" ] ; then
+			MINGW_PACKAGES="mingw-w64-dev g++-mingw-w64-x86-64"
+		else
+			MINGW_PACKAGES="mingw-w64-x86-64-dev g++-mingw-w64-x86-64"
+		fi
+		HOST_EXT="win64"
 	;;
-	HOST_VAL=i686-w64-mingw32)
-		MINGW_PACKAGES="mingw-w64-x86-64-dev g++-mingw-w64-x86-64"
+	i686-w64-mingw32)
+		MINGW_PACKAGES="gcc-mingw32"
+		HOST_EXT="win32"
 	;;
 	*)
-	echo "Unknown host... please install deps manually,or alter script"
-	return
+		echo "Unknown host... please install deps manually,or alter script"
+		exit 1	
 	;;
 esac
 
+#install the compiler
 install_mingw
+#---
+
+#Create the binaries we need
+createBaseBinaries
+
+#Obtain the needed dependencies
+grabDeps
+
+
 
 #set our needed environment variables
 PATH=${BASE}/bin/:/usr/$HOST_VAL/bin/:$PATH
@@ -981,8 +1228,9 @@ build_libiconv
 build_gettext 
 build_mathgl 
 build_ftgl 
+build_glew
 
-
+build_3Depict
 
 make_package
 
diff --git a/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype b/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype
index ef16b80..eccc5ef 100644
--- a/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype
+++ b/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype
@@ -1,5 +1,5 @@
---- configure	2013-04-06 23:46:42.000000000 +0200
-+++ /home/builder/mingw-debian-cross/deps/ftgl-2.1.3~rc5/configure	2013-03-24 15:08:57.000000000 +0100
+--- a/configure	2013-04-06 23:46:42.000000000 +0200
++++ b/configure	2013-03-24 15:08:57.000000000 +0100
 @@ -22541,12 +22541,15 @@
  /* Override any GCC internal prototype to avoid an error.
     Use char because int might match the return type of a GCC
diff --git a/packaging/mingw-debian-cross/patches/ftgl-override-configure b/packaging/mingw-debian-cross/patches/ftgl-override-configure
new file mode 100644
index 0000000..a24021a
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/ftgl-override-configure
@@ -0,0 +1,63 @@
+--- a/configure	2013-02-24 18:53:11.000000000 +0100
++++ b/configure	2013-02-23 13:07:55.000000000 +0100
+@@ -22481,7 +22481,6 @@
+ int
+ main ()
+ {
+-glBegin(GL_POINTS)
+   ;
+   return 0;
+ }
+@@ -22544,11 +22543,10 @@
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+-char glBegin ();
+-int
++#include <GL/gl.h>
++	int
+ main ()
+ {
+-return glBegin ();
+   ;
+   return 0;
+ }
+@@ -22597,11 +22595,10 @@
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+-char glBegin ();
++#include <GL/gl.h>
+ int
+ main ()
+ {
+-return glBegin ();
+   ;
+   return 0;
+ }
+@@ -23014,11 +23011,10 @@
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+-char gluNewTess ();
+-int
++#include <GL/glu.h>
++	int
+ main ()
+ {
+-return gluNewTess ();
+   ;
+   return 0;
+ }
+@@ -23067,11 +23063,9 @@
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+-char gluNewTess ();
+ int
+ main ()
+ {
+-return gluNewTess ();
+   ;
+   return 0;
+ }
diff --git a/packaging/mingw-debian-cross/patches/gettext-disable-tools b/packaging/mingw-debian-cross/patches/gettext-disable-tools
new file mode 100644
index 0000000..50b125d
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/gettext-disable-tools
@@ -0,0 +1,170 @@
+diff -r 39dc3bef2ec7 Makefile.am
+--- a/Makefile.am	Sun Feb 24 17:55:28 2013 +0100
++++ b/Makefile.am	Sun Feb 24 18:10:24 2013 +0100
+@@ -20,7 +20,7 @@
+ ACLOCAL = build-aux/fixaclocal @ACLOCAL@
+ ACLOCAL_AMFLAGS = -I m4
+ 
+-SUBDIRS = gnulib-local gettext-runtime gettext-tools
++SUBDIRS = gnulib-local gettext-runtime
+ 
+ EXTRA_DIST = \
+   version.sh DEPENDENCIES PACKAGING HACKING ChangeLog.0 autogen.sh \
+@@ -29,71 +29,17 @@
+   m4/libtool.m4
+ 
+ # Additional dependencies for configure, due to the use of autoconf --trace.
+-$(srcdir)/configure: $(srcdir)/gettext-runtime/configure.ac $(srcdir)/gettext-tools/configure.ac 
++$(srcdir)/configure: $(srcdir)/gettext-runtime/configure.ac 
+ 
+ # Verify that some files are the same.
+ distcheck-hook:
+-	cmp -s gettext-runtime/po/Makefile.in.in gettext-tools/po/Makefile.in.in
+-	cmp -s gettext-runtime/po/Rules-quot gettext-tools/po/Rules-quot
+-	cmp -s gettext-runtime/po/boldquot.sed gettext-tools/po/boldquot.sed
+-	cmp -s gettext-runtime/po/quot.sed gettext-tools/po/quot.sed
+-	cmp -s gettext-runtime/po/en at quot.header gettext-tools/po/en at quot.header
+-	cmp -s gettext-runtime/po/en at boldquot.header gettext-tools/po/en at boldquot.header
+-	cmp -s gettext-runtime/po/insert-header.sin gettext-tools/po/insert-header.sin
+-	cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/po/remove-potcdate.sin
+-	cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/examples/po/remove-potcdate.sin
+-	cmp -s gettext-runtime/m4/codeset.m4 gettext-tools/gnulib-m4/codeset.m4
+-	cmp -s gettext-runtime/m4/fcntl-o.m4 gettext-tools/gnulib-m4/fcntl-o.m4
+-	cmp -s gettext-runtime/m4/gettext.m4 gettext-tools/gnulib-m4/gettext.m4
+-	cmp -s gettext-runtime/m4/glibc2.m4 gettext-tools/gnulib-m4/glibc2.m4
+-	cmp -s gettext-runtime/m4/glibc21.m4 gettext-tools/gnulib-m4/glibc21.m4
+-	cmp -s gettext-runtime/m4/iconv.m4 gettext-tools/gnulib-m4/iconv.m4
+-	cmp -s gettext-runtime/m4/intdiv0.m4 gettext-tools/gnulib-m4/intdiv0.m4
+-	cmp -s gettext-runtime/m4/intl.m4 gettext-tools/gnulib-m4/intl.m4
+-	cmp -s gettext-runtime/m4/intldir.m4 gettext-tools/gnulib-m4/intldir.m4
+-	cmp -s gettext-runtime/m4/intlmacosx.m4 gettext-tools/gnulib-m4/intlmacosx.m4
+-	cmp -s gettext-runtime/m4/intmax.m4 gettext-tools/gnulib-m4/intmax.m4
+-	cmp -s gettext-runtime/m4/inttypes-pri.m4 gettext-tools/gnulib-m4/inttypes-pri.m4
+-	cmp -s gettext-runtime/m4/inttypes_h.m4 gettext-tools/gnulib-m4/inttypes_h.m4
+-	cmp -s gettext-runtime/m4/lcmessage.m4 gettext-tools/gnulib-m4/lcmessage.m4
+-	cmp -s gettext-runtime/m4/lock.m4 gettext-tools/gnulib-m4/lock.m4
+-	cmp -s gettext-runtime/m4/longlong.m4 gettext-tools/gnulib-m4/longlong.m4
+-	cmp -s gettext-runtime/m4/nls.m4 gettext-tools/gnulib-m4/nls.m4
+-	cmp -s gettext-runtime/m4/po.m4 gettext-tools/gnulib-m4/po.m4
+-	cmp -s gettext-runtime/m4/printf-posix.m4 gettext-tools/gnulib-m4/printf-posix.m4
+-	cmp -s gettext-runtime/m4/progtest.m4 gettext-tools/gnulib-m4/progtest.m4
+-	cmp -s gettext-runtime/m4/size_max.m4 gettext-tools/gnulib-m4/size_max.m4
+-	cmp -s gettext-runtime/m4/stdint_h.m4 gettext-tools/gnulib-m4/stdint_h.m4
+-	cmp -s gettext-runtime/m4/threadlib.m4 gettext-tools/gnulib-m4/threadlib.m4
+-	cmp -s gettext-runtime/m4/uintmax_t.m4 gettext-tools/gnulib-m4/uintmax_t.m4
+-	cmp -s gettext-runtime/m4/visibility.m4 gettext-tools/gnulib-m4/visibility.m4
+-	cmp -s gettext-runtime/m4/wchar_t.m4 gettext-tools/gnulib-m4/wchar_t.m4
+-	cmp -s gettext-runtime/m4/wint_t.m4 gettext-tools/gnulib-m4/wint_t.m4
+-	cmp -s gettext-runtime/m4/xsize.m4 gettext-tools/gnulib-m4/xsize.m4
+-	test "`sed 1,19d gettext-runtime/intl/config.charset | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/config.charset | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/localcharset.h | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localcharset.h | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/localcharset.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localcharset.c | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/localename.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localename.c | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/lock.h | md5sum`" = "`sed 1,16d gettext-tools/gnulib-lib/glthread/lock.h | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/lock.c | md5sum`" = "`sed -e 1,16d -e 's,glthread/,,g' gettext-tools/gnulib-lib/glthread/lock.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/printf-args.h gettext-runtime/libasprintf/printf-args.h
+ 	cmp -s gettext-runtime/intl/printf-args.c gettext-runtime/libasprintf/printf-args.c
+ 	cmp -s gettext-runtime/intl/printf-parse.h gettext-runtime/libasprintf/printf-parse.h
+ 	cmp -s gettext-runtime/intl/printf-parse.c gettext-runtime/libasprintf/printf-parse.c
+-	test "`sed 1,18d gettext-runtime/intl/ref-add.sin | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/ref-add.sin | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/ref-del.sin | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/ref-del.sin | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/relocatable.h | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/relocatable.h | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/relocatable.c | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/relocatable.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/vasnprintf.h gettext-runtime/libasprintf/vasnprintf.h
+-	test "`sed 1,18d gettext-runtime/intl/vasnprintf.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/vasnprintf.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/vasnprintf.c gettext-runtime/libasprintf/vasnprintf.c
+ 	cmp -s gettext-runtime/intl/xsize.h gettext-runtime/libasprintf/xsize.h
+-	test "`sed 1,18d gettext-runtime/intl/xsize.h | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/xsize.h | md5sum`"
+-	cmp -s gettext-runtime/man/help2man gettext-tools/man/help2man
+-	cmp -s gettext-runtime/man/x-to-1.in gettext-tools/man/x-to-1.in
+-	cmp -s gettext-runtime/libasprintf/texi2html gettext-tools/doc/texi2html
+-	cmp -s gettext-tools/examples/hello-java-awt/m4/TestAWT.java gettext-tools/examples/hello-java-swing/m4/TestAWT.java
+-	cmp -s gettext-tools/examples/hello-java-awt/m4/TestAWT.class gettext-tools/examples/hello-java-swing/m4/TestAWT.class
+ 	test "`sed 1,15d gnulib-local/lib/alloca.in.h | md5sum`" = "`sed 1,15d gettext-runtime/libasprintf/alloca.in.h | md5sum`"
+ 
+ # DJGPP port.
+diff -r eacf36bf5209 Makefile.in
+--- a/Makefile.in	Sun Feb 24 18:15:10 2013 +0100
++++ b/Makefile.in	Sun Feb 24 18:26:17 2013 +0100
+@@ -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.
+ 
+@@ -697,71 +697,17 @@
+ 
+ 
+ # Additional dependencies for configure, due to the use of autoconf --trace.
+-$(srcdir)/configure: $(srcdir)/gettext-runtime/configure.ac $(srcdir)/gettext-tools/configure.ac 
++$(srcdir)/configure: $(srcdir)/gettext-runtime/configure.ac 
+ 
+ # Verify that some files are the same.
+ distcheck-hook:
+-	cmp -s gettext-runtime/po/Makefile.in.in gettext-tools/po/Makefile.in.in
+-	cmp -s gettext-runtime/po/Rules-quot gettext-tools/po/Rules-quot
+-	cmp -s gettext-runtime/po/boldquot.sed gettext-tools/po/boldquot.sed
+-	cmp -s gettext-runtime/po/quot.sed gettext-tools/po/quot.sed
+-	cmp -s gettext-runtime/po/en at quot.header gettext-tools/po/en at quot.header
+-	cmp -s gettext-runtime/po/en at boldquot.header gettext-tools/po/en at boldquot.header
+-	cmp -s gettext-runtime/po/insert-header.sin gettext-tools/po/insert-header.sin
+-	cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/po/remove-potcdate.sin
+-	cmp -s gettext-runtime/po/remove-potcdate.sin gettext-tools/examples/po/remove-potcdate.sin
+-	cmp -s gettext-runtime/m4/codeset.m4 gettext-tools/gnulib-m4/codeset.m4
+-	cmp -s gettext-runtime/m4/fcntl-o.m4 gettext-tools/gnulib-m4/fcntl-o.m4
+-	cmp -s gettext-runtime/m4/gettext.m4 gettext-tools/gnulib-m4/gettext.m4
+-	cmp -s gettext-runtime/m4/glibc2.m4 gettext-tools/gnulib-m4/glibc2.m4
+-	cmp -s gettext-runtime/m4/glibc21.m4 gettext-tools/gnulib-m4/glibc21.m4
+-	cmp -s gettext-runtime/m4/iconv.m4 gettext-tools/gnulib-m4/iconv.m4
+-	cmp -s gettext-runtime/m4/intdiv0.m4 gettext-tools/gnulib-m4/intdiv0.m4
+-	cmp -s gettext-runtime/m4/intl.m4 gettext-tools/gnulib-m4/intl.m4
+-	cmp -s gettext-runtime/m4/intldir.m4 gettext-tools/gnulib-m4/intldir.m4
+-	cmp -s gettext-runtime/m4/intlmacosx.m4 gettext-tools/gnulib-m4/intlmacosx.m4
+-	cmp -s gettext-runtime/m4/intmax.m4 gettext-tools/gnulib-m4/intmax.m4
+-	cmp -s gettext-runtime/m4/inttypes-pri.m4 gettext-tools/gnulib-m4/inttypes-pri.m4
+-	cmp -s gettext-runtime/m4/inttypes_h.m4 gettext-tools/gnulib-m4/inttypes_h.m4
+-	cmp -s gettext-runtime/m4/lcmessage.m4 gettext-tools/gnulib-m4/lcmessage.m4
+-	cmp -s gettext-runtime/m4/lock.m4 gettext-tools/gnulib-m4/lock.m4
+-	cmp -s gettext-runtime/m4/longlong.m4 gettext-tools/gnulib-m4/longlong.m4
+-	cmp -s gettext-runtime/m4/nls.m4 gettext-tools/gnulib-m4/nls.m4
+-	cmp -s gettext-runtime/m4/po.m4 gettext-tools/gnulib-m4/po.m4
+-	cmp -s gettext-runtime/m4/printf-posix.m4 gettext-tools/gnulib-m4/printf-posix.m4
+-	cmp -s gettext-runtime/m4/progtest.m4 gettext-tools/gnulib-m4/progtest.m4
+-	cmp -s gettext-runtime/m4/size_max.m4 gettext-tools/gnulib-m4/size_max.m4
+-	cmp -s gettext-runtime/m4/stdint_h.m4 gettext-tools/gnulib-m4/stdint_h.m4
+-	cmp -s gettext-runtime/m4/threadlib.m4 gettext-tools/gnulib-m4/threadlib.m4
+-	cmp -s gettext-runtime/m4/uintmax_t.m4 gettext-tools/gnulib-m4/uintmax_t.m4
+-	cmp -s gettext-runtime/m4/visibility.m4 gettext-tools/gnulib-m4/visibility.m4
+-	cmp -s gettext-runtime/m4/wchar_t.m4 gettext-tools/gnulib-m4/wchar_t.m4
+-	cmp -s gettext-runtime/m4/wint_t.m4 gettext-tools/gnulib-m4/wint_t.m4
+-	cmp -s gettext-runtime/m4/xsize.m4 gettext-tools/gnulib-m4/xsize.m4
+-	test "`sed 1,19d gettext-runtime/intl/config.charset | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/config.charset | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/localcharset.h | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localcharset.h | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/localcharset.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localcharset.c | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/localename.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/localename.c | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/lock.h | md5sum`" = "`sed 1,16d gettext-tools/gnulib-lib/glthread/lock.h | md5sum`"
+-	test "`sed 1,17d gettext-runtime/intl/lock.c | md5sum`" = "`sed -e 1,16d -e 's,glthread/,,g' gettext-tools/gnulib-lib/glthread/lock.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/printf-args.h gettext-runtime/libasprintf/printf-args.h
+ 	cmp -s gettext-runtime/intl/printf-args.c gettext-runtime/libasprintf/printf-args.c
+ 	cmp -s gettext-runtime/intl/printf-parse.h gettext-runtime/libasprintf/printf-parse.h
+ 	cmp -s gettext-runtime/intl/printf-parse.c gettext-runtime/libasprintf/printf-parse.c
+-	test "`sed 1,18d gettext-runtime/intl/ref-add.sin | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/ref-add.sin | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/ref-del.sin | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/ref-del.sin | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/relocatable.h | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/relocatable.h | md5sum`"
+-	test "`sed 1,18d gettext-runtime/intl/relocatable.c | md5sum`" = "`sed 1,18d gettext-tools/gnulib-lib/relocatable.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/vasnprintf.h gettext-runtime/libasprintf/vasnprintf.h
+-	test "`sed 1,18d gettext-runtime/intl/vasnprintf.c | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/vasnprintf.c | md5sum`"
+ 	cmp -s gettext-runtime/intl/vasnprintf.c gettext-runtime/libasprintf/vasnprintf.c
+ 	cmp -s gettext-runtime/intl/xsize.h gettext-runtime/libasprintf/xsize.h
+-	test "`sed 1,18d gettext-runtime/intl/xsize.h | md5sum`" = "`sed 1,17d gettext-tools/gnulib-lib/xsize.h | md5sum`"
+-	cmp -s gettext-runtime/man/help2man gettext-tools/man/help2man
+-	cmp -s gettext-runtime/man/x-to-1.in gettext-tools/man/x-to-1.in
+-	cmp -s gettext-runtime/libasprintf/texi2html gettext-tools/doc/texi2html
+-	cmp -s gettext-tools/examples/hello-java-awt/m4/TestAWT.java gettext-tools/examples/hello-java-swing/m4/TestAWT.java
+-	cmp -s gettext-tools/examples/hello-java-awt/m4/TestAWT.class gettext-tools/examples/hello-java-swing/m4/TestAWT.class
+ 	test "`sed 1,15d gnulib-local/lib/alloca.in.h | md5sum`" = "`sed 1,15d gettext-runtime/libasprintf/alloca.in.h | md5sum`"
+ 
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/packaging/mingw-debian-cross/patches/gettext-win32-prefix b/packaging/mingw-debian-cross/patches/gettext-win32-prefix
new file mode 100644
index 0000000..6761562
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/gettext-win32-prefix
@@ -0,0 +1,70 @@
+diff -r 39dc3bef2ec7 gettext-runtime/configure.ac
+--- a/gettext-runtime/configure.ac	Sun Feb 24 17:55:28 2013 +0100
++++ b/gettext-runtime/configure.ac	Sun Feb 24 17:57:12 2013 +0100
+@@ -106,6 +106,35 @@
+ #endif
+ ])
+ 
++dnl Compilation on mingw and Cygwin needs special Makefile rules, because
++dnl 1. when we install a shared library, we must arrange to export
++dnl    auxiliary pointer variables for every exported variable,
++dnl 2. when we install a shared library and a static library simultaneously,
++dnl    the include file specifies __declspec(dllimport) and therefore we
++dnl    must arrange to define the auxiliary pointer variables for the
++dnl    exported variables _also_ in the static library.
++if test "$enable_shared" = yes; then
++  case "$host_os" in
++    mingw* | cygwin*) is_woe32dll=yes ;;
++    *) is_woe32dll=no ;;
++  esac
++else
++  is_woe32dll=no
++fi
++AM_CONDITIONAL([WOE32DLL], [test $is_woe32dll = yes])
++if test $is_woe32dll = yes; then
++  AC_DEFINE([WOE32DLL], [1],
++    [Define when --enable-shared is used on mingw or Cygwin.])
++fi
++
++INTL_EXPORTS_FLAGS=
++dnl 64-bit mingw does not prepend an underscore to C symbols.
++dnl USER_LABEL_PREFIX is set by gl_ASM_SYMBOL_PREFIX, inside gl_INIT.
++if test "$USER_LABEL_PREFIX" = _; then
++  INTL_EXPORTS_FLAGS="-DUSER_LABEL_PREFIX_UNDERSCORE $INTL_EXPORTS_FLAGS"
++fi
++AC_SUBST([INTL_EXPORTS_FLAGS])
++
+ dnl Check for tools needed for formatting the documentation.
+ ac_aux_dir_abs=`cd $ac_aux_dir && pwd`
+ AC_PATH_PROG([PERL], [perl], [$ac_aux_dir_abs/missing perl])
+diff -r 39dc3bef2ec7 gettext-runtime/intl/intl-exports.c
+--- a/gettext-runtime/intl/intl-exports.c	Sun Feb 24 17:55:28 2013 +0100
++++ b/gettext-runtime/intl/intl-exports.c	Sun Feb 24 17:57:12 2013 +0100
+@@ -18,7 +18,11 @@
+    USA.  */
+ 
+  /* IMP(x) is a symbol that contains the address of x.  */
+-#define IMP(x) _imp__##x
++#if USER_LABEL_PREFIX_UNDERSCORE
++# define IMP(x) _imp__##x
++#else
++# define IMP(x) __imp_##x
++#endif
+ 
+  /* Ensure that the variable x is exported from the library, and that a
+     pseudo-variable IMP(x) is available.  */
+diff -r 39dc3bef2ec7 gnulib-local/modules/gettext-runtime-misc
+--- a/gnulib-local/modules/gettext-runtime-misc	Sun Feb 24 17:55:28 2013 +0100
++++ b/gnulib-local/modules/gettext-runtime-misc	Sun Feb 24 17:57:12 2013 +0100
+@@ -15,6 +15,11 @@
+ # Parametrization of the 'relocatable' module.
+ AM_CPPFLAGS += -DDEPENDS_ON_LIBICONV=1 -DDEPENDS_ON_LIBINTL=1
+ 
++# Tell the mingw or Cygwin linker which symbols to export.
++if WOE32DLL
++AM_CPPFLAGS += @INTL_EXPORTS_FLAGS@
++endif
++
+ Include:
+ 
+ License:
diff --git a/packaging/mingw-debian-cross/patches/glew-makefile b/packaging/mingw-debian-cross/patches/glew-makefile
new file mode 100644
index 0000000..4262a54
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/glew-makefile
@@ -0,0 +1,35 @@
+--- a/Makefile	2013-07-07 15:37:19.000000000 +0200
++++ b/Makefile	2013-07-07 15:44:55.000000000 +0200
+@@ -28,19 +28,12 @@
+ ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ ## THE POSSIBILITY OF SUCH DAMAGE.
+ 
+-include config/version
++include config/Makefile.mingw
+ 
+ SHELL = /bin/sh
+-SYSTEM ?= $(shell config/config.guess | cut -d - -f 3 | sed -e 's/[0-9\.]//g;')
+-SYSTEM.SUPPORTED = $(shell test -f config/Makefile.$(SYSTEM) && echo 1)
++SYSTEM = HOST_VAL
+ 
+-ifeq ($(SYSTEM.SUPPORTED), 1)
+-include config/Makefile.$(SYSTEM)
+-else
+-$(error "Platform '$(SYSTEM)' not supported")
+-endif
+-
+-GLEW_DEST ?= /usr
++GLEW_DEST ?= BASEDIR
+ BINDIR ?= $(GLEW_DEST)/bin
+ LIBDIR ?= $(GLEW_DEST)/lib
+ INCDIR ?= $(GLEW_DEST)/include/GL
+--- a/config/Makefile.mingw	2013-07-07 15:43:48.000000000 +0200
++++ b/config/Makefile.mingw	2013-07-07 15:47:32.000000000 +0200
+@@ -1,7 +1,4 @@
+ NAME = glew32
+-CC = gcc
+-# use gcc for linking, with ld it does not work
+-LD = gcc
+ CFLAGS.SO = -DGLEW_BUILD
+ LDFLAGS.GL = -lglu32 -lopengl32 -lgdi32 -luser32 -lkernel32
+ LDFLAGS.EXTRA = -L/mingw/lib
diff --git a/packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch b/packaging/mingw-debian-cross/patches/wxwidgets2.8-2.8.12-mingw64-1.patch
similarity index 100%
rename from packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch
rename to packaging/mingw-debian-cross/patches/wxwidgets2.8-2.8.12-mingw64-1.patch
diff --git a/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch b/packaging/mingw-debian-cross/patches/wxwidgets2.8-wx-config-sysroot.patch
similarity index 94%
rename from packaging/mingw-debian-cross/patches/wx-config-sysroot.patch
rename to packaging/mingw-debian-cross/patches/wxwidgets2.8-wx-config-sysroot.patch
index c5a17cf..ba0ca09 100644
--- a/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch
+++ b/packaging/mingw-debian-cross/patches/wxwidgets2.8-wx-config-sysroot.patch
@@ -4,7 +4,7 @@
  # delegate out to anything in that prefix, then reset the build
  # tree prefix to provide the correct output for using this
  # uninstalled wx build.  Or put more simply:
-+sysroot=/home/pcuser/mingw64-cross/
++sysroot=REPLACE_BASENAME
  prefix=${this_prefix-$prefix}
  exec_prefix=${this_exec_prefix-$exec_prefix}
  
diff --git a/packaging/windows-installer/windows-installer.nsi b/packaging/mingw-debian-cross/windows-installer.nsi
similarity index 86%
rename from packaging/windows-installer/windows-installer.nsi
rename to packaging/mingw-debian-cross/windows-installer.nsi
index e505db6..08d51a8 100644
--- a/packaging/windows-installer/windows-installer.nsi
+++ b/packaging/mingw-debian-cross/windows-installer.nsi
@@ -2,7 +2,7 @@
 
 ; HM NIS Edit Wizard helper defines
 !define PRODUCT_NAME "3Depict"
-!define PRODUCT_VERSION "0.0.13"
+!define PRODUCT_VERSION "0.0.14"
 !define PRODUCT_PUBLISHER "D. Haley, A. Ceguerra"
 !define PRODUCT_WEB_SITE "http://threedepict.sourceforge.net"
 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\3Depict.exe"
@@ -68,7 +68,7 @@ Section "3Depict program" SEC01
   File "src\libjpeg-8.dll"
   File "src\libpng12-0.dll"
   File "src\libtiff-4.dll"
-  File "src\libz.so.1.2.7"
+  File "src\libz.dll"
   File "src\libstdc++-6.dll"
   File "src\libmgl-5.dll"
   File "src\libgcc_s_sjlj-1.dll"
@@ -87,19 +87,22 @@ Section "3Depict program" SEC01
   File /r locales\*.*
   
   SetOutPath "$INSTDIR\textures\"
-  File "data\textures\enlarge.png" 
-  File "data\textures\keyboard-alt.png" 
-  File "data\textures\keyboard-command.png" 
-  File "data\textures\keyboard-ctrl.png" 
-  File "data\textures\keyboard-shift.png" 
-  File "data\textures\keyboard-tab.png" 
-  File "data\textures\Left-Right-arrow.png" 
-  File "data\textures\Left_clicked_mouse.png" 
-  File "data\textures\middle_clicked_mouse.png" 
-  File "data\textures\Right-arrow.png" 
+  File "data\textures\animProgress0.png"
+  File "data\textures\animProgress1.png"
+  File "data\textures\animProgress2.png"
+  File "data\textures\enlarge.png"
+  File "data\textures\keyboard-alt.png"
+  File "data\textures\keyboard-command.png"
+  File "data\textures\keyboard-ctrl.png"
+  File "data\textures\keyboard-shift.png"
+  File "data\textures\keyboard-tab.png"
+  File "data\textures\Left_clicked_mouse.png"
+  File "data\textures\Left-Right-arrow.png"
+  File "data\textures\middle_clicked_mouse.png"
+  File "data\textures\Right-arrow.png"
   File "data\textures\Right_clicked_mouse.png"
   File "data\textures\rotateArrow.png"
-  File "data\textures\scroll_wheel_mouse.png" 
+  File "data\textures\scroll_wheel_mouse.png"
 SectionEnd
 
 Section -AdditionalIcons
@@ -133,6 +136,10 @@ FunctionEnd
 Section Uninstall
   Delete "$INSTDIR\${PRODUCT_NAME}.url"
   Delete "$INSTDIR\textures\uninst.exe"
+  
+  Delete "$INSTDIR\textures\animProgress0.png"
+  Delete "$INSTDIR\textures\animProgress1.png"
+  Delete "$INSTDIR\textures\animProgress2.png"
   Delete "$INSTDIR\textures\scroll_wheel_mouse.png"
   Delete "$INSTDIR\textures\rotateArrow.png"
   Delete "$INSTDIR\textures\Right_clicked_mouse.png"
@@ -146,6 +153,7 @@ Section Uninstall
   Delete "$INSTDIR\textures\keyboard-command.png"
   Delete "$INSTDIR\textures\keyboard-alt.png"
   Delete "$INSTDIR\textures\enlarge.png"
+ 
   Delete "$INSTDIR\3Depict.exe"
 
   Delete "$INSTDIR\manual.pdf"
@@ -172,7 +180,7 @@ Section Uninstall
   Delete "$INSTDIR\libjpeg-8.dll"
   Delete "$INSTDIR\libpng12-0.dll"
   Delete "$INSTDIR\libtiff-4.dll"
-  Delete "$INSTDIR\libz.so.1.2.7"
+  Delete "$INSTDIR\libz.dll"
   Delete "$INSTDIR\libstdc++-6.dll"
   Delete "$INSTDIR\libmgl-5.dll"
   Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
diff --git a/src/3Depict.cpp b/src/3Depict.cpp
index 33f0977..98a5267 100644
--- a/src/3Depict.cpp
+++ b/src/3Depict.cpp
@@ -1,5 +1,5 @@
 /*
- *	threeDepict.cpp - main program user interface and control implementation
+ *	threeDepict.cpp - main program implementation
  *	Copyright (C) 2013, D Haley 
 
  *	This program is free software: you can redistribute it and/or modify
@@ -20,8 +20,9 @@
 #include <wx/wx.h>
 #include <wx/cmdline.h>
 #include <wx/filename.h>
-#ifdef __APPLE__
 #include <wx/stdpaths.h>
+
+#ifdef __APPLE__
 #include "CoreFoundation/CoreFoundation.h"
 #endif
 
@@ -447,10 +448,11 @@ bool threeDepictApp::OnInit()
 #endif
 
 
+    MainFrame->Show();
+    
     if(commandLineFiles.GetCount())
     	MainFrame->SetCommandLineFiles(commandLineFiles);
 
-    MainFrame->Show();
     MainFrame->fixSplitterWindow();
     return true;
 }
diff --git a/src/Makefile.am b/src/Makefile.am
index 4666b16..c1c14ee 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,8 +22,9 @@ MSYS_PATH=/c/msys/1.0/local/include/
 bin_PROGRAMS= 3Depict
 
 #------- Common header files for all sub-modules
-COMMON_SOURCE_FILES =  common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp
-COMMON_HEADER_FILES = common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
+COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp
+COMMON_HEADER_FILES = common/pngread.h common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h \
+		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
 
 #-----------
 
@@ -48,16 +49,16 @@ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h
 		backend/filters/annotation.h backend/filters/geometryHelpers.h
 
 BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
-		     	backend/APT/APTClasses.cpp backend/APT/APTRanges.cpp \
+		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp \
 			backend/filters/K3DTree.cpp backend/filters/K3DTree-mk2.cpp\
 			backend/filter.cpp backend/filters/rdf.cpp \
-		       backend/viscontrol.cpp backend/plot.cpp  backend/configFile.cpp 
+		       backend/viscontrol.cpp backend/state.cpp backend/plot.cpp  backend/configFile.cpp 
 
 BACKEND_HEADER_FILES =  backend/animator.h backend/filtertreeAnalyse.h backend/filtertree.h\
-			backend/APT/APTClasses.h backend/APT/APTRanges.h \
+			backend/APT/ionhit.h backend/APT/APTFileIO.h backend/APT/APTRanges.h \
 			backend/filters/K3DTree.h backend/filters/K3DTree-mk2.h \
 			backend/filter.h backend/filters/rdf.h \
-			backend/viscontrol.h  backend/plot.h backend/configFile.h \
+			backend/viscontrol.h backend/state.h backend/plot.h backend/configFile.h \
 		        backend/tree.hh
 
 #------------
@@ -93,8 +94,8 @@ DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/
 GUI_SOURCE_FILES=gui/mainFrame.cpp gui/mathglPane.cpp gui/cropPanel.cpp gui/glPane.cpp  $(DIALOG_SOURCE_FILES)
 GUI_HEADER_FILES=gui/mainFrame.h gui/mathglPane.h gui/cropPanel.h gui/art.h gui/glPane.h $(DIALOG_HEADER_FILES)
 
-BASE_SOURCE_FILES=   3Depict.cpp testing.cpp pngread.c wxcomponents.cpp wxcommon.cpp 
-BASE_HEADER_FILES=   testing.h winconsole.h pngread.h  wxcomponents.h  wxcommon.h
+BASE_SOURCE_FILES=   3Depict.cpp testing.cpp  wxcomponents.cpp wxcommon.cpp winconsole.cpp 
+BASE_HEADER_FILES=   testing.h winconsole.h   wxcomponents.h  wxcommon.h
 #-----------
 
 
@@ -107,7 +108,7 @@ SOURCE_FILES=  $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(GUI_SOURCE_FILES) $(G
 
 #Do we have or need windows-XP "resource" files for look and feel?
 if HAVE_WINDRES
-3Depict_SOURCES=$(SOURCE_FILES)  winconsole.cpp 3Depict.rc
+3Depict_SOURCES=$(SOURCE_FILES)  3Depict.rc
 else
 3Depict_SOURCES=$(SOURCE_FILES)
 endif
diff --git a/src/Makefile.in b/src/Makefile.in
index c5d8265..38e0231 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -66,8 +66,8 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am__3Depict_SOURCES_DIST = 3Depict.cpp testing.cpp pngread.c \
-	wxcomponents.cpp wxcommon.cpp testing.h winconsole.h pngread.h \
+am__3Depict_SOURCES_DIST = 3Depict.cpp testing.cpp wxcomponents.cpp \
+	wxcommon.cpp winconsole.cpp testing.h winconsole.h \
 	wxcomponents.h wxcommon.h gui/mainFrame.cpp gui/mathglPane.cpp \
 	gui/cropPanel.cpp gui/glPane.cpp gui/dialogs/ExportPos.cpp \
 	gui/dialogs/ExportRngDialog.cpp gui/dialogs/prefDialog.cpp \
@@ -111,29 +111,32 @@ am__3Depict_SOURCES_DIST = 3Depict.cpp testing.cpp pngread.c \
 	backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
 	backend/filters/annotation.h backend/filters/geometryHelpers.h \
 	backend/animator.cpp backend/filtertreeAnalyse.cpp \
-	backend/filtertree.cpp backend/APT/APTClasses.cpp \
-	backend/APT/APTRanges.cpp backend/filters/K3DTree.cpp \
-	backend/filters/K3DTree-mk2.cpp backend/filter.cpp \
-	backend/filters/rdf.cpp backend/viscontrol.cpp \
-	backend/plot.cpp backend/configFile.cpp backend/animator.h \
+	backend/filtertree.cpp backend/APT/ionhit.cpp \
+	backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp \
+	backend/filters/K3DTree.cpp backend/filters/K3DTree-mk2.cpp \
+	backend/filter.cpp backend/filters/rdf.cpp \
+	backend/viscontrol.cpp backend/state.cpp backend/plot.cpp \
+	backend/configFile.cpp backend/animator.h \
 	backend/filtertreeAnalyse.h backend/filtertree.h \
-	backend/APT/APTClasses.h backend/APT/APTRanges.h \
-	backend/filters/K3DTree.h backend/filters/K3DTree-mk2.h \
-	backend/filter.h backend/filters/rdf.h backend/viscontrol.h \
+	backend/APT/ionhit.h backend/APT/APTFileIO.h \
+	backend/APT/APTRanges.h backend/filters/K3DTree.h \
+	backend/filters/K3DTree-mk2.h backend/filter.h \
+	backend/filters/rdf.h backend/viscontrol.h backend/state.h \
 	backend/plot.h backend/configFile.h backend/tree.hh \
 	gl/scene.cpp gl/drawables.cpp gl/effect.cpp gl/textures.cpp \
 	gl/select.cpp gl/cameras.cpp gl/isoSurface.cpp gl/scene.h \
 	gl/drawables.h gl/effect.h gl/textures.h gl/select.h \
-	gl/cameras.h gl/isoSurface.h common/stringFuncs.cpp \
-	common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp \
-	common/mathfuncs.cpp common/basics.cpp common/stringFuncs.h \
+	gl/cameras.h gl/isoSurface.h common/pngread.c \
+	common/stringFuncs.cpp common/xmlHelper.cpp \
+	common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp \
+	common/basics.cpp common/pngread.h common/stringFuncs.h \
 	common/constants.h common/xmlHelper.h common/colourmap.h \
 	common/mathfuncs.h common/basics.h common/translation.h \
 	common/endianTest.h common/assertion.h common/voxels.h \
-	winconsole.cpp 3Depict.rc
+	3Depict.rc
 am__objects_1 = 3Depict-3Depict.$(OBJEXT) 3Depict-testing.$(OBJEXT) \
-	3Depict-pngread.$(OBJEXT) 3Depict-wxcomponents.$(OBJEXT) \
-	3Depict-wxcommon.$(OBJEXT)
+	3Depict-wxcomponents.$(OBJEXT) 3Depict-wxcommon.$(OBJEXT) \
+	3Depict-winconsole.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = 3Depict-ExportPos.$(OBJEXT) \
 	3Depict-ExportRngDialog.$(OBJEXT) 3Depict-prefDialog.$(OBJEXT) \
@@ -161,26 +164,26 @@ am__objects_6 = 3Depict-allFilter.$(OBJEXT) \
 	3Depict-annotation.$(OBJEXT) 3Depict-geometryHelpers.$(OBJEXT)
 am__objects_7 = 3Depict-animator.$(OBJEXT) \
 	3Depict-filtertreeAnalyse.$(OBJEXT) \
-	3Depict-filtertree.$(OBJEXT) 3Depict-APTClasses.$(OBJEXT) \
-	3Depict-APTRanges.$(OBJEXT) 3Depict-K3DTree.$(OBJEXT) \
-	3Depict-K3DTree-mk2.$(OBJEXT) 3Depict-filter.$(OBJEXT) \
-	3Depict-rdf.$(OBJEXT) 3Depict-viscontrol.$(OBJEXT) \
+	3Depict-filtertree.$(OBJEXT) 3Depict-ionhit.$(OBJEXT) \
+	3Depict-APTFileIO.$(OBJEXT) 3Depict-APTRanges.$(OBJEXT) \
+	3Depict-K3DTree.$(OBJEXT) 3Depict-K3DTree-mk2.$(OBJEXT) \
+	3Depict-filter.$(OBJEXT) 3Depict-rdf.$(OBJEXT) \
+	3Depict-viscontrol.$(OBJEXT) 3Depict-state.$(OBJEXT) \
 	3Depict-plot.$(OBJEXT) 3Depict-configFile.$(OBJEXT)
 am__objects_8 = 3Depict-scene.$(OBJEXT) 3Depict-drawables.$(OBJEXT) \
 	3Depict-effect.$(OBJEXT) 3Depict-textures.$(OBJEXT) \
 	3Depict-select.$(OBJEXT) 3Depict-cameras.$(OBJEXT) \
 	3Depict-isoSurface.$(OBJEXT)
-am__objects_9 = 3Depict-stringFuncs.$(OBJEXT) \
-	3Depict-xmlHelper.$(OBJEXT) 3Depict-colourmap.$(OBJEXT) \
-	3Depict-voxels.$(OBJEXT) 3Depict-mathfuncs.$(OBJEXT) \
-	3Depict-basics.$(OBJEXT)
+am__objects_9 = 3Depict-pngread.$(OBJEXT) \
+	3Depict-stringFuncs.$(OBJEXT) 3Depict-xmlHelper.$(OBJEXT) \
+	3Depict-colourmap.$(OBJEXT) 3Depict-voxels.$(OBJEXT) \
+	3Depict-mathfuncs.$(OBJEXT) 3Depict-basics.$(OBJEXT)
 am__objects_10 = $(am__objects_1) $(am__objects_2) $(am__objects_4) \
 	$(am__objects_5) $(am__objects_6) $(am__objects_2) \
 	$(am__objects_7) $(am__objects_2) $(am__objects_8) \
 	$(am__objects_2) $(am__objects_9) $(am__objects_2)
 @HAVE_WINDRES_FALSE at am_3Depict_OBJECTS = $(am__objects_10)
 @HAVE_WINDRES_TRUE at am_3Depict_OBJECTS = $(am__objects_10) \
- at HAVE_WINDRES_TRUE@	3Depict-winconsole.$(OBJEXT) \
 @HAVE_WINDRES_TRUE@	3Depict.$(OBJEXT)
 3Depict_OBJECTS = $(am_3Depict_OBJECTS)
 am__DEPENDENCIES_1 =
@@ -363,8 +366,10 @@ MSYS_PATH = /c/msys/1.0/local/include/
 
 
 #------- Common header files for all sub-modules
-COMMON_SOURCE_FILES = common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp
-COMMON_HEADER_FILES = common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
+COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp
+COMMON_HEADER_FILES = common/pngread.h common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h \
+		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
+
 
 #-----------
 
@@ -389,16 +394,16 @@ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h
 		backend/filters/annotation.h backend/filters/geometryHelpers.h
 
 BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
-		     	backend/APT/APTClasses.cpp backend/APT/APTRanges.cpp \
+		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp \
 			backend/filters/K3DTree.cpp backend/filters/K3DTree-mk2.cpp\
 			backend/filter.cpp backend/filters/rdf.cpp \
-		       backend/viscontrol.cpp backend/plot.cpp  backend/configFile.cpp 
+		       backend/viscontrol.cpp backend/state.cpp backend/plot.cpp  backend/configFile.cpp 
 
 BACKEND_HEADER_FILES = backend/animator.h backend/filtertreeAnalyse.h backend/filtertree.h\
-			backend/APT/APTClasses.h backend/APT/APTRanges.h \
+			backend/APT/ionhit.h backend/APT/APTFileIO.h backend/APT/APTRanges.h \
 			backend/filters/K3DTree.h backend/filters/K3DTree-mk2.h \
 			backend/filter.h backend/filters/rdf.h \
-			backend/viscontrol.h  backend/plot.h backend/configFile.h \
+			backend/viscontrol.h backend/state.h backend/plot.h backend/configFile.h \
 		        backend/tree.hh
 
 
@@ -430,8 +435,8 @@ DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/
 
 GUI_SOURCE_FILES = gui/mainFrame.cpp gui/mathglPane.cpp gui/cropPanel.cpp gui/glPane.cpp  $(DIALOG_SOURCE_FILES)
 GUI_HEADER_FILES = gui/mainFrame.h gui/mathglPane.h gui/cropPanel.h gui/art.h gui/glPane.h $(DIALOG_HEADER_FILES)
-BASE_SOURCE_FILES = 3Depict.cpp testing.cpp pngread.c wxcomponents.cpp wxcommon.cpp 
-BASE_HEADER_FILES = testing.h winconsole.h pngread.h  wxcomponents.h  wxcommon.h
+BASE_SOURCE_FILES = 3Depict.cpp testing.cpp  wxcomponents.cpp wxcommon.cpp winconsole.cpp 
+BASE_HEADER_FILES = testing.h winconsole.h   wxcomponents.h  wxcommon.h
 #-----------
 SOURCE_FILES = $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(GUI_SOURCE_FILES) $(GUI_HEADER_FILES) \
 	       $(FILTER_FILES) $(FILTER_HEADER_FILES) \
@@ -441,7 +446,7 @@ SOURCE_FILES = $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(GUI_SOURCE_FILES) $(G
 @HAVE_WINDRES_FALSE at 3Depict_SOURCES = $(SOURCE_FILES)
 
 #Do we have or need windows-XP "resource" files for look and feel?
- at HAVE_WINDRES_TRUE@3Depict_SOURCES = $(SOURCE_FILES)  winconsole.cpp 3Depict.rc
+ at HAVE_WINDRES_TRUE@3Depict_SOURCES = $(SOURCE_FILES)  3Depict.rc
 
 #Tarball options
 EXTRA_DIST = gui/glade-skeleton myAppIcon.ico
@@ -530,7 +535,7 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-3Depict.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-APTClasses.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-APTFileIO.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-APTRanges.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ExportPos.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ExportRngDialog.Po at am__quote@
@@ -567,6 +572,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ionColour.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ionDownsample.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ionInfo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-ionhit.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-isoSurface.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-mainFrame.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-mathfuncs.Po at am__quote@
@@ -581,6 +587,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-select.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-spatialAnalysis.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-spectrumPlot.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-state.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-stringFuncs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-stringKeyFrameDialog.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/3Depict-testing.Po at am__quote@
@@ -608,19 +615,19 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
-3Depict-pngread.o: pngread.c
- at am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -MT 3Depict-pngread.o -MD -MP -MF $(DEPDIR)/3Depict-pngread.Tpo -c -o 3Depict-pngread.o `test -f 'pngread.c' || echo '$(srcdir)/'`pngread.c
+3Depict-pngread.o: common/pngread.c
+ at am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -MT 3Depict-pngread.o -MD -MP -MF $(DEPDIR)/3Depict-pngread.Tpo -c -o 3Depict-pngread.o `test -f 'common/pngread.c' || echo '$(srcdir)/'`common/pngread.c
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/3Depict-pngread.Tpo $(DEPDIR)/3Depict-pngread.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='pngread.c' object='3Depict-pngread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='common/pngread.c' object='3Depict-pngread.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -c -o 3Depict-pngread.o `test -f 'pngread.c' || echo '$(srcdir)/'`pngread.c
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -c -o 3Depict-pngread.o `test -f 'common/pngread.c' || echo '$(srcdir)/'`common/pngread.c
 
-3Depict-pngread.obj: pngread.c
- at am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -MT 3Depict-pngread.obj -MD -MP -MF $(DEPDIR)/3Depict-pngread.Tpo -c -o 3Depict-pngread.obj `if test -f 'pngread.c'; then $(CYGPATH_W) 'pngread.c'; else $(CYGPATH_W) '$(srcdir)/pngread.c'; fi`
+3Depict-pngread.obj: common/pngread.c
+ at am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -MT 3Depict-pngread.obj -MD -MP -MF $(DEPDIR)/3Depict-pngread.Tpo -c -o 3Depict-pngread.obj `if test -f 'common/pngread.c'; then $(CYGPATH_W) 'common/pngread.c'; else $(CYGPATH_W) '$(srcdir)/common/pngread.c'; fi`
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/3Depict-pngread.Tpo $(DEPDIR)/3Depict-pngread.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='pngread.c' object='3Depict-pngread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='common/pngread.c' object='3Depict-pngread.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -c -o 3Depict-pngread.obj `if test -f 'pngread.c'; then $(CYGPATH_W) 'pngread.c'; else $(CYGPATH_W) '$(srcdir)/pngread.c'; fi`
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CFLAGS) $(CFLAGS) -c -o 3Depict-pngread.obj `if test -f 'common/pngread.c'; then $(CYGPATH_W) 'common/pngread.c'; else $(CYGPATH_W) '$(srcdir)/common/pngread.c'; fi`
 
 .cpp.o:
 @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -692,6 +699,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-wxcommon.obj `if test -f 'wxcommon.cpp'; then $(CYGPATH_W) 'wxcommon.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcommon.cpp'; fi`
 
+3Depict-winconsole.o: winconsole.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-winconsole.o -MD -MP -MF $(DEPDIR)/3Depict-winconsole.Tpo -c -o 3Depict-winconsole.o `test -f 'winconsole.cpp' || echo '$(srcdir)/'`winconsole.cpp
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-winconsole.Tpo $(DEPDIR)/3Depict-winconsole.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='winconsole.cpp' object='3Depict-winconsole.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-winconsole.o `test -f 'winconsole.cpp' || echo '$(srcdir)/'`winconsole.cpp
+
+3Depict-winconsole.obj: winconsole.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-winconsole.obj -MD -MP -MF $(DEPDIR)/3Depict-winconsole.Tpo -c -o 3Depict-winconsole.obj `if test -f 'winconsole.cpp'; then $(CYGPATH_W) 'winconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/winconsole.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-winconsole.Tpo $(DEPDIR)/3Depict-winconsole.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='winconsole.cpp' object='3Depict-winconsole.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-winconsole.obj `if test -f 'winconsole.cpp'; then $(CYGPATH_W) 'winconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/winconsole.cpp'; fi`
+
 3Depict-mainFrame.o: gui/mainFrame.cpp
 @am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mainFrame.o -MD -MP -MF $(DEPDIR)/3Depict-mainFrame.Tpo -c -o 3Depict-mainFrame.o `test -f 'gui/mainFrame.cpp' || echo '$(srcdir)/'`gui/mainFrame.cpp
 @am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-mainFrame.Tpo $(DEPDIR)/3Depict-mainFrame.Po
@@ -1196,19 +1217,33 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filtertree.obj `if test -f 'backend/filtertree.cpp'; then $(CYGPATH_W) 'backend/filtertree.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filtertree.cpp'; fi`
 
-3Depict-APTClasses.o: backend/APT/APTClasses.cpp
- at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTClasses.o -MD -MP -MF $(DEPDIR)/3Depict-APTClasses.Tpo -c -o 3Depict-APTClasses.o `test -f 'backend/APT/APTClasses.cpp' || echo '$(srcdir)/'`backend/APT/APTClasses.cpp
- at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/APTClasses.cpp' object='3Depict-APTClasses.o' libtool=no @AMDEPBACKSLASH@
+3Depict-ionhit.o: backend/APT/ionhit.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionhit.o -MD -MP -MF $(DEPDIR)/3Depict-ionhit.Tpo -c -o 3Depict-ionhit.o `test -f 'backend/APT/ionhit.cpp' || echo '$(srcdir)/'`backend/APT/ionhit.cpp
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-ionhit.Tpo $(DEPDIR)/3Depict-ionhit.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/ionhit.cpp' object='3Depict-ionhit.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionhit.o `test -f 'backend/APT/ionhit.cpp' || echo '$(srcdir)/'`backend/APT/ionhit.cpp
+
+3Depict-ionhit.obj: backend/APT/ionhit.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionhit.obj -MD -MP -MF $(DEPDIR)/3Depict-ionhit.Tpo -c -o 3Depict-ionhit.obj `if test -f 'backend/APT/ionhit.cpp'; then $(CYGPATH_W) 'backend/APT/ionhit.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/ionhit.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-ionhit.Tpo $(DEPDIR)/3Depict-ionhit.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/ionhit.cpp' object='3Depict-ionhit.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionhit.obj `if test -f 'backend/APT/ionhit.cpp'; then $(CYGPATH_W) 'backend/APT/ionhit.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/ionhit.cpp'; fi`
+
+3Depict-APTFileIO.o: backend/APT/APTFileIO.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTFileIO.o -MD -MP -MF $(DEPDIR)/3Depict-APTFileIO.Tpo -c -o 3Depict-APTFileIO.o `test -f 'backend/APT/APTFileIO.cpp' || echo '$(srcdir)/'`backend/APT/APTFileIO.cpp
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-APTFileIO.Tpo $(DEPDIR)/3Depict-APTFileIO.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/APTFileIO.cpp' object='3Depict-APTFileIO.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTClasses.o `test -f 'backend/APT/APTClasses.cpp' || echo '$(srcdir)/'`backend/APT/APTClasses.cpp
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTFileIO.o `test -f 'backend/APT/APTFileIO.cpp' || echo '$(srcdir)/'`backend/APT/APTFileIO.cpp
 
-3Depict-APTClasses.obj: backend/APT/APTClasses.cpp
- at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTClasses.obj -MD -MP -MF $(DEPDIR)/3Depict-APTClasses.Tpo -c -o 3Depict-APTClasses.obj `if test -f 'backend/APT/APTClasses.cpp'; then $(CYGPATH_W) 'backend/APT/APTClasses.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTClasses.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/APTClasses.cpp' object='3Depict-APTClasses.obj' libtool=no @AMDEPBACKSLASH@
+3Depict-APTFileIO.obj: backend/APT/APTFileIO.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTFileIO.obj -MD -MP -MF $(DEPDIR)/3Depict-APTFileIO.Tpo -c -o 3Depict-APTFileIO.obj `if test -f 'backend/APT/APTFileIO.cpp'; then $(CYGPATH_W) 'backend/APT/APTFileIO.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTFileIO.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-APTFileIO.Tpo $(DEPDIR)/3Depict-APTFileIO.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/APT/APTFileIO.cpp' object='3Depict-APTFileIO.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTClasses.obj `if test -f 'backend/APT/APTClasses.cpp'; then $(CYGPATH_W) 'backend/APT/APTClasses.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTClasses.cpp'; fi`
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTFileIO.obj `if test -f 'backend/APT/APTFileIO.cpp'; then $(CYGPATH_W) 'backend/APT/APTFileIO.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTFileIO.cpp'; fi`
 
 3Depict-APTRanges.o: backend/APT/APTRanges.cpp
 @am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTRanges.o -MD -MP -MF $(DEPDIR)/3Depict-APTRanges.Tpo -c -o 3Depict-APTRanges.o `test -f 'backend/APT/APTRanges.cpp' || echo '$(srcdir)/'`backend/APT/APTRanges.cpp
@@ -1294,6 +1329,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-viscontrol.obj `if test -f 'backend/viscontrol.cpp'; then $(CYGPATH_W) 'backend/viscontrol.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/viscontrol.cpp'; fi`
 
+3Depict-state.o: backend/state.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-state.o -MD -MP -MF $(DEPDIR)/3Depict-state.Tpo -c -o 3Depict-state.o `test -f 'backend/state.cpp' || echo '$(srcdir)/'`backend/state.cpp
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-state.Tpo $(DEPDIR)/3Depict-state.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/state.cpp' object='3Depict-state.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-state.o `test -f 'backend/state.cpp' || echo '$(srcdir)/'`backend/state.cpp
+
+3Depict-state.obj: backend/state.cpp
+ at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-state.obj -MD -MP -MF $(DEPDIR)/3Depict-state.Tpo -c -o 3Depict-state.obj `if test -f 'backend/state.cpp'; then $(CYGPATH_W) 'backend/state.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/state.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-state.Tpo $(DEPDIR)/3Depict-state.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='backend/state.cpp' object='3Depict-state.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-state.obj `if test -f 'backend/state.cpp'; then $(CYGPATH_W) 'backend/state.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/state.cpp'; fi`
+
 3Depict-plot.o: backend/plot.cpp
 @am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-plot.o -MD -MP -MF $(DEPDIR)/3Depict-plot.Tpo -c -o 3Depict-plot.o `test -f 'backend/plot.cpp' || echo '$(srcdir)/'`backend/plot.cpp
 @am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-plot.Tpo $(DEPDIR)/3Depict-plot.Po
@@ -1504,20 +1553,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-basics.obj `if test -f 'common/basics.cpp'; then $(CYGPATH_W) 'common/basics.cpp'; else $(CYGPATH_W) '$(srcdir)/common/basics.cpp'; fi`
 
-3Depict-winconsole.o: winconsole.cpp
- at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-winconsole.o -MD -MP -MF $(DEPDIR)/3Depict-winconsole.Tpo -c -o 3Depict-winconsole.o `test -f 'winconsole.cpp' || echo '$(srcdir)/'`winconsole.cpp
- at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-winconsole.Tpo $(DEPDIR)/3Depict-winconsole.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='winconsole.cpp' object='3Depict-winconsole.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-winconsole.o `test -f 'winconsole.cpp' || echo '$(srcdir)/'`winconsole.cpp
-
-3Depict-winconsole.obj: winconsole.cpp
- at am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-winconsole.obj -MD -MP -MF $(DEPDIR)/3Depict-winconsole.Tpo -c -o 3Depict-winconsole.obj `if test -f 'winconsole.cpp'; then $(CYGPATH_W) 'winconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/winconsole.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/3Depict-winconsole.Tpo $(DEPDIR)/3Depict-winconsole.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='winconsole.cpp' object='3Depict-winconsole.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-winconsole.obj `if test -f 'winconsole.cpp'; then $(CYGPATH_W) 'winconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/winconsole.cpp'; fi`
-
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \
diff --git a/src/backend/APT/APTClasses.cpp b/src/backend/APT/APTFileIO.cpp
similarity index 79%
rename from src/backend/APT/APTClasses.cpp
rename to src/backend/APT/APTFileIO.cpp
index ed8436d..9739b96 100644
--- a/src/backend/APT/APTClasses.cpp
+++ b/src/backend/APT/APTFileIO.cpp
@@ -16,11 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "APTClasses.h"
-#include "../../common/stringFuncs.h"
+#include "APTFileIO.h"
+#include "ionhit.h"
 
+#include "../../common/stringFuncs.h"
 #include "../../common/translation.h"
 
+#include <cstring>
+#include <new>
+
 
 using std::pair;
 using std::string;
@@ -28,6 +32,9 @@ using std::vector;
 using std::ifstream;
 using std::make_pair;
 
+
+const size_t PROGRESS_REDUCE=5000;
+
 const char *POS_ERR_STRINGS[] = { "",
        				NTRANS("Memory allocation failure on POS load"),
 				NTRANS("Error opening pos file"),
@@ -59,46 +66,8 @@ const char *ION_TEXT_ERR_STRINGS[] = { "",
 					NTRANS("Incorrect number of fields in file"),
 					NTRANS("Unable to allocate memory to store data"),
 					};
-//!Create an pos file from a vector of IonHits
-unsigned int IonVectorToPos(const vector<IonHit> &ionVec, const string &filename)
-{
-	std::ofstream CFile(filename.c_str(),std::ios::binary);
-	float floatBuffer[4];
-
-	if (!CFile)
-		return 1;
-
-	for (unsigned int ui=0; ui<ionVec.size(); ui++)
-	{
-		ionVec[ui].makePosData(floatBuffer);
-		CFile.write((char *)floatBuffer,4*sizeof(float));
-	}
-	return 0;
-}
 
 
-
-void appendPos(const vector<IonHit> &points, const char *name)
-{
-	std::ofstream posFile(name,std::ios::binary|std::ios::app);	
-
-	float data[4];	
-	
-	for(unsigned int ui=0; ui< points.size(); ui++)
-	{
-		points[ui].makePosData(data);
-		posFile.write((char *)data, 4*sizeof(float));
-	}
-}
-
-void getPointsFromIons(const vector<IonHit> &ions, vector<Point3D> &p)
-{
-	p.resize(ions.size());
-#pragma omp parallel for
-	for(size_t ui=0;ui<ions.size();ui++)
-		p[ui] = ions[ui].getPosRef();
-}
-
 unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, unsigned int index[], vector<IonHit> &posIons,const char *posFile, size_t limitCount,
 	       	unsigned int &progress, bool (*callback)(bool),bool strongSampling)
 {
@@ -296,11 +265,6 @@ unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int output
 	
 	//calculate the number of points stored in the POS file
 	IonHit hit;
-	typedef struct IONHIT
-	{
-		float pos[3];
-		float massToCharge;
-	} IONHIT;
 	size_t pointCount=0;
 	//regular case
 	size_t curBufferSize=BUFFERSIZE;
@@ -358,7 +322,7 @@ unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int output
 			}
 			
 			unsigned int ui;
-			for(ui=0; ui<curBufferSize2; ui+=(sizeof(IONHIT)))
+			for(ui=0; ui<curBufferSize2; ui+=IonHit::DATA_SIZE)
 			{
 				hit.setHit((float*)(buffer2+ui));
 				//Data bytes stored in pos files are big
@@ -397,7 +361,7 @@ unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int output
 
 		curBufferSize = curBufferSize >> 1 ;
 		curBufferSize2 = curBufferSize2 >> 1 ;
-	}while(curBufferSize2 >= sizeof(IONHIT));
+	}while(curBufferSize2 >= IonHit::DATA_SIZE);
 	
 	ASSERT((unsigned int)CFile.tellg() == fileSize);
 	delete[] buffer;
@@ -703,159 +667,3 @@ unsigned int limitLoadTextFile(unsigned int numColsTotal, unsigned int selectedC
 
 }
 
-IonHit::IonHit() 
-{
-	//At this point I deliberately don't initialise the point class
-	//as in DEBUG mode, the point class will catch failure to init
-}
-
-IonHit::IonHit(const IonHit &obj2) : massToCharge(obj2.massToCharge), pos(obj2.pos)
-{
-}
-
-IonHit::IonHit(const Point3D &p, float newMass) : massToCharge(newMass), pos(p)
-{
-}
-
-void IonHit::setMassToCharge(float newMass)
-{
-	massToCharge=newMass;
-}
-
-float IonHit::getMassToCharge() const
-{
-	return massToCharge;
-}	
-
-
-void IonHit::setPos(const Point3D &p)
-{
-	pos=p;
-}
-
-#ifdef __LITTLE_ENDIAN__
-void IonHit::switchEndian()
-{
-	
-	pos.switchEndian();
-	floatSwapBytes(&(massToCharge));
-}
-#endif
-
-const IonHit &IonHit::operator=(const IonHit &obj)
-{
-	massToCharge=obj.massToCharge;
-	pos = obj.pos;
-
-	return *this;
-}
-
-IonHit IonHit::operator+(const Point3D &obj)
-{
-	//FIXME: I think this is wrong???
-	ASSERT(false);
-	pos.add(obj);	
-	return *this;
-}
-
-void IonHit::makePosData(float *floatArr) const
-{
-	ASSERT(floatArr);
-	//copy positional information
-	pos.copyValueArr(floatArr);
-
-	//copy mass to charge data
-	*(floatArr+3) = massToCharge;
-		
-	#ifdef __LITTLE_ENDIAN__
-		floatSwapBytes(floatArr);
-		floatSwapBytes((floatArr+1));
-		floatSwapBytes((floatArr+2));
-		floatSwapBytes((floatArr+3));
-	#endif
-}
-
-Point3D IonHit::getPos() const
-{
-	return pos;
-}	
-
-bool IonHit::hasNaN()
-{
-	return (std::isnan(massToCharge) || std::isnan(pos[0]) || 
-				std::isnan(pos[1]) || std::isnan(pos[2]));
-}
-
-
-
-
-
-void getPointSum(const std::vector<IonHit> &points,Point3D &centroid)
-{
-	//TODO: Paralellise me
-	centroid=Point3D(0,0,0);
-	for(unsigned int ui=0;ui<points.size();ui++)
-		centroid+=points[ui].getPos();
-}
-
-BoundCube getIonDataLimits(const std::vector<IonHit> &points)
-{
-	ASSERT(points.size());
-
-	BoundCube b;	
-	b.setInverseLimits();	
-#ifndef OPENMP
-	float bounds[3][2];
-	for(unsigned int ui=0;ui<3;ui++)
-	{
-		bounds[ui][0]=std::numeric_limits<float>::max();
-		bounds[ui][1]=-std::numeric_limits<float>::max();
-	}
-	
-	for(unsigned int ui=0; ui<points.size(); ui++)
-	{
-
-		for(unsigned int uj=0; uj<3; uj++)
-		{
-			Point3D p;
-			p=points[ui].getPos();
-			if(p.getValue(uj) < bounds[uj][0])
-				bounds[uj][0] = p.getValue(uj);
-			
-			if(p.getValue(uj) > bounds[uj][1])
-				bounds[uj][1] = p.getValue(uj);
-		}
-	}
-
-	b.setBounds(bounds[0][0],bounds[1][0],
-			bounds[2][0],bounds[0][1],
-			bounds[1][1],bounds[2][1]);
-#else
-	// parallel version
-	vector<BoundCube> cubes;
-
-	unsigned int nT=omp_get_max_threads();
-	cubes.resize(nT);
-	for(unsigned int ui=0;ui<cubes.size();ui++)
-		cube[ui].setInverseLimits();
-
-	unsigned int tCount=1;
-	#pragma omp parallel for reduction(tCount|+)
-	for(unsigned int ui=0;ui<points.size();ui++)
-	{
-		Point3D p;
-		p=points[ui].getPos();
-		for(unsigned int uj=0;uj<3;uj++)
-		{
-			b.setBounds(uj,0,std::min(b.getBound(uj,0),p[uj]));
-			b.setBounds(uj,1,std::min(b.getBound(uj,0),p[uj]));
-		}
-	}
-
-	for(unsigned int ui=0;ui<std::min(tCount,nT);ui++)
-		b.expand(cubes[ui]);
-
-#endif
-
-	return b;
-}
diff --git a/src/backend/APT/APTClasses.h b/src/backend/APT/APTFileIO.h
similarity index 54%
rename from src/backend/APT/APTClasses.h
rename to src/backend/APT/APTFileIO.h
index 60c3210..ffa443a 100644
--- a/src/backend/APT/APTClasses.h
+++ b/src/backend/APT/APTFileIO.h
@@ -21,8 +21,7 @@
 
 #include "common/basics.h"
 
-#include <cstring>//memcpy
-#include <new>//std::bad_alloc
+class IonHit;
 
 //!Allowable export ion formats
 enum
@@ -33,10 +32,6 @@ enum
 using std::vector;
 
 class IonHit;
-class Point3D;
-
-
-const unsigned int PROGRESS_REDUCE=5000;
 
 extern const char *POS_ERR_STRINGS[];
 
@@ -56,58 +51,6 @@ enum posErrors
 };
 
 
-//!make a pos file from a set of a set of IonHits
-unsigned int IonVectorToPos(const vector<IonHit> &points, const std::string &name);
-
-
-//obtain a vector of points from an ion hit vector, by stripping out only the 3D point information 
-void getPointsFromIons(const vector<IonHit> &ions, vector<Point3D> &pts);
-
-//!make/append to a pos file from a set of a set of IonHits
-void appendPos(const vector<IonHit> &points, const char *name);
-
-//!Set the bounds from an array of ion hits
-BoundCube getIonDataLimits(const vector<IonHit> &p);//
-
-//!Get the sum of all Point3Ds in an ion vector
-void getPointSum(const std::vector<IonHit> &points,Point3D &centroid);
-
-//!This is a data holding class for POS file ions, from
-/* Pos ions are typically obtained via reconstructed apt detector hits
- * and are of form (x,y,z mass/charge)
- */
-class IonHit
-{
-	private:
-		float massToCharge; // mass to charge ratio in Atomic Mass Units per (charge on electron)
-		Point3D pos; //position (xyz) in nm
-	public:
-		IonHit();
-		//copy constructor
-		IonHit(const IonHit &);
-		IonHit(const Point3D &p, float massToCharge);
-
-		void setHit(float *arr) { pos.setValueArr(arr); massToCharge=arr[3];};
-		void setMassToCharge(float newMassToCharge);
-		void setPos(const Point3D &pos);
-		void setPos(float fX, float fY, float fZ)
-			{ pos.setValue(fX,fY,fZ);};
-		Point3D getPos() const;
-		inline const Point3D &getPosRef() const {return pos;};
-		//returns true if any of the 4 data pts are NaN
-		bool hasNaN();
-
-#ifdef __LITTLE_ENDIAN__		
-		void switchEndian();
-#endif
-		//this does the endian switch for you
-		//but you must supply a valid array.
-		void makePosData(float *floatArr) const;
-		float getMassToCharge() const;
-		const IonHit &operator=(const IonHit &obj);
-		float operator[](unsigned int ui) const;	
-		IonHit operator+(const Point3D &obj);
-};	
 
 
 //!Load a pos file directly into a single ion list
diff --git a/src/backend/APT/APTRanges.cpp b/src/backend/APT/APTRanges.cpp
index 6b628bb..9888584 100644
--- a/src/backend/APT/APTRanges.cpp
+++ b/src/backend/APT/APTRanges.cpp
@@ -16,17 +16,19 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-
-
 #include "APTRanges.h"
 
+#include "ionhit.h"
+
 #include "../../common/constants.h"
 #include "../../common/stringFuncs.h"
 #include "../../common/translation.h"
 
 #include <map>
+#include <fstream>
 #include <clocale>
 #include <numeric>
+#include <cstring>
 
 using std::string;
 using std::vector;
@@ -35,6 +37,8 @@ using std::make_pair;
 using std::map;
 using std::accumulate;
 
+//Arbitrary maximum range file line size
+const size_t MAX_LINE_SIZE = 16536;
 
 const char *rangeErrStrings[] = 
 {
@@ -46,6 +50,7 @@ const char *rangeErrStrings[] =
 	NTRANS("Error reading the short name for ion."),
 	NTRANS("Error reading colour data in the file, expecting 3 decimal values, space separated."),
 	NTRANS("Tried skipping to table separator line (line with dashes), but did not find it."),	
+	NTRANS("Number of ions in the table header did not match the number specified at the start of the file"),
 	NTRANS("Unexpected failure whilst trying to skip over range lead-in data (bit before range start value)"),
 	NTRANS("Range table had an incorrect number of entries, should be 2 or 3 + number of ranges"),
 	NTRANS("Unable to read range start and end values"),
@@ -55,136 +60,15 @@ const char *rangeErrStrings[] =
 	NTRANS("Range file appears to contain malformed data, check things like start and ends of m/c are not equal or flipped."),
 	NTRANS("Range file appears to be inconsistent (eg, overlapping ranges)"),
 	NTRANS("No ion name mapping found  for multiple ion."),
+	NTRANS("Polyatomic extension range matches multiple masses in first section"),
 };
 
 const char *RANGE_EXTS[] = { "rng",
-			  "rrng",
 			  "env",
+			  "rng",
+			  "rrng",
 				""};
 
-
-//No two entries in table may match. NUM_ELEMENTS contains number of entries
-const char *cpAtomNaming[][2] = { 
-	{"Hydrogen","H"},
-	{"Helium","He"},
-	{"Lithium","Li"},
-	{"Beryllium","Be"},
-	{"Boron","B"},
-	{"Carbon","C"},
-	{"Nitrogen","N"},
-	{"Oxygen","O"},
-	{"Fluorine","F"},
-	{"Neon","Ne"},
-	{"Sodium","Na"},
-	{"Magnesium","Mg"},
-	{"Aluminium","Al"},
-	{"Silicon","Si"},
-	{"Phosphorus","P"},
-	{"Sulfur","S"},
-	{"Chlorine","Cl"},
-	{"Argon","Ar"},
-	{"Potassium","K"},
-	{"Calcium","Ca"},
-	{"Scandium","Sc"},
-	{"Titanium","Ti"},
-	{"Vanadium","V"},
-	{"Chromium","Cr"},
-	{"Manganese","Mn"},
-	{"Iron","Fe"},
-	{"Cobalt","Co"},
-	{"Nickel","Ni"},
-	{"Copper","Cu"},
-	{"Zinc","Zn"},
-	{"Gallium","Ga"},
-	{"Germanium","Ge"},
-	{"Arsenic","As"},
-	{"Selenium","Se"},
-	{"Bromine","Br"},
-	{"Krypton","Kr"},
-	{"Rubidium","Rb"},
-	{"Strontium","Sr"},
-	{"Yttrium","Y"},
-	{"Zirconium","Zr"},
-	{"Niobium","Nb"},
-	{"Molybdenum","Mo"},
-	{"Technetium","Tc"},
-	{"Ruthenium","Ru"},
-	{"Rhodium","Rh"},
-	{"Palladium","Pd"},
-	{"Silver","Ag"},
-	{"Cadmium","Cd"},
-	{"Indium","In"},
-	{"Tin","Sn"},
-	{"Antimony","Sb"},
-	{"Tellurium","Te"},
-	{"Iodine","I"},
-	{"Xenon","Xe"},
-	{"Caesium","Cs"},
-	{"Barium","Ba"},
-	{"Lanthanum","La"},
-	{"Cerium","Ce"},
-	{"Praseodymium","Pr"},
-	{"Neodymium","Nd"},
-	{"Promethium","Pm"},
-	{"Samarium","Sm"},
-	{"Europium","Eu"},
-	{"Gadolinium","Gd"},
-	{"Terbium","Tb"},
-	{"Dysprosium","Dy"},
-	{"Holmium","Ho"},
-	{"Erbium","Er"},
-	{"Thulium","Tm"},
-	{"Ytterbium","Yb"},
-	{"Lutetium","Lu"},
-	{"Hafnium","Hf"},
-	{"Tantalum","Ta"},
-	{"Tungsten","W"},
-	{"Rhenium","Re"},
-	{"Osmium","Os"},
-	{"Iridium","Ir"},
-	{"Platinum","Pt"},
-	{"Gold","Au"},
-	{"Mercury","Hg"},
-	{"Thallium","Tl"},
-	{"Lead","Pb"},
-	{"Bismuth","Bi"},
-	{"Polonium","Po"},
-	{"Astatine","At"},
-	{"Radon","Rn"},
-	{"Francium","Fr"},
-	{"Radium","Ra"},
-	{"Actinium","Ac"},
-	{"Thorium","Th"},
-	{"Protactinium","Pa"},
-	{"Uranium","U"},
-	{"Neptunium","Np"},
-	{"Plutonium","Pu"},
-	{"Americium","Am"},
-	{"Curium","Cm"},
-	{"Berkelium","Bk"},
-	{"Californium","Cf"},
-	{"Einsteinium","Es"},
-	{"Fermium","Fm"},
-	{"Mendelevium","Md"},
-	{"Nobelium","No"},
-	{"Lawrencium","Lr"},
-	{"Rutherfordium","Rf"},
-	{"Dubnium","Db"},
-	{"Seaborgium","Sg"},
-	{"Bohrium","Bh"},
-	{"Hassium","Hs"},
-	{"Meitnerium","Mt"},
-	{"Darmstadtium","Ds"},
-	{"Roentgenium","Rg"},
-	{"Ununbium","Uub"},
-	{"Ununtrium","Uut"},
-	{"Ununquadium","Uuq"},
-	{"Ununpentium","Uup"},
-	{"Ununhexium","Uuh"},
-	{"Ununseptium","Uus"},
-	{"Ununoctium","Uuo"}
-};
-
 bool decomposeIonNames(const std::string &name,
 		std::vector<pair<string,size_t> > &fragments)
 {
@@ -391,6 +275,7 @@ bool matchComposedName(const std::map<string,size_t> &composedNames,
 
 RangeFile::RangeFile() : errState(0)
 {
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(RANGE_EXTS)==RANGE_FORMAT_END_OF_ENUM+1);
 }
 
 unsigned int RangeFile::write(std::ostream &f, size_t format) const
@@ -564,6 +449,10 @@ unsigned int RangeFile::open(const char *rangeFilename, unsigned int fileFormat)
 		case RANGE_FORMAT_RRNG:
 			errCode=openRRNG(fpRange);
 			break;
+		//Cameca "double" rng format, in the wild as of mid 2013
+		case RANGE_FORMAT_DBL_ORNL:
+			errCode=openDoubleRNG(fpRange);
+			break;
 		default:
 			ASSERT(false);
 			fclose(fpRange);
@@ -576,99 +465,689 @@ unsigned int RangeFile::open(const char *rangeFilename, unsigned int fileFormat)
 	fclose(fpRange);
 	if(errCode)
 	{
-		errState=errCode;
+		errState=errCode;
+		
+		if(strcmp(oldLocale,"C"))
+			setlocale(LC_NUMERIC,oldLocale);
+		free(oldLocale);
+
+		return errState;
+	}
+
+	//revert back to user's locale, as needed
+	if(strcmp(oldLocale,"C"))
+		setlocale(LC_NUMERIC,oldLocale);
+
+	free(oldLocale);
+	
+	
+	//Run self consistency check on freshly loaded data
+	if(!isSelfConsistent())
+	{
+		errState=RANGE_ERR_DATA_INCONSISTENT;
+		return errState;
+	}
+	
+	return 0;
+}
+
+bool RangeFile::openGuessFormat(const char *rangeFilename)
+{
+	unsigned int assumedFileFormat;
+
+
+	//Try to auto-detect the filetype
+	assumedFileFormat=detectFileType(rangeFilename);
+
+	//Use the guessed format
+	if(open(rangeFilename,assumedFileFormat))
+	{
+		unsigned int errStateRestore;
+		errStateRestore=errState;
+		//If that failed, go to plan B-- Brute force.
+		//try all readers
+		bool openOK=false;
+
+		for(unsigned int ui=0;ui<RANGE_FORMAT_END_OF_ENUM; ui++)
+		{
+			if(ui == assumedFileFormat)
+				continue;
+
+			if(!open(rangeFilename,ui))
+			{
+				assumedFileFormat=ui;
+				openOK=true;
+				break;
+			}
+		}
+	
+		if(!openOK)
+		{
+			//Restore the error state for the assumed file format
+			errState=errStateRestore;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+unsigned int RangeFile::openDoubleRNG(FILE *fpRange)
+{
+	//Cameca modified range file format, as discussed here:
+	// https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=25
+
+	//Basically, the file is two range files back to back, with a single separator line
+	// where the multiple ion names and colours and table are given in the second file
+
+	clear();
+	RangeFile tmpRange[2];
+
+	unsigned int errCode;
+	errCode=tmpRange[0].openRNG(fpRange);
+	if(errCode)
+		return errCode;
+
+	//Spin forwards ot the "polyatomic extension" line
+
+		
+	char *inBuffer = new char[MAX_LINE_SIZE];
+	// skip over <LF> 
+	char *ret;
+	ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
+
+	while(ret && strlen(ret) < MAX_LINE_SIZE-1  && ret[0] != '-')
+	{
+		ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
+	}
+
+	if(!ret || strlen(ret) >= MAX_LINE_SIZE -1)
+	{
+		delete[] inBuffer;
+		return RANGE_ERR_FORMAT;
+	}
+	
+	//Read the "polyatomic extension" line
+	errCode=tmpRange[1].openRNG(fpRange);
+
+	if(errCode)
+	{
+		delete[] inBuffer;
+		return errCode;
+	}
+	//Now merge the two range files by using the mass pair data as a key
+
+	//Find the matching ranges
+	//range IDs from first and second file who have matching rnage values
+	vector< pair<size_t,size_t> > rangeMatches;
+	//IonID from the first dataset that we will need to replace
+	vector<size_t> overrideIonID;
+	for(size_t ui=0;ui<tmpRange[0].getNumRanges();ui++)
+	{
+		for(size_t uj=0;uj<tmpRange[1].getNumRanges();uj++)
+		{
+			if (tmpRange[0].getRange(ui) == tmpRange[1].getRange(uj))
+			{
+				rangeMatches.push_back(make_pair(ui,uj));
+				overrideIonID.push_back(tmpRange[0].getIonID((unsigned int)ui));
+			}
+		}
+	}
+
+	//Take the data from the first range,
+	// then discard the overlapping ions
+	tmpRange[0].ionNames.swap(ionNames);
+	tmpRange[0].colours.swap(colours);
+	tmpRange[0].ionIDs.swap(ionIDs);
+	tmpRange[0].ranges.swap(ranges);
+
+
+	//Ensure there are no non-unique ion entries
+	{
+	vector<size_t> uniqItems=overrideIonID;
+	std::sort(uniqItems.begin(),uniqItems.end());
+
+	if(std::unique(uniqItems.begin(),uniqItems.end()) != uniqItems.end())
+	{
+		delete[] inBuffer;
+		return RANGE_ERR_NONUNIQUE_POLYATOMIC;
+	}
+	}
+
+	//Replace ionnames with new ion name and colour
+	for(size_t ui=0;ui<overrideIonID.size();ui++)
+	{
+		size_t ids[2];
+		ids[0]=overrideIonID[ui];
+		ids[1] = tmpRange[1].getIonID((unsigned int)rangeMatches[ui].second);
+		//Replace first rangefile colour and name with that of the second
+		ionNames[ids[0]] = tmpRange[1].ionNames[ids[1]];
+		colours[ids[0]] = tmpRange[1].colours[ids[1]];
+	}
+
+	ASSERT(isSelfConsistent());
+
+	delete[] inBuffer;
+	return 0;
+
+}
+
+unsigned int RangeFile::openRNG( FILE *fpRange)
+{
+	clear();
+
+	//Oak-Ridge "Format" - this is based purely on example, as no standard exists
+	//the classic example is from Miller, "Atom probe: Analysis at the atomic scale"
+	//but alternate output forms exist. Our only strategy is to try to be as accommodating
+	//as reasonably possible
+	unsigned int errCode;
+
+	unsigned int numRanges;
+	unsigned int numIons;	
+
+	//Load the range file header
+	if((errCode=readRNGHeader(fpRange, ionNames, colours,numRanges,numIons)))
+		return errCode;
+
+	char *inBuffer = new char[MAX_LINE_SIZE];
+	// skip over <LF> 
+	char *ret;
+	ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
+	if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
+	{
+		delete[] inBuffer;
+		return RANGE_ERR_FORMAT;
+	}
+	// read the column header line 
+	ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
+
+	if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
+	{
+		delete[] inBuffer;
+		return RANGE_ERR_FORMAT;
+	}
+
+	//We should be at the line which has lots of dashes
+	if(inBuffer[0] != '-')
+	{
+		delete[] inBuffer;
+		return RANGE_ERR_FORMAT_TABLESEPARATOR;
+	}
+
+	
+	//Load the rangefile frequency table
+	vector<string> colHeaders;
+	vector<unsigned int > frequencyEntries;
+	
+	{
+	vector<string> warnings;
+	vector<pair<float,float> > massData;
+	errCode=readRNGFreqTable(fpRange,inBuffer,numIons,numRanges,ionNames,
+				colHeaders, frequencyEntries,massData,warnings);
+	if(errCode)
+	{
+		delete[] inBuffer;
+		return errCode;
+	}
+
+	warnings.swap(warnMessages);
+	ranges.swap(massData);
+	}
+
+
+
+	//Because of a certain software's output
+	//it can generate a range listing like this (table +example colour line only)
+	//
+	// these are invalid according to white book
+	//  and the "Atom Probe Microscopy", (Springer series in Materials Science
+	//   vol. 160) descriptions
+	//
+	// Cu2 1.0 1.0 1.0 (Cu2)
+	// ------------Cu Ni Mg Si CuNi4 Mg3Si2 Cu2
+	// . 12.3 23.5 1 4 0 0 0 0 0
+	// . 32.1 43.2 0 0 3 2 0 0 0
+	// . 56.7 89.0 2 0 0 0 0 0 0
+	//
+	// which we get blamed for not supporting :(
+	//
+	//So, we have to scan the lists of ions, and create
+	//tentative "combined" ion names, from the list of ions at the top.
+	//
+	//However, this violates the naming system in the "white book" (Miller, Atom probe: Analysis at the atomic scale)
+	// scheme, which might allow something like
+	// U235U238
+	// as a single range representing a single ion. So they bastardise it by placing the zero columns
+	// as a hint marker. Technically speaking, the zero column entries should not exist
+	// in the format - as they would correspond to a non-existent species (or rather, an unreferenced species).
+	// To check the case of certain programs using cluster ions like this, we have to engage in some
+	// hacky-heuristics, check for 
+	// 	- Columns with only zero entries, 
+	// 	- which have combined numerical headers
+	//
+	// 	Then handle this as a separate case. FFS.
+
+	//-- Build a sparse vector of composed ions
+	std::map<string,size_t> composeMap;
+
+	for(size_t uj=0;uj<numIons;uj++)
+	{
+		bool maybeComposed;
+		maybeComposed=true;
+		for(size_t ui=0; ui<numRanges;ui++)
+		{
+			//Scan through the range listing to try to
+			//find a non-zero entries
+			if(frequencyEntries[numIons*ui + uj])
+			{
+				maybeComposed=false;
+				break;
+			}
+		}
+
+		//If the ion has a column full of zeroes, and
+		//the ion looks like its composable, then
+		//decompose it for later references
+		if(maybeComposed)
+			composeMap.insert(make_pair(ionNames[uj].first,uj));
+	}
+	//--
+		
+	//vector of entries that are multiples, but don't have a 
+	// matching compose key
+	std::vector<pair<size_t, map<size_t,size_t > > > unassignedMultiples;
+
+	//Loop through each range's freq table entries, to determine if
+	// the ion is composed (has more than one "1" in multiplicity listing)
+	for(size_t ui=0;ui<numRanges;ui++)
+	{
+		std::map<size_t,size_t > freqEntries;
+		size_t freq;
+
+	
+		//Find the nonzero entries in this row
+		//--
+		freqEntries.clear();
+		freq=0;
+		for(size_t uj=0;uj<numIons;uj++)
+		{
+			size_t thisEntry;
+			thisEntry=frequencyEntries[numIons*ui+uj];
+			if(!thisEntry)
+				continue;
+		
+			//Record nonzero entries
+			freq+=thisEntry;
+			freqEntries.insert(make_pair(uj,thisEntry));
+		}
+		//--
+
+		if(freq ==1)
+		{
+			//Simple case - we only had a single [1] in
+			//a row for the 
+			ASSERT(freqEntries.size() == 1);
+			ionIDs.push_back( freqEntries.begin()->first);
+		}
+		else if (freq > 1)
+		{
+			if(composeMap.empty())
+			{
+				//We have a multiple, but no way of composing it!
+				// we will need ot build our own table entry.
+				// For now, just store the freq tableentry
+				unassignedMultiples.push_back(make_pair(ui,freqEntries));
+				ionIDs.push_back(-2);
+			}
+			else
+			{
+				//More complex case
+				// ion appears to be composed of multiple fragments.
+				//First entry is the ion name, second is the number of times it occurs 
+				// (ie value in freq table, on this range line)
+				vector<pair<string,size_t> > entries;
+
+				for(map<size_t,size_t>::iterator it=freqEntries.begin();it!=freqEntries.end();++it)
+					entries.push_back(make_pair(ionNames[it->first].first,it->second));
+
+				//try to match the composed name to the entries
+				size_t offset;
+				if(!matchComposedName(composeMap,entries,offset))
+				{
+					//We failed to match the ion against a composed name.
+					// cannot deal with this case.
+					//
+					// we can't just build a new ion name,
+					// as we don't have a colour specification for this.
+					//
+					// We can't use the regular ion name, without 
+					// tracking multiplicity (and then what to do with it in every case - 
+					// seems only a special case for composition? eg. 
+					// Is it a sep. species when clustering? Who knows!)
+					delete[] inBuffer;
+					
+					return RANGE_ERR_DATA_NOMAPPED_IONNAME;
+				}
+				ASSERT(offset < ionNames.size());
+				ionIDs.push_back( offset);
+			}
+
+
+		}
+		else //0
+		{
+			//Range was useless - had no nonzero values
+			//in frequency table.
+			//Set to bad ionID - we will kill this later.
+			ionIDs.push_back(-1);
+		}
+	}
+
+	//Loop through any ranges with a bad ionID (== -1), then delete them by popping
+	for(size_t ui=0;ui<ionIDs.size();ui++)
+	{
+		if(ionIDs[ui] == (size_t)-1)
+		{
+			std::swap(ranges[ui],ranges.back());
+			ranges.pop_back();
+
+			std::swap(ionIDs[ui],ionIDs.back());
+			ionIDs.pop_back();
+		}
+	}
+
+
+	//Check for any leftover unhandled cases
+	if(unassignedMultiples.size())
+	{
+		//OK, so we didn't deal with a few cases before
+		// lets sort these out now
+
+		//Create a name + list of ranges mapping
+		map<string,vector<int> > newNames;
+		
+		for(size_t ui=0;ui<unassignedMultiples.size();ui++)
+		{
+			ComparePairFirstReverse cmp;
+			//create a flattened name from the map as a unique key
+			//eg { Cu , 2 } | { Au, 1} | {O , 3} => O3Cu2Au
+			//--
+			{
+			vector<pair<size_t,size_t> > flatData;
+			
+			std::map<size_t,size_t> &m=unassignedMultiples[ui].second;
+			for(std::map<size_t,size_t>::const_iterator it=m.begin(); it!=m.end();++it)
+				flatData.push_back(make_pair(it->first,it->second));
+			std::sort(flatData.begin(),flatData.end(),cmp);
+
+			string nameStr;
+			for(size_t uj=0;uj<flatData.size();uj++)
+			{
+				string tmpStr;
+
+				stream_cast(tmpStr,flatData[uj].second);
+				//Use short name then value
+				nameStr+=ionNames[flatData[uj].first].first + tmpStr;
+			}
+			
+			//Append the new range/create a new entry
+			newNames[nameStr].push_back(unassignedMultiples[ui].first);
+
+
+			}
+		}
+
+		//Create one new name per new string we generated,
+		for(map<string,vector<int> >::iterator it=newNames.begin(); it!=newNames.end();++it)
+		{
+			for(size_t ui=0;ui<it->second.size();ui++)
+			{
+				ASSERT(ionIDs[it->second[ui]] == (size_t)-2);
+				ionIDs[it->second[ui]] =ionNames.size();
+			}
+			ionNames.push_back(make_pair(it->first,it->first));
+			//make a new random colour
+			RGBf col;
+			col.red=rand()/(float)std::numeric_limits<int>::max();
+			col.green=rand()/(float)std::numeric_limits<int>::max();
+			col.blue=rand()/(float)std::numeric_limits<int>::max();
+
+			colours.push_back(col);
+		}
+
+	}
+
+
+	delete[] inBuffer;
+	return 0;
+}
+
+unsigned int RangeFile::detectFileType(const char *rangeFile)
+{
+	enum
+	{
+		STATUS_NOT_CHECKED=0,
+		STATUS_IS_NOT,
+		STATUS_IS_MAYBE,
+	};
+
+	//create a fail-on-unimplemnted type detection scheme
+	vector<unsigned int > typeStatus(RANGE_FORMAT_END_OF_ENUM,STATUS_NOT_CHECKED);
+
+	//Check for RNG/Double RNG
+	//--
+	//first line in file should be two digits
+	{
+		std::ifstream f(rangeFile);
+
+		if(!f)
+			return RANGE_FORMAT_END_OF_ENUM;
+
+		std::string tmpStr;
+		size_t nCount;
+
+		//retrieve the line
+		getline(f,tmpStr);
+		//strip exterior whitespace
+		tmpStr=stripWhite(tmpStr);
+
+		//break it apart
+		vector<string> strs;
+		splitStrsRef(tmpStr.c_str()," ",strs);
+
+		//Drop the whitepace
+		stripZeroEntries(strs);	
+
+		if( strs.size() != 2)
+		{
+			//OK, quick parse failed. give up
+			typeStatus[RANGE_FORMAT_ORNL]=STATUS_IS_NOT;
+			typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_NOT;
+			goto skipoutRNGChecks;
+		}
+
+		//Check for two space separated markers, parsable as ints
+		size_t nIons,nRanges;
+		bool castRes[2];
+		castRes[0]=stream_cast(nIons,strs[0]);
+		castRes[1]=stream_cast(nRanges,strs[1]);
+		
+		if( castRes[0] || castRes[1])
+		{
+			//OK, quick parse failed. give up
+			typeStatus[RANGE_FORMAT_ORNL]=STATUS_IS_NOT;
+			typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_NOT;
+			goto skipoutRNGChecks;
+		}
+	
+
+		typeStatus[RANGE_FORMAT_ORNL]=STATUS_IS_MAYBE;
+		typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_MAYBE;
+
+		//spin forwards to find dash line
+		nCount=2*nIons+1;
+
+		while(nCount--)
+		{
+			getline(f,tmpStr);
+
+			//shouldn't hit eof
+			if(f.eof())
+			{
+				tmpStr.clear();
+				break;
+			}
+		}
+
+		if(!tmpStr.size() || tmpStr[0] != '-')
+		{
+			typeStatus[RANGE_FORMAT_ORNL]=STATUS_IS_NOT;
+			typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_NOT;
+			goto skipoutRNGChecks;
+
+		}
+
+		//Now, spin forwards until we either hit EOF or our double-dash marker
+
+		while(!f.eof())
+		{
+			getline(f,tmpStr);
+
+			if(tmpStr.size() > 2 &&
+				tmpStr[0] == '-' && tmpStr[1] == '-')
+			{
+				//OK, we saw a double dash. Thats forbidden under
+				// ORNL , and allowable under double ORNL
+				typeStatus[RANGE_FORMAT_ORNL]=STATUS_IS_NOT;
+				break;
+			}
+		}
+
+		if(f.eof())
+		{
+			//we did not see a double-dash, must be a vanilla ORNL file
+			typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_NOT;
+		}
+
+skipoutRNGChecks:
+		;
+	}
+	//--
+
+	//Check for RRNG, if RNG did not match
+	//--
+	if(typeStatus[RANGE_FORMAT_ORNL] != STATUS_IS_MAYBE && typeStatus[RANGE_FORMAT_DBL_ORNL] !=STATUS_IS_MAYBE)
+	{
+		std::ifstream f(rangeFile);
+
+		if(!f)
+			return RANGE_FORMAT_END_OF_ENUM;
+
+		//Check for existance of lines that match format section
+		std::vector<string> sections;
+		sections.push_back("[Ions]");
+		sections.push_back("[Ranges]");
+
+		vector<bool> haveSection(sections.size(),false);
+	
+		bool foundAllSections=false;
+
+		//Scan through each line, looking for a matching section header
+		while(!f.eof())
+		{
+
+			//Get line, stripped of whitspace
+			std::string tmpStr;
+			getline(f,tmpStr);
+			tmpStr=stripWhite(tmpStr);
+
+			//See if we have this header
+			for(size_t ui=0;ui<sections.size();ui++)
+			{
+				if(sections[ui] == tmpStr)
+				{
+					haveSection[ui]=true;
+
+					//Check to see if we have any sections left
+					if(std::find(haveSection.begin(),haveSection.end(),false)
+							== haveSection.end())
+						foundAllSections=true;
+
+					break;
+				}
+			}
+		
+			if(foundAllSections)
+				break;
+		}
+
+		if(foundAllSections)
+			typeStatus[RANGE_FORMAT_RRNG]=STATUS_IS_MAYBE;
+		else
+			typeStatus[RANGE_FORMAT_RRNG]=STATUS_IS_NOT;
+
+	}
+	else
+	{
+		//cannot be both maybe an RNG/Double RNG and an RRNG
+		typeStatus[RANGE_FORMAT_RRNG]=STATUS_IS_NOT;
+	}
+	//--
+
+	//Check for ENV
+	//--
+	if(typeStatus[RANGE_FORMAT_ORNL] != STATUS_IS_MAYBE && typeStatus[RANGE_FORMAT_DBL_ORNL] !=STATUS_IS_MAYBE &&
+			typeStatus[RANGE_FORMAT_RRNG] != STATUS_IS_MAYBE)
+	{
+		//TODO: Less lazy implementation
+		RangeFile tmpRng;
+		FILE *f;
+		f=fopen(rangeFile,"r");
 		
-		if(strcmp(oldLocale,"C"))
-			setlocale(LC_NUMERIC,oldLocale);
-		free(oldLocale);
-
-		return errState;
+		if(!f || tmpRng.openENV(f))
+			typeStatus[RANGE_FORMAT_ENV]=STATUS_IS_NOT;
+		else
+			typeStatus[RANGE_FORMAT_ENV]=STATUS_IS_MAYBE;
+		if(f)
+			fclose(f);
 	}
-
-	//revert back to user's locale, as needed
-	if(strcmp(oldLocale,"C"))
-		setlocale(LC_NUMERIC,oldLocale);
-
-	free(oldLocale);
-	
-	
-	//Run self consistency check on freshly loaded data
-	if(!isSelfConsistent())
+	else
 	{
-		errState=RANGE_ERR_DATA_INCONSISTENT;
-		return errState;
+		//cannot be both maybe an RNG/Double RNG/RRNG and an env
+		typeStatus[RANGE_FORMAT_ENV]=STATUS_IS_NOT;
 	}
-	
-	return 0;
-}
 
-bool RangeFile::openGuessFormat(const char *rangeFilename)
-{
-	unsigned int assumedFileFormat;
-	string s;
-	s=rangeFilename;
-	vector<string> sVec;
-	splitStrsRef(s.c_str(),'.',sVec);
-
-	if(sVec.empty())
-		assumedFileFormat=RANGE_FORMAT_ORNL;
-	else if(lowercase(sVec[sVec.size()-1]) == "rrng")
-		assumedFileFormat=RANGE_FORMAT_RRNG;
-	else if(lowercase(sVec[sVec.size()-1]) == "env")
-		assumedFileFormat=RANGE_FORMAT_ENV;
-	else
-		assumedFileFormat=RANGE_FORMAT_ORNL;
+	//--
 
-	//Use the guessed format
-	if(open(rangeFilename,assumedFileFormat))
+	//Check there is only one STATUS_IS_MAYBE or STATUS_NOT_CHECKED
+	if(std::count(typeStatus.begin(),typeStatus.end(),(unsigned int)STATUS_IS_NOT) == typeStatus.size()-1)
 	{
-		unsigned int errStateRestore;
-		errStateRestore=errState;
-		//If that failed, go to plan B-- Brute force.
-		//try all readers
-		bool openOK=false;
-
-		for(unsigned int ui=1;ui<RANGE_FORMAT_END_OF_ENUM; ui++)
+		//OK, there can only be one.  Return the format that has not
+		//  been rejected
+		for(size_t ui=0;ui<typeStatus.size();ui++)
 		{
-			if(ui == assumedFileFormat)
-				continue;
+			if(typeStatus[ui]==STATUS_IS_MAYBE)
+				return ui;
 
-			if(!open(rangeFilename,ui))
-			{
-				assumedFileFormat=ui;
-				openOK=true;
-				break;
-			}
-		}
-	
-		if(!openOK)
-		{
-			//Restore the error state for the assumed file format
-			errState=errStateRestore;
-			return false;
 		}
+		//in this case, we only have  NOT_CHECKED remaning. So, we hvae no idea
+		return RANGE_FORMAT_END_OF_ENUM;
+
 	}
 
-	return true;
+
+	return RANGE_FORMAT_END_OF_ENUM;
+
 }
 
-unsigned int RangeFile::openRNG( FILE *fpRange)
-{
-	clear();
 
-	//Oak-Ridge "Format" - this is based purely on example, as no standard exists
-	//the classic example is from Miller, "Atom probe: Analysis at the atomic scale"
-	//but alternate output forms exist. Our only strategy is to try to be as accommodating
-	//as reasonably possible
-	const size_t MAX_LINE_SIZE = 16536;
-	char *inBuffer = new char[MAX_LINE_SIZE];
-	unsigned int tempInt;
+unsigned int RangeFile::readRNGHeader(FILE *fpRange, vector<pair<string,string> > &strNames,
+			vector<RGBf> &fileColours, unsigned int &numRanges, unsigned int &numIons)
+{
 
-	unsigned int numRanges;
-	unsigned int numIons;	
+	char *inBuffer= new char[MAX_LINE_SIZE];
 	
-	
-	//Read out the number of ions and ranges int hef ile	
+	//Read out the number of ions and ranges in the file	
 	if(fscanf(fpRange, "%64u %64u", &numIons, &numRanges) != 2)
 	{
 		
@@ -682,15 +1161,9 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 		return  RANGE_ERR_EMPTY;
 	}
 	
-	//Reserve Storage
-	ionNames.reserve(numIons);
-	colours.reserve(numIons);
-	ranges.reserve(numRanges);
-	ionIDs.reserve(numRanges);
-	
+
 	RGBf colourStruct;
-	pair<string, string> namePair;
-	
+	pair<string,string> namePair;
 	//Read ion short and full names as well as colour info
 	for(unsigned int i=0; i<numIons; i++)
 	{
@@ -741,58 +1214,46 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 			return RANGE_ERR_FORMAT_COLOUR;
 		}
 		
-		ionNames.push_back(namePair);	
-		colours.push_back(colourStruct);	
+		strNames.push_back(namePair);	
+		fileColours.push_back(colourStruct);	
 	}	
-	
-	// skip over <LF> 
-	char *ret;
-	ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
-	if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
-	{
-		delete[] inBuffer;
-		return RANGE_ERR_FORMAT;
-	}
-	// read the column header line 
-	ret=fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange); 
 
-	if(!ret || strlen(ret) >= MAX_LINE_SIZE-1)
-	{
-		delete[] inBuffer;
-		return RANGE_ERR_FORMAT;
-	}
+	delete[] inBuffer;
+	return 0;
+}
 
-	//We should be at the line which has lots of dashes
-	if(inBuffer[0] != '-')
+unsigned int RangeFile::readRNGFreqTable(FILE *fpRange, char *inBuffer,const unsigned int numIons, 
+			const unsigned int numRanges,const vector<pair<string,string> > &names, 
+			vector<string> &colHeaders, vector<unsigned int > &tableEntries,
+			vector<pair<float,float> > &massData, vector<string> &warnings)
+{
+	string entry;
+	char *ptrBegin;
+	ptrBegin=inBuffer;
+	while(*ptrBegin && *ptrBegin == '-')
+		ptrBegin++;
+	splitStrsRef(ptrBegin," \n",colHeaders);
+	if(!colHeaders.size() )
 	{
-		delete[] inBuffer;
 		return RANGE_ERR_FORMAT_TABLESEPARATOR;
 	}
-
-
-	vector<string> colHeaders;
-	splitStrsRef(inBuffer,' ',colHeaders);
-
+	
 	//remove whitespace from each entry
 	for(size_t ui=0;ui<colHeaders.size();ui++)
-		stripWhite(colHeaders[ui]);
-	stripZeroEntries(colHeaders);
-	
-
-	if(!colHeaders.size() )
 	{
-		delete[] inBuffer;
-		return RANGE_ERR_FORMAT_TABLESEPARATOR;
+		stripChars(colHeaders[ui],"\f\n\r\t ");
 	}
+	
+	stripZeroEntries(colHeaders);
+
 
 	if(colHeaders.size() > 1)
 	{
 
-		if(colHeaders.size() -1 !=numIons)
+		if(colHeaders.size() !=numIons)
 		{
 			// Emit warning
-			delete[] inBuffer;
-			return RANGE_ERR_FORMAT_TABLESEPARATOR;
+			return RANGE_ERR_FORMAT_TABLEHEADER_NUMIONS;
 		}
 	
 		//Strip any trailing newlines off the last of the  colheaders,
@@ -806,9 +1267,9 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 		for(size_t ui=1;ui<colHeaders.size();ui++)
 		{
 			//look for a corresponding entry in the column headers
-			if(ionNames[ui-1].second != colHeaders[ui])
+			if(names[ui-1].second != colHeaders[ui])
 			{
-				warnMessages.push_back(TRANS("Range headings do not match order of the ions listed in the name specifications. The name specification ordering will be used when reading the range table, as the range heading section is declared as a comment in the file-format specifications, and is not to be intepreted by this program. Check range-species associations actually match what you expect."));
+				warnings.push_back(TRANS("Range headings do not match order of the ions listed in the name specifications. The name specification ordering will be used when reading the range table, as the range heading section is declared as a comment in the file-format specifications, and is not to be intepreted by this program. Check range-species associations actually match what you expect."));
 				break;
 			}
 
@@ -816,11 +1277,8 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 
 	}
 
-	vector<unsigned int > frequencyEntries;
-	frequencyEntries.clear();
-	frequencyEntries.resize(numRanges*numIons,0);
+	tableEntries.resize(numRanges*numIons,0);
 	//Load in each range file line
-	tempInt=0;
 	pair<float,float> massPair;
 
 	for(unsigned int i=0; i<numRanges; i++)
@@ -843,7 +1301,6 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 		if(entries.size() != numIons + 2 &&
 			entries.size() !=numIons+3)
 		{
-			delete[] inBuffer;
 			return RANGE_ERR_FORMAT_RANGETABLE;
 		}
 
@@ -855,197 +1312,49 @@ unsigned int RangeFile::openRNG( FILE *fpRange)
 		
 		if(stream_cast(massPair.first,entries[entryOff]))
 		{
-			delete[] inBuffer;
 			return RANGE_ERR_FORMAT_MASS_PAIR;
 		}
 		if(stream_cast(massPair.second,entries[entryOff+1]))
 		{
-			delete[] inBuffer;
 			return RANGE_ERR_FORMAT_MASS_PAIR;
 		}
 
 		if(massPair.first >= massPair.second)
 		{
-			delete[] inBuffer;
 			return RANGE_ERR_DATA_FLIPPED;
 		}
 
-		ranges.push_back(massPair);	
-		//Load the range data line
+		massData.push_back(massPair);
 
+		//Load the range data line
 		entryOff+=2;
 		for(unsigned int j=0; j<numIons; j++)
 		{
+			size_t tempInt;
 			if(stream_cast(tempInt,entries[entryOff+j]))
 			{
-				delete[] inBuffer;
 				return RANGE_ERR_FORMAT_TABLE_ENTRY;
 			}
 			
 			if(tempInt)
-				frequencyEntries[numIons*i + j]=tempInt;
+				tableEntries[numIons*i + j]=tempInt;
 			
 		}
 
+		
 	}
 	
+	
 	//Do some post-processing on the range table
 	//
 	//Prevent rangefiles that have no valid ranges
 	//from being loaded
-	size_t nMax=std::accumulate(frequencyEntries.begin(),frequencyEntries.end(),0);
+	size_t nMax=std::accumulate(tableEntries.begin(),tableEntries.end(),0);
 	if(!nMax)
 	{
-		delete[] inBuffer;
 		return RANGE_ERR_DATA_TOO_MANY_USELESS_RANGES;
 	}
 
-
-	//Because of a certain software's output
-	//it can generate a range listing like this (table +example colour line only)
-	//
-	// these are invalid according to white book
-	//  and the "Atom Probe Microscopy", (Springer series in Materials Science
-	//   vol. 160) descriptions
-	//
-	// Cu2 1.0 1.0 1.0 (Cu2)
-	// ------------Cu Ni Mg Si CuNi4 Mg3Si2 Cu2
-	// . 12.3 23.5 1 4 0 0 0 0 0
-	// . 32.1 43.2 0 0 3 2 0 0 0
-	// . 56.7 89.0 2 0 0 0 0 0 0
-	//
-	// which we get blamed for not supporting :(
-	//
-	//So, we have to scan the lists of ions, and create
-	//tentative "combined" ion names, from the list of ions at the top.
-	//
-	//However, this violates the naming system in the "white book" (Miller, Atom probe: Analysis at the atomic scale)
-	// scheme, which might allow something like
-	// U235U238
-	// as a single range representing a single ion. So they bastardise it by placing the zero columns
-	// as a hint marker. Technically speaking, the zero column entries should not exist
-	// in the format - as they would correspond to a non-existent species (or rather, an unreferenced species).
-	// To check the case of certain programs using cluster ions like this, we have to engage in some
-	// hacky-heuristics, check for 
-	// 	- Columns with only zero entries, 
-	// 	- which have combined numerical headers
-	//
-	// 	Then handle this as a separate case. FFS.
-
-	//-- Build a sparse vector of composed ions
-	std::map<string,size_t> composeMap;
-
-	for(size_t uj=0;uj<numIons;uj++)
-	{
-		bool maybeComposed;
-		maybeComposed=true;
-		for(size_t ui=0; ui<numRanges;ui++)
-		{
-			//Scan through the range listing to try to
-			//find a non-zero entries
-			if(frequencyEntries[numIons*ui + uj])
-			{
-				maybeComposed=false;
-				break;
-			}
-		}
-
-		//If the ion has a column full of zeroes, and
-		//the ion looks like its composable, then
-		//decompose it for later references
-		if(maybeComposed)
-			composeMap.insert(make_pair(ionNames[uj].first,uj));
-	}
-	//--
-
-
-	//Loop through each range's freq table entries, to determine if
-	// the ion is composed (has more than one "1" in multiplicity listing)
-	for(size_t ui=0;ui<numRanges;ui++)
-	{
-		std::map<size_t,size_t > freqEntries;
-		size_t freq;
-
-		freqEntries.clear();
-		freq=0;
-		for(size_t uj=0;uj<numIons;uj++)
-		{
-			size_t thisEntry;
-			thisEntry=frequencyEntries[numIons*ui+uj];
-			freq+=thisEntry;
-
-			if(thisEntry)
-			{
-				freqEntries.insert(make_pair(uj,thisEntry));
-			}
-		}
-
-		if(freq ==1)
-		{
-			//Simple case - we only had a single [1] in
-			//a row for the 
-			ASSERT(freqEntries.size() == 1);
-			ionIDs.push_back( freqEntries.begin()->first);
-		}
-		else if (freq > 1)
-		{
-			//More complex case
-			// ion appears to be composed of multiple fragments.
-			//First entry is the ion name, second is the number of times it occurs 
-			// (ie value in freq table, on this range line)
-			vector<pair<string,size_t> > entries;
-
-			for(map<size_t,size_t>::iterator it=freqEntries.begin();it!=freqEntries.end();++it)
-				entries.push_back(make_pair(ionNames[it->first].first,it->second));
-
-			//try to match the composed name to the
-			size_t offset;
-			if(!matchComposedName(composeMap,entries,offset))
-			{
-				//We failed to match the ion against a composed name.
-				// cannot deal with this case.
-				//
-				// we can't just build a new ion name,
-				// as we don't have a colour specification for this.
-				//
-				// We can't use the regular ion name, without 
-				// tracking multiplicity (and then what to do with it in every case - 
-				// seems only a special case for composition? eg. 
-				// Is it a sep. species when clustering? Who knows!)
-				delete[] inBuffer;
-				
-				return RANGE_ERR_DATA_NOMAPPED_IONNAME;
-			}
-
-
-
-
-			ASSERT(offset < ionNames.size());
-			ionIDs.push_back( offset);
-		}
-		else //0
-		{
-			//Range was useless - had no nonzero values
-			//in frequency table.
-			//Set to bad ionID - we will kill this later.
-			ionIDs.push_back(-1);
-		}
-	}
-
-	//Loop through any ranges with a bad ionID (== -1), then delete them by popping
-	for(size_t ui=0;ui<ionIDs.size();ui++)
-	{
-		if(ionIDs[ui] == (size_t)-1)
-		{
-			std::swap(ranges[ui],ranges.back());
-			ranges.pop_back();
-
-			std::swap(ionIDs[ui],ionIDs.back());
-			ionIDs.pop_back();
-		}
-	}
-
-	delete[] inBuffer;
 	return 0;
 }
 
@@ -1056,7 +1365,6 @@ unsigned int RangeFile::openENV(FILE *fpRange)
 	//Ruoen group "environment file" format
 	//This is not a standard file format, so the
 	//reader is a best-effort implementation, based upon example
-	const unsigned int MAX_LINE_SIZE=4096;	
 	char *inBuffer = new char[MAX_LINE_SIZE];
 	unsigned int numRanges;
 	unsigned int numIons;	
@@ -1246,7 +1554,6 @@ unsigned int RangeFile::openRRNG(FILE *fpRange)
 {
 	clear();
 	
-	const unsigned int MAX_LINE_SIZE=4096;
 	char *inBuffer = new char[MAX_LINE_SIZE];
 	unsigned int numRanges;
 	unsigned int numBasicIons;
@@ -2070,40 +2377,6 @@ bool RangeFile::isRanged(string shortName, bool caseSensitive)
 	return false;
 }
 
-unsigned int RangeFile::atomicNumberFromRange(unsigned int range) const
-{
-	if(range > ranges.size())
-		return 0;
-
-	string str= getName(getIonID(range));
-
-	for(unsigned int ui=0; ui<NUM_ELEMENTS; ui++)
-	{
-		if(str ==  string(cpAtomNaming[ui][0])
-				|| str == string(cpAtomNaming[ui][1]))
-			return ui+1;
-	}
-
-	return 0;	
-}
-
-unsigned int RangeFile::atomicNumberFromIonID(unsigned int ionID) const
-{
-	if(ionID > ionIDs.size())
-		return 0;
-
-	string str= getName(ionID);
-
-	for(unsigned int ui=0; ui<NUM_ELEMENTS; ui++)
-	{
-		if(str ==  string(cpAtomNaming[ui][0])
-				|| str == string(cpAtomNaming[ui][1]))
-			return ui+1;
-	}
-
-	return 0;	
-}
-
 void RangeFile::setColour(unsigned int id, const RGBf &r) 
 {
 	ASSERT(id < colours.size());
@@ -2276,3 +2549,4 @@ void RangeFile::setIonID(unsigned int range, unsigned int newIonId)
 	ASSERT(newIonId < ionIDs.size());
 	ionIDs[range] = newIonId;
 }
+
diff --git a/src/backend/APT/APTRanges.h b/src/backend/APT/APTRanges.h
index 60e6291..8309665 100644
--- a/src/backend/APT/APTRanges.h
+++ b/src/backend/APT/APTRanges.h
@@ -19,7 +19,11 @@
 #ifndef APTRANGES_H
 #define APTRANGES_H
 
-#include "APTClasses.h"
+#include <vector>
+#include <string>
+
+
+#include "backend/APT/ionhit.h"
 
 enum{	
 	RANGE_ERR_OPEN =1, 
@@ -29,6 +33,7 @@ enum{
 	RANGE_ERR_FORMAT_SHORTNAME,
 	RANGE_ERR_FORMAT_COLOUR,
 	RANGE_ERR_FORMAT_TABLESEPARATOR,
+	RANGE_ERR_FORMAT_TABLEHEADER_NUMIONS,
 	RANGE_ERR_FORMAT_RANGE_DUMMYCHARS,
 	RANGE_ERR_FORMAT_RANGETABLE,
 	RANGE_ERR_FORMAT_MASS_PAIR,
@@ -38,6 +43,7 @@ enum{
 	RANGE_ERR_DATA_FLIPPED,
 	RANGE_ERR_DATA_INCONSISTENT,
 	RANGE_ERR_DATA_NOMAPPED_IONNAME,
+	RANGE_ERR_NONUNIQUE_POLYATOMIC,
 	RANGE_ERR_ENUM_END
 };
 
@@ -52,7 +58,8 @@ typedef struct RGBf
 //Number of elements stored in the table
 const unsigned int NUM_ELEMENTS=119;
 
-enum{ RANGE_FORMAT_ORNL=1,
+enum{ RANGE_FORMAT_ORNL,
+	RANGE_FORMAT_DBL_ORNL,
 	RANGE_FORMAT_ENV,
 	RANGE_FORMAT_RRNG,
 	RANGE_FORMAT_END_OF_ENUM //not a format, just end of enumueration.
@@ -91,6 +98,25 @@ class RangeFile
 		//!Load an ORNL formatted "RNG" rangefile
 		// caller must supply and release file pointer
 		unsigned int openRNG(FILE *fp);
+		
+		//Read the header section of an RNG file
+		static unsigned int readRNGHeader(FILE *fpRange, 
+			std::vector<std::pair<std::string,std::string> > &strNames,
+			std::vector<RGBf> &fileColours, unsigned int &numRanges, 
+								unsigned int &numIons);
+
+		//Read the range frequency table
+		static unsigned int readRNGFreqTable(FILE *fpRange, char *inBuffer, 
+				const unsigned int numIons, const unsigned int numRanges,
+				const std::vector<std::pair<std::string,std::string> > &names,
+					std::vector<std::string> &colHeaders, 
+					std::vector<unsigned int > &tableEntries,
+					std::vector<std::pair<float,float> > &massData,
+					std::vector<std::string> &warnings);
+
+		unsigned int openDoubleRNG(FILE *fp);
+
+
 		//!Load an RRNG file
 		// caller must supply and release file pointer
 		unsigned int openRRNG(FILE *fp);
@@ -102,7 +128,7 @@ class RangeFile
 		RangeFile();
 		//!Open a specified range file
 		unsigned int open(const char *rangeFile, unsigned int format=RANGE_FORMAT_ORNL);	
-		//!Open a specified range file
+		//!Open a specified range file - returns true on success
 		bool openGuessFormat(const char *rangeFile);
 
 		//!is the extension string the same as that for a range file? I don't advocate this method, but it is convenient in a pinch.
@@ -110,6 +136,10 @@ class RangeFile
 		//!Grab a vector that contains all the extensions that are valid for range files
 		static void getAllExts(std::vector<std::string> &exts);
 
+		//Attempt to detect the file format of an unknown rangefile.
+		// returns enum value on success, or RANGE_FORMAT_END_OF_ENUM on failure
+		static unsigned int detectFileType(const char *file);
+
 		//!Print the translated error associated with the current range file state
 		void printErr(std::ostream &strm) const;
 		//!Retrieve the translated error associated with the current range file state
diff --git a/src/backend/APT/ionhit.cpp b/src/backend/APT/ionhit.cpp
new file mode 100644
index 0000000..3d15e68
--- /dev/null
+++ b/src/backend/APT/ionhit.cpp
@@ -0,0 +1,281 @@
+/*
+ * ionhit.cpp - Ion event data class
+ * Copyright (C) 2013  D Haley
+ * 
+ * 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 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "ionhit.h"
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+using std::vector;
+
+
+IonHit::IonHit() 
+{
+	//At this point I deliberately don't initialise the point class
+	//as in DEBUG mode, the point class will catch failure to init
+}
+
+IonHit::IonHit(const IonHit &obj2) : massToCharge(obj2.massToCharge), pos(obj2.pos)
+{
+}
+
+IonHit::IonHit(const Point3D &p, float newMass) : massToCharge(newMass), pos(p)
+{
+}
+
+void IonHit::setMassToCharge(float newMass)
+{
+	massToCharge=newMass;
+}
+
+float IonHit::getMassToCharge() const
+{
+	return massToCharge;
+}	
+
+
+void IonHit::setPos(const Point3D &p)
+{
+	pos=p;
+}
+
+#ifdef __LITTLE_ENDIAN__
+void IonHit::switchEndian()
+{
+	
+	pos.switchEndian();
+	floatSwapBytes(&(massToCharge));
+}
+#endif
+
+const IonHit &IonHit::operator=(const IonHit &obj)
+{
+	massToCharge=obj.massToCharge;
+	pos = obj.pos;
+
+	return *this;
+}
+
+IonHit IonHit::operator+(const Point3D &obj)
+{
+	//FIXME: I think this is wrong???
+	ASSERT(false);
+	pos.add(obj);	
+	return *this;
+}
+
+//!Create an pos file from a vector of IonHits
+unsigned int IonHit::makePos(const vector<IonHit> &ionVec, const char *filename)
+{
+	std::ofstream CFile(filename,std::ios::binary);
+	float floatBuffer[4];
+
+	if (!CFile)
+		return 1;
+
+	for (unsigned int ui=0; ui<ionVec.size(); ui++)
+	{
+		ionVec[ui].makePosData(floatBuffer);
+		CFile.write((char *)floatBuffer,4*sizeof(float));
+	}
+	return 0;
+}
+
+unsigned int IonHit::appendPos(const vector<IonHit> &points, const char *name)
+{
+	std::ofstream posFile(name,std::ios::binary|std::ios::app);	
+
+
+	if(!posFile)
+		return 1;
+
+	float data[4];	
+	
+	for(unsigned int ui=0; ui< points.size(); ui++)
+	{
+		points[ui].makePosData(data);
+		posFile.write((char *)data, 4*sizeof(float));
+	}
+
+
+	if(posFile.good())
+		return 0;
+	else
+		return 1;
+}
+
+void IonHit::getPoints(const vector<IonHit> &ions, vector<Point3D> &p)
+{
+	p.resize(ions.size());
+#pragma omp parallel for
+	for(size_t ui=0;ui<ions.size();ui++)
+		p[ui] = ions[ui].getPosRef();
+}
+
+void IonHit::makePosData(float *floatArr) const
+{
+	ASSERT(floatArr);
+	//copy positional information
+	pos.copyValueArr(floatArr);
+
+	//copy mass to charge data
+	*(floatArr+3) = massToCharge;
+		
+	#ifdef __LITTLE_ENDIAN__
+		floatSwapBytes(floatArr);
+		floatSwapBytes((floatArr+1));
+		floatSwapBytes((floatArr+2));
+		floatSwapBytes((floatArr+3));
+	#endif
+}
+
+Point3D IonHit::getPos() const
+{
+	return pos;
+}	
+
+bool IonHit::hasNaN()
+{
+	return (std::isnan(massToCharge) || std::isnan(pos[0]) || 
+				std::isnan(pos[1]) || std::isnan(pos[2]));
+}
+
+void IonHit::getCentroid(const std::vector<IonHit> &points,Point3D &centroid)
+{
+	centroid=Point3D(0,0,0);
+	size_t nPoints=points.size();
+#ifdef _OPENMP
+	
+	//Parallel version
+	//--
+	vector<Point3D> centroids(omp_get_max_threads(),Point3D(0,0,0));
+#pragma omp parallel for 
+	for(size_t ui=0;ui<nPoints;ui++)
+		centroids[omp_get_thread_num()]+=points[ui].getPos();
+
+	for(size_t ui=0;ui<centroids.size();ui++)
+		centroid+=centroids[ui];
+	//--
+
+#else
+	for(unsigned int ui=0;ui<nPoints;ui++)
+		centroid+=points[ui].getPos();
+#endif
+	
+	centroid*=1.0f/(float)nPoints;
+}
+
+void IonHit::getBoundCube(const std::vector<IonHit> &points,BoundCube &b)
+{
+	ASSERT(points.size());
+
+#ifndef _OPENMP
+	float bounds[3][2];
+	for(unsigned int ui=0;ui<3;ui++)
+	{
+		bounds[ui][0]=std::numeric_limits<float>::max();
+		bounds[ui][1]=-std::numeric_limits<float>::max();
+	}
+	
+	for(unsigned int ui=0; ui<points.size(); ui++)
+	{
+		Point3D p;
+		p=points[ui].getPos();
+		for(unsigned int uj=0; uj<3; uj++)
+		{
+			bounds[uj][0] = std::min(p.getValue(uj),bounds[uj][0]);
+			bounds[uj][1] = std::max(p.getValue(uj),bounds[uj][1]);
+		}
+	}
+
+	b.setBounds(bounds[0][0],bounds[1][0],
+			bounds[2][0],bounds[0][1],
+			bounds[1][1],bounds[2][1]);
+#else
+	// parallel version
+	unsigned int nT=omp_get_max_threads();
+	vector<BoundCube> cubes(nT);
+
+	for(unsigned int ui=0;ui<cubes.size();ui++)
+		cubes[ui].setInverseLimits(true);
+
+	#pragma omp parallel for 
+	for(unsigned int ui=0;ui<points.size();ui++)
+	{
+		Point3D p;
+		p=points[ui].getPos();
+
+		size_t tid=omp_get_thread_num();
+
+		//Move upper and lower bounds
+		for(unsigned int uj=0;uj<3;uj++)
+		{
+			BoundCube &threadCube=cubes[tid];
+
+			threadCube.setBound(uj,0,std::min(threadCube.getBound(uj,0),p[uj]));
+			threadCube.setBound(uj,1,std::max(threadCube.getBound(uj,1),p[uj]));
+		}
+	}
+
+	b.setInverseLimits(true);	
+	for(unsigned int ui=0;ui<nT;ui++)
+		b.expand(cubes[ui]);
+#endif
+
+}
+
+
+
+#ifdef DEBUG
+bool testIonHit();
+
+
+bool testAPTClasses()
+{
+	return testIonHit();
+}
+
+bool testIonHit()
+{
+	//tgest the boundcube function
+	vector<IonHit> h;
+	IonHit hit;
+	hit.setMassToCharge(1);
+	
+	for(size_t ui=0;ui<8;ui++)
+	{
+		hit.setPos(Point3D(ui&4,ui&2,ui&1));
+		h.push_back(hit);
+	}
+
+	BoundCube bc;
+	IonHit::getBoundCube(h,bc);
+	TEST(bc.isValid(),"check boundcube");
+
+	BoundCube biggerBox;
+	for(size_t ui=0;ui<3;ui++)
+	{
+		biggerBox.setBound(ui,0,-1.5f);
+		biggerBox.setBound(ui,0,1.5f);
+	}
+
+	TEST(biggerBox.contains(bc),"Check boundcube size");
+
+}
+
+#endif
diff --git a/src/backend/APT/ionhit.h b/src/backend/APT/ionhit.h
new file mode 100644
index 0000000..1c06843
--- /dev/null
+++ b/src/backend/APT/ionhit.h
@@ -0,0 +1,85 @@
+/*
+ * ionhit.h - Ion event data class
+ * Copyright (C) 2013  D Haley
+ * 
+ * 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 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IONHIT_H
+#define IONHIT_H
+
+#include "common/basics.h"
+class Point3D;
+
+//!This is a data holding class for POS file ions, from
+/* Pos ions are typically obtained via reconstructed apt detector hits
+ * and are of form (x,y,z mass/charge)
+ */
+class IonHit
+{
+	private:
+		float massToCharge; // mass to charge ratio in Atomic Mass Units per (charge on electron)
+		Point3D pos; //position (xyz) in nm
+	public:
+		IonHit();
+		//copy constructor
+		IonHit(const IonHit &);
+		IonHit(const Point3D &p, float massToCharge);
+
+		//Size of data when stored in a file record
+		static const  unsigned int DATA_SIZE = 16;
+
+		void setHit(float *arr) { pos.setValueArr(arr); massToCharge=arr[3];};
+		void setMassToCharge(float newMassToCharge);
+		void setPos(const Point3D &pos);
+		void setPos(float fX, float fY, float fZ)
+			{ pos.setValue(fX,fY,fZ);};
+		Point3D getPos() const;
+		inline const Point3D &getPosRef() const {return pos;};
+		//returns true if any of the 4 data pts are NaN
+		bool hasNaN();
+
+#ifdef __LITTLE_ENDIAN__		
+		void switchEndian();
+#endif
+		//this does the endian switch for you
+		//but you must supply a valid array.
+		void makePosData(float *floatArr) const;
+		float getMassToCharge() const;
+
+
+		//Helper functions
+		//--
+		//get the points from a vector of of ionhits
+		static void getPoints(const std::vector<IonHit> &ions, std::vector<Point3D> &pts);
+
+		//Get the bounding cube from a vector of ionhits
+		static void getBoundCube(const std::vector<IonHit> &p, BoundCube &b);
+
+		//Get the centroid from a vector of ion hits
+		static void getCentroid(const std::vector<IonHit> &points, Point3D &centroid);
+		
+		//Add these points to a pos file
+		static unsigned int appendPos(const std::vector<IonHit> &points, const char *name);
+
+		//Save a pos file, overwriting any previous data at this location
+		static unsigned int makePos(const std::vector<IonHit> &points, const char *name);
+		//---
+
+		const IonHit &operator=(const IonHit &obj);
+		float operator[](unsigned int ui) const;	
+		IonHit operator+(const Point3D &obj);
+};
+
+#endif
diff --git a/src/backend/configFile.cpp b/src/backend/configFile.cpp
index 46e5f55..3618bdd 100644
--- a/src/backend/configFile.cpp
+++ b/src/backend/configFile.cpp
@@ -43,10 +43,10 @@ using std::string;
 
 
 ConfigFile::ConfigFile() : configLoadOK(false), panelMode(CONFIG_PANELMODE_REMEMBER),
-	haveIntialAppSize(false), mouseZoomRatePercent(100),mouseMoveRatePercent(100),
+	haveInitialAppSize(false), mouseZoomRatePercent(100),mouseMoveRatePercent(100),
 	allowOnline(true), allowOnlineVerCheck(true), leftRightSashPos(0),
-	topBottomSashPos(0),filterSashPos(0),plotListSashPos(0)
-
+	topBottomSashPos(0),filterSashPos(0),plotListSashPos(0), haveMaxPoints(false),
+	maxPointsScene(0)
 { 
 }
 
@@ -107,18 +107,18 @@ void ConfigFile::setFilterDefaults(const vector<Filter *>  &defs)
 
 bool ConfigFile::getInitialAppSize(unsigned int &x, unsigned int &y) const
 {
-	if(haveIntialAppSize)
+	if(haveInitialAppSize)
 	{
 		x=initialSizeX;
 		y=initialSizeY;
 	}
 	
-	return haveIntialAppSize;
+	return haveInitialAppSize;
 }
 
 void ConfigFile::setInitialAppSize(unsigned int x, unsigned int y)
 {
-	haveIntialAppSize=true;
+	haveInitialAppSize=true;
 	initialSizeX=x;
 	initialSizeY=y;
 }
@@ -199,7 +199,7 @@ unsigned int ConfigFile::read()
 				XMLGetAttrib(nodePtr,initialSizeY,"height"))
 			{
 				if( initialSizeX >0 && initialSizeY > 0)
-					haveIntialAppSize=true;
+					haveInitialAppSize=true;
 			}
 		}
 		nodePtr=nodeStack.top();
@@ -461,6 +461,15 @@ unsigned int ConfigFile::read()
 		}
 		nodePtr=nodeStack.top();
 		nodeStack.pop();
+
+
+		nodeStack.push(nodePtr);
+		haveMaxPoints=XMLGetNextElemAttrib(nodePtr,maxPointsScene,"maxdisplaypoints","value");
+
+		nodePtr=nodeStack.top();
+		nodeStack.pop();
+
+
 nodeptrEndJump:
 		;
 
@@ -529,7 +538,7 @@ bool ConfigFile::write()
 	f<< "<threeDepictconfig>" << endl;
 	f<<tabs(1)<< "<writer version=\"" << PROGRAM_VERSION << "\"/>" << endl;
 
-	if(haveIntialAppSize)	
+	if(haveInitialAppSize)	
 	{
 		f<<tabs(1)<< "<initialwinsize width=\"" << initialSizeX << "\" height=\"" <<
 				initialSizeY << "\"/>" << endl;
@@ -587,6 +596,10 @@ bool ConfigFile::write()
 			f << tabs(2) << "<pos name=\"plotlist\" value=\"" << plotListSashPos<< "\"/>" << endl;
 	f << tabs(1) << "</sashposition>" << endl;
 
+
+	if(haveMaxPoints)
+		f << tabs(1) << "<maxdisplaypoints value=\"" << maxPointsScene << "\"/>" << endl;
+
 	f << "</threeDepictconfig>" << endl;
 
 	ASSERT(isValidXML(filename.c_str()));
diff --git a/src/backend/configFile.h b/src/backend/configFile.h
index 410a9c4..2c5cd31 100644
--- a/src/backend/configFile.h
+++ b/src/backend/configFile.h
@@ -68,7 +68,7 @@ class ConfigFile
 		//!Initial application window size in pixels
 		unsigned int initialSizeX,initialSizeY;
 		//!Do we have a valid initial app size?
-		bool haveIntialAppSize;
+		bool haveInitialAppSize;
 
 		//!Percentile speeds for mouse zoom and move 
 		unsigned int mouseZoomRatePercent,mouseMoveRatePercent;
@@ -82,8 +82,14 @@ class ConfigFile
 		//!fractional initial positions of sashes in main UI
 		float leftRightSashPos,topBottomSashPos,
 		      		filterSashPos,plotListSashPos;
-					
-					
+
+		//!True if config has a valid maxPoints value
+		bool haveMaxPoints;
+
+		//!Max. number of points to display in 3D scene
+		// 0 for unlimited
+		size_t maxPointsScene;
+
 	public:
 		ConfigFile(); 
 		~ConfigFile(); 
@@ -114,6 +120,10 @@ class ConfigFile
 		//even if it is not in the array (use hardcoded)
 		Filter *getDefaultFilter(unsigned int type) const;
 
+		bool getHaveMaxPoints() const { return haveMaxPoints;}
+		size_t getMaxPoints() const { return maxPointsScene;}
+		void setMaxPoints(size_t maxP) { haveMaxPoints=true; maxPointsScene=maxP;}
+
 		//!Return startup status of UI panels
 		bool getPanelEnabled(unsigned int panelID) const;
 		
diff --git a/src/backend/filter.cpp b/src/backend/filter.cpp
index 4a112d6..7721e15 100644
--- a/src/backend/filter.cpp
+++ b/src/backend/filter.cpp
@@ -285,10 +285,6 @@ void FilterPropGroup::checkConsistent() const
 }
 #endif
 
-void IonStreamData::clear()
-{
-	data.clear();
-}
 
 void VoxelStreamData::clear()
 {
@@ -458,6 +454,48 @@ IonStreamData::IonStreamData() : representationType(ION_REPRESENT_POINTS),
 	streamType=STREAM_TYPE_IONS;
 }
 
+void IonStreamData::clear()
+{
+	data.clear();
+}
+
+IonStreamData *IonStreamData::cloneSampled(float fraction) const
+
+{
+	IonStreamData *out = new IonStreamData;
+
+	out->representationType=representationType;
+	out->r=r;
+	out->g=g;
+	out->b=b;
+	out->a=a;
+	out->ionSize=ionSize;
+	out->valueType=valueType;
+	out->parent=parent;
+	out->cached=0;
+
+
+	out->data.reserve(fraction*data.size()*0.9f);
+
+	
+	RandNumGen rng;
+	rng.initTimer();
+	for(size_t ui=0;ui<data.size();ui++)
+	{
+		if(rng.genUniformDev() < fraction)
+			out->data.push_back(data[ui]);	
+	}
+
+	return out;
+}
+
+size_t IonStreamData::getNumBasicObjects() const
+{
+	return data.size();
+}
+
+
+
 VoxelStreamData::VoxelStreamData() : representationType(VOXEL_REPRESENT_POINTCLOUD),
 	r(1.0f),g(0.0f),b(0.0f),a(0.3f), splatSize(2.0f),isoLevel(0.5f)
 {
@@ -523,7 +561,7 @@ bool Filter::haveCache() const
 	return cacheOK;
 }
 
-void Filter::getSelectionDevices(vector<SelectionDevice<Filter> *> &outD)
+void Filter::getSelectionDevices(vector<SelectionDevice *> &outD) const
 {
 	outD.resize(devices.size());
 
@@ -576,6 +614,31 @@ void Filter::initFilter(const std::vector<const FilterStreamData *> &dataIn,
 	std::copy(dataIn.begin(),dataIn.end(),dataOut.begin());
 }
 
+bool ProgressData::operator==( const ProgressData &oth) const
+{
+	if(filterProgress!=oth.filterProgress ||
+		(totalProgress!=oth.totalProgress) ||
+		(totalNumFilters!=oth.totalNumFilters) ||
+		(step!=oth.step) ||
+		(maxStep!=oth.maxStep) ||
+		(curFilter!=oth.curFilter )||
+		(stepName!=oth.stepName) )
+		return false;
+
+	return true;
+}
+
+const ProgressData &ProgressData::operator=(const ProgressData &oth)
+{
+	filterProgress=oth.filterProgress;
+	totalProgress=oth.totalProgress;
+	totalNumFilters=oth.totalNumFilters;
+	step=oth.step;
+	maxStep=oth.maxStep;
+	curFilter=oth.curFilter;
+	stepName=oth.stepName;
+}
+
 #ifdef DEBUG
 extern Filter *makeFilter(unsigned int ui);
 extern Filter *makeFilter(const std::string &s);
diff --git a/src/backend/filter.h b/src/backend/filter.h
index 7ba7b7e..8d533e1 100644
--- a/src/backend/filter.h
+++ b/src/backend/filter.h
@@ -17,15 +17,20 @@
 */
 #ifndef FILTER_H
 #define FILTER_H
+
 class Filter;
 class FilterStreamData;
+
 class ProgressData;
 class RangeFileFilter;
 
+#include "APT/ionhit.h"
+
 #include "APT/APTRanges.h"
 #include "common/constants.h"
 
 #include "gl/select.h"
+#include "gl/drawables.h"
 
 #include "common/voxels.h"
 
@@ -116,6 +121,7 @@ enum
 	//VoxelStreamData
 	VOXEL_REPRESENT_POINTCLOUD,
 	VOXEL_REPRESENT_ISOSURF,
+	VOXEL_REPRESENT_AXIAL_SLICE,
 	VOXEL_REPRESENT_END
 };
 
@@ -135,7 +141,6 @@ enum
 //
 
 //Forward dec.
-class FilterStreamData;
 class wxPropertyGrid;
 
 //!Return the number of elements in a vector of filter data - i.e. the sum of the number of objects within each stream. Only masked streams (STREAM_TYPE_*) will be counted
@@ -246,7 +251,16 @@ class IonStreamData : public FilterStreamData
 public:
 	IonStreamData();
 	void clear();
-	size_t getNumBasicObjects() const  { return data.size();};
+
+	//Sample the data vector to the specified fraction
+	void sample(float fraction);
+
+	//Duplicate this object, but only using a sampling of the data
+	// vector. The retuend object must be deleted by the
+	// caller. Cached status is *not* duplicated
+	IonStreamData *cloneSampled(float fraction) const;
+
+	size_t getNumBasicObjects() const;
 	
 	unsigned int representationType;
 	float r,g,b,a;
@@ -412,7 +426,7 @@ class Filter
 		//Filter output cache
 		std::vector<FilterStreamData *> filterOutputs;
 		//!User interaction "Devices" associated with this filter
-		std::vector<SelectionDevice<Filter> *> devices;
+		std::vector<SelectionDevice *> devices;
 	public:	
 		Filter() ;
 		virtual ~Filter();
@@ -522,7 +536,7 @@ class Filter
 		 * another at this level (for example setting two devices on one primitve,
 		 * with the same mouse/key bindings). So dont do that.
 		 */
-		void getSelectionDevices(vector<SelectionDevice<Filter> *> &devices);
+		void getSelectionDevices(vector<SelectionDevice *> &devices) const;
 
 
 		//!Update the output statistics for this filter (num items of streams of each type output)
@@ -592,6 +606,9 @@ class ProgressData
 		//!Name of current operation, if specified
 		std::string stepName;
 
+		bool operator==(const ProgressData &o) const;
+		const ProgressData &operator=(const ProgressData &o);
+
 		void reset() { filterProgress=totalProgress=step=maxStep=0;curFilter=0; stepName.clear();};
 		void clock() { filterProgress=step=maxStep=0;curFilter=0;totalProgress++; stepName.clear();};
 };
diff --git a/src/backend/filters/K3DTree-mk2.cpp b/src/backend/filters/K3DTree-mk2.cpp
index b7c1901..61fa062 100644
--- a/src/backend/filters/K3DTree-mk2.cpp
+++ b/src/backend/filters/K3DTree-mk2.cpp
@@ -18,6 +18,7 @@
 
 #include "K3DTree-mk2.h"
 
+#include "backend/APT/ionhit.h"
 
 #include <stack>
 #include <queue>
@@ -55,7 +56,7 @@ void K3DTreeMk2::resetPts(std::vector<IonHit> &p, bool clear)
 	
 
 	//Compute bounding box for indexedPoints
-	treeBounds=getIonDataLimits(p);
+	IonHit::getBoundCube(p,treeBounds);
 
 #pragma omp parallel for
 	for(size_t ui=0;ui<indexedPoints.size();ui++)
@@ -108,6 +109,8 @@ size_t K3DTreeMk2::size() const
 bool K3DTreeMk2::build()
 {
 
+	const size_t PROGRESS_REDUCE=5000;
+
 	using std::make_pair;
 
 	enum
diff --git a/src/backend/filters/K3DTree-mk2.h b/src/backend/filters/K3DTree-mk2.h
index 4897922..94f3038 100644
--- a/src/backend/filters/K3DTree-mk2.h
+++ b/src/backend/filters/K3DTree-mk2.h
@@ -19,6 +19,12 @@
 #ifndef K3DTREEMK2_H
 #define K3DTREEMK2_H
 
+#include <vector>
+#include <utility>
+
+#include "common/basics.h"
+#include "backend/APT/ionhit.h"
+
 //This is the second revision of my KD tree implementation
 //The goals here are, as compared to the first
 //	- Improved build performance by minimising memory allocation calls
@@ -26,10 +32,6 @@
 //	- index based construction for smaller in-tree storage
 
 
-
-#include "../APT/APTClasses.h" //For IonHit
-
-
 //!Functor allowing for sorting of points in 3D
 /*! Used by KD Tree to sort points based around which splitting axis is being used
  * once the axis is set, points will be ranked based upon their relative value in
diff --git a/src/backend/filters/K3DTree.cpp b/src/backend/filters/K3DTree.cpp
index 40f228a..4e6cfe0 100644
--- a/src/backend/filters/K3DTree.cpp
+++ b/src/backend/filters/K3DTree.cpp
@@ -17,8 +17,9 @@
  */
 #include "K3DTree.h"
 
-using std::vector;
+#include "backend/APT/ionhit.h"
 
+using std::vector;
 
 //Axis compare
 //==========
diff --git a/src/backend/filters/allFilter.cpp b/src/backend/filters/allFilter.cpp
index fe0bb3c..fd66597 100644
--- a/src/backend/filters/allFilter.cpp
+++ b/src/backend/filters/allFilter.cpp
@@ -42,6 +42,17 @@ Filter *makeFilter(const std::string &s)
 	return  f;
 }
 
+bool isValidFilterName(const std::string &s)
+{
+	for(unsigned int ui=0;ui<FILTER_TYPE_ENUM_END; ui++)
+	{
+		if(FILTER_NAMES[ui] == s)
+			return true;
+	}
+
+	return false;
+}
+
 Filter *makeFilter(unsigned int ui)
 {
 	Filter *f;
@@ -100,6 +111,8 @@ Filter *makeFilter(unsigned int ui)
 	return  f;
 }
 
+
+
 Filter *makeFilterFromDefUserString(const std::string &s)
 {
 	//This is a bit of a hack. Build each object, then retrieve its string.
diff --git a/src/backend/filters/allFilter.h b/src/backend/filters/allFilter.h
index c6dd44e..ed8a140 100644
--- a/src/backend/filters/allFilter.h
+++ b/src/backend/filters/allFilter.h
@@ -33,6 +33,10 @@
 #include "ionInfo.h"
 #include "annotation.h"
 
+
+//!Returns true if the string is a valid filter name
+bool isValidFilterName(const std::string &s);
+
 //!Create a "true default" filter from its true name string
 Filter *makeFilter(const string  &s) ;
 //!Create a true default filter from its enum value FILTER_TYPE_*
diff --git a/src/backend/filters/annotation.cpp b/src/backend/filters/annotation.cpp
index 1bff0f4..811bfa3 100644
--- a/src/backend/filters/annotation.cpp
+++ b/src/backend/filters/annotation.cpp
@@ -26,6 +26,7 @@ enum
 {
 	KEY_POSITION=1,
 	KEY_MODE,
+	KEY_ENABLE,
 	KEY_UPVEC,
 	KEY_ACROSSVEC,
 	KEY_ANNOTATE_TEXT,
@@ -75,10 +76,10 @@ const char *annotationModeStrings[] =
 AnnotateFilter::AnnotateFilter() : annotationMode(ANNOTATION_TEXT),
 	position(Point3D(0,0,0)), target(Point3D(1,0,0)), upVec(Point3D(0,0,1)),
 	acrossVec(Point3D(0,1,0)), textSize(1.0f), annotateSize(1.0f),
-	sphereAngleSize(1.5f),r(0),g(0),b(1),a(1),active(true),showAngleText(true), 
+	sphereMarkerSize(1.5f),r(0),g(0),b(1),a(1),active(true),showAngleText(true), 
 	reflexAngle(true), angleFormatPreDecimal(0),angleFormatPostDecimal(0),
 	linearFixedTicks(true),linearMeasureTicks(10),linearMeasureSpacing(10.0f),
-	fontSizeLinearMeasure(5),linearMeasureMarkerSize(3)	
+	fontSizeLinearMeasure(5)
 {
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(annotationModeStrings) == ANNOTATION_MODE_END);
 
@@ -90,7 +91,7 @@ AnnotateFilter::AnnotateFilter() : annotationMode(ANNOTATION_TEXT),
 	
 	textSize=1;
 	annotateSize=1;
-	sphereAngleSize=1.5;
+	sphereMarkerSize=1.5;
 	
 	//Set the colour to default blue
 	r=g=0;b=a=1.0;
@@ -103,7 +104,6 @@ AnnotateFilter::AnnotateFilter() : annotationMode(ANNOTATION_TEXT),
 	linearMeasureTicks=10;
 	linearFixedTicks=true;
 	linearMeasureSpacing=10.0f;
-	linearMeasureMarkerSize=3.0f;
 	lineSize=1.0f;
 	angleFormatPreDecimal=angleFormatPostDecimal=0;
 
@@ -126,7 +126,7 @@ Filter *AnnotateFilter::cloneUncached() const
 
 	p->textSize=textSize;
 	p->annotateSize=annotateSize;
-	p->sphereAngleSize=sphereAngleSize;
+	p->sphereMarkerSize=sphereMarkerSize;
 
 	p->r=r;
 	p->g=g;
@@ -146,7 +146,6 @@ Filter *AnnotateFilter::cloneUncached() const
 	p->linearFixedTicks=linearFixedTicks;
 	p->linearMeasureSpacing=linearMeasureSpacing;
 	p->linearMeasureTicks=linearMeasureTicks;
-	p->linearMeasureMarkerSize=linearMeasureMarkerSize;
 	p->lineSize=lineSize;
 
 	//We are copying whether to cache or not,
@@ -193,7 +192,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dt->setAlignment(DRAWTEXT_ALIGN_CENTRE);
 		
 		dt->canSelect=true;
-		SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+		SelectionDevice *s = new SelectionDevice(this);
 		SelectionBinding bind[1];
 		
 		bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_TEXT_BIND_ORIGIN,
@@ -222,7 +221,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dv->canSelect=true;
 		dv->wantsLight=true;
 
-		SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+		SelectionDevice *s = new SelectionDevice(this);
 		SelectionBinding bind[2];
 		
 		bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_VECTOR_BIND_TARGET,
@@ -248,12 +247,12 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		for(unsigned int ui=0;ui<3;ui++)
 		{
 			DrawSphere *dS;
-			SelectionDevice<Filter> *s= new SelectionDevice<Filter>(this);
+			SelectionDevice *s= new SelectionDevice(this);
 			SelectionBinding bind[2];
 
 			dS=new DrawSphere;
 			dS->setOrigin(anglePos[ui]);
-			dS->setRadius(sphereAngleSize);
+			dS->setRadius(sphereMarkerSize);
 			dS->setColour(r,g,b,a);
 
 			dS->canSelect=true;
@@ -445,14 +444,14 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 			//Start marker
 			DrawSphere *dS;
 			dS = new DrawSphere;
-			dS->setRadius(linearMeasureMarkerSize);
+			dS->setRadius(sphereMarkerSize);
 			dS->setOrigin(position);
 			dS->setColour(r,g,b,a);
 
 			dS->canSelect=true;
 			dS->wantsLight=true;
 			
-			SelectionDevice<Filter> *s= new SelectionDevice<Filter>(this);
+			SelectionDevice *s= new SelectionDevice(this);
 			SelectionBinding bind[4];
 			//Create binding for sphere translation.
 			//Note that each binding is a bit different, as it
@@ -475,10 +474,10 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		
 		
 			//Now do the second sphere (end marker)
-			s= new SelectionDevice<Filter>(this);
+			s= new SelectionDevice(this);
 			dS = new DrawSphere;
 			
-			dS->setRadius(linearMeasureMarkerSize);
+			dS->setRadius(sphereMarkerSize);
 			dS->setOrigin(target);
 			dS->setColour(r,g,b,a);
 
@@ -518,12 +517,25 @@ size_t AnnotateFilter::numBytesForCache(size_t nObjects) const
 
 void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 {
-	string str;
+	string tmpStr;
 	FilterProperty p;
 	size_t curGroup=0;
 
+	tmpStr=boolStrEnc(active);	
+
+	p.name=TRANS("Enable");
+	p.data=tmpStr;
+	p.key=KEY_ENABLE;
+	p.helpText=TRANS("Enable/disable annotation");
+	p.type=PROPERTY_TYPE_BOOL;
+	propertyList.addProperty(p,curGroup);
+
+	if(!active)
+		return;
+
+
+
 	vector<pair<unsigned int,string> > choices;
-	string tmpStr;
 	
 	for(unsigned int ui=0;ui<ANNOTATION_MODE_END; ui++)
 	{
@@ -782,7 +794,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 
 			}
 			
-			stream_cast(tmpStr,sphereAngleSize);
+			stream_cast(tmpStr,sphereMarkerSize);
 			p.name=TRANS("Sphere size");
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_REAL;
@@ -868,6 +880,15 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 				p.helpText=TRANS("Distance between tick marks along ruler");
 				propertyList.addProperty(p,curGroup);
 			}
+			
+			
+			stream_cast(tmpStr,sphereMarkerSize);
+			p.name=TRANS("Sphere size");
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_REAL;
+			p.key=KEY_SPHERE_ANGLE_SIZE;
+			p.helpText=TRANS("Marker sphere size for manipulating tool");
+			propertyList.addProperty(p,curGroup);
 
 			break;
 		}
@@ -877,10 +898,10 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 
 
 	genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0),
-		(unsigned char)(b*255),(unsigned char)(a*255),str);
+		(unsigned char)(b*255),(unsigned char)(a*255),tmpStr);
 	p.key=KEY_COLOUR;
 	p.name=TRANS("Colour");
-	p.data=str;
+	p.data=tmpStr;
 	p.type=PROPERTY_TYPE_COLOUR;
 	p.helpText=TRANS("Colour for ruler and ticks");
 	propertyList.addProperty(p,curGroup);
@@ -893,6 +914,27 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 	string stripped=stripWhite(value);
 	switch(key)
 	{
+		case KEY_ENABLE:
+		{
+			bool tmpV;
+			
+			if( value == "1")
+				tmpV=true;
+			else if(value == "0")
+				tmpV=false;
+			else
+			{
+				ASSERT(false);
+				return false;
+			}
+
+			if(tmpV!=active)
+			{
+				active=tmpV;
+				needUpdate=true;
+			}
+			break;
+		}
 		case KEY_MODE:
 		{
 			unsigned int newMode;
@@ -1129,10 +1171,10 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 			float tmp;
 			stream_cast(tmp,value);
 
-			if(tmp == sphereAngleSize)
+			if(tmp == sphereMarkerSize)
 				return false;
 
-			sphereAngleSize=tmp;
+			sphereMarkerSize=tmp;
 			needUpdate=true;
 
 			break;
@@ -1293,7 +1335,8 @@ bool AnnotateFilter::writeState(std::ostream &f,unsigned int format, unsigned in
 			f << tabs(depth+1) << "<annotatetext value=\""<<escapeXML(annotateText)<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<textsize value=\""<<textSize<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<annotatesize value=\""<<annotateSize<< "\"/>"  << endl;
-			f << tabs(depth+1) << "<sphereanglesize value=\""<<sphereAngleSize<< "\"/>"  << endl;
+			//DEPRECATE: rename this element. It has been repurposed.
+			f << tabs(depth+1) << "<sphereanglesize value=\""<<sphereMarkerSize<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<linesize value=\""<<lineSize<< "\"/>"  << endl;
 			std::string colourString;
 			genColString((unsigned char)(r*255),(unsigned char)(g*255),
@@ -1409,9 +1452,9 @@ bool AnnotateFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 		return false;
 
 
-	if(!XMLGetNextElemAttrib(nodePtr,sphereAngleSize,"sphereanglesize","value"))
+	if(!XMLGetNextElemAttrib(nodePtr,sphereMarkerSize,"sphereanglesize","value"))
 		return false;
-	if(sphereAngleSize<0.0f)
+	if(sphereMarkerSize<0.0f)
 		return false;
 
 	if(!XMLGetNextElemAttrib(nodePtr,lineSize,"linesize","value"))
@@ -1515,7 +1558,7 @@ void AnnotateFilter::setPropFromBinding(const SelectionBinding &b)
 			b.getValue(anglePos[2]);
 			break;
 		case BINDING_ANGLE_SPHERERADIUS:
-			b.getValue(sphereAngleSize);
+			b.getValue(sphereMarkerSize);
 			break;
 		default:
 			ASSERT(false);
diff --git a/src/backend/filters/annotation.h b/src/backend/filters/annotation.h
index 01c23cc..dbed5dc 100644
--- a/src/backend/filters/annotation.h
+++ b/src/backend/filters/annotation.h
@@ -45,7 +45,7 @@ class AnnotateFilter : public Filter
 		//annotation text string
 		std::string annotateText;
 		//Text display style, arrow annotation size, handle size for angle spheres
-		float textSize,annotateSize,sphereAngleSize,lineSize;
+		float textSize,annotateSize,sphereMarkerSize,lineSize;
 
 		//Annotation colour
 		float r,g,b,a;
@@ -73,8 +73,6 @@ class AnnotateFilter : public Filter
 		//Font-size for linear measure object 
 		float fontSizeLinearMeasure;
 
-		//Measure end-marker size
-		float linearMeasureMarkerSize;
 	public:
 		//!Constructor
 		AnnotateFilter();
diff --git a/src/backend/filters/boundingBox.cpp b/src/backend/filters/boundingBox.cpp
index 051ecc5..98f2ec9 100644
--- a/src/backend/filters/boundingBox.cpp
+++ b/src/backend/filters/boundingBox.cpp
@@ -1147,7 +1147,7 @@ bool boxVolumeTest()
 	}
 
 
-	TEST(havePrismDrawable, "bounding box existance test");
+	TEST(havePrismDrawable, "bounding box existence test");
 	
 	TEST(fabs(bc.volume() - 1.0f) 
 		< sqrt(std::numeric_limits<float>::epsilon()),
diff --git a/src/backend/filters/clusterAnalysis.cpp b/src/backend/filters/clusterAnalysis.cpp
index 6a5ec2a..185b671 100644
--- a/src/backend/filters/clusterAnalysis.cpp
+++ b/src/backend/filters/clusterAnalysis.cpp
@@ -2908,8 +2908,8 @@ void ClusterAnalysisFilter::getSingularValues(const vector<vector<IonHit> > &clu
 
 			//Compute the cluster's centre of mass (assuming unit mass per object)
 			Point3D centroid[2];
-			getPointSum(clusteredCore[ui],centroid[0]);
-			getPointSum(clusteredBulk[ui],centroid[1]);
+			IonHit::getCentroid(clusteredCore[ui],centroid[0]);
+			IonHit::getCentroid(clusteredBulk[ui],centroid[1]);
 		
 			Point3D clusterCentre;
 			clusterCentre= centroid[0]+centroid[1];
@@ -2977,7 +2977,7 @@ void ClusterAnalysisFilter::getSingularValues(const vector<vector<IonHit> > &clu
 			}
 			//Compute the cluster's centre of mass (assuming unit mass per object)
 			Point3D centroid;
-			getPointSum(clusteredCore[ui],centroid);
+			IonHit::getCentroid(clusteredCore[ui],centroid);
 			centroid*=1.0f/(float)(clusteredCore[ui].size());
 			//Allocate space, by growing as needed
 			if(numEntries*DIMENSION > dataSize)
diff --git a/src/backend/filters/compositionProfile.cpp b/src/backend/filters/compositionProfile.cpp
index 880212a..dc5119f 100644
--- a/src/backend/filters/compositionProfile.cpp
+++ b/src/backend/filters/compositionProfile.cpp
@@ -181,7 +181,7 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 				//tapered cylinder)
 				dC->lockRadii();
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b;
 				//Bind the drawable object to the properties we wish
 				//to be able to modify
@@ -250,7 +250,7 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 				//The object is selectable
 				dS->canSelect=true;
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b[3];
 
 				//Apple doesn't have right click, so we need
@@ -322,6 +322,10 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 	float length;
 	unsigned int numBins, errCode;
 	errCode=getBinData(numBins,length);
+
+	if(!numBins)
+		return 0;
+
 	if(errCode)
 		return errCode;
 
@@ -648,7 +652,9 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 					newPt*=sqrt(vectorParams[1].sqrMag());
 				}
 			}
-			
+			if(newPt.sqrMag() < sqrt(std::numeric_limits<float>::epsilon()))
+				return false;
+
 			if(!(vectorParams[1] == newPt ))
 			{
 				vectorParams[1] = newPt;
@@ -762,6 +768,9 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 			if(stream_cast(newRad,value))
 				return false;
 
+			if(newRad < sqrt(std::numeric_limits<float>::epsilon()))
+				return false;
+
 			if(scalarParams[0] != newRad )
 			{
 				scalarParams[0] = newRad;
@@ -1515,8 +1524,22 @@ void CompositionProfileFilter::setPropFromBinding(const SelectionBinding &b)
 			b.getValue(vectorParams[0]);
 			break;
 		case BINDING_CYLINDER_DIRECTION:
+		{
+			Point3D pOld=vectorParams[1];
 			b.getValue(vectorParams[1]);
+			//Test getting the bin data.
+			// if something is wrong, abort
+			float length;
+			unsigned int numBins;
+			unsigned int errCode= getBinData(numBins,length);
+			if(errCode || !numBins)
+			{
+				vectorParams[1]=pOld;
+				return;
+			}
+
 			break;
+		}
 		default:
 			ASSERT(false);
 	}
@@ -1524,7 +1547,7 @@ void CompositionProfileFilter::setPropFromBinding(const SelectionBinding &b)
 	clearCache();
 }
 
-unsigned int CompositionProfileFilter::getPrimitiveId(const std::string &primitiveName) const
+unsigned int CompositionProfileFilter::getPrimitiveId(const std::string &primitiveName) 
 {
 	for(size_t ui=0;ui<PRIMITIVE_END; ui++)
 	{
diff --git a/src/backend/filters/compositionProfile.h b/src/backend/filters/compositionProfile.h
index 2b3c79c..eb47d72 100644
--- a/src/backend/filters/compositionProfile.h
+++ b/src/backend/filters/compositionProfile.h
@@ -83,7 +83,7 @@ class CompositionProfileFilter : public Filter
 		static void binIon(unsigned int targetBin, const RangeStreamData* rng, const std::map<unsigned int,unsigned int> &ionIDMapping,
 			vector<vector<size_t> > &frequencyTable, float massToCharge);
 
-		unsigned int getPrimitiveId(const std::string &s) const;
+		static unsigned int getPrimitiveId(const std::string &s);;
 
 		//obtain the size of each bin, and number of bins required for profile
 		unsigned int getBinData(unsigned int &numBins, float &binLength) const;
diff --git a/src/backend/filters/dataLoad.cpp b/src/backend/filters/dataLoad.cpp
index b272a39..00fdc62 100644
--- a/src/backend/filters/dataLoad.cpp
+++ b/src/backend/filters/dataLoad.cpp
@@ -25,6 +25,8 @@
 #include "filterCommon.h"
 
 
+#include "backend/APT/APTFileIO.h"
+
 //Default number of ions to load
 const size_t MAX_IONS_LOAD_DEFAULT=5*1024*1024/(4*sizeof(float)); //5 MB worth.
 
@@ -364,7 +366,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 
 
 	BoundCube dataCube;
-	dataCube = getIonDataLimits(ionData->data);
+	IonHit::getBoundCube(ionData->data,dataCube);
 
 	if(dataCube.isNumericallyBig())
 	{
@@ -1200,7 +1202,7 @@ bool posFileTest()
 		return true;
 	}
 
-	if(IonVectorToPos(hits,posName))
+	if(IonHit::makePos(hits,posName))
 	{
 		WARN(false,"Unable to create test output file. Unit test was indeterminate. Requires write access to excution path");
 		return true;
diff --git a/src/backend/filters/externalProgram.cpp b/src/backend/filters/externalProgram.cpp
index 89e9b64..15b766e 100644
--- a/src/backend/filters/externalProgram.cpp
+++ b/src/backend/filters/externalProgram.cpp
@@ -16,10 +16,12 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include "externalProgram.h"
-#include "../../wxcommon.h"
 
 #include "filterCommon.h"
 
+#include "../../wxcommon.h"
+#include "backend/APT/APTFileIO.h"
+
 #include <wx/filename.h>
 #include <wx/dir.h>
 
@@ -144,7 +146,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 
 				s = stlStr(tmpStr);
 				s+=".pos";
-				if(IonVectorToPos(i->data,s))
+				if(IonHit::makePos(i->data,s.c_str()))
 				{
 					//Uh-oh problem. Clean up and exit
 					return WRITEPOS_FAIL;
diff --git a/src/backend/filters/filterCommon.cpp b/src/backend/filters/filterCommon.cpp
index ca7d374..fe00b28 100644
--- a/src/backend/filters/filterCommon.cpp
+++ b/src/backend/filters/filterCommon.cpp
@@ -18,6 +18,7 @@
 
 #include "filterCommon.h"
 
+#include "common/colourmap.h"
 
 
 
@@ -660,3 +661,36 @@ unsigned int doHull(unsigned int bufferSize, double *buffer,
 
 	return 0;
 }
+
+
+DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap) 
+{
+	//Set up the colour bar. Place it in a draw stream type
+	DrawColourBarOverlay *dc = new DrawColourBarOverlay;
+
+	vector<float> r,g,b;
+	r.resize(nColours);
+	g.resize(nColours);
+	b.resize(nColours);
+
+	for (unsigned int ui=0;ui<nColours;ui++)
+	{
+		unsigned char rgb[3]; //RGB array
+		float value;
+		value = (float)(ui)*(maxV-minV)/(float)nColours + minV;
+		//Pick the desired colour map
+		colourMapWrap(colourMap,rgb,value,minV,maxV);
+		r[ui]=rgb[0]/255.0f;
+		g[ui]=rgb[1]/255.0f;
+		b[ui]=rgb[2]/255.0f;
+	}
+
+	dc->setColourVec(r,g,b);
+
+	dc->setSize(0.08,0.6);
+	dc->setPosition(0.1,0.1);
+	dc->setMinMax(minV,maxV);
+
+
+	return dc;
+}
diff --git a/src/backend/filters/filterCommon.h b/src/backend/filters/filterCommon.h
index 5a88f2a..9dc69ed 100644
--- a/src/backend/filters/filterCommon.h
+++ b/src/backend/filters/filterCommon.h
@@ -24,7 +24,6 @@
 #include "common/stringFuncs.h"
 #include "common/xmlHelper.h"
 
-#include "backend/APT/APTClasses.h"
 #include "backend/APT/APTRanges.h"
 
 //QHull library
@@ -50,6 +49,8 @@ enum
 	HULL_ERR_ENUM_END
 };
 
+const size_t PROGRESS_REDUCE=5000;
+
 //serialise 3D std::vectors to specified output stream in XML format
 void writeVectorsXML(std::ostream &f, const char *containerName,
 		const std::vector<Point3D> &vectorParams, unsigned int depth);
@@ -127,4 +128,8 @@ unsigned int computeConvexHull(const std::vector<const FilterStreamData*> &data,
 unsigned int computeConvexHull(const std::vector<Point3D> &data, 
 			unsigned int *progress, bool (*callback)(bool), 
 			std::vector<Point3D> &hullPts, bool freeHull=true);
+
+//Draw a colour bar
+DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap) ;
+
 #endif
diff --git a/src/backend/filters/geometryHelpers.cpp b/src/backend/filters/geometryHelpers.cpp
index cde5f1b..5b3f123 100644
--- a/src/backend/filters/geometryHelpers.cpp
+++ b/src/backend/filters/geometryHelpers.cpp
@@ -18,10 +18,16 @@
 
 
 #include "geometryHelpers.h"
+
+#include "backend/APT/ionhit.h"
+
 #ifdef _OPENMP
 #include <omp.h>
 #endif
 
+
+using std::vector;
+
 const size_t DEFAULT_NUM_CALLBACK=5000;
 
 //These numbers have not been optimised. On a 2CPU system, I cannot find
diff --git a/src/backend/filters/geometryHelpers.h b/src/backend/filters/geometryHelpers.h
index 7d56637..d189a92 100644
--- a/src/backend/filters/geometryHelpers.h
+++ b/src/backend/filters/geometryHelpers.h
@@ -18,9 +18,9 @@
 #ifndef GEOMETRYHELPER_H
 #define GEOMETRYHELPER_H
 
+#include "backend/APT/ionhit.h"
 
-#include "../APT/APTClasses.h"
-
+#include <vector>
 
 enum
 {
@@ -130,28 +130,28 @@ class CropHelper
 		//Run the input filtering in linear (single CPU) mode
 		// allocHint, if >0 , is the recommended fraction of input to reserve
 		// ahead of copying
-		unsigned int runFilterLinear(const vector<IonHit> &dataIn,
-				vector<IonHit> &dataOut,float allocHint);
+		unsigned int runFilterLinear(const std::vector<IonHit> &dataIn,
+				std::vector<IonHit> &dataOut,float allocHint);
 	
 		//Run the input filtering in parallel (multi CPU) mode
-		unsigned int runFilterParallel(const vector<IonHit> &dataIn,
-				vector<IonHit> &dataOut,float allocHint);
+		unsigned int runFilterParallel(const std::vector<IonHit> &dataIn,
+				std::vector<IonHit> &dataOut,float allocHint);
 	public:
 	
 		//Input vectors and scalars represent the fundamental
 		// basis for the desired geometry
 		CropHelper(bool (*callback)(bool), unsigned int *prog, 
 			size_t totalData,size_t filterMode,
-			vector<Point3D> &vectors, vector<float> &scalars);
+			std::vector<Point3D> &vectors, std::vector<float> &scalars);
 		
 		//Filter the input ion data in order to generate output points
 		// output data may contain previous data - this will be appended to,
 		// not overwritten
-		unsigned int runFilter(const vector<IonHit> &dataIn,
-				vector<IonHit> &dataOut);
+		unsigned int runFilter(const std::vector<IonHit> &dataIn,
+				std::vector<IonHit> &dataOut);
 
 
-		void setMapMaxima(size_t maxima){mapMax=maxima;};
+		void setMapMaxima(size_t maxima){ASSERT(maxima); mapMax=maxima;};
 		//Map an ion from its 3D coordinate to a 1D coordinate along the 
 		// selected geometric primitive. Returns true if the ion is mappable (i.e. inside selected primitive mode)
 		unsigned int mapIon1D(const IonHit &ionIn ) const;
diff --git a/src/backend/filters/ionClip.cpp b/src/backend/filters/ionClip.cpp
index 1e5d833..3696be3 100644
--- a/src/backend/filters/ionClip.cpp
+++ b/src/backend/filters/ionClip.cpp
@@ -161,7 +161,7 @@ unsigned int IonClipFilter::refresh(const std::vector<const FilterStreamData *>
 				//The object is selectable
 				dS->canSelect=true;
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b[3];
 
 				//Apple doesn't have right click, so we need
@@ -218,7 +218,7 @@ unsigned int IonClipFilter::refresh(const std::vector<const FilterStreamData *>
 				dS->canSelect=true;
 				dV->canSelect=true;
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b[2];
 				//Bind the drawable object to the properties we wish
 				//to be able to modify
@@ -264,7 +264,7 @@ unsigned int IonClipFilter::refresh(const std::vector<const FilterStreamData *>
 				//tapered cylinder)
 				dC->lockRadii();
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b;
 				//Bind the drawable object to the properties we wish
 				//to be able to modify
@@ -333,7 +333,7 @@ unsigned int IonClipFilter::refresh(const std::vector<const FilterStreamData *>
 				//The object is selectable
 				dR->canSelect=true;
 
-				SelectionDevice<Filter> *s = new SelectionDevice<Filter>(this);
+				SelectionDevice *s = new SelectionDevice(this);
 				SelectionBinding b[2];
 				//Bind the drawable object to the properties we wish
 				//to be able to modify
diff --git a/src/backend/filters/ionColour.cpp b/src/backend/filters/ionColour.cpp
index b5124d3..3b20249 100644
--- a/src/backend/filters/ionColour.cpp
+++ b/src/backend/filters/ionColour.cpp
@@ -22,6 +22,7 @@
 #include "common/colourmap.h"
 
 
+
 const unsigned int MAX_NUM_COLOURS=256;
 enum
 {
@@ -70,38 +71,6 @@ size_t IonColourFilter::numBytesForCache(size_t nObjects) const
 		return (size_t)((float)(nObjects*IONDATA_SIZE));
 }
 
-DrawColourBarOverlay *IonColourFilter::makeColourBar() const
-{
-	//If we have ions, then we should draw a colour bar
-	//Set up the colour bar. Place it in a draw stream type
-	DrawColourBarOverlay *dc = new DrawColourBarOverlay;
-
-	vector<float> r,g,b;
-	r.resize(nColours);
-	g.resize(nColours);
-	b.resize(nColours);
-
-	for (unsigned int ui=0;ui<nColours;ui++)
-	{
-		unsigned char rgb[3]; //RGB array
-		float value;
-		value = (float)(ui)*(mapBounds[1]-mapBounds[0])/(float)nColours + mapBounds[0];
-		//Pick the desired colour map
-		colourMapWrap(colourMap,rgb,value,mapBounds[0],mapBounds[1]);
-		r[ui]=rgb[0]/255.0f;
-		g[ui]=rgb[1]/255.0f;
-		b[ui]=rgb[2]/255.0f;
-	}
-
-	dc->setColourVec(r,g,b);
-
-	dc->setSize(0.08,0.6);
-	dc->setPosition(0.1,0.1);
-	dc->setMinMax(mapBounds[0],mapBounds[1]);
-
-
-	return dc;
-}
 
 
 unsigned int IonColourFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
@@ -124,7 +93,8 @@ unsigned int IonColourFilter::refresh(const std::vector<const FilterStreamData *
 		{
 			DrawStreamData *d = new DrawStreamData;
 			d->parent=this;
-			d->drawables.push_back(makeColourBar());
+			d->drawables.push_back(makeColourBar(mapBounds[0],
+					mapBounds[1],nColours,colourMap));
 			d->cached=0;
 			getOut.push_back(d);
 		}
@@ -222,7 +192,7 @@ unsigned int IonColourFilter::refresh(const std::vector<const FilterStreamData *
 	if(foundIons && showColourBar)
 	{
 		DrawStreamData *d = new DrawStreamData;
-		d->drawables.push_back(makeColourBar());
+		d->drawables.push_back(makeColourBar(mapBounds[0],mapBounds[1],nColours,colourMap));
 		d->parent=this;
 		d->cached=0;
 		getOut.push_back(d);
diff --git a/src/backend/filters/ionColour.h b/src/backend/filters/ionColour.h
index fe65a0e..96ff982 100644
--- a/src/backend/filters/ionColour.h
+++ b/src/backend/filters/ionColour.h
@@ -42,7 +42,6 @@ class IonColourFilter: public Filter
 		//!Should we display the colour bar?
 		bool showColourBar;
 
-		DrawColourBarOverlay* makeColourBar() const;
 	public:
 		IonColourFilter();
 		//!Duplicate filter contents, excluding cache.
diff --git a/src/backend/filters/ionInfo.cpp b/src/backend/filters/ionInfo.cpp
index dc1c284..fa1f546 100644
--- a/src/backend/filters/ionInfo.cpp
+++ b/src/backend/filters/ionInfo.cpp
@@ -59,7 +59,7 @@ bool getRectilinearBounds(const std::vector<const FilterStreamData *> &dataIn, B
 			if(ions->data.size() >1)
 			{
 				ions = (const IonStreamData*)dataIn[ui];
-				c=getIonDataLimits(ions->data);
+				IonHit::getBoundCube(ions->data,c);
 
 				if(c.isValid())
 				{
@@ -233,15 +233,13 @@ unsigned int IonInfoFilter::refresh(const std::vector<const FilterStreamData *>
 			str=std::string(TRANS("--Counts--") );
 			consoleOutput.push_back(str);
 			
-			size_t totalRanged;
+			//sum all ions *except* the unranged.
+			for(size_t ui=0;ui<numIons.size()-1;ui++)
+				numRanged+=numIons[ui];
+				
 			if(wantNormalise)
 			{
-				totalRanged=0;
-				//sum all ions *except* the unranged.
-				for(size_t ui=0;ui<numIons.size()-1;ui++)
-					totalRanged+=numIons[ui];
-				
-				stream_cast(str,totalRanged);
+				stream_cast(str,numRanged);
 				str=TRANS("Total Ranged\t")+str;
 			}
 			else
@@ -257,8 +255,8 @@ unsigned int IonInfoFilter::refresh(const std::vector<const FilterStreamData *>
 			{
 				if(wantNormalise)
 				{
-					if(totalRanged)
-						stream_cast(str,((float)numIons[ui])/(float)totalRanged);
+					if(numRanged)
+						stream_cast(str,((float)numIons[ui])/(float)numRanged);
 					else
 						str=TRANS("n/a");
 				}
@@ -278,9 +276,6 @@ unsigned int IonInfoFilter::refresh(const std::vector<const FilterStreamData *>
 			str=std::string("----------");
 			consoleOutput.push_back(str);
 	
-			
-			for(size_t ui=0;ui<numIons.size();ui++)
-				numRanged++;
 		}
 		else
 		{
@@ -558,7 +553,7 @@ void IonInfoFilter::setPropFromBinding(const SelectionBinding &b)
 }
 
 unsigned int IonInfoFilter::convexHullEstimateVol(const vector<const FilterStreamData*> &data, 
-								float &volume,bool (*callback)(bool))const
+								float &volume,bool (*callback)(bool))
 {
 	volume=0;
 
@@ -832,7 +827,7 @@ bool volumeBoxTest()
 	f->getConsoleStrings(consoleStrings); 
 	
 	//weak test for the console string size
-	TEST(consoleStrings.size(), "console strings existance test");
+	TEST(consoleStrings.size(), "console strings existence test");
 
 
 	//Ensure that the rectilinear volume is the same as
@@ -901,7 +896,7 @@ bool volumeSphereTest()
 	f->getConsoleStrings(consoleStrings); 
 
 	//weak test for the console string size
-	TEST(consoleStrings.size(), "console strings existance test");
+	TEST(consoleStrings.size(), "console strings existence test");
 
 
 	float volMeasure,volReal;
@@ -926,7 +921,7 @@ bool volumeSphereTest()
 	volReal =4.0f/3.0f*M_PI*OUTLINE_RADIUS*OUTLINE_RADIUS*OUTLINE_RADIUS;
 	TEST(fabs(volMeasure -volReal) < 0.05*volReal, "volume test, convex est. of sphere");
 	
-	TEST(consoleStrings.size(), "console strings existance test");
+	TEST(consoleStrings.size(), "console strings existence test");
 
 	delete d;
 	delete f;
diff --git a/src/backend/filters/ionInfo.h b/src/backend/filters/ionInfo.h
index cf31a4c..7f031c8 100644
--- a/src/backend/filters/ionInfo.h
+++ b/src/backend/filters/ionInfo.h
@@ -62,8 +62,8 @@ class IonInfoFilter : public Filter
 		//Convex hull volume estimation routine.
 		//returns 0 on success. global "qh " "object"  will contain
 		//the hull. Volume is computed.
-		unsigned int convexHullEstimateVol(const vector<const FilterStreamData*> &data, 
-							float &vol,bool (*callback)(bool)) const;
+		static unsigned int convexHullEstimateVol(const vector<const FilterStreamData*> &data, 
+							float &vol,bool (*callback)(bool));
 	public:
 		//!Constructor
 		IonInfoFilter();
diff --git a/src/backend/filters/rangeFile.cpp b/src/backend/filters/rangeFile.cpp
index c78c59c..34bd3e1 100644
--- a/src/backend/filters/rangeFile.cpp
+++ b/src/backend/filters/rangeFile.cpp
@@ -19,15 +19,7 @@
 
 #include "filterCommon.h"
 
-enum
-{
-	KEY_RANGE_ACTIVE=1,
-	KEY_DROP_UNRANGED,
-	KEY_RANGE_FILENAME,
-	KEY_RANGE_IONID,
-	KEY_ENABLE_ALL_IONS, //Limited to ~100K ions
-	KEY_ENABLE_ALL_RANGES=100000,
-};
+#include <algorithm>
 
 const unsigned int NUM_ROWS_ION=3;
 const unsigned int NUM_ROWS_RANGE=4;
@@ -117,314 +109,377 @@ unsigned int RangeFileFilter::refresh(const std::vector<const FilterStreamData *
 		return 0;
 	}
 
-	vector<IonStreamData *> d;
+	
+	//See if we have enabled ranges and ions
+	bool haveEnabled;
+	haveEnabled= (std::find(enabledRanges.begin(),
+			   	enabledRanges.end(),(char)1) !=enabledRanges.end()) && 
+			(std::find(enabledIons.begin(),
+			   	enabledIons.end(),(char)1) !=enabledIons.end());
+
+	//Nothing enabled? Nothing to do!
+	if(!(!haveEnabled && dropUnranged))
+	{
+		vector<IonStreamData *> d;
+
+		//Split the output up into chunks, one for each range, 
+		//Extra 1 for unranged ions	
+		d.resize(rng.getNumIons()+1);
 
-	//Split the output up into chunks, one for each range, 
-	//Extra 1 for unranged ions	
-	d.resize(rng.getNumIons()+1);
 
-	//Generate output filter streams. 
-	for(unsigned int ui=0;ui<d.size(); ui++)
-	{
-		d[ui] = new IonStreamData;
-		d[ui]->parent=this;
-	}
+		bool haveDefIonColour=false;
+		//GCC complains about this, but this is protected by haveDefIonColour.
+		RGBf defIonColour;
 
-	bool haveDefIonColour=false;
-	//GCC complains about this, but this is protected by haveDefIonColour.
-	RGBf defIonColour;
+		//Try to maintain ion size if possible
+		bool haveIonSize,sameSize; // have we set the ionSize?
+		float ionSize;
+		haveIonSize=false;
+		sameSize=true;
 
-	//Try to maintain ion size if possible
-	bool haveIonSize,sameSize; // have we set the ionSize?
-	float ionSize;
-	haveIonSize=false;
-	sameSize=true;
 
+		progress.step=1;
+		progress.filterProgress=0;
+		progress.stepName=TRANS("Pre-Allocate");
+		progress.maxStep=2;	
 
-	progress.step=1;
-	progress.filterProgress=0;
-	progress.stepName=TRANS("Pre-Allocate");
-	progress.maxStep=2;	
+		vector<size_t> dSizes;
+		dSizes.resize(d.size(),0);
+		size_t totalSize=numElements(dataIn);
 
-	vector<size_t> dSizes;
-	dSizes.resize(d.size(),0);
-	size_t totalSize=numElements(dataIn);
-	
-	//Step 1: Do a first sweep to obtain range sizes needed
-	// then reserve the same amount of mem as we need on the output
-	//========================
-	for(unsigned int ui=0;ui<dataIn.size() ;ui++)
-	{
-		switch(dataIn[ui]->getStreamType())
+
+		//Check to see if there are any enabled ranges
+		
+		//Generate output filter streams. 
+		for(unsigned int ui=0;ui<d.size(); ui++)
+		{
+			d[ui] = new IonStreamData;
+			d[ui]->parent=this;
+		}
+		
+		if(!haveEnabled)
 		{
-			case STREAM_TYPE_IONS: 
+			//There are no enabled ranges at all.
+			dSizes.back()=totalSize;
+		}
+		else
+		{
+			//Step 1: Do a first sweep to obtain range sizes needed
+			// then reserve the same amount of mem as we need on the output
+			//========================
+			for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 			{
+				switch(dataIn[ui]->getStreamType())
+				{
+					case STREAM_TYPE_IONS: 
+					{
 
 #ifdef _OPENMP
-				//Create a unique array for each thread, so they don't try
-				//to modify the same data structure
-				unsigned int nT =omp_get_max_threads(); 
-				vector<size_t> *dSizeArr = new vector<size_t>[nT];
-				for(unsigned int uk=0;uk<nT;uk++)
-					dSizeArr[uk].resize(dSizes.size(),0);
+						//Create a unique array for each thread, so they don't try
+						//to modify the same data structure
+						unsigned int nT =omp_get_max_threads(); 
+						vector<size_t> *dSizeArr = new vector<size_t>[nT];
+						for(unsigned int uk=0;uk<nT;uk++)
+							dSizeArr[uk].resize(dSizes.size(),0);
 #endif
-				const IonStreamData *src = ((const IonStreamData *)dataIn[ui]);
-				size_t n=0;
+						const IonStreamData *src = ((const IonStreamData *)dataIn[ui]);
+						size_t n=0;
 
 
-				unsigned int curProg=NUM_CALLBACK;
-				bool spin=false;
-				#pragma omp parallel for firstprivate(curProg)
-				for(size_t uj=0; uj<src->data.size();uj++)
-				{
+						unsigned int curProg=NUM_CALLBACK;
+						bool spin=false;
+						#pragma omp parallel for firstprivate(curProg)
+						for(size_t uj=0; uj<src->data.size();uj++)
+						{
 #ifdef _OPENMP
-					unsigned int thisT=omp_get_thread_num();
+							unsigned int thisT=omp_get_thread_num();
 #endif
-					if(spin)
-						continue;
-					
-					//get the range ID for this particular ion.
-					unsigned int rangeID;
-					rangeID=rng.getRangeID(src->data[uj].getMassToCharge());
-
-					//If ion is unranged, then it will have a rangeID of -1
-					if(rangeID != (unsigned int)-1 && enabledRanges[rangeID] )
-					{
-						unsigned int ionID=rng.getIonID(rangeID);
-
-						//if we are going to keep the ion
-						//then increment this array size
-						if(enabledIons[ionID])
-						{
-							#ifdef _OPENMP
-								dSizeArr[thisT][ionID]++;
-							#else
-								dSizes[ionID]++;
-							#endif
-
-						}
-					}
-					
-					//update progress periodically
-					if(!curProg--)
-					{
+							if(spin)
+								continue;
+							
+							//get the range ID for this particular ion.
+							unsigned int rangeID;
+							rangeID=rng.getRangeID(src->data[uj].getMassToCharge());
+
+							//If ion is unranged, then it will have a rangeID of -1
+							if(rangeID != (unsigned int)-1 && enabledRanges[rangeID] )
+							{
+								unsigned int ionID=rng.getIonID(rangeID);
+
+								//if we are going to keep the ion
+								//then increment this array size
+								if(enabledIons[ionID])
+								{
+									#ifdef _OPENMP
+										dSizeArr[thisT][ionID]++;
+									#else
+										dSizes[ionID]++;
+									#endif
+
+								}
+							}
+							
+							//update progress periodically
+							if(!curProg--)
+							{
 #pragma omp critical
-						{
-						n+=NUM_CALLBACK;
-						progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
-						curProg=NUM_CALLBACK;
+								{
+								n+=NUM_CALLBACK;
+								progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
+								curProg=NUM_CALLBACK;
 
 
-						if(!(*callback)(false))
-							spin=true;
+								if(!(*callback)(false))
+									spin=true;
+								}
+							}
 						}
-					}
-				}
 
-				if(spin)
-					return RANGEFILE_ABORT_FAIL;
+						if(spin)
+							return RANGEFILE_ABORT_FAIL;
 #ifdef _OPENMP
-				//Merge the arrays back together
-				for(unsigned int uk=0;uk<nT;uk++)
-				{
-					for(unsigned int uj=0;uj<dSizes.size();uj++)
-						dSizes[uj] = dSizes[uj]+dSizeArr[uk][uj];
-				}
-				delete[] dSizeArr;
+						//Merge the arrays back together
+						for(unsigned int uk=0;uk<nT;uk++)
+						{
+							for(unsigned int uj=0;uj<dSizes.size();uj++)
+								dSizes[uj] = dSizes[uj]+dSizeArr[uk][uj];
+						}
+						delete[] dSizeArr;
 #endif
 
+					}
+				}
 			}
 		}
-	}
-
 
-	//reserve the vector to the exact size we need
-	try
-	{
-		for(size_t ui=0;ui<d.size();ui++)
-			d[ui]->data.reserve(dSizes[ui]);
-	}
-	catch(std::bad_alloc)
-	{
-		for(size_t ui=0;ui<d.size();ui++)
-			delete d[ui];
-		return RANGEFILE_BAD_ALLOC;
-	}
+		//reserve the vector to the exact size we need
+		try
+		{
+			for(size_t ui=0;ui<d.size();ui++)
+				d[ui]->data.reserve(dSizes[ui]);
+		}
+		catch(std::bad_alloc)
+		{
+			for(size_t ui=0;ui<d.size();ui++)
+				delete d[ui];
+			return RANGEFILE_BAD_ALLOC;
+		}
 
-	dSizes.clear();
-	//===================================
+		dSizes.clear();
+		//===================================
 
-	//Update progress info
-	progress.step=2;
-	progress.filterProgress=0;
-	progress.stepName=TRANS("Range");
-	size_t n=0;
+		//Update progress info
+		progress.step=2;
+		progress.filterProgress=0;
+		progress.stepName=TRANS("Range");
 
 
-	
+		
 
-	//Step 2: Go through each data stream, if it is an ion stream, range it.
-	//	I tried parallelising this a few different ways, but the linear performance wa simply better.
-	//		- Tried an array of openmp locks
-	//		- Tried keeping a unique offset number and fixing the size of the output vectors
-	//		- Tried straight criticalling the push_back
-	//	 Trying to merge vectors in // is tricky. result was 9-10x slower than linear
-	//=========================================
-	for(unsigned int ui=0;ui<dataIn.size() ;ui++)
-	{
-		switch(dataIn[ui]->getStreamType())
+		//Step 2: Go through each data stream, if it is an ion stream, range it.
+		//=========================================
+		if(haveEnabled)
 		{
-			case STREAM_TYPE_IONS: 
+			//	I tried parallelising this a few different ways, but the linear performance wa simply better.
+			//		- Tried an array of openmp locks
+			//		- Tried keeping a unique offset number and fixing the size of the output vectors
+			//		- Tried straight criticalling the push_back
+			//	 Trying to merge vectors in // is tricky. result was 9-10x slower than linear
+		
+			size_t n=0;
+			for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 			{
-				//Set the default (unranged) ion colour, by using
-				//the first input ion colour.
-				if(!haveDefIonColour)
-				{
-					defIonColour.red =  ((IonStreamData *)dataIn[ui])->r;
-					defIonColour.green =  ((IonStreamData *)dataIn[ui])->g;
-					defIonColour.blue =  ((IonStreamData *)dataIn[ui])->b;
-					haveDefIonColour=true;
-				}
-			
-				//Check for ion size consistency	
-				if(haveIonSize)
+				switch(dataIn[ui]->getStreamType())
 				{
-					sameSize &= (fabs(ionSize-((const IonStreamData *)dataIn[ui])->ionSize) 
-									< std::numeric_limits<float>::epsilon());
-				}
-				else
-				{
-					ionSize=((const IonStreamData *)dataIn[ui])->ionSize;
-					haveIonSize=true;
-				}
+					case STREAM_TYPE_IONS: 
+					{
+						//Set the default (unranged) ion colour, by using
+						//the first input ion colour.
+						if(!haveDefIonColour)
+						{
+							defIonColour.red =  ((IonStreamData *)dataIn[ui])->r;
+							defIonColour.green =  ((IonStreamData *)dataIn[ui])->g;
+							defIonColour.blue =  ((IonStreamData *)dataIn[ui])->b;
+							haveDefIonColour=true;
+						}
+					
+						//Check for ion size consistency	
+						if(haveIonSize)
+						{
+							sameSize &= (fabs(ionSize-((const IonStreamData *)dataIn[ui])->ionSize) 
+											< std::numeric_limits<float>::epsilon());
+						}
+						else
+						{
+							ionSize=((const IonStreamData *)dataIn[ui])->ionSize;
+							haveIonSize=true;
+						}
 
-				unsigned int curProg=NUM_CALLBACK;
-				const size_t off=d.size()-1;
+						unsigned int curProg=NUM_CALLBACK;
+						const size_t off=d.size()-1;
 
-				for(vector<IonHit>::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin();
-					       it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it)
-				{
-					unsigned int rangeID;
-					rangeID=rng.getRangeID(it->getMassToCharge());
+						for(vector<IonHit>::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin();
+							       it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it)
+						{
+							unsigned int rangeID;
+							rangeID=rng.getRangeID(it->getMassToCharge());
 
-					//If ion is unranged, then it will have a rangeID of -1
-					if(rangeID != (unsigned int)-1)
-					{
-						unsigned int ionID;
-						ionID=rng.getIonID(rangeID);
+							//If ion is unranged, then it will have a rangeID of -1
+							if(rangeID != (unsigned int)-1)
+							{
+								unsigned int ionID;
+								ionID=rng.getIonID(rangeID);
 
-						//Only retain the ion if the ionID and rangeID are enabled
-						if(enabledRanges[rangeID] && enabledIons[ionID])
-						{
-							ASSERT(ionID < enabledRanges.size());
+								//Only retain the ion if the ionID and rangeID are enabled
+								if(enabledRanges[rangeID] && enabledIons[ionID])
+								{
+									ASSERT(ionID < enabledRanges.size());
 
-							d[ionID]->data.push_back(*it);
-						}
-					}
-					else if(!dropUnranged)//If it is unranged, then the rangeID is still -1 (as above).
-					{
-						d[off]->data.push_back(*it);
-					}
+									d[ionID]->data.push_back(*it);
+								}
+							}
+							else if(!dropUnranged)//If it is unranged, then the rangeID is still -1 (as above).
+							{
+								d[off]->data.push_back(*it);
+							}
 
-					//update progress periodically
-					if(!curProg--)
-					{
-						n+=NUM_CALLBACK;
-						progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
-						curProg=NUM_CALLBACK;
+							//update progress periodically
+							if(!curProg--)
+							{
+								n+=NUM_CALLBACK;
+								progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
+								curProg=NUM_CALLBACK;
+
+								
+								if(!(*callback)(false))
+								{
+									//Free space allocated for output ion streams...
+									for(unsigned int ui=0;ui<d.size();ui++)
+										delete d[ui];
+									return RANGEFILE_ABORT_FAIL;
+								}
+							}
 
-						
-						if(!(*callback)(false))
-						{
-							//Free space allocated for output ion streams...
-							for(unsigned int ui=0;ui<d.size();ui++)
-								delete d[ui];
-							return RANGEFILE_ABORT_FAIL;
 						}
-					}
 
+
+					}
+						break;
+					case STREAM_TYPE_RANGE:
+						//Purposely do nothing. This blocks propagation of other ranges
+						//i.e. there can only be one in any given node of the tree.
+						break;
+					default:
+						getOut.push_back(dataIn[ui]);
+						break;
 				}
+			}
+		}
+		else
+		{
+			//We have no ranges enabled, thus everything must go in the "unranged" section
+			d.back()->data.resize(totalSize);
 
+			size_t off=0;
+			for(unsigned int ui=0;ui<dataIn.size() ;ui++)
+			{
+				switch(dataIn[ui]->getStreamType())
+				{
+					case STREAM_TYPE_IONS:
+					{
+						const vector<IonHit> &ionHitVec=((const IonStreamData *)dataIn[ui])->data;
+						vector<IonHit> &outputVec=(d.back())->data;
+#pragma omp parallel for
+						for(size_t ui=0;ui<ionHitVec.size();ui++)
+							outputVec[off+ui]=ionHitVec[ui];
+						break;
+					}
+					case STREAM_TYPE_RANGE:
+						break;
+					default:
+						getOut.push_back(dataIn[ui]);
+						break;
+				}
+			}
 
+			if(!(*callback)(false))
+			{
+				//Free space allocated for output ion streams...
+				for(unsigned int ui=0;ui<d.size();ui++)
+					delete d[ui];
+				return RANGEFILE_ABORT_FAIL;
 			}
-				break;
-			case STREAM_TYPE_RANGE:
-				//Purposely do nothing. This blocks propagation of other ranges
-				//i.e. there can only be one in any given node of the tree.
-				break;
-			default:
-				getOut.push_back(dataIn[ui]);
-				break;
 		}
-	}
-	//=========================================
+		//=========================================
 
 
-	//Step 3 : Set up any properties for the output streams that we need, like colour, size, caching. Trim any empty results.
-	//======================================
-	//Set the colour of the output ranges
-	//and whether to cache.
-	for(unsigned int ui=0; ui<rng.getNumIons(); ui++)
-	{
-		RGBf rngCol;
-		rngCol = rng.getColour(ui);
-		d[ui]->r=rngCol.red;
-		d[ui]->g=rngCol.green;
-		d[ui]->b=rngCol.blue;
-		d[ui]->a=1.0;
+		//Step 3 : Set up any properties for the output streams that we need, like colour, size, caching. Trim any empty results.
+		//======================================
+		//Set the colour of the output ranges
+		//and whether to cache.
+		for(unsigned int ui=0; ui<rng.getNumIons(); ui++)
+		{
+			RGBf rngCol;
+			rngCol = rng.getColour(ui);
+			d[ui]->r=rngCol.red;
+			d[ui]->g=rngCol.green;
+			d[ui]->b=rngCol.blue;
+			d[ui]->a=1.0;
 
-	}
+		}
 
-	//If all the ions are the same size, then propagate
-	//Otherwise use the default ionsize
-	if(haveIonSize && sameSize)
-	{
-		for(unsigned int ui=0;ui<d.size();ui++)
-			d[ui]->ionSize=ionSize;
-	}
-	
-	//Set the unranged colour
-	if(haveDefIonColour && d.size())
-	{
-		d[d.size()-1]->r = defIonColour.red;
-		d[d.size()-1]->g = defIonColour.green;
-		d[d.size()-1]->b = defIonColour.blue;
-		d[d.size()-1]->a = 1.0f;
-	}
+		//If all the ions are the same size, then propagate
+		//Otherwise use the default ionsize
+		if(haveIonSize && sameSize)
+		{
+			for(unsigned int ui=0;ui<d.size();ui++)
+				d[ui]->ionSize=ionSize;
+		}
+		
+		//Set the unranged colour
+		if(haveDefIonColour && d.size())
+		{
+			d[d.size()-1]->r = defIonColour.red;
+			d[d.size()-1]->g = defIonColour.green;
+			d[d.size()-1]->b = defIonColour.blue;
+			d[d.size()-1]->a = 1.0f;
+		}
 
-	//remove any zero sized ranges
-	for(unsigned int ui=0;ui<d.size();)
-	{
-		if(!(d[ui]->data.size()))
+		//remove any zero sized ranges
+		for(unsigned int ui=0;ui<d.size();)
 		{
-			delete d[ui];
-			std::swap(d[ui],d.back());
-			d.pop_back();
+			if(!(d[ui]->data.size()))
+			{
+				delete d[ui];
+				std::swap(d[ui],d.back());
+				d.pop_back();
+			}
+			else
+				ui++;
 		}
-		else
-			ui++;
-	}
 
-	//======================================
+		//======================================
 
-	//Having ranged all streams, merge them back into one ranged stream.
-	if(cache)
-	{
-		for(unsigned int ui=0;ui<d.size(); ui++)
+		//Having ranged all streams, merge them back into one ranged stream.
+		if(cache)
 		{
-			d[ui]->cached=1; //IMPORTANT: ->cached must be set PRIOR to push back
-			filterOutputs.push_back(d[ui]);
+			for(unsigned int ui=0;ui<d.size(); ui++)
+			{
+				d[ui]->cached=1; //IMPORTANT: ->cached must be set PRIOR to push back
+				filterOutputs.push_back(d[ui]);
+			}
 		}
-	}
-	else
-	{
+		else
+		{
+			for(unsigned int ui=0;ui<d.size(); ui++)
+				d[ui]->cached=0; //IMPORTANT: ->cached must be set PRIOR to push back
+			cacheOK=false;
+		}
+		
 		for(unsigned int ui=0;ui<d.size(); ui++)
-			d[ui]->cached=0; //IMPORTANT: ->cached must be set PRIOR to push back
-		cacheOK=false;
+			getOut.push_back(d[ui]);
 	}
-	
-	for(unsigned int ui=0;ui<d.size(); ui++)
-		getOut.push_back(d[ui]);
+
 
 	//Put out rangeData
 	RangeStreamData *rngData=new RangeStreamData;
@@ -504,7 +559,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 	prop.name=TRANS("File");
 	prop.type=PROPERTY_TYPE_STRING;
 	prop.helpText=TRANS("File to use for range data");
-	prop.key=KEY_RANGE_FILENAME;
+	prop.key=RANGE_KEY_RANGE_FILENAME;
 	prop.data=rngName;
 
 	p.addProperty(prop,curGroup);	
@@ -518,7 +573,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 	prop.name=TRANS("Drop unranged");
 	prop.type=PROPERTY_TYPE_BOOL;
 	prop.helpText=TRANS("Remove unranged points when generating output");
-	prop.key=KEY_DROP_UNRANGED;
+	prop.key=RANGE_KEY_DROP_UNRANGED;
 	prop.data=tmpStr;
 
 	p.addProperty(prop,curGroup);
@@ -541,7 +596,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 		prop.helpText=TRANS("Enable/disable all ions at once");
 		prop.data=str;
 		prop.type=PROPERTY_TYPE_BOOL;
-		prop.key=KEY_ENABLE_ALL_IONS;
+		prop.key=RANGE_KEY_ENABLE_ALL_IONS;
 
 		p.addProperty(prop,curGroup);
 
@@ -557,7 +612,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.helpText=TRANS("Enable/disable specified ion");
 			prop.data=rng.getName(ui);
 			prop.type=PROPERTY_TYPE_STRING;
-			prop.key=NUM_ROWS_ION*ui+1+KEY_ENABLE_ALL_IONS;
+			prop.key=NUM_ROWS_ION*ui+1+RANGE_KEY_ENABLE_ALL_IONS;
 
 			p.addProperty(prop,curGroup);
 
@@ -571,7 +626,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.type=PROPERTY_TYPE_BOOL;
 			prop.helpText=TRANS("If true, ion is used in output");
 			prop.data=str;
-			prop.key=NUM_ROWS_ION*ui+2+KEY_ENABLE_ALL_IONS;
+			prop.key=NUM_ROWS_ION*ui+2+RANGE_KEY_ENABLE_ALL_IONS;
 		
 			p.addProperty(prop,curGroup);
 
@@ -587,7 +642,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.data=thisCol;
 			prop.type=PROPERTY_TYPE_COLOUR;
 			prop.helpText=TRANS("Colour used to represent ion");
-			prop.key=NUM_ROWS_ION*ui+3+KEY_ENABLE_ALL_IONS;
+			prop.key=NUM_ROWS_ION*ui+3+RANGE_KEY_ENABLE_ALL_IONS;
 
 			p.addProperty(prop,curGroup);
 		}
@@ -614,7 +669,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 		prop.helpText=TRANS("Enable/disable all ranges");
 		prop.data=str;
 		prop.type=PROPERTY_TYPE_BOOL;
-		prop.key=KEY_ENABLE_ALL_RANGES;
+		prop.key=RANGE_KEY_ENABLE_ALL_RANGES;
 	
 		p.addProperty(prop,curGroup);
 		
@@ -633,14 +688,14 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.data=str;
 			prop.type=PROPERTY_TYPE_BOOL;
 			prop.helpText=TRANS("Enable/disable specified range (ion must also be enabled to activiate range)");
-			prop.key=KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+1;
+			prop.key=RANGE_KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+1;
 			p.addProperty(prop,curGroup);
 
 			prop.name=string(TRANS("Ion ")) + suffix;
 			prop.data=rng.getName(rng.getIonID(ui));
 			prop.type=PROPERTY_TYPE_STRING;
 			prop.helpText=TRANS("Name of ion associate to this range");
-			prop.key=KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+2;
+			prop.key=RANGE_KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+2;
 			p.addProperty(prop,curGroup);
 
 			std::pair<float,float > thisRange;
@@ -652,7 +707,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.data=rangeVal;
 			prop.type=PROPERTY_TYPE_REAL;
 			prop.helpText=TRANS("Start value for range");
-			prop.key=KEY_ENABLE_ALL_RANGES + NUM_ROWS_RANGE*ui +3;
+			prop.key=RANGE_KEY_ENABLE_ALL_RANGES + NUM_ROWS_RANGE*ui +3;
 			p.addProperty(prop,curGroup);
 		
 			stream_cast(rangeVal,thisRange.second);
@@ -660,7 +715,7 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			prop.data=rangeVal;
 			prop.type=PROPERTY_TYPE_REAL;
 			prop.helpText=TRANS("Stopping value for range`");
-			prop.key=KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+4;
+			prop.key=RANGE_KEY_ENABLE_ALL_RANGES+NUM_ROWS_RANGE*ui+4;
 			p.addProperty(prop,curGroup);
 		}
 		p.setGroupTitle(curGroup,TRANS("Ranges"));
@@ -678,7 +733,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 	switch(key)
 	{
-		case KEY_RANGE_FILENAME:
+		case RANGE_KEY_RANGE_FILENAME:
 		{
 			if(value != rngName)
 			{
@@ -708,7 +763,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 			break;
 		}
-		case KEY_DROP_UNRANGED: //Enable/disable unranged dropping
+		case RANGE_KEY_DROP_UNRANGED: //Enable/disable unranged dropping
 		{
 			unsigned int valueInt;
 			if(stream_cast(valueInt,value))
@@ -716,7 +771,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 			if(valueInt ==0 || valueInt == 1)
 			{
-				if((int)dropUnranged!= valueInt)
+				if(dropUnranged!= (bool)valueInt)
 				{
 					needUpdate=true;
 					dropUnranged=valueInt;
@@ -732,7 +787,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 			break;
 		}	
-		case KEY_ENABLE_ALL_RANGES:
+		case RANGE_KEY_ENABLE_ALL_RANGES:
 		{
 
 			bool allEnable;
@@ -759,7 +814,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 			break;
 		}
-		case KEY_ENABLE_ALL_IONS:
+		case RANGE_KEY_ENABLE_ALL_IONS:
 		{
 
 			bool allEnable;
@@ -787,15 +842,15 @@ bool RangeFileFilter::setProperty(unsigned int key,
 		}
 		default:
 		{
-			if(key < KEY_ENABLE_ALL_RANGES)
+			if(key < RANGE_KEY_ENABLE_ALL_RANGES)
 			{
 				//structured group, each with NUM_ROWS_ION per grouping.
 				//The ion ID is simply the row number/NUM_ROWS_ION.
 				//similarly the element is given by remainder 
-				unsigned int ionID=((key-1)-KEY_ENABLE_ALL_IONS)/NUM_ROWS_ION;
+				unsigned int ionID=((key-1)-RANGE_KEY_ENABLE_ALL_IONS)/NUM_ROWS_ION;
 				ASSERT(ionID < rng.getNumIons());
-				ASSERT(key <=NUM_ROWS_ION*rng.getNumIons()+KEY_ENABLE_ALL_IONS);
-				unsigned int prop = ((key-1)-KEY_ENABLE_ALL_IONS)-ionID*NUM_ROWS_ION;
+				ASSERT(key <=NUM_ROWS_ION*rng.getNumIons()+RANGE_KEY_ENABLE_ALL_IONS);
+				unsigned int prop = ((key-1)-RANGE_KEY_ENABLE_ALL_IONS)-ionID*NUM_ROWS_ION;
 
 				switch(prop)
 				{
@@ -860,8 +915,8 @@ bool RangeFileFilter::setProperty(unsigned int key,
 			}
 			else
 			{
-				unsigned int rangeId=((key-1)-KEY_ENABLE_ALL_RANGES)/NUM_ROWS_RANGE;
-				unsigned int prop = ((key-1)-KEY_ENABLE_ALL_RANGES)-rangeId*NUM_ROWS_RANGE;
+				unsigned int rangeId=((key-1)-RANGE_KEY_ENABLE_ALL_RANGES)/NUM_ROWS_RANGE;
+				unsigned int prop = ((key-1)-RANGE_KEY_ENABLE_ALL_RANGES)-rangeId*NUM_ROWS_RANGE;
 				switch(prop)
 				{
 					//Range active
diff --git a/src/backend/filters/rangeFile.h b/src/backend/filters/rangeFile.h
index edd8b07..97b7463 100644
--- a/src/backend/filters/rangeFile.h
+++ b/src/backend/filters/rangeFile.h
@@ -21,6 +21,14 @@
 #include "../filter.h"
 #include "../../common/translation.h"
 
+enum
+{
+	RANGE_KEY_RANGE_ACTIVE=1,
+	RANGE_KEY_DROP_UNRANGED,
+	RANGE_KEY_RANGE_FILENAME,
+	RANGE_KEY_ENABLE_ALL_IONS, //Limited to ~100K ions
+	RANGE_KEY_ENABLE_ALL_RANGES=100000,
+};
 
 //!Range file filter
 class RangeFileFilter : public Filter
@@ -50,7 +58,9 @@ class RangeFileFilter : public Filter
 		void setFormat(unsigned int format);
 	
 		std::vector<char> getEnabledRanges() const {return enabledRanges;};
-		void setEnabledRanges(vector<char> i) {enabledRanges = i;};
+		void setEnabledRanges(const vector<char> &i) {enabledRanges = i;};
+		
+		std::vector<char> getEnabledIons() const {return enabledIons;};
 
 
 		RangeFileFilter(); 
diff --git a/src/backend/filters/spatialAnalysis.cpp b/src/backend/filters/spatialAnalysis.cpp
index a0ad275..910fe02 100644
--- a/src/backend/filters/spatialAnalysis.cpp
+++ b/src/backend/filters/spatialAnalysis.cpp
@@ -267,7 +267,7 @@ unsigned int SpatialAnalysisFilter::refresh(const std::vector<const FilterStream
 				//Create the user interaction device required for the user
 				// to interact with the algorithm parameters 
 				// as this is not cached at this time
-				SelectionDevice<Filter> *s;
+				SelectionDevice *s;
 				DrawStreamData *d= new DrawStreamData;
 				d->parent=this;
 				d->cached=0;
@@ -897,6 +897,9 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 			if(stream_cast(newRad,value))
 				return false;
 
+			if(newRad < sqrt(std::numeric_limits<float>::epsilon()))
+				return false;
+
 			if(scalarParams[0] != newRad )
 			{
 				scalarParams[0] = newRad;
@@ -911,6 +914,9 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 			if(!newPt.parse(value))
 				return false;
 
+			if(newPt.sqrMag() < sqrt(std::numeric_limits<float>::epsilon()))
+				return false;
+
 			if(!(vectorParams[1] == newPt ))
 			{
 				vectorParams[1] = newPt;
@@ -1236,8 +1242,13 @@ void SpatialAnalysisFilter::setPropFromBinding(const SelectionBinding &b)
 			b.getValue(scalarParams[0]);
 			break;
 		case BINDING_CYLINDER_DIRECTION:
-			b.getValue(vectorParams[1]);
+		{
+			Point3D p;
+			b.getValue(p);
+			if(p.sqrMag() > sqrt(std::numeric_limits<float>::epsilon()))
+				vectorParams[1]=p;
 			break;
+		}
 		case BINDING_CYLINDER_ORIGIN:
 			b.getValue(vectorParams[0]);
 			break;
@@ -2377,7 +2388,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 }
 
 void SpatialAnalysisFilter::createCylinder(DrawStreamData * &drawData,
-		SelectionDevice<Filter> * &s) const
+		SelectionDevice * &s) const
 {
 	//Origin + normal
 	ASSERT(vectorParams.size() == 2);
@@ -2401,7 +2412,7 @@ void SpatialAnalysisFilter::createCylinder(DrawStreamData * &drawData,
 	//tapered cylinder)
 	dC->lockRadii();
 
-	s = new SelectionDevice<Filter>(this);
+	s = new SelectionDevice(this);
 	SelectionBinding b;
 	//Bind the drawable object to the properties we wish
 	//to be able to modify
@@ -2580,10 +2591,10 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 	
 	//Strip away the real value information, leaving just point data
 	vector<Point3D> src,dest;
-	getPointsFromIons(ionsInside,src);
+	IonHit::getPoints(ionsInside,src);
 	ionsInside.clear();
 	
-	getPointsFromIons(ionsOutside,dest);
+	IonHit::getPoints(ionsOutside,dest);
 	ionsOutside.clear();
 
 	K3DTree tree;
@@ -2714,7 +2725,7 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 	
 	//Create the user interaction device required for the user
 	// to interact with the algorithm parameters 
-	SelectionDevice<Filter> *s;
+	SelectionDevice *s;
 	DrawStreamData *d= new DrawStreamData;
 	d->parent=this;
 	d->cached=0;
diff --git a/src/backend/filters/spatialAnalysis.h b/src/backend/filters/spatialAnalysis.h
index 5123bea..c32394e 100644
--- a/src/backend/filters/spatialAnalysis.h
+++ b/src/backend/filters/spatialAnalysis.h
@@ -105,7 +105,7 @@ class SpatialAnalysisFilter : public Filter
 		//Create a 3D manipulable cylinder as an output drawable
 		// using the parameters stored inside the vector/scalar params
 		// both parameters are outputs from this function
-		void createCylinder(DrawStreamData* &d, SelectionDevice<Filter> * &s) const;
+		void createCylinder(DrawStreamData* &d, SelectionDevice * &s) const;
 
 		//Scan input datstreams to build a two point vectors,
 		// one of those with points specified as "target" 
diff --git a/src/backend/filters/spectrumPlot.cpp b/src/backend/filters/spectrumPlot.cpp
index 336884d..1a2a556 100644
--- a/src/backend/filters/spectrumPlot.cpp
+++ b/src/backend/filters/spectrumPlot.cpp
@@ -519,7 +519,7 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 			//Only update as needed
 			if(valueInt ==0 || valueInt == 1)
 			{
-				if((int)autoExtrema != valueInt)
+				if(autoExtrema != (bool)valueInt)
 				{
 					needUpdate=true;
 					autoExtrema=valueInt;
@@ -583,7 +583,7 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 			//Only update as needed
 			if(valueInt ==0 || valueInt == 1)
 			{
-				if((int)logarithmic != valueInt)
+				if(logarithmic != (bool)valueInt)
 				{
 					needUpdate=true;
 					logarithmic=valueInt;
diff --git a/src/backend/filters/transform.cpp b/src/backend/filters/transform.cpp
index 3b464e5..053c94f 100644
--- a/src/backend/filters/transform.cpp
+++ b/src/backend/filters/transform.cpp
@@ -142,7 +142,7 @@ size_t TransformFilter::numBytesForCache(size_t nObjects) const
 	return (size_t)-1;
 }
 
-DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice<Filter>* &s) const
+DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice* &s) const
 {
 	//construct a new primitive, do not cache
 	DrawStreamData *drawData=new DrawStreamData;
@@ -170,7 +170,7 @@ DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice<Filter>* &s) c
 	{
 		dS->canSelect=true;
 
-		s=new SelectionDevice<Filter>(this);
+		s=new SelectionDevice(this);
 		SelectionBinding b;
 
 		b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN,
@@ -210,7 +210,7 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 					transformMode == MODE_SCALE_ANISOTROPIC ||
 					transformMode == MODE_SCALE_ISOTROPIC) )
 			{
-				SelectionDevice<Filter> *s;
+				SelectionDevice *s;
 				getOut.push_back(makeMarkerSphere(s));
 				if(s)
 					devices.push_back(s);
@@ -241,7 +241,7 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 					ions = (const IonStreamData*)dataIn[ui];
 					if(ions->data.size())
 					{
-						thisB = getIonDataLimits(ions->data);
+						IonHit::getBoundCube(ions->data,thisB);
 						#pragma omp critical
 						masterB.expand(thisB);
 					}
@@ -295,7 +295,7 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 			transformMode == MODE_SCALE_ANISOTROPIC || 
 			transformMode == MODE_SCALE_ISOTROPIC) )
 	{
-		SelectionDevice<Filter> *s;
+		SelectionDevice *s;
 		getOut.push_back(makeMarkerSphere(s));
 		if(s)
 			devices.push_back(s);
@@ -1908,8 +1908,8 @@ bool rotateTest()
 	// however we don't quite have  a sphere, so we could have (at the most extreme,
 	// a cube)
 	BoundCube bc[2];
-	bc[0]=getIonDataLimits(d->data);
-	bc[1]=getIonDataLimits(outData->data);
+	IonHit::getBoundCube(d->data,bc[0]);
+	IonHit::getBoundCube(outData->data,bc[1]);
 
 	float volumeRat;
 	volumeRat = bc[0].volume()/bc[1].volume();
@@ -1974,8 +1974,8 @@ bool translateTest()
 
 	//Bound cube should move exactly as per the translation
 	BoundCube bc[2];
-	bc[0]=getIonDataLimits(d->data);
-	bc[1]=getIonDataLimits(outData->data);
+	IonHit::getBoundCube(d->data,bc[0]);
+	IonHit::getBoundCube(outData->data,bc[1]);
 
 	for(unsigned int ui=0;ui<3;ui++)
 	{
@@ -2056,8 +2056,8 @@ bool scaleTest()
 	//Scaling around its centre of mass
 	// should scale the bounding box by the cube of the scale factor
 	BoundCube bc[2];
-	bc[0]=getIonDataLimits(d->data);
-	bc[1]=getIonDataLimits(outData->data);
+	IonHit::getBoundCube(d->data,bc[0]);
+	IonHit::getBoundCube(outData->data,bc[1]);
 
 	float cubeOfScale=scaleFact*scaleFact*scaleFact;
 
diff --git a/src/backend/filters/transform.h b/src/backend/filters/transform.h
index 771f733..f4abac4 100644
--- a/src/backend/filters/transform.h
+++ b/src/backend/filters/transform.h
@@ -47,7 +47,7 @@ class TransformFilter : public Filter
 		static std::string getNoiseTypeString(unsigned int i);
 
 		//!Make the marker sphere
-		DrawStreamData* makeMarkerSphere(SelectionDevice<Filter>* &s) const;
+		DrawStreamData* makeMarkerSphere(SelectionDevice* &s) const;
 		
 		//!random number generator
 		RandNumGen randGen;
diff --git a/src/backend/filters/voxelise.cpp b/src/backend/filters/voxelise.cpp
index 269cd95..5f990a6 100644
--- a/src/backend/filters/voxelise.cpp
+++ b/src/backend/filters/voxelise.cpp
@@ -17,7 +17,7 @@
 */
 
 #include "voxelise.h"
-
+#include "common/colourmap.h"
 #include "filterCommon.h"
 
 #include <map>
@@ -31,13 +31,24 @@ enum
 	KEY_WIDTHBINSX,
 	KEY_WIDTHBINSY,
 	KEY_WIDTHBINSZ,
+	
 	KEY_COUNT_TYPE,
 	KEY_NORMALISE_TYPE,
 	KEY_SPOTSIZE,
-	KEY_TRANSPARANCY,
+	KEY_TRANSPARENCY,
 	KEY_COLOUR,
 	KEY_ISOLEVEL,
 	KEY_VOXEL_REPRESENTATION_MODE,
+	
+	KEY_VOXEL_SLICE_COLOURAUTO,
+	KEY_MAPEND,
+	KEY_MAPSTART,
+	KEY_SHOW_COLOURBAR,
+	KEY_VOXEL_COLOURMODE,
+	KEY_VOXEL_SLICE_AXIS,
+	KEY_VOXEL_SLICE_OFFSET,
+	KEY_VOXEL_SLICE_INTERP,
+	
 	KEY_FILTER_MODE,
 	KEY_FILTER_BOUNDARY_MODE,
 	KEY_FILTER_BINS,
@@ -72,6 +83,9 @@ enum
 	VOXELISE_FILTERBOUNDMODE_MAX// keep this at the end so it's a bookend for the last value
 };
 
+
+//Error codes and corresponding strings
+//--
 enum
 {
 	VOXELISE_ABORT_ERR,
@@ -79,6 +93,17 @@ enum
 	VOXELISE_CONVOLVE_ERR,
 	VOXELISE_BOUNDS_INVALID_ERR
 };
+//--
+
+
+//!Can we keep the cached contents, when transitioning from
+// one representation to the other- this is only the case
+// when _KEEPCACHE [] is true for both representations
+const bool VOXEL_REPRESENT_KEEPCACHE[] = {
+	true,
+	true,
+	false
+};
 
 const char *NORMALISE_TYPE_STRING[] = {
 		NTRANS("None (Raw count)"),
@@ -89,7 +114,8 @@ const char *NORMALISE_TYPE_STRING[] = {
 
 const char *REPRESENTATION_TYPE_STRING[] = {
 		NTRANS("Point Cloud"),
-		NTRANS("Isosurface")
+		NTRANS("Isosurface"),
+		NTRANS("Axial slice")
 	};
 
 const char *VOXELISE_FILTER_TYPE_STRING[]={
@@ -102,6 +128,11 @@ const char *VOXELISE_FILTER_BOUND_STRING[] ={
 	NTRANS("Bounce")
 	};
 
+const char *VOXELISE_SLICE_INTERP_STRING[]={
+	NTRANS("None"),
+	NTRANS("Linear")
+	};
+
 //This is not a member of voxels.h, as the voxels do not have any concept of the IonHit
 int countPoints(Voxels<float> &v, const std::vector<IonHit> &points, 
 				bool noWrap,bool (*callback)(bool))
@@ -150,6 +181,7 @@ VoxeliseFilter::VoxeliseFilter()
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXELISE_FILTER_BOUND_STRING) ==  VOXELISE_FILTERBOUNDMODE_MAX);
 
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(REPRESENTATION_TYPE_STRING) == VOXEL_REPRESENT_END);
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXEL_REPRESENT_KEEPCACHE) == VOXEL_REPRESENT_END);
 
 	splatSize=1.0f;
 	a=0.9f;
@@ -163,6 +195,11 @@ VoxeliseFilter::VoxeliseFilter()
 	
 	representation=VOXEL_REPRESENT_POINTCLOUD;
 
+	colourMap=0;
+	autoColourMap=true;
+	colourMapBounds[0]=0;
+	colourMapBounds[1]=1;
+
 
 	//Ficticious bounds.
 	bc.setBounds(Point3D(0,0,0),Point3D(1,1,1));
@@ -175,6 +212,13 @@ VoxeliseFilter::VoxeliseFilter()
 	numeratorAll = false;
 	denominatorAll = true;
 
+	sliceInterpolate=SLICE_INTERP_NONE;
+	sliceBoundMode=BOUND_MIRROR;
+	sliceAxis=0;
+	sliceOffset=0.5;
+	showColourBar=false;
+
+
 	cacheOK=false;
 	cache=true; //By default, we should cache, but decision is made higher up
 
@@ -228,12 +272,33 @@ Filter *VoxeliseFilter::cloneUncached() const
 	else
 		p->rsdIncoming=0;
 
+
+
+	p->colourMap = colourMap;
+
+	p->nColours = nColours;
+	p->showColourBar = showColourBar;
+	p->autoColourMap = autoColourMap;
+	p->colourMapBounds[0] = colourMapBounds[0];
+	p->colourMapBounds[1] = colourMapBounds[1];
+
+	p->sliceInterpolate = sliceInterpolate;
+	p->sliceBoundMode= sliceBoundMode;
+	p->sliceAxis = sliceAxis;
+	p->sliceOffset = sliceOffset;
+
 	p->cache=cache;
 	p->cacheOK=false;
 	p->userString=userString;
 	return p;
 }
 
+void VoxeliseFilter::clearCache() 
+{
+	voxelCache.clear();
+	Filter::clearCache();
+}
+
 size_t VoxeliseFilter::numBytesForCache(size_t nObjects) const
 {
 	//if we are using fixed width, we know the answer.
@@ -335,206 +400,202 @@ unsigned int VoxeliseFilter::refresh(const std::vector<const FilterStreamData *>
 	}
 
 
-	Point3D minP,maxP;
-
-	bc.setInverseLimits();
-		
-	for (size_t i = 0; i < dataIn.size(); i++) 
+	Voxels<float> voxelData;
+	if(!voxelCache.getSize())
 	{
-		//Check for ion stream types. Block others from propagation.
-		if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
+		Point3D minP,maxP;
 
-		const IonStreamData *is = (const IonStreamData *)dataIn[i];
-		//Don't work on empty or single object streams (bounding box needs to be defined)
-		if (is->getNumBasicObjects() < 2) continue;
-	
-		BoundCube bcTmp;
-		bcTmp=getIonDataLimits(is->data);
+		bc.setInverseLimits();
+			
+		for (size_t i = 0; i < dataIn.size(); i++) 
+		{
+			//Check for ion stream types. Block others from propagation.
+			if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
+
+			const IonStreamData *is = (const IonStreamData *)dataIn[i];
+			//Don't work on empty or single object streams (bounding box needs to be defined)
+			if (is->getNumBasicObjects() < 2) continue;
+		
+			BoundCube bcTmp;
+			IonHit::getBoundCube(is->data,bcTmp);
 
-		//Bounds could be invalid if, for example, we had coplanar axis aligned points
-		if (!bcTmp.isValid()) continue;
+			//Bounds could be invalid if, for example, we had coplanar axis aligned points
+			if (!bcTmp.isValid()) continue;
 
-		bc.expand(bcTmp);
-	}
-	//No bounding box? Tough cookies
-	if (!bc.isValid() || bc.isFlat()) return VOXELISE_BOUNDS_INVALID_ERR;
+			bc.expand(bcTmp);
+		}
+		//No bounding box? Tough cookies
+		if (!bc.isValid() || bc.isFlat()) return VOXELISE_BOUNDS_INVALID_ERR;
 
-	bc.getBounds(minP,maxP);	
-	if (fixedWidth) 
-		calculateNumBinsFromWidths(binWidth, nBins);
-	else
-		calculateWidthsFromNumBins(binWidth, nBins);
+		bc.getBounds(minP,maxP);	
+		if (fixedWidth) 
+			calculateNumBinsFromWidths(binWidth, nBins);
+		else
+			calculateWidthsFromNumBins(binWidth, nBins);
+		
+		//Disallow empty bounding boxes (ie, produce no output)
+		if(minP == maxP)
+			return 0;
 	
-	//Disallow empty bounding boxes (ie, produce no output)
-	if(minP == maxP)
-		return 0;
+		//Rebuild the voxels from the point dta
+		Voxels<float> vsDenom;
+		voxelData.setCallbackMethod(callback);
+		voxelData.init(nBins[0], nBins[1], nBins[2], bc);
+		voxelData.fill(0);
 		
-	VoxelStreamData *vs = new VoxelStreamData();
-	vs->parent=this;
-	vs->data.setCallbackMethod(callback);
-	vs->data.init(nBins[0], nBins[1], nBins[2], bc);
-	vs->representationType= representation;
-	vs->splatSize = splatSize;
-	vs->isoLevel=isoLevel;
-	vs->data.fill(0);
-	vs->r=r;
-	vs->g=g;
-	vs->b=b;
-	vs->a=a;
-
-	Voxels<float> vsDenom;
-	if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
-		normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL) {
-		//Check we actually have incoming data
-		ASSERT(rsdIncoming);
-		vsDenom.setCallbackMethod(callback);
-		vsDenom.init(nBins[0], nBins[1], nBins[2], bc);
-		vsDenom.fill(0);
-	}
-
-	const IonStreamData *is;
-	if(rsdIncoming)
-	{
+		if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
+			normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL) {
+			//Check we actually have incoming data
+			ASSERT(rsdIncoming);
+			vsDenom.setCallbackMethod(callback);
+			vsDenom.init(nBins[0], nBins[1], nBins[2], bc);
+			vsDenom.fill(0);
+		}
 
-		for (size_t i = 0; i < dataIn.size(); i++) 
+		const IonStreamData *is;
+		if(rsdIncoming)
 		{
-			
-			//Check for ion stream types. Don't use anything else in counting
-			if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
-			
-			is= (const IonStreamData *)dataIn[i];
 
-			
-			//Count the numerator ions	
-			if(is->data.size())
+			for (size_t i = 0; i < dataIn.size(); i++) 
 			{
-				//Check what Ion type this stream belongs to. Assume all ions
-				//in the stream belong to the same group
-				unsigned int ionID;
-				ionID = getIonstreamIonID(is,rsdIncoming->rangeFile);
-
-				bool thisIonEnabled;
-				if(ionID!=(unsigned int)-1)
-					thisIonEnabled=enabledIons[0][ionID];
-				else
-					thisIonEnabled=false;
-
-				if(thisIonEnabled)
-				{
-					countPoints(vs->data,is->data,true,callback);
-				}
-			}
-		
-			//If the user requests normalisation, compute the denominator dataset
-			if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL) {
+				
+				//Check for ion stream types. Don't use anything else in counting
+				if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
+				
+				is= (const IonStreamData *)dataIn[i];
+
+				
+				//Count the numerator ions	
 				if(is->data.size())
 				{
 					//Check what Ion type this stream belongs to. Assume all ions
 					//in the stream belong to the same group
 					unsigned int ionID;
-					ionID = rsdIncoming->rangeFile->getIonID(is->data[0].getMassToCharge());
+					ionID = getIonstreamIonID(is,rsdIncoming->rangeFile);
 
 					bool thisIonEnabled;
 					if(ionID!=(unsigned int)-1)
-						thisIonEnabled=enabledIons[1][ionID];
+						thisIonEnabled=enabledIons[0][ionID];
 					else
 						thisIonEnabled=false;
 
 					if(thisIonEnabled)
-						countPoints(vsDenom,is->data,true,callback);
+					{
+						countPoints(voxelData,is->data,true,callback);
+					}
+				}
+			
+				//If the user requests normalisation, compute the denominator dataset
+				if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL) {
+					if(is->data.size())
+					{
+						//Check what Ion type this stream belongs to. Assume all ions
+						//in the stream belong to the same group
+						unsigned int ionID;
+						ionID = rsdIncoming->rangeFile->getIonID(is->data[0].getMassToCharge());
+
+						bool thisIonEnabled;
+						if(ionID!=(unsigned int)-1)
+							thisIonEnabled=enabledIons[1][ionID];
+						else
+							thisIonEnabled=false;
+
+						if(thisIonEnabled)
+							countPoints(vsDenom,is->data,true,callback);
+					}
+				} else if (normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
+				{
+					countPoints(vsDenom,is->data,true,callback);
 				}
-			} else if (normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
-			{
-				countPoints(vsDenom,is->data,true,callback);
-			}
 
-			if(!(*callback)(false))
-			{
-				delete vs;
-				return VOXELISE_ABORT_ERR;
+				if(!(*callback)(false))
+					return VOXELISE_ABORT_ERR;
 			}
+		
+			//Perform normalsiation	
+			if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
+				voxelData.calculateDensity();
+			else if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
+					 normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
+				voxelData /= vsDenom;
 		}
-	
-		//Perform normalsiation	
-		if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
-			vs->data.calculateDensity();
-		else if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
-				 normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
-			vs->data /= vsDenom;
-	}
-	else
-	{
-		//No range data.  Just count
-		for (size_t i = 0; i < dataIn.size(); i++) 
+		else
 		{
-			
-			if(dataIn[i]->getStreamType() == STREAM_TYPE_IONS)
+			//No range data.  Just count
+			for (size_t i = 0; i < dataIn.size(); i++) 
 			{
-				is= (const IonStreamData *)dataIn[i];
-
-				countPoints(vs->data,is->data,true,callback);
 				
-				if(!(*callback)(false))
+				if(dataIn[i]->getStreamType() == STREAM_TYPE_IONS)
 				{
-					delete vs;
-					return VOXELISE_ABORT_ERR;
-				}
+					is= (const IonStreamData *)dataIn[i];
+
+					countPoints(voxelData,is->data,true,callback);
+					
+					if(!(*callback)(false))
+						return VOXELISE_ABORT_ERR;
 
+				}
 			}
-		}
-		ASSERT(normaliseType != VOXELISE_NORMALISETYPE_COUNT2INVOXEL
-				&& normaliseType!=VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL);
-		if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
-			vs->data.calculateDensity();
-	}	
+			ASSERT(normaliseType != VOXELISE_NORMALISETYPE_COUNT2INVOXEL
+					&& normaliseType!=VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL);
+			if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
+				voxelData.calculateDensity();
+		}	
 
-	vsDenom.clear();
+		vsDenom.clear();
 
 
-	//Perform voxel filtering
-	switch(filterMode)
-	{
-		case VOXELISE_FILTERTYPE_NONE:
-			break;
-		case VOXELISE_FILTERTYPE_GAUSS:
+		//Perform voxel filtering
+		switch(filterMode)
 		{
-			Voxels<float> kernel,res;
+			case VOXELISE_FILTERTYPE_NONE:
+				break;
+			case VOXELISE_FILTERTYPE_GAUSS:
+			{
+				Voxels<float> kernel,res;
 
-			map<unsigned int, unsigned int> modeMap;
+				map<unsigned int, unsigned int> modeMap;
 
 
-			modeMap[VOXELISE_FILTERBOUNDMODE_ZERO]=BOUND_ZERO;
-			modeMap[VOXELISE_FILTERBOUNDMODE_BOUNCE]=BOUND_MIRROR;
+				modeMap[VOXELISE_FILTERBOUNDMODE_ZERO]=BOUND_ZERO;
+				modeMap[VOXELISE_FILTERBOUNDMODE_BOUNCE]=BOUND_MIRROR;
 
-			//FIXME: This will be SLOW. need to use IIR or some other
-			//fast technique
+				//FIXME: This will be SLOW. need to use IIR or some other
+				//fast technique
+				
+				//Construct the gaussian convolution
+				kernel.setGaussianKernelCube(gaussDev,(float)filterBins,filterBins);
+				//Normalise the kernel
+				float sum;
+				sum=kernel.getSum();
+				kernel/=sum;
 			
-			//Construct the gaussian convolution
-			kernel.setGaussianKernelCube(gaussDev,(float)filterBins,filterBins);
-			//Normalise the kernel
-			float sum;
-			sum=kernel.getSum();
-			kernel/=sum;
-		
-			if(res.resize(vs->data))
-				return VOXELISE_MEMORY_ERR; 
+				if(res.resize(voxelData))
+					return VOXELISE_MEMORY_ERR; 
 
-			//Gaussian kernel is separable (rank 1)
-			if(vs->data.separableConvolve(kernel,res,modeMap[filterBoundaryMode]))
-				return VOXELISE_CONVOLVE_ERR;
+				//Gaussian kernel is separable (rank 1)
+				if(voxelData.separableConvolve(kernel,res,modeMap[filterBoundaryMode]))
+					return VOXELISE_CONVOLVE_ERR;
 
-			vs->data.swap(res);
+				voxelData.swap(res);
 
-			res.clear();
-			break;
+				res.clear();
+				break;
+			}
+			default:
+				ASSERT(false);
 		}
-		default:
-			ASSERT(false);
+	
+		voxelCache=voxelData;
+	}
+	else
+	{
+		//Use the cached value
+		voxelData=voxelCache;
 	}
-
 	
 	float min,max;
-	vs->data.minMax(min,max);
+	voxelData.minMax(min,max);
 
 
 	string sMin,sMax;
@@ -542,23 +603,124 @@ unsigned int VoxeliseFilter::refresh(const std::vector<const FilterStreamData *>
 	stream_cast(sMax,max);
 	consoleOutput.push_back(std::string(TRANS("Voxel Limits (min,max): (") + sMin + string(","))
 		       	+  sMax + ")");
-	if(cache)
+
+
+	//Update the bounding cube
 	{
-		vs->cached=1;
-		cacheOK=true;
-		filterOutputs.push_back(vs);
+	Point3D p1,p2;
+	voxelData.getBounds(p1,p2);
+	lastBounds.setBounds(p1,p2);
+	}
+
+
+	switch(representation)
+	{
+		case VOXEL_REPRESENT_ISOSURF:
+		case VOXEL_REPRESENT_POINTCLOUD:
+		{
+			VoxelStreamData *vs = new VoxelStreamData();
+			vs->parent=this;
+			std::swap(vs->data,voxelData);
+			vs->representationType= representation;
+			vs->splatSize = splatSize;
+			vs->isoLevel=isoLevel;
+			vs->r=r;
+			vs->g=g;
+			vs->b=b;
+			vs->a=a;
+
+			if(cache)
+			{
+				vs->cached=1;
+				cacheOK=true;
+				filterOutputs.push_back(vs);
+			}
+			else
+				vs->cached=0;
+			
+			//Store the voxels on the output
+			getOut.push_back(vs);
+			break;
+		}
+		case VOXEL_REPRESENT_AXIAL_SLICE:
+		{
+			DrawStreamData *d = new DrawStreamData;
+
+			//Create the voxel slice
+			float minV,maxV;
+			{
+			DrawTexturedQuad *dq = new DrawTexturedQuad();
+
+			getTexturedSlice(voxelData,sliceAxis,sliceOffset,
+						sliceInterpolate,minV,maxV,*dq);
+
+			dq->canSelect=true;
+
+
+			SelectionDevice *s = new SelectionDevice(this);
+			SelectionBinding b;
+			//Bind translation to sphere left click
+			b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_QUAD_BIND_ORIGIN,
+					BINDING_PLANE_ORIGIN,dq->getOrigin(),dq);
+			b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE);
+			s->addBinding(b);
+
+			devices.push_back(s);
+
+			d->drawables.push_back(dq);
+			}
+			
+			
+			if(showColourBar)
+				d->drawables.push_back(makeColourBar(minV,maxV,255,colourMap));
+			d->cached=0;
+			d->parent=this;
+			
+			getOut.push_back(d);
+		
+		
+			cacheOK=false;
+		}
 	}
-	else
-		vs->cached=0;
 
 
-	//Store the voxels on the output
-	getOut.push_back(vs);
 	
 	//Copy the inputs into the outputs, provided they are not voxels
 	return 0;
 }
 
+void VoxeliseFilter::setPropFromBinding(const SelectionBinding &b)
+{
+	switch(b.getID())
+	{
+		case BINDING_PLANE_ORIGIN:
+		{
+			ASSERT(representation == VOXEL_REPRESENT_AXIAL_SLICE);
+			ASSERT(lastBounds.isValid());
+		
+			//Convert the world coordinate value into a
+			// fractional value of voxel bounds
+			Point3D p;
+			float f;
+			b.getValue(p);
+			f=p[sliceAxis];
+
+			float minB,maxB;
+			minB = lastBounds.getBound(sliceAxis,0);
+			maxB = lastBounds.getBound(sliceAxis,1);
+			sliceOffset= (f -minB)/(maxB-minB);
+			
+			sliceOffset=std::min(sliceOffset,1.0f);
+			sliceOffset=std::max(sliceOffset,0.0f);
+			ASSERT(sliceOffset<=1 && sliceOffset>=0);
+			break;
+		}
+		default:
+			ASSERT(false);
+	}
+
+}
+
 std::string VoxeliseFilter::getNormaliseTypeString(int type){
 	ASSERT(type < VOXELISE_NORMALISETYPE_MAX);
 	return TRANS(NORMALISE_TYPE_STRING[type]);
@@ -800,6 +962,8 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 	choices.push_back(make_pair((unsigned int)VOXEL_REPRESENT_POINTCLOUD,tmpStr));
 	tmpStr=getRepresentTypeString(VOXEL_REPRESENT_ISOSURF);
 	choices.push_back(make_pair((unsigned int)VOXEL_REPRESENT_ISOSURF,tmpStr));
+	tmpStr=getRepresentTypeString(VOXEL_REPRESENT_AXIAL_SLICE);
+	choices.push_back(make_pair((unsigned int)VOXEL_REPRESENT_AXIAL_SLICE,tmpStr));
 	
 	tmpStr= choiceString(choices,representation);
 
@@ -809,12 +973,13 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 	p.helpText=TRANS("3D display method");
 	p.key=KEY_VOXEL_REPRESENTATION_MODE;
 	propertyList.addProperty(p,curGroup);
-	propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 
 	switch(representation)
 	{
 		case VOXEL_REPRESENT_POINTCLOUD:
 		{
+			propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
+
 			stream_cast(tmpStr,splatSize);
 			p.name=TRANS("Spot size");
 			p.data=tmpStr;
@@ -828,12 +993,16 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_REAL;
 			p.helpText=TRANS("How \"see through\" each point is (0 - opaque, 1 - invisible)");
-			p.key=KEY_TRANSPARANCY;
+			p.key=KEY_TRANSPARENCY;
 			propertyList.addProperty(p,curGroup);
+			
 			break;
 		}
 		case VOXEL_REPRESENT_ISOSURF:
 		{
+			//-- Isosurface paramters --
+			propertyList.setGroupTitle(curGroup,TRANS("Surf. param."));
+
 			stream_cast(tmpStr,isoLevel);
 			p.name=TRANS("Isovalue");
 			p.data=tmpStr;
@@ -842,8 +1011,11 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_ISOLEVEL;
 			propertyList.addProperty(p,curGroup);
 		
+			//-- 
 				
+			curGroup++;
 
+			//-- Isosurface appearance --
 			//Convert the ion colour to a hex string	
 			genColString((unsigned char)(r*255),(unsigned char)(g*255),
 					(unsigned char)(b*255),(unsigned char)(a*255),tmpStr);
@@ -859,21 +1031,129 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_REAL;
 			p.helpText=TRANS("How \"see through\" each facet is (0 - opaque, 1 - invisible)");
-			p.key=KEY_TRANSPARANCY;
+			p.key=KEY_TRANSPARENCY;
 			propertyList.addProperty(p,curGroup);
 			
+			propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
+			//----
+			
+			break;
+		}
+		case VOXEL_REPRESENT_AXIAL_SLICE:
+		{
+			//-- Slice parameters --
+			propertyList.setGroupTitle(curGroup,TRANS("Slice param."));
+
+			vector<pair<unsigned int, string> > choices;
+			
+			
+			choices.push_back(make_pair(0,"x"));	
+			choices.push_back(make_pair(1,"y"));	
+			choices.push_back(make_pair(2,"z"));	
+			p.name=TRANS("Slice Axis");
+			p.data=choiceString(choices,sliceAxis);
+			p.type=PROPERTY_TYPE_CHOICE;
+			p.helpText=TRANS("Normal for the planar slice");
+			p.key=KEY_VOXEL_SLICE_AXIS;
+			propertyList.addProperty(p,curGroup);
+			choices.clear();
+			
+
+			stream_cast(tmpStr,sliceOffset);
+			p.name=TRANS("Slice Coord");
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_REAL;
+			p.helpText=TRANS("Fractional coordinate that slice plane passes through");
+			p.key=KEY_VOXEL_SLICE_OFFSET;
+			propertyList.addProperty(p,curGroup);
+		
+			
+			p.name=TRANS("Interp. Mode");
+			for(unsigned int ui=0;ui<SLICE_INTERP_ENUM_END;ui++)
+			{
+				choices.push_back(make_pair(ui,
+					TRANS(VOXELISE_SLICE_INTERP_STRING[ui])));
+			}
+			p.data=choiceString(choices,sliceInterpolate);
+			p.type=PROPERTY_TYPE_CHOICE;
+			p.helpText=TRANS("Interpolation mode for direction normal to slice");
+			p.key=KEY_VOXEL_SLICE_INTERP;
+			propertyList.addProperty(p,curGroup);
+			choices.clear();
+			// ---	
+			curGroup++;
+
+			
+
+			//-- Slice visualisation parameters --
+			for(unsigned int ui=0;ui<NUM_COLOURMAPS; ui++)
+				choices.push_back(make_pair(ui,getColourMapName(ui)));
+
+			tmpStr=choiceString(choices,colourMap);
+
+			p.name=TRANS("Colour mode");
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_CHOICE;
+			p.helpText=TRANS("Colour scheme used to assign points colours by value");
+			p.key=KEY_VOXEL_COLOURMODE;
+			propertyList.addProperty(p,curGroup);
+
+			if(showColourBar)
+				tmpStr="1";
+			else
+				tmpStr="0";
+			
+			p.name=TRANS("Show Bar");
+			p.key=KEY_SHOW_COLOURBAR;
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_BOOL;
+			propertyList.addProperty(p,curGroup);
+
+			if(autoColourMap)
+				tmpStr="1";
+			else
+				tmpStr="0";	
+			p.name=TRANS("Auto Bounds");
+			p.helpText=TRANS("Auto-compute min/max values in map"); 
+			p.data= tmpStr;
+			p.key=KEY_VOXEL_SLICE_COLOURAUTO;;
+			p.type=PROPERTY_TYPE_BOOL;
+			propertyList.addProperty(p,curGroup);
+
+			if(!autoColourMap)
+			{
+
+				stream_cast(tmpStr,colourMapBounds[0]);
+				p.name=TRANS("Map start");
+				p.helpText=TRANS("Assign points with this value to the first colour in map"); 
+				p.data= tmpStr;
+				p.key=KEY_MAPSTART;;
+				p.type=PROPERTY_TYPE_REAL;
+				propertyList.addProperty(p,curGroup);
+
+				stream_cast(tmpStr,colourMapBounds[1]);
+				p.name=TRANS("Map end");
+				p.helpText=TRANS("Assign points with this value to the last colour in map"); 
+				p.data= tmpStr;
+				p.key=KEY_MAPEND;
+				p.type=PROPERTY_TYPE_REAL;
+				propertyList.addProperty(p,curGroup);
+			}
+			// ---	
+
 			break;
 		}
 		default:
 			ASSERT(false);
 			;
 	}
-	
+	curGroup++;
+
 	//----------------------------
 }
 
-bool VoxeliseFilter::setProperty(  unsigned int key,
-									  const std::string &value, bool &needUpdate)
+bool VoxeliseFilter::setProperty(unsigned int key,
+		  const std::string &value, bool &needUpdate)
 {
 	
 	needUpdate=false;
@@ -903,8 +1183,6 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 			if(!i)
 				return false;
 
-			needUpdate=true;
-			nBins[0]=i;
 			//if the result is different, the
 			//cache should be invalidated
 			if(i!=nBins[0])
@@ -1047,7 +1325,7 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 			}
 			break;
 		}
-		case KEY_TRANSPARANCY:
+		case KEY_TRANSPARENCY:
 		{
 			float f;
 			if(stream_cast(f,value))
@@ -1124,17 +1402,19 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 		}
 		case KEY_VOXEL_REPRESENTATION_MODE:
 		{
-			 unsigned int i;
+			unsigned int i;
 			for (i = 0; i < VOXEL_REPRESENT_END; i++)
 				if (value == getRepresentTypeString(i)) break;
 			if (i == VOXEL_REPRESENT_END)
 				return false;
 			needUpdate=true;
-			representation=i;
 			//Go in and manually adjust the cached
 			//entries to have the new value, rather
 			//than doing a full recomputation
-			if(cacheOK)
+
+			//TODO: Can we instead of caching the Stream, simply cache the voxel data?
+			representation=i;
+			if(cacheOK && (VOXEL_REPRESENT_KEEPCACHE[i] && VOXEL_REPRESENT_KEEPCACHE[representation]))
 			{
 				for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 				{
@@ -1143,6 +1423,11 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 					d->representationType=representation;
 				}
 			}
+			else
+			{
+				clearCache();
+			}
+			
 			break;
 		}
 		case KEY_ENABLE_NUMERATOR:
@@ -1175,7 +1460,7 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 		}
 		case KEY_FILTER_MODE:
 		{
-			 unsigned int i;
+			unsigned int i;
 			for (i = 0; i < VOXEL_REPRESENT_END; i++)
 				if (value == getFilterTypeString(i)) break;
 			if (i == VOXEL_REPRESENT_END)
@@ -1221,8 +1506,166 @@ bool VoxeliseFilter::setProperty(  unsigned int key,
 			}
 			break;
 		}
+		case KEY_VOXEL_SLICE_COLOURAUTO:
+		{
+			bool b;
+			if(stream_cast(b,value))
+				return false;
+
+			//if the result is different, the
+			//cache should be invalidated
+			if(b!=autoColourMap)
+			{
+				needUpdate=true;
+				autoColourMap=b;
+				//Clear the generic filter cache, but
+				// not the voxel cache
+				Filter::clearCache();
+			}
+			break;
+		}	
+		case KEY_VOXEL_SLICE_AXIS:
+		{
+			unsigned int i;
+			string axisLabels[3]={"x","y","z"};
+			for (i = 0; i < 3; i++)
+				if( value == axisLabels[i]) break;
+				
+			if( i >= 3)
+				return false;
+
+			if(i != sliceAxis)
+			{
+				needUpdate=true;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+				sliceAxis=i;
+			}
+			break;
+		}
+		case KEY_VOXEL_SLICE_INTERP:
+		{
+			unsigned int i;
+			for (i = 0; i < SLICE_INTERP_ENUM_END; i++)
+				if( value == TRANS(VOXELISE_SLICE_INTERP_STRING[i])) break;
+				
+			if( i >= SLICE_INTERP_ENUM_END)
+				return false;
+
+			if(i != sliceInterpolate)
+			{
+				needUpdate=true;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+				sliceInterpolate=i;
+			}
+			break;
+		}
+		case KEY_VOXEL_SLICE_OFFSET:
+		{
+			float f;
+			if(stream_cast(f,value))
+				return false;
+
+			if(f < 0.0f || f > 1.0f)
+				return false;
+
+
+			if( f != sliceOffset)
+			{
+				needUpdate=true;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+				sliceOffset=f;
+			}
+
+			break;
+		}
+		case KEY_VOXEL_COLOURMODE:
+		{
+			unsigned int tmpMap;
+			tmpMap=(unsigned int)-1;
+			for(unsigned int ui=0;ui<NUM_COLOURMAPS;ui++)
+			{
+				if(value== getColourMapName(ui))
+				{
+					tmpMap=ui;
+					break;
+				}
+			}
+
+			if(tmpMap >=NUM_COLOURMAPS || tmpMap ==colourMap)
+				return false;
+
+			//clear the generic filter cache (i.e. cached outputs)
+			//but not the voxel cache
+			Filter::clearCache();
+			
+			needUpdate=true;
+			colourMap=tmpMap;
+			break;
+		}
+		case KEY_SHOW_COLOURBAR:
+		{
+			bool b;
+			if(stream_cast(b,value))
+				return false;
+
+			//if the result is different, the
+			//cache should be invalidated
+			if(b!=showColourBar)
+			{
+				needUpdate=true;
+				showColourBar=b;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+			}
+			break;
+		}	
+		case KEY_MAPSTART:
+		{
+			float f;
+			if(stream_cast(f,value))
+				return false;
+			if(f >= colourMapBounds[1])
+				return false;
+		
+			if(f!=colourMapBounds[0])
+			{
+				needUpdate=true;
+				colourMapBounds[0]=f;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+			}
+			break;
+		}
+		case KEY_MAPEND:
+		{
+			float f;
+			if(stream_cast(f,value))
+				return false;
+			if(f <= colourMapBounds[0])
+				return false;
+		
+			if(f!=colourMapBounds[1])
+			{
+				needUpdate=true;
+				colourMapBounds[1]=f;
+				//clear the generic filter cache (i.e. cached outputs)
+				//but not the voxel cache
+				Filter::clearCache();
+			}
+			break;
+		}
 		default:
 		{
+			//Check for jump to denominator or numerator section
+			// TODO: This is a bit of a hack.
 			if (key >= KEY_ENABLE_DENOMINATOR*1000) {
 				bool b;
 				if(stream_cast(b,value))
@@ -1304,6 +1747,19 @@ bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned in
 			f << tabs(depth+1) << "<isovalue value=\""<<isoLevel << "\"/>" << endl;
 			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
 				<< "\" a=\"" << a << "\"/>" <<endl;
+
+			f << tabs(depth+1) << "<axialslice>" << endl;
+			f << tabs(depth+2) << "<offset value=\""<<sliceOffset<< "\"/>" << endl;
+			f << tabs(depth+2) << "<interpolate value=\""<<sliceInterpolate<< "\"/>" << endl;
+			f << tabs(depth+2) << "<axis value=\""<<sliceAxis<< "\"/>" << endl;
+			f << tabs(depth+2) << "<colourbar show=\""<<(showColourBar?1:0)<< 
+					"\" auto=\"" << (autoColourMap?1:0)<< "\" min=\"" <<
+					colourMapBounds[0] << "\" max=\"" << 
+					colourMapBounds[1] << "\"/>" << endl;
+			f << tabs(depth+1) << "</axialslice>" << endl;
+
+
+
 			f << tabs(depth) << "</" << trueName() <<">" << endl;
 			break;
 		}
@@ -1486,6 +1942,54 @@ bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 		return false;
 
 	//====
+
+	//try to retrieve slice, where possible
+	if(!XMLHelpFwdToElem(nodePtr,"axialslice"))
+	{
+		xmlNodePtr sliceNodes;
+		sliceNodes=nodePtr->xmlChildrenNode;
+
+		if(!sliceNodes)
+			return false;
+
+		if(!XMLGetNextElemAttrib(sliceNodes,sliceOffset,"offset","value"))
+			return false;
+
+		sliceOffset=std::min(sliceOffset,1.0f);
+		sliceOffset=std::max(sliceOffset,0.0f);
+		
+		
+		if(!XMLGetNextElemAttrib(sliceNodes,sliceInterpolate,"interpolate","value"))
+			return false;
+
+		if(sliceInterpolate >=SLICE_INTERP_ENUM_END)
+			return false;
+
+		if(!XMLGetNextElemAttrib(sliceNodes,sliceAxis,"axis","value"))
+			return false;
+
+		if(sliceAxis > 2)
+			sliceAxis=2;
+		
+		if(!XMLGetNextElemAttrib(sliceNodes,showColourBar,"colourbar","show"))
+			return false;
+
+		if(!XMLGetAttrib(sliceNodes,autoColourMap,"auto"))
+			return false;
+		
+		if(!XMLGetAttrib(sliceNodes,colourMapBounds[0],"min"))
+			return false;
+
+		if(!XMLGetAttrib(sliceNodes,colourMapBounds[1],"max"))
+			return false;
+
+		if(colourMapBounds[0] >= colourMapBounds[1])
+			return false;
+	}
+	
+
+
+
 	return true;
 	
 }
@@ -1506,9 +2010,111 @@ unsigned int VoxeliseFilter::getRefreshUseMask() const
 	return STREAM_TYPE_IONS | STREAM_TYPE_RANGE;
 }
 
-void VoxeliseFilter::setPropFromBinding(const SelectionBinding &b)
+void VoxeliseFilter::getTexturedSlice(const Voxels<float> &v, 
+			size_t axis,float offset, size_t interpolateMode,
+			float &minV,float &maxV,DrawTexturedQuad &texQ) const
 {
-}	
+	ASSERT(axis < 3);
+
+
+	size_t dim[3]; //dim0 and 2 are the in-plane axes. dim3 is the normal axis
+	v.getSize(dim[0],dim[1],dim[2]);
+
+	switch(axis)
+	{
+		//x-normal
+		case 0:
+			rotate3(dim[0],dim[1],dim[2]);
+			std::swap(dim[0],dim[1]);
+			break;
+		//y-normal
+		case 1:
+			rotate3(dim[2],dim[1],dim[0]);
+			break;
+		//z-normal
+		case 2:
+			std::swap(dim[0],dim[1]);
+			break;
+			
+	}
+
+
+	ASSERT(dim[0] >0 && dim[1] >0);
+	
+	texQ.resize(dim[0],dim[1],3);
+
+	//Generate the texture from the voxel data
+	//---
+	float *data = new float[dim[0]*dim[1]];
+	
+
+	ASSERT(offset >=0 && offset <=1.0f);
+
+	v.getSlice(axis,offset,data,interpolateMode,sliceBoundMode);
+
+	if(autoColourMap)
+	{
+		minV=minValue(data,dim[0]*dim[1]);
+		maxV=maxValue(data,dim[0]*dim[1]);
+	}
+	else
+	{
+		minV=colourMapBounds[0];
+		maxV=colourMapBounds[1];
+
+	}
+	ASSERT(minV <=maxV);
+
+	unsigned char rgb[3];
+	for(size_t ui=0;ui<dim[0];ui++)
+	{
+		for(size_t uj=0;uj<dim[1];uj++)
+		{
+			colourMapWrap(colourMap,rgb, data[ui*dim[1] + uj],
+					minV,maxV);
+			
+			texQ.setData(ui,uj,rgb);	
+		}
+	}
+
+	delete[] data;
+	//---
+	
+	
+	
+	//Set the vertices of the quad
+	//--
+	//compute the real position of the plane
+	float minPos,maxPos,offsetRealPos;
+	v.getAxisBounds(axis,minPos,maxPos);
+	offsetRealPos = ((float)offset)*(maxPos-minPos) + minPos; 
+	
+	
+	Point3D verts[4];
+	v.getBounds(verts[0],verts[2]);
+	//set opposite vertices to upper and lower bounds of quad
+	verts[0][axis]=verts[2][axis]=offsetRealPos;
+	//set other vertices to match, then shift them in the axis plane
+	verts[1]=verts[0]; 
+	verts[3]=verts[2];
+
+
+	unsigned int shiftAxis=(axis+1)%3;
+	verts[1][shiftAxis] = verts[2][shiftAxis];
+	verts[3][shiftAxis] = verts[0][shiftAxis];
+
+	//Correction for y texture orientation
+	if(axis==1)
+		std::swap(verts[1],verts[3]);
+
+	texQ.setVertices(verts);
+	//--
+
+	//Upload the texture to the video card
+	texQ.rebindTexture();
+
+}
+
 
 #ifdef DEBUG
 bool voxelSingleCountTest()
diff --git a/src/backend/filters/voxelise.h b/src/backend/filters/voxelise.h
index e1a9878..3ceb373 100644
--- a/src/backend/filters/voxelise.h
+++ b/src/backend/filters/voxelise.h
@@ -31,7 +31,10 @@ private:
 
 	//!Stepping mode - fixed width or fixed number of bins
 	bool fixedWidth;
-	
+
+	//Cache to use for voxel info
+	Voxels<float> voxelCache;
+
 	//!number of bins (if using fixed bins)
 	unsigned long long nBins[INDEX_LENGTH];
 	//!Width of each bin (if using fixed wdith)
@@ -66,13 +69,42 @@ private:
 	float isoLevel;
 	//!Default output representation mode
 	unsigned int representation;
+
+	//!Colour map to use when using axial slices
+	unsigned int colourMap;
+
+	//Number of colour levels for colour map
+	size_t nColours;
+	//Whether to show the colour map bar or not
+	bool showColourBar;
+	//Whether to use an automatic colour bound, or to use user spec
+	bool autoColourMap;
+	//Colour map start/end
+	float colourMapBounds[2];
+
+	//Interpolation mode to use when slicing	
+	size_t sliceInterpolate;
+	//Interpolation boundary handling mode
+	size_t sliceBoundMode;
+	//Axis that is normal to the slice 0,1,2 => x,y,z
+	size_t sliceAxis;
+	//Fractional offset from lower bound of data cube [0,1]
+	float sliceOffset;
+
+	//Obtain a textured slice from the given voxel set
+	void getTexturedSlice(const Voxels<float> &f,
+		size_t axis,float offset, size_t interpolateMode,
+		float &minV, float &maxV, DrawTexturedQuad &texQ) const;
+
+	BoundCube lastBounds;
+
 public:
 	VoxeliseFilter();
 	~VoxeliseFilter() { if(rsdIncoming) delete rsdIncoming;}
 	//!Duplicate filter contents, excluding cache.
 	Filter *cloneUncached() const;
 
-
+	virtual void clearCache();
 	
 	//!Get approx number of bytes for caching output
 	size_t numBytesForCache(size_t nObjects) const;
diff --git a/src/backend/filtertree.cpp b/src/backend/filtertree.cpp
index 6a7564e..66e5583 100644
--- a/src/backend/filtertree.cpp
+++ b/src/backend/filtertree.cpp
@@ -262,7 +262,6 @@ void FilterTree::initFilterTree() const
 {
 	vector< const FilterStreamData *> curData;
 	stack<vector<const FilterStreamData * > > inDataStack;
-	list<vector<const FilterStreamData * > > outData;
 	
 	FilterRefreshCollector refreshCollector;
 
@@ -541,7 +540,7 @@ void FilterTree::getFilterRefreshStarts(vector<tree<Filter *>::iterator > &propS
 }
 
 unsigned int FilterTree::refreshFilterTree(list<FILTER_OUTPUT_DATA > &outData, 
-		std::vector<SelectionDevice<Filter> *> &devices,
+		std::vector<SelectionDevice *> &devices,
 		vector<pair<const Filter* , string> > &consoleMessages,
 	       	ProgressData &curProg, bool (*callback)(bool)) const
 {
@@ -686,7 +685,7 @@ unsigned int FilterTree::refreshFilterTree(list<FILTER_OUTPUT_DATA > &outData,
 			(*callback)(false);
 
 
-			vector<SelectionDevice<Filter> *> curDevices;
+			vector<SelectionDevice *> curDevices;
 			//Retrieve the user interaction "devices", and send them to the scene
 			(*filtIt)->getSelectionDevices(curDevices);
 
@@ -938,9 +937,9 @@ unsigned int FilterTree::loadXML(const xmlNodePtr &treeParent, std::ostream &err
 			std::string tmpStr;
 			tmpStr=(char *)nodePtr->name;
 
-			newFilt=makeFilter(tmpStr);
-			if(newFilt)
+			if(isValidFilterName(tmpStr))
 			{
+				newFilt=makeFilter(tmpStr);
 				if (!newFilt->readState(nodePtr->xmlChildrenNode,stateFileDir))
 				{
 					needCleanup=true;
@@ -1266,9 +1265,7 @@ void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &c
 		const PlotStreamData *p;
 		p =(const PlotStreamData*)curData[ui];
 
-#ifdef DEBUG
 		p->checkSelfConsistent();
-#endif
 	}
 	
 	//Voxel output streams should only have known types
@@ -1284,6 +1281,36 @@ void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &c
 		ASSERT(p->representationType< VOXEL_REPRESENT_END);
 	}
 
+	//Ensure that any output drawables that are selectable have
+	// parent filters with selection devices
+	for(size_t ui=0; ui<curData.size();ui++)
+	{
+		if(curData[ui]->getStreamType() != STREAM_TYPE_DRAW)
+			continue;
+
+		const DrawStreamData *p;
+		p =(const DrawStreamData*)curData[ui];
+	
+		for(size_t uj=0;uj<p->drawables.size();uj++)
+		{
+			if ( p->drawables[uj]->canSelect )
+			{
+				vector<SelectionDevice *> devices;
+				p->parent->getSelectionDevices(devices);
+				ASSERT(devices.size());
+
+				for(size_t uk=0;uk<devices.size();uk++)
+				{
+					ASSERT(devices[uk]->getNumBindings());
+				}
+			}
+		
+			//Drawables with selection devices cannot be cached
+			ASSERT(!p->cached);
+		}
+
+	}
+
 }
 #endif
 
@@ -1757,7 +1784,7 @@ bool FilterTree::reparentFilter(Filter *f, const Filter *newParent)
 }
 
 
-void FilterTree::clearCache(const Filter *filter)
+void FilterTree::clearCache(const Filter *filter,bool includeSelf)
 {
 	if(!filter)
 	{
@@ -1785,7 +1812,11 @@ void FilterTree::clearCache(const Filter *filter)
 			//Do not traverse siblings
 			if(filters.depth(filterIt) >= filters.depth(it) && it!=filterIt )
 				break;
-		
+
+			//If we dont want to include self,  then skip
+			if( !includeSelf && *it == filter)
+				continue;
+
 			(*it)->clearCache();
 		}
 	}
diff --git a/src/backend/filtertree.h b/src/backend/filtertree.h
index 47bb063..5fc724e 100644
--- a/src/backend/filtertree.h
+++ b/src/backend/filtertree.h
@@ -111,7 +111,7 @@ class FilterTree
 		// deleting the filterstream data correctly. To do this, use the "safeDeleteFilterList" function.
 		unsigned int refreshFilterTree(	
 			std::list<FILTER_OUTPUT_DATA> &outData,
-			std::vector<SelectionDevice<Filter> *> &devices,std::vector<std::pair<const Filter *,string> > &consoleMessages,
+			std::vector<SelectionDevice *> &devices,std::vector<std::pair<const Filter *,string> > &consoleMessages,
 						ProgressData &curProg, bool (*callback)(bool)) const;
 		
 		//!Safely delete data generated by refreshFilterTree(...). 
@@ -160,8 +160,9 @@ class FilterTree
 		//!Set the filter user text
 		bool setFilterString(Filter *, const std::string &s);
 		
-		//!Invalidate the cache of a given Filter and all its children. set to 0 to clear all.
-		void clearCache(const Filter *filt);
+		//!Invalidate the cache of a given Filter and all its children. 
+		// set to 0 to clear all.
+		void clearCache(const Filter *filt,bool includeSelf=true);
 		
 		
 		//!Invalidate the cache of a given type of filter
diff --git a/src/backend/filtertreeAnalyse.cpp b/src/backend/filtertreeAnalyse.cpp
index 51877d4..4bd630b 100644
--- a/src/backend/filtertreeAnalyse.cpp
+++ b/src/backend/filtertreeAnalyse.cpp
@@ -22,11 +22,115 @@
 
 //Needed to obtain filter data keys
 //----
-#include "filters/dataLoad.h"
-#include "filters/ionDownsample.h"
-#include "filters/compositionProfile.h"
+#include "filters/allFilter.h"
 //----
 
+#include <numeric>
+
+bool filterIsSampling(const Filter *f)
+{
+	bool affectsSampling=false;
+
+
+	FilterPropGroup props;
+	f->getProperties(props);
+
+
+
+	switch(f->getType())
+	{
+		case FILTER_TYPE_DATALOAD:
+		{
+			//Check if load limiting is on
+			//Not strictly true. If data file is smaller (in MB) than this number
+			// (which we don't know here), then this will be false.
+			if(props.hasProp(DATALOAD_KEY_SAMPLE))
+				affectsSampling = (props.getPropValue(DATALOAD_KEY_SAMPLE).data!= "0");
+			else
+				affectsSampling=false;
+		}
+		case FILTER_TYPE_IONDOWNSAMPLE:
+		{
+			FilterProperty p;
+			if(props.hasProp(KEY_IONDOWNSAMPLE_FIXEDOUT))
+			{
+				p=props.getPropValue(KEY_IONDOWNSAMPLE_FIXEDOUT);
+				//If using  fixed output mode, then
+				// we may affect the output ion density
+				// if the count is low. How low? 
+				// We don't know with the information to hand...
+				affectsSampling=(p.data== "1");
+			}
+			else
+			{
+				//If randomly sampling, then we are definitely affecting the results
+				//if we are not including every ion
+				if(props.hasProp(KEY_IONDOWNSAMPLE_FRACTION))
+				{
+					p=props.getPropValue(KEY_IONDOWNSAMPLE_FRACTION);
+					float sampleFrac;
+					stream_cast(sampleFrac,p.data);
+					affectsSampling=(sampleFrac < 1.0f);
+				}
+				else
+					affectsSampling=false;
+			}
+
+			break;
+		}
+	}
+
+
+	return affectsSampling;
+}
+
+bool affectedBySampling(const Filter *f, bool haveRngParent)
+{
+	FilterPropGroup props;
+	f->getProperties(props);
+	
+	bool affected=false;
+	//See if filter is configured to affect spatial analysis
+	switch(f->getType())
+	{
+		case FILTER_TYPE_CLUSTER_ANALYSIS:
+		{
+			affected=haveRngParent;
+			break;
+		}
+		case FILTER_TYPE_COMPOSITION:
+		{
+			FilterProperty p;
+			p=props.getPropValue(COMPOSITION_KEY_NORMALISE);
+
+			//If using normalise mode, and we do not have a range parent
+			//then filter is in "density" plotting mode, which is affected by
+			//this analysis
+			affected= (p.data== "1" && !haveRngParent);
+			break;
+		}
+		case FILTER_TYPE_SPATIAL_ANALYSIS:
+		{
+			affected=true;
+			break;
+		}
+	}
+
+	return affected;
+}
+
+bool needsRangeParent(const Filter *f)
+{
+	switch(f->getType())
+	{
+		case FILTER_TYPE_CLUSTER_ANALYSIS:
+			return true;
+		default:
+			return false;
+	}
+
+}
+
 void FilterTreeAnalyse::getAnalysisResults(std::vector<FILTERTREE_ERR> &errs) const
 {
 	errs.resize(analysisResults.size());
@@ -44,17 +148,18 @@ void FilterTreeAnalyse::analyse(const FilterTree &f)
 	//Check for spatial sampling altering some results in later analyses
 	spatialSampling(f);
 	
-	//Check for compositional biasing altering some later analysis
+	//Check for compositional biasing altering some later anaylsis
 	compositionAltered(f);
 
+	//Check for filters that do not have a parent, which is required
+	checkRequiredParent(f);
+
 	emitTypes.clear();
 	blockTypes.clear();
 
 }
 
 
-
-
 void FilterTreeAnalyse::blockingPairError(const FilterTree &f)
 {
 	//Examine the emit and block/use masks for each filter's parent (emit)
@@ -107,7 +212,7 @@ void FilterTreeAnalyse::blockingPairError(const FilterTree &f)
 			
 				analysisResults.push_back(treeErr);
 			}
-			//If the parent does not emit a usable objects 
+			//If the parent does not emit a useable objects 
 			//for the child filter, this is bad too.
 			// - else if, so we don't double up on warnings
 			else if( !(parentEmit & curUse) && !childFilter->isUsefulAsAppend())
@@ -133,99 +238,6 @@ void FilterTreeAnalyse::blockingPairError(const FilterTree &f)
 
 }
 
-bool filterIsSampling(const Filter *f)
-{
-	bool affectsSampling=false;
-
-
-	FilterPropGroup props;
-	f->getProperties(props);
-
-
-
-	switch(f->getType())
-	{
-		case FILTER_TYPE_DATALOAD:
-		{
-			//Check if load limiting is on
-			//Not strictly true. If data file is smaller (in MB) than this number
-			// (which we don't know here), then this will be false.
-			if(props.hasProp(DATALOAD_KEY_SAMPLE))
-				affectsSampling = (props.getPropValue(DATALOAD_KEY_SAMPLE).data!= "0");
-			else
-				affectsSampling=false;
-		}
-		case FILTER_TYPE_IONDOWNSAMPLE:
-		{
-			FilterProperty p;
-			if(props.hasProp(KEY_IONDOWNSAMPLE_FIXEDOUT))
-			{
-				p=props.getPropValue(KEY_IONDOWNSAMPLE_FIXEDOUT);
-				//If using  fixed output mode, then
-				// we may affect the output ion density
-				// if the count is low. How low? 
-				// We don't know with the information to hand...
-				affectsSampling=(p.data== "1");
-			}
-			else
-			{
-				//If randomly sampling, then we are definitely affecting the results
-				//if we are not including every ion
-				if(props.hasProp(KEY_IONDOWNSAMPLE_FRACTION))
-				{
-					p=props.getPropValue(KEY_IONDOWNSAMPLE_FRACTION);
-					float sampleFrac;
-					stream_cast(sampleFrac,p.data);
-					affectsSampling=(sampleFrac < 1.0f);
-				}
-				else
-					affectsSampling=false;
-			}
-
-			break;
-		}
-	}
-
-
-	return affectsSampling;
-}
-
-bool affectedBySampling(const Filter *f, bool haveRngParent)
-{
-	FilterPropGroup props;
-	f->getProperties(props);
-	
-	bool affected;
-	//See if filter is configured to affect spatial analysis
-	switch(f->getType())
-	{
-		case FILTER_TYPE_CLUSTER_ANALYSIS:
-		{
-			affected=haveRngParent;
-			break;
-		}
-		case FILTER_TYPE_COMPOSITION:
-		{
-			FilterProperty p;
-			p=props.getPropValue(COMPOSITION_KEY_NORMALISE);
-
-			//If using normalise mode, and we do not have a range parent
-			//then filter is in "density" plotting mode, which is affected by
-			//this analysis
-			affected= (p.data== "1" && !haveRngParent);
-			break;
-		}
-		case FILTER_TYPE_SPATIAL_ANALYSIS:
-		case FILTER_TYPE_IONINFO:
-		{
-			affected=true;
-			break;
-		}
-	}
-
-	return affected;
-}
-
 
 void FilterTreeAnalyse::spatialSampling(const FilterTree &f)
 {
@@ -306,6 +318,67 @@ void FilterTreeAnalyse::spatialSampling(const FilterTree &f)
 	}
 }
 
+void FilterTreeAnalyse::checkRequiredParent(const FilterTree &f)
+{
+	const tree<Filter *> &treeFilt=f.getTree();
+	vector<pair< tree<Filter*>::pre_order_iterator , size_t> > childrenNeedsParent;
+
+	for(tree<Filter*>::pre_order_iterator it = treeFilt.begin(); it!=treeFilt.end(); ++it)
+	{
+		//Enumerate all the filters that need a range parent
+		if(needsRangeParent(*it))
+			childrenNeedsParent.push_back(make_pair(it,(size_t)FILTER_TYPE_RANGEFILE));
+	}
+
+	//Check each of the reported children, each time it was reported
+	for(size_t ui=0;ui<childrenNeedsParent.size();ui++)
+	{
+		tree<Filter *>::pre_order_iterator it;
+		size_t type;
+
+		it = childrenNeedsParent[ui].first;
+		type = childrenNeedsParent[ui].second;
+
+		tree<Filter *>::pre_order_iterator parentIt;
+		bool foundParent;
+		foundParent=false;
+
+		//walk back up the tree, to locate the parent (technically ancestor)
+		// we are looking for
+		while(it != treeFilt.begin())
+		{
+			it= treeFilt.parent(it);
+			if((*it)->getType() == type)
+			{
+				foundParent=true;
+				break;
+			}
+		}
+
+		//If we couldnt find a parent, then this is an error.
+		// let the user know
+		if(!foundParent)
+		{
+
+			std::string tmpStr;
+			Filter *tmpFilt = makeFilter(type);
+			tmpStr=tmpFilt->typeString();
+			delete tmpFilt;
+
+
+			FILTERTREE_ERR treeErr;
+			treeErr.reportedFilters.push_back(*(childrenNeedsParent[ui].first));
+
+			treeErr.verboseReportMessage = TRANS("Filter needs parent \"")  + 
+					tmpStr + TRANS("\" but does not have one. Filter may not function correctly until this parent is given.");
+			treeErr.shortReportMessage = TRANS("Filter missing needed parent");
+			treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing.
+			analysisResults.push_back(treeErr);
+		}
+
+	}
+}
+
 
 bool filterAltersComposition(const Filter *f)
 {
@@ -349,6 +422,33 @@ bool filterAltersComposition(const Filter *f)
 			}
 			break;
 		}
+		case FILTER_TYPE_RANGEFILE:
+		{
+			const RangeFileFilter *r;
+			r = (const RangeFileFilter*)f;
+
+			vector<char> enabledIons,enabledRanges;
+			enabledIons = r->getEnabledIons();
+
+			if(enabledIons.size() > 1)
+			{
+				size_t nEnabled=std::accumulate(enabledIons.begin(),enabledIons.end(),0);
+
+				if(nEnabled > 0 && nEnabled < enabledIons.size())
+					return true;
+			}
+	
+			enabledRanges=r->getEnabledRanges();
+			if(enabledRanges.size() > 1)
+			{
+				size_t nEnabled=std::accumulate(enabledRanges.begin(),enabledRanges.end(),0);
+
+				if(nEnabled > 0 && nEnabled < enabledRanges.size())
+					return true;
+			}
+
+			break;
+		}
 	}
 
 
diff --git a/src/backend/filtertreeAnalyse.h b/src/backend/filtertreeAnalyse.h
index 939c3ee..829fdcd 100644
--- a/src/backend/filtertreeAnalyse.h
+++ b/src/backend/filtertreeAnalyse.h
@@ -62,6 +62,8 @@ class FilterTreeAnalyse
 		void spatialSampling(const FilterTree &f);
 
 		void compositionAltered(const FilterTree &f);
+
+		void checkRequiredParent(const FilterTree &f);
 	public:
 		void analyse(const FilterTree &f);
 
diff --git a/src/backend/plot.cpp b/src/backend/plot.cpp
index 692f898..6ca21ac 100644
--- a/src/backend/plot.cpp
+++ b/src/backend/plot.cpp
@@ -43,6 +43,17 @@ using std::string;
 using std::pair;
 using std::vector;
 
+float makePositiveLog(float v)
+
+{
+	if(v <=1.0f)
+		v=0.0f;
+	else
+		v=log10(v);
+
+	return v;
+}
+
 
 //Axis min/max bounding box is disallowed to be exactly zero on any given axis
 // perform a little "push off" by this fudge factor
@@ -397,7 +408,7 @@ void PlotWrapper::setBounds(float xMin, float xMax,
 	ASSERT(xMin<xMax);
 	ASSERT(yMin<=yMax);
 	xUserMin=xMin;
-	yUserMin=std::max(0.0f,yMin);
+	yUserMin=yMin;
 	xUserMax=xMax;
 	yUserMax=yMax;
 
@@ -573,6 +584,21 @@ unsigned int PlotWrapper::getVisibleType() const
 	return visibleType;
 }
 
+bool PlotWrapper::visibleEmpty() const
+{
+	bool empty=true;
+	for(unsigned int ui=0;ui<plottingData.size() ; ui++)
+	{
+		if(plottingData[ui]->visible)
+		{
+			empty&=plottingData[ui]->empty();
+			if(!empty)
+				return false;
+		}
+	}
+
+}
+
 void PlotWrapper::drawPlot(mglGraph *gr) const
 {
 	unsigned int visType = getVisibleType();
@@ -603,11 +629,14 @@ void PlotWrapper::drawPlot(mglGraph *gr) const
 	{
 		if(plottingData[ui]->visible)
 		{
+			float tmpMinX,tmpMinY,tmpMaxX,tmpMaxY;
+			plottingData[ui]->getBounds(
+				tmpMinX,tmpMaxX,tmpMinY,tmpMaxY);
 
-			minX=std::min(minX,plottingData[ui]->minX);
-			maxX=std::max(maxX,plottingData[ui]->maxX);
-			minY=std::min(minY,plottingData[ui]->minY);
-			maxY=std::max(maxY,plottingData[ui]->maxY);
+			minX=std::min(minX,tmpMinX);
+			maxX=std::max(maxX,tmpMaxX);
+			minY=std::min(minY,tmpMinY);
+			maxY=std::max(maxY,tmpMaxY);
 
 
 			if(!xLabel.size())
@@ -699,11 +728,7 @@ void PlotWrapper::drawPlot(mglGraph *gr) const
 				min.x=minX;
 				min.y=minY;
 				max.x=maxX;
-
-				if(useLogPlot && maxY > 0.0f)
-					max.y =log10(maxY);
-				else
-					max.y=maxY;
+				max.y=maxY;
 
 				axisCross.x = minX;
 				axisCross.y=min.y;
@@ -959,7 +984,6 @@ void Plot1D::setData(const vector<float> &vX, const vector<float> &vY,
 		maxY+=AXIS_MIN_TOLERANCE;
 	}
 }
-//---
 
 
 void Plot1D::setData(const vector<std::pair<float,float> > &v)
@@ -969,6 +993,7 @@ void Plot1D::setData(const vector<std::pair<float,float> > &v)
 	setData(v,dummyVar);
 
 }
+
 void Plot1D::setData(const vector<std::pair<float,float> > &v,const vector<float> &vErr) 
 {
 	//Fill up vectors with data
@@ -988,22 +1013,22 @@ void Plot1D::setData(const vector<std::pair<float,float> > &v,const vector<float
 	//Compute minima and maxima of plot data, and keep a copy of it
 	float maxThis=-std::numeric_limits<float>::max();
 	float minThis=std::numeric_limits<float>::max();
+
+	// --------- X Values ---
 	for(unsigned int ui=0;ui<v.size();ui++)
 	{
 		minThis=std::min(minThis,v[ui].first);
 		maxThis=std::max(maxThis,v[ui].first);
 	}
-
 	minX=minThis;
 	maxX=maxThis;
-	if(maxX - minX < AXIS_MIN_TOLERANCE)
-	{
-		minX-=AXIS_MIN_TOLERANCE;
-		maxX+=AXIS_MIN_TOLERANCE;
-	}
+	//------------
 
-	maxThis=-std::numeric_limits<float>::max();
+
+	// Y values, taking into account any error bars
+	//------------------
 	minThis=std::numeric_limits<float>::max();
+	maxThis=-std::numeric_limits<float>::max();
 	if(vErr.size())
 	{
 		ASSERT(vErr.size() == v.size());
@@ -1023,32 +1048,32 @@ void Plot1D::setData(const vector<std::pair<float,float> > &v,const vector<float
 
 	}
 	minY=minThis;
-	maxY=1.10f*maxThis; //The 1.10 is because mathgl chops off data
-	
-	if(maxY - minY < AXIS_MIN_TOLERANCE)
-	{
-		minY-=AXIS_MIN_TOLERANCE;
-		maxY+=AXIS_MIN_TOLERANCE;
-	}
-
-
+	maxY=maxThis; 
+	//------------------
 }
 
 void Plot1D::getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const
 {
-	//OK, we are going to have to scan for max/min
 	xMin=minX;
 	xMax=maxX;
 	yMin=minY;
 	yMax=maxY;
 
+	ASSERT(yMin <=yMax);
 	//If we are in log mode, then we need to set the
 	//log of that bound before emitting it.
-	if(logarithmic && yMax)
+	if(logarithmic)
 	{
-		yMin=log10(std::max(yMin,1.0f));
-		yMax=log10(yMax);
+		//Disallow negative logarithmic bounds
+		yMax=makePositiveLog(yMax);
 	}
+	ASSERT(yMin <=yMax);
+}
+
+bool Plot1D::empty() const
+{
+	ASSERT(xValues.size() == yValues.size());
+	return xValues.empty();
 }
 
 void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
@@ -1056,8 +1081,11 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 	bool showErrs;
 
 	mglData xDat,yDat,eDat;
+
 	ASSERT(visible);
-		
+	
+
+	//Make a copy of the data we need to use
 	float *bufferX,*bufferY,*bufferErr;
 	bufferX = new float[xValues.size()];
 	bufferY = new float[yValues.size()];
@@ -1066,16 +1094,14 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 	if(showErrs)
 		bufferErr = new float[errBars.size()];
 
+	//Pre-process the data, before handing to mathgl
+	//--
 	if(logarithmic)
 	{
 		for(unsigned int uj=0;uj<xValues.size(); uj++)
 		{
-		bufferX[uj] = xValues[uj];
-			
-			if(yValues[uj] > 0.0)
-				bufferY[uj] = log10(yValues[uj]);
-			else
-				bufferY[uj] = 0;
+			bufferX[uj] = xValues[uj];
+			bufferY[uj] = makePositiveLog(yValues[uj]);
 
 		}
 	}
@@ -1093,15 +1119,23 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 				bufferErr[uj] = errBars[uj];
 		}
 	}
+	//--
 	
 	//Mathgl needs to know where to put the error bars.	
 	ASSERT(!showErrs  || errBars.size() ==xValues.size());
 	
+	//Initialise the mathgl data
+	//--
 	xDat.Set(bufferX,xValues.size());
 	yDat.Set(bufferY,yValues.size());
 
-	eDat.Set(bufferErr,errBars.size());
-
+	if(showErrs)
+		eDat.Set(bufferErr,errBars.size());
+	//--
+	
+	
+	//Obtain a colour code to use for the plot, based upon
+	// the actual colour we wish to use
 	char colourCode[2];
 	colourCode[0]=fixer.getNextBestColour(r,g,b);
 	colourCode[1]='\0';
@@ -1166,7 +1200,8 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 }
 
 
-void Plot1D::addRegion(unsigned int parentPlot,unsigned int regionID,float start, float end, 
+
+void Plot1D::addRegion(unsigned int regionID,float start, float end, 
 			float rNew, float gNew, float bNew, Filter *parentFilter)
 {
 	ASSERT(start <end);
diff --git a/src/backend/plot.h b/src/backend/plot.h
index ea9e76a..0823c3e 100644
--- a/src/backend/plot.h
+++ b/src/backend/plot.h
@@ -63,7 +63,7 @@ unsigned int plotID(const std::string &plotString);
 //!Return the error mode type, given the human readable string
 unsigned int plotErrmodeID(const std::string &s);
 		
-//!Nasty hack class to change mathgl API from named char pallette to rgb specification
+//!Nasty hack class to change mathgl API from named char palette to rgb specification
 class MGLColourFixer
 {
 	private:
@@ -77,7 +77,7 @@ class MGLColourFixer
 		//Get the best colour that is available
 		// returns the char to give to mathgl; may be exact,
 		// maybe nearest match, depending upon number of colours used
-		// and mgl pallette size
+		// and mgl palette size
 		char getNextBestColour(float r, float g, float b);
 
 		static unsigned int getMaxColours();
@@ -101,6 +101,7 @@ class PlotRegion
 		unsigned int id;
 		//!Unique ID for region across entire multiplot
 		unsigned int uniqueID;
+
 };
 
 //!Base class for data plotting
@@ -143,7 +144,10 @@ class PlotBase
 		//!integer to show which of the n plots that the parent generated
 		//that this data is represented by
 		unsigned int parentPlotIndex;
-		
+	
+		//True if the plot has data
+		virtual bool empty() const=0;
+
 		//Draw the plot onto a given MGL graph
 		virtual void drawPlot(mglGraph *graph, MGLColourFixer &fixer) const=0;
 
@@ -187,7 +191,7 @@ class Plot1D : public PlotBase
 		
 	public:
 		Plot1D();
-		
+		virtual bool empty() const;
 		
 		void getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const;
 
@@ -200,9 +204,8 @@ class Plot1D : public PlotBase
 							const vector<float> &symYErr);
 
 		//!Append a region to the plot
-		void addRegion(unsigned int parentPlot, unsigned int regionId,
-			       		float start, float end,	float r,float g, 
-						float b, Filter *parentFilter);
+		void addRegion(unsigned int regionId, float start, float end,	
+				float r,float g, float b, Filter *parentFilter);
 		
 		//!Try to move a region from its current position to a new position
 		//return the test coord. valid methods are 0 (left extend), 1 (slide), 2 (right extend)
@@ -286,6 +289,9 @@ class PlotWrapper
 		//!Destructor must delete target plots
 		~PlotWrapper();
 
+		//Returns true if the visible plots have no data
+		// in the case of no visible plots, returns true.
+		bool visibleEmpty() const;
 
 		bool isInteractionLocked() const { return interactionLocked;};
 
diff --git a/src/backend/state.cpp b/src/backend/state.cpp
new file mode 100644
index 0000000..ba615ea
--- /dev/null
+++ b/src/backend/state.cpp
@@ -0,0 +1,985 @@
+/*
+ *	state.cpp - user session state handler
+ *	Copyright (C) 2013, D Haley 
+
+ *	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 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 General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "state.h"
+
+#include "common/translation.h"
+#include "common/xmlHelper.h"
+#include "common/stringFuncs.h"
+
+const unsigned int MAX_UNDO_SIZE=10;
+
+#include <unistd.h>
+
+
+AnalysisState::AnalysisState()
+{
+	modifyLevel=STATE_MODIFIED_NONE;
+	useRelativePathsForSave=false;
+	activeCamera=0;
+}
+
+
+void AnalysisState::operator=(const AnalysisState &oth)
+{
+	clear();
+
+	activeTree=oth.activeTree;
+	
+	stashedTrees=oth.stashedTrees;
+
+	effects.resize(oth.effects.size());
+	for(size_t ui=0;ui<effects.size();ui++)
+		effects[ui]= oth.effects[ui]->clone();
+
+	savedCameras.resize(oth.savedCameras.size());
+	for(size_t ui=0;ui<savedCameras.size();ui++)
+		savedCameras[ui]= oth.savedCameras[ui]->clone();
+
+
+	undoTrees=oth.undoTrees; 
+	redoTrees=oth.redoTrees;
+
+	fileName=oth.fileName;
+	workingDir=oth.workingDir;
+	useRelativePathsForSave=oth.useRelativePathsForSave;
+
+	rBack=oth.rBack;
+	gBack=oth.gBack;
+	bBack=oth.bBack;
+
+	worldAxisMode=oth.worldAxisMode;
+	activeCamera=oth.activeCamera;
+
+	modifyLevel=oth.modifyLevel;
+
+
+	redoFilterStack=oth.redoFilterStack;
+	undoFilterStack=oth.undoFilterStack;
+
+}
+
+
+void AnalysisState::clear()
+{
+	activeTree.clear();
+	
+	stashedTrees.clear();
+
+	clearCams();
+
+	clearEffects();
+
+	undoTrees.clear(); 
+	redoTrees.clear();
+
+	fileName.clear();
+	workingDir.clear();
+}
+
+void AnalysisState::clearCams()
+{
+	for(size_t ui=0;ui<savedCameras.size();ui++)
+		delete savedCameras[ui];
+	savedCameras.clear();
+}
+
+void AnalysisState::clearEffects()
+{
+	for(size_t ui=0;ui<effects.size();ui++)
+		delete effects[ui];
+
+	effects.clear();
+
+}
+bool AnalysisState::save(const char *cpFilename, std::map<string,string> &fileMapping,
+		bool writePackage) const
+{
+	//Open file for output
+	std::ofstream f(cpFilename);
+
+	if(!f)
+		return false;
+	
+	//Write header, also use local language if available
+	const char *headerMessage = NTRANS("This file is a \"state\" file for the 3Depict program, and stores information about a particular analysis session. This file should be a valid \"XML\" file");
+
+	f << "<!--" <<  headerMessage;
+	if(TRANS(headerMessage) != headerMessage) 
+		f << endl << TRANS(headerMessage); 
+	
+	f << "-->" <<endl;
+
+
+
+	//Write state open tag 
+	f<< "<threeDepictstate>" << endl;
+	f<<tabs(1)<< "<writer version=\"" << PROGRAM_VERSION << "\"/>" << endl;
+	//write general settings
+	//---------------
+	f << tabs(1) << "<backcolour r=\"" << rBack << "\" g=\"" << 
+		 gBack  << "\" b=\"" << bBack << "\"/>" <<  endl;
+	
+	f << tabs(1) << "<showaxis value=\"" << worldAxisMode << "\"/>"  << endl;
+
+
+	if(useRelativePathsForSave)
+	{
+		//Save path information
+		//Note: When writing packages, 
+		//- we don't want to leak path names to remote systems 
+		//and
+		//- we cannot assume that directory structures are preserved between systems
+		//
+		//so don't keep working directory in this case.
+		if(writePackage || workingDir.empty() )
+		{
+			//Are we saving the sate as a package, if so
+			//make sure we let other 3depict loaders know
+			//that we want to use relative paths
+			f << tabs(1) << "<userelativepaths/>"<< endl;
+		}
+		else
+		{
+			//Not saving a package, however we could be, 
+			//for example, be autosaving a load-from-package. 
+			//We want to keep relative paths, but
+			//want to be able to find files if something goes askew
+			f << tabs(1) << "<userelativepaths origworkdir=\"" << workingDir << "\"/>"<< endl;
+		}
+	}
+
+	//---------------
+
+
+	//Write filter tree
+	//---------------
+	if(!activeTree.saveXML(f,fileMapping,writePackage,useRelativePathsForSave))
+		return  false;
+	//---------------
+
+	//Save all cameras.
+	f <<tabs(1) <<  "<cameras>" << endl;
+
+	//First camera is the "working" camera, which is unnamed
+	f << tabs(2) << "<active value=\"" << activeCamera << "\"/>" << endl;
+	
+	for(unsigned int ui=0;ui<savedCameras.size();ui++)
+	{
+		//ask each camera to write its own state, tab indent 2
+		savedCameras[ui]->writeState(f,STATE_FORMAT_XML,2);
+	}
+	f <<tabs(1) <<  "</cameras>" << endl;
+	
+	if(stashedTrees.size())
+	{
+		f << tabs(1) << "<stashedfilters>" << endl;
+
+		for(unsigned int ui=0;ui<stashedTrees.size();ui++)
+		{
+			f << tabs(2) << "<stash name=\"" << stashedTrees[ui].first
+				<< "\">" << endl;
+			stashedTrees[ui].second.saveXML(f,fileMapping,
+					writePackage,useRelativePathsForSave,3);
+			f << tabs(2) << "</stash>" << endl;
+		}
+
+
+
+
+		f << tabs(1) << "</stashedfilters>" << endl;
+	}
+
+	//Save any effects
+	if(effects.size())
+	{
+		f <<tabs(1) <<  "<effects>" << endl;
+		for(unsigned int ui=0;ui<effects.size();ui++)
+			effects[ui]->writeState(f,STATE_FORMAT_XML,1);
+		f <<tabs(1) <<  "</effects>" << endl;
+
+	}
+
+
+
+	//Close XMl tag.	
+	f<< "</threeDepictstate>" << endl;
+
+	//Debug check to ensure we have written a valid xml file
+	ASSERT(isValidXML(cpFilename));
+
+	modifyLevel=STATE_MODIFIED_NONE;
+
+	return true;
+}
+
+bool AnalysisState::load(const char *cpFilename, std::ostream &errStream, bool merge) 
+{
+	clear();
+
+	//Load the state from an XML file
+	
+	//here we use libxml2's loading routines
+	//http://xmlsoft.org/
+	//Tutorial: http://xmlsoft.org/tutorial/xmltutorial.pdf
+	xmlDocPtr doc;
+	xmlParserCtxtPtr context;
+
+	context =xmlNewParserCtxt();
+
+
+	if(!context)
+	{
+		errStream << TRANS("Failed to allocate parser") << std::endl;
+		return false;
+	}
+
+	//Open the XML file
+	doc = xmlCtxtReadFile(context, cpFilename, NULL,0);
+
+	if(!doc)
+		return false;
+	
+	//release the context
+	xmlFreeParserCtxt(context);
+	
+
+	//By default, lets not use relative paths
+	if(!merge)
+		useRelativePathsForSave=false;
+
+	//Lets do some parsing goodness
+	//ahh parsing - verbose and boring
+	FilterTree newFilterTree;
+	vector<Camera *> newCameraVec;
+	vector<Effect *> newEffectVec;
+	vector<pair<string,FilterTree > > newStashes;
+
+	std::string stateDir=onlyDir(cpFilename);
+	try
+	{
+		std::stack<xmlNodePtr>  nodeStack;
+		//retrieve root node	
+		xmlNodePtr nodePtr = xmlDocGetRootElement(doc);
+
+		//Umm where is our root node guys?
+		if(!nodePtr)
+		{
+			errStream << TRANS("Unable to retrieve root node in input state file... Is this really a non-empty XML file?") <<  endl;
+			throw 1;
+		}
+		
+		//This *should* be an threeDepict state file
+		if(xmlStrcmp(nodePtr->name, (const xmlChar *)"threeDepictstate"))
+		{
+			errStream << TRANS("Base state node missing. Is this really a state XML file??") << endl;
+			throw 1;
+		}
+		//push root tag	
+		nodeStack.push(nodePtr);
+		
+		//Now in threeDepictstate tag
+		nodePtr = nodePtr->xmlChildrenNode;
+		xmlChar *xmlString;
+		//check for version tag & number
+		if(!XMLHelpFwdToElem(nodePtr,"writer"))
+		{
+			xmlString=xmlGetProp(nodePtr, (const xmlChar *)"version"); 
+
+			if(xmlString)
+			{
+				string tmpVer;
+				
+				tmpVer =(char *)xmlString;
+				//Check to see if only contains 0-9 period and "-" characters (valid version number)
+				if(tmpVer.find_first_not_of("0123456789.-")== std::string::npos)
+				{
+					//Check between the writer reported version, and the current program version
+					vector<string> vecStrs;
+					vecStrs.push_back(tmpVer);
+					vecStrs.push_back(PROGRAM_VERSION);
+
+					if(getMaxVerStr(vecStrs)!=PROGRAM_VERSION)
+					{
+						errStream << TRANS("State was created by a newer version of this program.. ")
+							<< TRANS("file reading will continue, but may fail.") << endl ;
+					}
+				}
+				else
+				{
+					errStream<< TRANS("Warning, unparseable version number in state file. File reading will continue, but may fail") << endl;
+				}
+				xmlFree(xmlString);
+			}
+		}
+		else
+		{
+			errStream<< TRANS("Unable to find the \"writer\" node") << endl;
+			throw 1;
+		}
+	
+
+		//Get the background colour
+		//====
+		float rTmp,gTmp,bTmp;
+		if(XMLHelpFwdToElem(nodePtr,"backcolour"))
+		{
+			errStream<< TRANS("Unable to find the \"backcolour\" node.") << endl;
+			throw 1;
+		}
+
+		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"r");
+		if(!xmlString)
+		{
+			errStream<< TRANS("\"backcolour\" node missing \"r\" value.") << endl;
+			throw 1;
+		}
+		if(stream_cast(rTmp,(char *)xmlString))
+		{
+			errStream<< TRANS("Unable to interpret \"backColour\" node's \"r\" value.") << endl;
+			throw 1;
+		}
+
+		xmlFree(xmlString);
+		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"g");
+		if(!xmlString)
+		{
+			errStream<< TRANS("\"backcolour\" node missing \"g\" value.") << endl;
+			throw 1;
+		}
+
+		if(stream_cast(gTmp,(char *)xmlString))
+		{
+			errStream<< TRANS("Unable to interpret \"backColour\" node's \"g\" value.") << endl;
+			throw 1;
+		}
+
+		xmlFree(xmlString);
+		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"b");
+		if(!xmlString)
+		{
+			errStream<< TRANS("\"backcolour\" node missing \"b\" value.") << endl;
+			throw 1;
+		}
+
+		if(stream_cast(bTmp,(char *)xmlString))
+		{
+			errStream<< TRANS("Unable to interpret \"backColour\" node's \"b\" value.") << endl;
+			throw 1;
+		}
+
+		if(rTmp > 1.0 || gTmp>1.0 || bTmp > 1.0 || 
+			rTmp < 0.0 || gTmp < 0.0 || bTmp < 0.0)
+		{
+			errStream<< TRANS("\"backcolour\"s rgb values must be in range [0,1]") << endl;
+			throw 1;
+		}
+		rBack=rTmp;
+		gBack=gTmp;
+		bBack=bTmp;
+		
+		xmlFree(xmlString);
+
+		nodeStack.push(nodePtr);
+
+
+		if(!XMLHelpFwdToElem(nodePtr,"userelativepaths"))
+		{
+			useRelativePathsForSave=true;
+
+			//Try to load the original working directory, if possible
+			if(!XMLGetAttrib(nodePtr,workingDir,"origworkdir"))
+				workingDir.clear();
+		}
+		
+		nodePtr=nodeStack.top();
+
+		//====
+		
+		//Get the axis visibility
+		if(!XMLGetNextElemAttrib(nodePtr,worldAxisMode,"showaxis","value"))
+		{
+			errStream << TRANS("Unable to find or interpret \"showaxis\" node") << endl;
+			throw 1;
+		}
+
+		//find filtertree data
+		if(XMLHelpFwdToElem(nodePtr,"filtertree"))
+		{
+			errStream << TRANS("Unable to locate \"filtertree\" node.") << endl;
+			throw 1;
+		}
+
+		//Load the filter tree
+		if(newFilterTree.loadXML(nodePtr,errStream,stateDir))
+			throw 1;
+
+		//Read camera states, if present
+		nodeStack.push(nodePtr);
+		if(!XMLHelpFwdToElem(nodePtr,"cameras"))
+		{
+			//Move to camera active tag 
+			nodePtr=nodePtr->xmlChildrenNode;
+			if(XMLHelpFwdToElem(nodePtr,"active"))
+			{
+				errStream << TRANS("Cameras section missing \"active\" node.") << endl;
+				throw 1;
+			}
+
+			//read ID of active cam
+			xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
+			if(!xmlString)
+			{
+				errStream<< TRANS("Unable to find property \"value\"  for \"cameras->active\" node.") << endl;
+				throw 1;
+			}
+
+			if(stream_cast(activeCamera,xmlString))
+			{
+				errStream<< TRANS("Unable to interpret property \"value\"  for \"cameras->active\" node.") << endl;
+				throw 1;
+			}
+
+		
+			//Spin through the list of each camera	
+			while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE))
+			{
+				std::string tmpStr;
+				tmpStr =(const char *)nodePtr->name;
+				Camera *thisCam;
+				thisCam=0;
+				
+				//work out the camera type
+				if(tmpStr == "persplookat")
+				{
+					thisCam = new CameraLookAt;
+					if(!thisCam->readState(nodePtr->xmlChildrenNode))
+					{
+						std::string s =TRANS("Failed to interpret camera state for camera : "); 
+
+						errStream<< s <<  newCameraVec.size() << endl;
+						throw 1;
+					}
+				}
+				else
+				{
+					errStream << TRANS("Unable to interpret the camera type for camera : ") << newCameraVec.size() <<  endl;
+					throw 1;
+				}
+
+				ASSERT(thisCam);
+				newCameraVec.push_back(thisCam);	
+			}
+
+			//Enforce active cam value validity
+			if(newCameraVec.size() < activeCamera)
+				activeCamera=0;
+
+		}
+		
+		nodePtr=nodeStack.top();
+		nodeStack.pop();
+		
+		nodeStack.push(nodePtr);
+		//Read stashes if present
+		if(!XMLHelpFwdToElem(nodePtr,"stashedfilters"))
+		{
+			nodeStack.push(nodePtr);
+
+			//Move to stashes 
+			nodePtr=nodePtr->xmlChildrenNode;
+
+			while(!XMLHelpFwdToElem(nodePtr,"stash"))
+			{
+				string stashName;
+				FilterTree newStashTree;
+				newStashTree.clear();
+
+				//read name of stash
+				xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name");
+				if(!xmlString)
+				{
+					errStream << TRANS("Unable to locate stash name for stash ") << newStashTree.size()+1 << endl;
+					throw 1;
+				}
+				stashName=(char *)xmlString;
+
+				if(!stashName.size())
+				{
+					errStream << TRANS("Empty stash name for stash ") << newStashTree.size()+1 << endl;
+					throw 1;
+				}
+
+				xmlNodePtr tmpNode;
+				tmpNode=nodePtr->xmlChildrenNode;
+				
+				if(XMLHelpFwdToElem(tmpNode,"filtertree"))
+				{
+					errStream << TRANS("No filter tree for stash:") << stashName << endl;
+					throw 1;
+				}
+
+				if(newStashTree.loadXML(tmpNode,errStream,stateDir))
+				{
+					errStream << TRANS("For stash ") << newStashTree.size()+1 << endl;
+					throw 1;
+				}
+				
+				//if there were any valid elements loaded (could be empty, for exmapl)
+				if(newStashTree.size())
+					newStashes.push_back(make_pair(stashName,newStashTree));
+			}
+
+			nodePtr=nodeStack.top();
+			nodeStack.pop();
+		}
+		nodePtr=nodeStack.top();
+		nodeStack.pop();
+	
+		//Read effects, if present
+		nodeStack.push(nodePtr);
+
+		//Read effects if present
+		if(!XMLHelpFwdToElem(nodePtr,"effects"))
+		{
+			std::string tmpStr;
+			nodePtr=nodePtr->xmlChildrenNode;
+			while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE))
+			{
+				tmpStr =(const char *)nodePtr->name;
+
+				Effect *e;
+				e = makeEffect(tmpStr);
+				if(!e)
+				{
+					errStream << TRANS("Unrecognised effect :") << tmpStr << endl;
+					throw 1;
+				}
+
+				//Check the effects are unique
+				for(unsigned int ui=0;ui<newEffectVec.size();ui++)
+				{
+					if(newEffectVec[ui]->getType()== e->getType())
+					{
+						delete e;
+						errStream << TRANS("Duplicate effect found") << tmpStr << TRANS(" cannot use.") << endl;
+						throw 1;
+					}
+
+				}
+
+				nodeStack.push(nodePtr);
+				//Parse the effect
+				if(!e->readState(nodePtr))
+				{
+					errStream << TRANS("Error reading effect : ") << e->getName() << std::endl;
+				
+					throw 1;
+				}
+				nodePtr=nodeStack.top();
+				nodeStack.pop();
+
+
+				newEffectVec.push_back(e);				
+			}
+		}
+		nodePtr=nodeStack.top();
+		nodeStack.pop();
+
+
+
+		nodeStack.push(nodePtr);
+	}
+	catch (int)
+	{
+		//Code threw an error, just say "bad parse" and be done with it
+		xmlFreeDoc(doc);
+		return false;
+	}
+	xmlFreeDoc(doc);	
+
+	//Check that stashes are uniquely named
+	// do brute force search, as there are unlikely to be many stashes	
+	for(unsigned int ui=0;ui<newStashes.size();ui++)
+	{
+		for(unsigned int uj=0;uj<newStashes.size();uj++)
+		{
+			if(ui == uj)
+				continue;
+
+			//If these match, states not uniquely named,
+			//and thus statefile is invalid.
+			if(newStashes[ui].first == newStashes[uj].first)
+				return false;
+
+		}
+	}
+
+	if(!merge)
+	{
+		//Erase any viscontrol data, seeing as we got this far	
+		clear(); 
+		//Now replace it with the new data
+		activeTree.swap(newFilterTree);
+		std::swap(stashedTrees,newStashes);
+	}
+	else
+	{
+		//If we are merging, then there is a chance
+		//of a name-clash. We avoid this by trying to append -merge continuously
+		for(unsigned int ui=0;ui<newStashes.size();ui++)
+		{
+			//protect against overload (very unlikely)
+			unsigned int maxCount;
+			maxCount=100;
+			while(hasFirstInPairVec(stashedTrees,newStashes[ui]) && --maxCount)
+				newStashes[ui].first+=TRANS("-merge");
+
+			if(maxCount)
+				stashedTrees.push_back(newStashes[ui]);
+			else
+				errStream << TRANS(" Unable to merge stashes correctly. This is improbable, so please report this.") << endl;
+		}
+
+		activeTree.addFilterTree(newFilterTree,0);
+		undoTrees.clear();
+		redoTrees.clear();
+	}
+
+	activeTree.initFilterTree();
+	
+	//Wipe the existing cameras, and then put the new cameras in place
+	if(!merge)
+		savedCameras.clear();
+	
+	//Set a default camera as needed. We don't need to track its unique ID, as this is
+	//"invisible" to the UI
+	if(!savedCameras.size())
+	{
+		Camera *c=new CameraLookAt();
+		savedCameras.push_back(c);
+		activeCamera=0;
+	}
+
+	//spin through
+	for(unsigned int ui=0;ui<newCameraVec.size();ui++)
+	{
+		if(merge)
+		{
+			//Don't merge the default camera (which has no name)
+			if(newCameraVec[ui]->getUserString().empty())
+				continue;
+
+			//Keep trying new names appending "-merge" each time to obtain a new, and hopefully unique name
+			// Abort after many times
+			unsigned int maxCount;
+			maxCount=100;
+			while(camNameExists(newCameraVec[ui]->getUserString()) && --maxCount)
+			{
+				newCameraVec[ui]->setUserString(newCameraVec[ui]->getUserString()+"-merge");
+			}
+
+			//If we have any attempts left, then it worked
+			if(maxCount)
+				savedCameras.push_back(newCameraVec[ui]);
+		}
+		else
+		{
+			//If there is no userstring, then its a  "default"
+			// camera (one that does not show up to the users,
+			// and cannot be erased from the scene)
+			// set it directly. Otherwise, its a user camera.
+			savedCameras.push_back(newCameraVec[ui]);
+			activeCamera=ui;
+		}
+
+	}
+
+	fileName=cpFilename;
+
+
+	if(workingDir.empty())
+	{
+		char *wd;
+#if defined(__APPLE__)
+		//Apple defines a special getcwd that just works
+		wd = getcwd(NULL, 0);
+#elif defined(WIN32) || defined(WIN64)
+		//getcwd under POSIX is not clearly defined, it requires
+		// an input number of bytes that are enough to hold the path,
+		// however it does not define how one goes about obtaining the
+		// number of bytes needed. 
+		char *wdtemp = (char*)malloc(PATH_MAX*20);
+		wd=getcwd(wdtemp,PATH_MAX*20);
+		if(!wd)
+		{
+			free(wdtemp);
+			return false;	
+		}
+
+#else
+		//GNU extension, which just does it (tm).
+		wd = get_current_dir_name();
+#endif
+		workingDir=wd;
+		free(wd);
+	}
+
+	//If we are merging then the default state has been altered
+	// if we are not merging, then it is overwritten
+	if(merge)
+		setModifyLevel(STATE_MODIFIED_DATA);
+	else
+		setModifyLevel(STATE_MODIFIED_NONE);
+
+	//Perform sanitisation on results
+	return true;
+}
+
+bool AnalysisState::camNameExists(const std::string &s) const
+{
+	for(size_t ui=0; ui<savedCameras.size(); ui++) 
+	{
+		if (savedCameras[ui]->getUserString() == s ) 
+			return true;
+	}
+	return false;
+}
+
+void AnalysisState::copyFilterTree(FilterTree &f) const
+{
+	f = activeTree;
+}
+
+int AnalysisState::getWorldAxisMode() const 
+{
+	return worldAxisMode;
+}
+
+void AnalysisState::copyCams(vector<Camera *> &cams) const 
+{
+	ASSERT(!cams.size());
+
+	cams.resize(savedCameras.size());
+	for(size_t ui=0;ui<savedCameras.size();ui++)
+		cams[ui] = savedCameras[ui]->clone();
+}
+
+void AnalysisState::copyCamsByRef(vector<const Camera *> &camRef) const
+{
+	camRef.resize(savedCameras.size());
+	for(size_t ui=0;ui<camRef.size();ui++)
+		camRef[ui]=savedCameras[ui];
+}
+
+const Camera *AnalysisState::getCam(size_t offset) const
+{
+	return savedCameras[offset];
+}
+
+void AnalysisState::removeCam(size_t offset)
+{
+	ASSERT(offset < savedCameras.size());
+	savedCameras.erase(savedCameras.begin()+offset);
+	if(activeCamera >=savedCameras.size())
+		activeCamera=0;
+}
+
+void AnalysisState::addCamByClone(const Camera *c)
+{
+	setModifyLevel(STATE_MODIFIED_ANCILLARY);
+	savedCameras.push_back(c->clone());
+}
+
+bool AnalysisState::setCamProperty(size_t offset, unsigned int key, const std::string &str)
+{
+	if(offset == activeCamera)
+		setModifyLevel(STATE_MODIFIED_VIEW);
+	else
+		setModifyLevel(STATE_MODIFIED_ANCILLARY);
+	return savedCameras[offset]->setProperty(key,str);
+}
+
+bool AnalysisState::getUseRelPaths() const 
+{
+	return useRelativePathsForSave;
+}
+		
+void AnalysisState::getBackgroundColour(float &r, float &g, float &b) const
+{
+	r=rBack;
+	g=gBack;
+	b=bBack;
+}
+
+void AnalysisState::copyEffects(vector<Effect *> &e) const
+{
+	e.clear();
+	for(size_t ui=0;ui<effects.size();ui++)
+		e[ui]=effects[ui]->clone();
+}
+
+
+void AnalysisState::setBackgroundColour(float &r, float &g, float &b)
+{
+	if(rBack != r || gBack!=g || bBack!=b)
+		setModifyLevel(STATE_MODIFIED_VIEW);
+	rBack=r;
+	gBack=g;
+	bBack=b;
+
+}
+
+void AnalysisState::setWorldAxisMode(unsigned int mode)
+{
+	if(mode)
+		setModifyLevel(STATE_MODIFIED_VIEW);
+	worldAxisMode=mode;
+}
+
+void AnalysisState::setCamerasByCopy(vector<Camera *> &c, unsigned int active)
+{
+	setModifyLevel(STATE_MODIFIED_DATA);
+	clearCams();
+
+	savedCameras.swap(c);
+	activeCamera=active;
+}
+
+void AnalysisState::setCameraByClone(const Camera *c, unsigned int offset)
+{
+	ASSERT(offset < savedCameras.size()); 
+	delete savedCameras[offset];
+	savedCameras[offset]=c->clone(); 
+
+	if(offset == activeCamera)
+		setModifyLevel(STATE_MODIFIED_VIEW);
+	else
+		setModifyLevel(STATE_MODIFIED_ANCILLARY);
+}
+
+void AnalysisState::setEffectsByCopy(const vector<const Effect *> &e)
+{
+	setModifyLevel(STATE_MODIFIED_VIEW);
+	clearEffects();
+
+	effects.resize(e.size());
+	for(size_t ui=0;ui<e.size();ui++)
+		effects[ui] = e[ui]->clone();
+
+}
+
+
+void AnalysisState::setUseRelPaths(bool useRel)
+{
+	useRelativePathsForSave=useRel;
+}
+void AnalysisState::setWorkingDir(const std::string &work)
+{
+	if(work!=workingDir)
+		setModifyLevel(STATE_MODIFIED_DATA);
+
+	workingDir=work;
+}
+
+void AnalysisState::setFilterTreeByClone(const FilterTree &f)
+{
+	setModifyLevel(STATE_MODIFIED_DATA);
+	activeTree=f;
+}
+
+void AnalysisState::setStashedTreesByClone(const vector<std::pair<string,FilterTree> > &s)
+{
+	setModifyLevel(STATE_MODIFIED_ANCILLARY);
+	stashedTrees=s;
+}
+
+void AnalysisState::addStashedTree(const std::pair<string,FilterTree> &s)
+{
+	setModifyLevel(STATE_MODIFIED_ANCILLARY);
+	stashedTrees.push_back(s);
+}
+
+void AnalysisState::copyStashedTrees(std::vector<std::pair<string,FilterTree > > &s) const
+{
+	s=stashedTrees;
+}
+
+void AnalysisState::copyStashedTree(size_t offset,std::pair<string,FilterTree> &s) const
+{
+	s.first=stashedTrees[offset].first;
+	s.second=stashedTrees[offset].second;
+}
+
+
+void AnalysisState::pushUndoStack()
+{
+	if(undoFilterStack.size() > MAX_UNDO_SIZE)
+		undoFilterStack.pop_front();
+
+	undoFilterStack.push_back(activeTree);
+	redoFilterStack.clear();
+}
+
+void AnalysisState::popUndoStack(bool restorePopped)
+{
+	ASSERT(undoFilterStack.size());
+
+	//Save the current filters to the redo stack.
+	// note that the copy constructor will generate a clone for us.
+	redoFilterStack.push_back(activeTree);
+
+	if(redoFilterStack.size() > MAX_UNDO_SIZE)
+		redoFilterStack.pop_front();
+
+	if(restorePopped)
+	{
+		//Swap the current filter cache out with the undo stack result
+		std::swap(activeTree,undoFilterStack.back());
+		
+	}
+
+	//Pop the undo stack
+	undoFilterStack.pop_back();
+
+	setModifyLevel(STATE_MODIFIED_DATA);
+}
+
+void AnalysisState::popRedoStack()
+{
+	ASSERT(undoFilterStack.size() <=MAX_UNDO_SIZE);
+	undoFilterStack.push_back(activeTree);
+
+	activeTree.clear();
+	//Swap the current filter cache out with the redo stack result
+	activeTree.swap(redoFilterStack.back());
+	
+	//Pop the redo stack
+	redoFilterStack.pop_back();
+
+	setModifyLevel(STATE_MODIFIED_DATA);
+}
+
+
+void AnalysisState::eraseStash(size_t offset)
+{
+	ASSERT(offset < stashedTrees.size());
+	setModifyLevel(STATE_MODIFIED_ANCILLARY);
+	stashedTrees.erase(stashedTrees.begin() + offset);
+}
+
diff --git a/src/backend/state.h b/src/backend/state.h
new file mode 100644
index 0000000..ce371f2
--- /dev/null
+++ b/src/backend/state.h
@@ -0,0 +1,266 @@
+/*
+ *	state.h - user session state handler
+ *	Copyright (C) 2013, D Haley 
+
+ *	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 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 General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <string>
+#include <vector>
+
+#include "gl/cameras.h"
+#include "gl/effect.h"
+
+
+#include "tree.hh"
+#include "filtertree.h"
+
+
+
+struct FilterTreeState
+{
+	//The tree of filters in the current state
+	FilterTree filterTree;
+	//True for items that can be seen by the user
+	tree<bool> visibility;
+
+	//index (BFS search wise) of the selected item
+	size_t selectedBFSIndex;
+};
+
+enum
+{
+	STATE_MODIFIED_NONE=0,
+	STATE_MODIFIED_VIEW, // the 3D view has chaged
+	STATE_MODIFIED_ANCILLARY, //Eg stashes, inactive cameras, and other things that might get saved
+	STATE_MODIFIED_DATA // actual data output is latered
+};
+
+//The underlying data for any given state in the analysis toolchain
+class AnalysisState
+{
+	private:
+		//Items that should be written to file
+		// on state save
+		//===
+		//!Viewing cameras for looking at results
+		std::vector<Camera *> savedCameras;
+
+		//!Filter trees that have been designated as inactive, but
+		// user would like to have them around for use
+		std::vector<std::pair<string,FilterTree> > stashedTrees;
+
+		//!Undo/redo stack for current state
+		std::vector<FilterTreeState > undoTrees,redoTrees;
+
+		//Scene modification 3D Effects 
+		std::vector<const Effect *> effects;
+
+		//!Filter analysis stree	
+		FilterTree activeTree;
+
+		//Background colours
+		float rBack,gBack,bBack;
+		
+		//Viewing mode for the world indication axes
+		int worldAxisMode;
+
+		//Camera user has currently activated
+		size_t activeCamera;
+
+
+		//true if systme should be using relative paths when
+		// saving state
+		bool useRelativePathsForSave;
+		
+		//!Working directory for saving
+		std::string workingDir;
+		//===
+
+		//true if modification to state has occured
+		mutable int modifyLevel;
+
+		//file to save to
+		std::string fileName;
+		
+		//!Undo filter tree stack 
+		std::deque<FilterTree> undoFilterStack,redoFilterStack;
+		
+		
+		bool camNameExists(const std::string &s)  const ;
+
+		//Clear the effect vector
+		void clearEffects();
+		
+		//Clear the camera data vector
+		void clearCams();
+
+		void setModifyLevel(int newLevel) { modifyLevel=std::max(newLevel,modifyLevel);}
+	public:
+		AnalysisState();
+		//Wipe the state clean
+		void clear();
+
+
+		void operator=(const AnalysisState &oth);
+
+		
+
+		//Load an XML representation of the analysis state
+		// - returns true on success, false on fail
+		// - errStream will have human readable messages in 
+		//	the case that there is a failure
+		// - set merge to true, if should attempt to merge 
+		//	the two states together
+		bool load(const char *cpFilename, 
+				std::ostream &errStream, 
+				bool merge) ;
+
+		//save an XML-ised representation of the analysis sate
+		//	- mapping provides the on-disk to local name mapping to use when saving
+		// 	- write package says if state should attempt to ensure that output
+		// 		state is fully self-contained, and locally referenced
+		bool save(const char *cpFilename, std::map<string,string> &fileMapping,
+				bool writePackage) const ;
+
+
+		//Return the current state's filename
+		string getFilename() const { return fileName; }
+		//Return the current state's filename
+		void setFilename(std::string &s) {fileName=s; }
+	
+		//obtain the world axis display state
+		int getWorldAxisMode() const;
+
+
+
+		//obtain the scene background colour
+		void getBackgroundColour(float &r, float &g, float &b) const;
+
+		//Copy the internal effect vector. 
+		//	-Must manually delete each pointer
+		void copyEffects(vector<Effect *> &effects) const;
+
+		//Set the background colour for the 
+		void setBackgroundColour(float &r, float &g, float &b);
+
+		//set the display mode for the world XYZ axes
+		void setWorldAxisMode(unsigned int mode);
+	
+		// === Cameras ===
+		//Set the camera vector, clearing any existing cams
+		// note that control of pointers will be taken
+		void setCamerasByCopy(vector<Camera *> &c, unsigned int active);
+
+
+		void setCameraByClone(const Camera *c, unsigned int offset) ;
+
+		//Obtain the ID of the active camera
+		size_t getActiveCam() const  { return activeCamera;};
+
+		//Set
+		void setActiveCam(size_t offset) {ASSERT(offset < savedCameras.size()); activeCamera=offset; };
+
+		//Remove the  camera at the specified offset
+		void removeCam(size_t offset);
+		
+		const Camera *getCam(size_t offset) const;
+		//Obtain a copy of the internal camera vector.
+		// - must delete the copy manually.
+		void copyCams(vector<Camera *> &cams) const;
+
+		//Obtain a copy of the internal camera vector.
+		// note that this reference has limited validity, and may be
+		// invalidated if the state is modified
+		void copyCamsByRef(vector<const Camera *> &cams) const;
+
+		size_t getNumCams() const { return savedCameras.size();}
+
+		//Add a camera by cloning an existing camera
+		void addCamByClone(const Camera *c);
+
+		bool setCamProperty(size_t offset, unsigned int key, const std::string &value);
+		//=====
+
+		//Set the effect vector
+		void setEffectsByCopy(const vector<const Effect *> &e);
+
+		//Set whether to use relative paths in saved file
+		void setUseRelPaths(bool useRel);
+		//get whether to use relative paths in saved file
+		bool getUseRelPaths() const;
+
+		//Set the working directory to be specified when using relative paths
+		void setWorkingDir(const std::string &work);
+		//Set the working directory to be specified when using relative paths
+		std::string getWorkingDir() const { return workingDir;};
+
+		//Set the active filter tree - note that the tree is a "clone" of the
+		// original tree - i.e. the incoming tree is duplicated
+		void setFilterTreeByClone(const FilterTree &f);
+		
+		//Obtain a copy of the internal filter tree
+		void copyFilterTree(FilterTree &f) const;
+
+		///Set the stashed filters to use internally
+		void setStashedTreesByClone(const vector<std::pair<string,FilterTree> > &s);
+
+		//Add an element to the stashed filters
+		void addStashedTree( const std::pair<string,FilterTree> &);
+
+		//Retrieve the specified stashed filter
+		void copyStashedTree(size_t offset, std::pair<string,FilterTree > &) const;
+
+		//retrieve all stashed filters
+		void copyStashedTrees(std::vector<std::pair<std::string,FilterTree> > &stashList) const;
+
+		//Remove the stash at the specified offset
+		void eraseStash(size_t offset);
+
+		//Return the number of stash elements
+		size_t getStashCount()  const { return stashedTrees.size();}
+
+
+		//Push the filter tree undo stack
+		void pushUndoStack();
+
+		//Pop the filter tree undo stack. If restorePopped is true,
+		// then the internal filter tree is updated with the stack tree
+		void popUndoStack(bool restorePopped=true);
+
+		//Pop the redo stack, this unconditionally enforces an update of the
+		// active internal tree
+		void popRedoStack();
+
+		//Obtain the size of the undo stack
+		size_t getUndoSize() const { return undoFilterStack.size();};
+		//obtain the size of the redo stack
+		size_t getRedoSize() const { return redoFilterStack.size();};
+
+		//Clear undo/redo filter tree stacks
+		void clearUndoRedoStacks() { undoFilterStack.clear(); redoFilterStack.clear();}
+		
+		//true if the state has been modified since last load/save.
+		int stateModifyLevel() const { return modifyLevel;};
+
+		//Returns true if there is any data in the stash or the active tree
+		bool hasStateData() const { return (stashedTrees.size() || activeTree.size());}
+
+		//TODO: REMOVE ME - needed for viscontrol linkage
+		void setStateModified(int state) const { modifyLevel=state;}
+
+};
+
+
diff --git a/src/backend/viscontrol.cpp b/src/backend/viscontrol.cpp
index ad43919..21089c7 100644
--- a/src/backend/viscontrol.cpp
+++ b/src/backend/viscontrol.cpp
@@ -22,11 +22,10 @@
 #include "wxcomponents.h"
 #include "gl/scene.h"
 
-#include "common/stringFuncs.h"
-#include "common/translation.h"
-#include "common/xmlHelper.h"
 
 
+#include "common/stringFuncs.h"
+
 using std::list;
 using std::stack;
 
@@ -39,23 +38,14 @@ wxStopWatch* delayTime=0;
 bool *abortVisCtlOp=0;
 
 
+//Number of points to limit to, by default
+const unsigned int DEFAULT_POINT_OUTPUT_LIMIT = 1500000;
 
 //A callback function for yielding the window bound to viscontrol.
 // Calling the callback will only cause a yield if sufficient time has passed
 // the parameter describes whether or not to allow for overriding of the timer
 bool wxYieldCallback(bool forceYield)
 {
-#ifdef __DEBUG__ 
-	//Function should not be re-entering itself
-	// this does not guarantee non-reentrancy, but can
-#ifdef HAVE_CPP11X
-	static std::atomic_bool reEntranceCanaryActive=false;
-#else
-	static bool reEntranceCanaryActive=false;
-#endif
-	ASSERT(!reEntranceCanaryActive);
-	reEntranceCanaryActive=true;
-#endif
 	const unsigned int YIELD_MS=75;
 
 	ASSERT(delayTime);
@@ -67,9 +57,6 @@ bool wxYieldCallback(bool forceYield)
 	}
 
 	ASSERT(abortVisCtlOp);
-#ifdef __DEBUG__ 
-	reEntranceCanaryActive=true;
-#endif
 	return !(*abortVisCtlOp);
 }
 
@@ -79,28 +66,27 @@ VisController::VisController()
 	targetScene=0;
 	targetPlots=0;
 	targetRawGrid=0;
+
+
 	doProgressAbort=false;
+
 	ASSERT(!abortVisCtlOp);
 	abortVisCtlOp=&doProgressAbort;
+
+	limitIonOutput=DEFAULT_POINT_OUTPUT_LIMIT;
+
 	amRefreshing=false;
 	pendingUpdates=false;
-	useRelativePathsForSave=false;
 	curProg.reset();
 	//Assign global variable its init value
 	ASSERT(!delayTime); //Should not have been united yet.
 
 	delayTime = new wxStopWatch();
+
 }
 
 VisController::~VisController()
 {
-	//clean up the stash trees
-	stashedFilters.clear();
-
-	//Delete the undo and redo stack trees
-	undoFilterStack.clear();
-	redoFilterStack.clear();
-
 	ASSERT(delayTime);
 	//delete global variable that visControl is responsible for
 	delete delayTime;
@@ -120,6 +106,8 @@ void VisController::addFilter(Filter *f, bool isBase,size_t parentId)
 	else
 		filterTree.addFilter(f,0);
 
+	currentState.setFilterTreeByClone(filterTree);
+
 	//the filter map is now invalid, as we added an element to the tree,
 	//and don't have a unique value for it. We need to relayout.
 	filterMap.clear();
@@ -134,6 +122,7 @@ void VisController::addFilterTree(FilterTree &f, bool isBase,size_t parentId)
 	else
 		filterTree.addFilterTree(f,filterMap[parentId]);
 
+	currentState.setFilterTreeByClone(filterTree);
 	//the filter map is now invalid, as we added an element to the tree,
 	//and don't have a unique value for it. we need to relayout.
 	filterMap.clear();
@@ -164,6 +153,8 @@ void VisController::switchoutFilterTree(FilterTree &f)
 
 	//Swap the internal tree with our clone
 	f.swap(filterTree);
+	
+	currentState.setFilterTreeByClone(filterTree);
 }
 
 //!Duplicate a branch of the tree to a new position. Do not copy cache,
@@ -176,6 +167,7 @@ bool VisController::copyFilter(size_t toCopy, size_t newParent,bool copyToRoot)
 	
 		ret=filterTree.copyFilter(filterMap[toCopy],filterMap[newParent]);
 
+	currentState.setFilterTreeByClone(filterTree);
 	if(ret)
 	{
 		//Delete the filtermap, as the current data is not valid anymore
@@ -207,7 +199,6 @@ size_t VisController::getIdByFilter(const Filter *f) const
 	}
 
 	ASSERT(false);
-	return -1; //keep gcc quiet
 }
 
 void VisController::getFiltersByType(std::vector<const Filter *> &filters, unsigned int type)  const
@@ -221,6 +212,7 @@ void VisController::removeFilterSubtree(size_t filterId)
 	//Save current filter state to undo stack
 	pushUndoStack();
        	filterTree.removeSubtree(filterMap[filterId]);
+	currentState.setFilterTreeByClone(filterTree);
 	//Delete the filtermap, as the current data is not valid anymore
 	filterMap.clear();
 }
@@ -242,6 +234,8 @@ bool VisController::setFilterProperty(size_t filterId,
 		// restoring would destroy the cache
 		popUndoStack(false);
 	}
+	else
+		currentState.setFilterTreeByClone(filterTree);
 
 	return setOK;
 }
@@ -272,7 +266,7 @@ unsigned int VisController::refreshFilterTree(bool doUpdateScene)
 
 	//Run the tree refresh system.
 	unsigned int errCode;
-	vector<SelectionDevice<Filter> *> devices;
+	vector<SelectionDevice *> devices;
 	vector<pair<const Filter*, string> > consoleMessages;
 	errCode=filterTree.refreshFilterTree(refreshData,devices,
 			consoleMessages,curProg,wxYieldCallback);
@@ -311,11 +305,14 @@ unsigned int VisController::refreshFilterTree(bool doUpdateScene)
 	}
 	
 	
-	targetScene->clearObjs();
-	targetScene->addSelectionDevices(devices);
-
 	if(doUpdateScene)
-		updateScene(outData);
+		updateScene(outData,devices);
+	else
+	{
+		targetScene->clearObjs();
+		targetScene->clearRefObjs();
+	}
+	
 	//Stop timer
 	delayTime->Pause();
 	amRefreshing=false;
@@ -325,7 +322,7 @@ unsigned int VisController::refreshFilterTree(bool doUpdateScene)
 
 unsigned int VisController::refreshFilterTree(list<FILTER_OUTPUT_DATA> &outData)
 {
-	vector<SelectionDevice<Filter> *> devices;
+	vector<SelectionDevice *> devices;
 	vector<pair<const Filter *, string> > consoleStrs;
 	return filterTree.refreshFilterTree(outData,devices,
 			consoleStrs,curProg,wxYieldCallback);
@@ -334,18 +331,13 @@ unsigned int VisController::refreshFilterTree(list<FILTER_OUTPUT_DATA> &outData)
 void VisController::setScene(Scene *theScene)
 {
 	targetScene=theScene;
-	//Set a default camera as needed. We don't need to track its unique ID, as this is
-	//"invisible" to the UI
-	if(!targetScene->getNumCams())
-	{
-		Camera *c=new CameraLookAt();
-		unsigned int id;
-		id=targetScene->addCam(c);
-		targetScene->setActiveCam(id);
-	}
-
 	//Inform scene about vis control.
 	targetScene->setViscontrol(this);
+	
+	Camera *c;
+	c= targetScene->cloneActiveCam();
+	currentState.addCamByClone(c);
+	delete c;
 }
 	
 void VisController::setYieldWindow(wxWindow *newYield)
@@ -380,14 +372,26 @@ void VisController::updateFilterPropGrid(wxPropertyGrid *g,size_t filterId) cons
 }
 
 
-bool VisController::setCamProperties(size_t camUniqueID,unsigned int key, const std::string &value)
+bool VisController::setCamProperties(size_t camID,unsigned int key, const std::string &value)
 {
-	return targetScene->setCamProperty(camUniqueID,key,value);
-}
-
+	size_t offset=camID;
 
+	bool result=currentState.setCamProperty(offset,key,value);
+	if(result && offset == currentState.getActiveCam())
+	{
+		const Camera *c;
+		c=currentState.getCam(currentState.getActiveCam());
+		targetScene->setActiveCamByClone(c);
+	}
 
+	return result;
+}
 
+void VisController::getCameraUpdates()
+{
+	const Camera *c=targetScene->getActiveCam();
+	currentState.setCameraByClone(c,currentState.getActiveCam());
+}
 
 bool VisController::hasUpdates() const
 {
@@ -421,7 +425,8 @@ void VisController::getFilterUpdates()
 				//the filter, this could make a change that
 				//modifies output so we need to clear 
 				//all subtree caches to force reprocessing
-				filterTree.clearCache(*it);
+
+				filterTree.clearCache(*it,false);
 
 				(*it)->setPropFromBinding(bindings[ui].second);
 #ifdef DEBUG
@@ -435,21 +440,76 @@ void VisController::getFilterUpdates()
 
 	}
 
+	currentState.setFilterTreeByClone(filterTree);
 	//we have retrieved the updates.
 	pendingUpdates=false;
 }
 
 //public interface to updateScene
-unsigned int VisController::doUpdateScene(list<vector<const FilterStreamData *> > &sceneData,
+unsigned int VisController::doUpdateScene(list<vector<const FilterStreamData *> > &sceneData, vector<SelectionDevice *> &devices,
 		bool releaseData)
 {
 	amRefreshing=true;
-	unsigned int errCode=updateScene(sceneData,releaseData);
+	unsigned int errCode=updateScene(sceneData,devices,releaseData);
 	amRefreshing=false;
 	return errCode;
 
 }
-unsigned int VisController::updateScene(list<vector<const FilterStreamData *> > &sceneData,
+
+void VisController::throttleSceneInput(list<vector<const FilterStreamData *> > &sceneData) const
+{
+	//Count the number of input ions, as we may need to perform culling,
+	if(!limitIonOutput)
+		return;
+
+	size_t inputIonCount=0;
+	for(list<vector<const FilterStreamData *> >::const_iterator it=sceneData.begin(); 
+							it!=sceneData.end(); ++it)
+		inputIonCount+=numElements(*it,STREAM_TYPE_IONS);
+
+	//If limit is higher than what we have, no culling required
+	if(limitIonOutput >=inputIonCount)
+		return;
+
+	//Need to cull
+	float cullFraction = (float)limitIonOutput/(float)inputIonCount;
+
+	for(list<vector<const FilterStreamData *> >::iterator it=sceneData.begin(); 
+							it!=sceneData.end(); ++it)
+	{
+		for(unsigned int ui=0;ui<it->size(); ui++)
+		{
+			if((*it)[ui]->getStreamType() != STREAM_TYPE_IONS)
+				continue;
+			//Obtain the ion data pointer
+			const IonStreamData *ionData;
+			ionData=((const IonStreamData *)((*it)[ui]));
+
+
+			//TODO: Is there a way we can treat cached and uncached itmes
+			// differently, without violating const-ness?
+			//Duplicate this object, then forget
+			// about the old one
+			// We can't modify the input, even when uncached,
+			// as the object is const
+			IonStreamData *newIonData;
+			newIonData=ionData->cloneSampled(cullFraction);
+
+			//Prevent leakage due to non-cached-ness
+			if(!ionData->cached)
+				delete ionData;
+
+			(*it)[ui] = newIonData;
+
+		}
+	}
+		
+
+
+}
+
+
+unsigned int VisController::updateScene(list<vector<const FilterStreamData *> > &sceneData, vector<SelectionDevice *> &devices,
 				bool releaseData)
 {
 	//Plot wrapper should be set
@@ -471,10 +531,15 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	//erase the contents of each plot 
 	targetPlots->clear(true); //Clear, but preserve selection information.
 
+
+	//Names for plots
 	vector<std::pair<size_t,string> > plotLabels;
-	
-	//-- Build buffer of new objects to send to scene
 
+
+	throttleSceneInput(sceneData);
+
+
+	//-- Build buffer of new objects to send to scene
 	for(list<vector<const FilterStreamData *> > ::iterator it=sceneData.begin(); 
 							it!=sceneData.end(); ++it)
 	{
@@ -561,8 +626,7 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 								//add a region to the plot,
 								//using the region data stored
 								//in the plot stream
-								plotNew->addRegion(plotID,
-									plotData->regionID[ui],
+								plotNew->addRegion(plotData->regionID[ui],
 									plotData->regions[ui].first,
 									plotData->regions[ui].second,
 									plotData->regionR[ui],
@@ -772,6 +836,8 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	targetScene->clearObjs();
 	targetScene->clearRefObjs();
 
+
+
 	//For speed, we have to treat ions specially.
 	// for now, use a display list (these are no longer recommended in opengl, 
 	// but they are much easier to use than extensions)
@@ -779,7 +845,12 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	for(size_t ui=0;ui<sceneDrawables.size();ui++)
 	{
 		if(sceneDrawables[ui]->getType() == DRAW_TYPE_MANYPOINT)
+		{
 			drawIons.push_back((DrawManyPoints*)sceneDrawables[ui]);
+			sceneDrawables.erase(sceneDrawables.begin()+ui);
+			ui--;
+
+		}
 	}
 
 	if(totalIonCount < MAX_NUM_DRAWABLE_POINTS && drawIons.size() >1)
@@ -824,18 +895,16 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	}
 	
 	for(size_t ui=0;ui<sceneDrawables.size();ui++)
-	{
-		//We handled the ion case above.
-		if(sceneDrawables[ui]->getType() != STREAM_TYPE_IONS)
-			targetScene->addDrawable(sceneDrawables[ui]);
-	}
+		targetScene->addDrawable(sceneDrawables[ui]);
 
 	sceneDrawables.clear();
 	targetScene->computeSceneLimits();
+	targetScene->addSelectionDevices(devices);
 	targetScene->lockInteraction(false);
 	//===============
 
 
+
 	return 0;
 }
 
@@ -844,44 +913,71 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 
 unsigned int VisController::addCam(const std::string &camName)
 {
+	//Duplicate the current camera, and give it a new name
 	Camera *c=targetScene->cloneActiveCam();
 	c->setUserString(camName);
-	//Store the camera
-	unsigned int id = targetScene->addCam(c);
-	targetScene->setActiveCam(0);
+
+	//create an ID for this camera, then add to scene 
+	size_t id =currentState.getNumCams();
+	
+	currentState.addCamByClone(c);
+	delete c;
+	
 	return id;
 }
 
-bool VisController::removeCam(unsigned int uniqueID)
+bool VisController::removeCam(unsigned int offset)
 {
-	targetScene->removeCam(uniqueID);
-	targetScene->setDefaultCam();
+	//obtain the offset to the camera from its unique id
+	currentState.removeCam(offset);
+
+	if(!currentState.getNumCams())
+	{
+		const Camera *c;
+		c = targetScene->getActiveCam();
+		currentState.addCamByClone(c);
+	}
+	else
+	{
+		size_t activeCam=currentState.getActiveCam();
+		targetScene->setActiveCamByClone(currentState.getCam(activeCam) );
+	}
+
 	return true;
 }
 
-bool VisController::setCam(unsigned int uniqueID)
+bool VisController::setCam(unsigned int offset)
 {
-	targetScene->setActiveCam(uniqueID);
+	ASSERT(offset < currentState.getNumCams());
+	
+	currentState.setActiveCam(offset);
+	targetScene->setActiveCamByClone(currentState.getCam(offset));
+	
 	return true;
 }
 
-void VisController::updateCamPropertyGrid(wxPropertyGrid *g,unsigned int camID) const
+void VisController::updateCamPropertyGrid(wxPropertyGrid *g,unsigned int offset) const
 {
 
+	//Erase the grid
 	g->clearKeys();
-	if(targetScene->isDefaultCam())
+
+	//Abort if there are no cameras
+	if(!currentState.getNumCams())
 		return;
 
+	//Obtain the properties of the currently active camera
 	CameraProperties p;
-	
-	targetScene->getCamProperties(camID,p);
+	currentState.getCam(offset)->getProperties(p);
 
+	//Set the property grid
 	g->setNumGroups(p.data.size());
 	//Create the keys for the property grid to do its thing
 	for(unsigned int ui=0;ui<p.data.size();ui++)
 	{
 		for(unsigned int uj=0;uj<p.data[ui].size();uj++)
 		{
+			//TODO: ADD TOOLTIP
 			g->addKey(p.data[ui][uj].first, ui,p.keys[ui][uj],
 				p.types[ui][uj],p.data[ui][uj].second,string(""));
 		}
@@ -908,20 +1004,26 @@ bool VisController::reparentFilter(size_t filter, size_t newParent)
 		return false;
 	}
 	
+	currentState.setFilterTreeByClone(filterTree);
 	return true;
 }
 
 
 bool VisController::setFilterString(size_t id,const std::string &s)
 {
-	//Save current filter state to undo stack
-	pushUndoStack();
 	
 	Filter *p=(Filter *)getFilterById(id);
 
 	if(s != p->getUserString())
 	{
+		//Save current filter state to undo stack
+		pushUndoStack();
+		
+		//Do the actual update
 		p->setUserString(s);
+		
+		//Update the current state	
+		currentState.setFilterTreeByClone(filterTree);
 		return true;
 	}
 
@@ -930,691 +1032,132 @@ bool VisController::setFilterString(size_t id,const std::string &s)
 
 unsigned int VisController::numCams() const 
 {
-	return targetScene->getNumCams();
+	return currentState.getNumCams();
 }
 		
 void VisController::ensureSceneVisible(unsigned int direction)
 {
+	currentState.setStateModified(true);
 	targetScene->ensureVisible(direction);
 }
 
+
 bool VisController::saveState(const char *cpFilename, std::map<string,string> &fileMapping,
-		bool writePackage) const
+		bool writePackage,bool resetModifyLevel) const
 {
-	//Open file for output
-	std::ofstream f(cpFilename);
-
-	if(!f)
-		return false;
-	
-	//Write header, also use local language if available
-	const char *headerMessage = NTRANS("This file is a \"state\" file for the 3Depict program, and stores information about a particular analysis session. This file should be a valid \"XML\" file");
-
-	f << "<!--" <<  headerMessage;
-	if(TRANS(headerMessage) != headerMessage) 
-		f << endl << TRANS(headerMessage); 
-	
-	f << "-->" <<endl;
-
-
-
-	//Write state open tag 
-	f<< "<threeDepictstate>" << endl;
-	f<<tabs(1)<< "<writer version=\"" << PROGRAM_VERSION << "\"/>" << endl;
-	//write general settings
-	//---------------
-	float backR,backG,backB;
-
-	targetScene->getBackgroundColour(backR,backG,backB);
-	f << tabs(1) << "<backcolour r=\"" << backR << "\" g=\"" << backG  << "\" b=\"" << backB << "\"/>" <<  endl;
-	
-	f << tabs(1) << "<showaxis value=\"";
-       	if(targetScene->getWorldAxisVisible())
-	       f<< "1";
-       	else
-		f << "0";
-	f<< "\"/>"  << endl;
-
-
-	if(useRelativePathsForSave)
-	{
-		//Save path information
-		//Note: When writing packages, 
-		//- we don't want to leak path names to remote systems 
-		//and
-		//- we cannot assume that directory structures are preserved between systems
-		//
-		//so don't keep working directory in this case.
-		if(writePackage || workingDir.empty() )
-		{
-			//Are we saving the sate as a package, if so
-			//make sure we let other 3depict loaders know
-			//that we want to use relative paths
-			f << tabs(1) << "<userelativepaths/>"<< endl;
-		}
-		else
-		{
-			//Not saving a package, however we could be, 
-			//for example, be autosaving a load-from-package. 
-			//We want to keep relative paths, but
-			//want to be able to find files if something goes askew
-			f << tabs(1) << "<userelativepaths origworkdir=\"" << workingDir << "\"/>"<< endl;
-		}
-	}
-
-	//---------------
-
-
-	//Write filter tree
-	//---------------
-	if(!filterTree.saveXML(f,fileMapping,writePackage,useRelativePathsForSave))
-		return  false;
-	//---------------
+	AnalysisState state;
 
-	vector<Camera *> camVec;
 
-	unsigned int active=targetScene->duplicateCameras(camVec);
-
-	//Save all cameras.
-	f <<tabs(1) <<  "<cameras>" << endl;
-
-	//First camera is the "working" camera, which is unnamed
-	f << tabs(2) << "<active value=\"" << active << "\"/>" << endl;
-	
-	for(unsigned int ui=0;ui<camVec.size();ui++)
-	{
-		//ask each camera to write its own state, tab indent 2
-		camVec[ui]->writeState(f,STATE_FORMAT_XML,2);
-		delete camVec[ui];
-	}
-	f <<tabs(1) <<  "</cameras>" << endl;
+	//Make a copy of the state, as some variables are still stored in viscontrol's scope
+	state=currentState; 
 	
-	camVec.clear();
+	//-- scene variables --
+	float rBack,gBack,bBack;
+	targetScene->getBackgroundColour(rBack,gBack,bBack);
+	state.setBackgroundColour(rBack,gBack,bBack);
+       	
+	state.setWorldAxisMode(targetScene->getWorldAxisVisible());
 
-	if(stashedFilters.size())
-	{
-		f << tabs(1) << "<stashedfilters>" << endl;
-
-		for(unsigned int ui=0;ui<stashedFilters.size();ui++)
-		{
-			stashedFilters[ui].second.saveXML(f,fileMapping,
-					writePackage,useRelativePathsForSave,1);
-		}
-
-
-
-
-		f << tabs(1) << "</stashedfilters>" << endl;
-	}
-
-	//Save any effects
 	vector<const Effect *> effectVec;
+	
 	targetScene->getEffects(effectVec);
+	state.setEffectsByCopy(effectVec);
+	//------
 
-	if(effectVec.size())
-	{
-		f <<tabs(1) <<  "<effects>" << endl;
-		for(unsigned int ui=0;ui<effectVec.size();ui++)
-			effectVec[ui]->writeState(f,STATE_FORMAT_XML,1);
-		f <<tabs(1) <<  "</effects>" << endl;
-
-	}
-
-
-
-	//Close XMl tag.	
-	f<< "</threeDepictstate>" << endl;
-
-	//Debug check to ensure we have written a valid xml file
-	ASSERT(isValidXML(cpFilename));
+	//-- viscontrol variables
+	state.setFilterTreeByClone(filterTree);
+	//--
 
-	return true;
+	if(resetModifyLevel)
+		currentState.setStateModified(false);
+	return state.save(cpFilename,fileMapping,writePackage);
 }
 
 bool VisController::loadState(const char *cpFilename, std::ostream &errStream, bool merge,bool noUpdating) 
 {
-	//Load the state from an XML file
-	
-	//here we use libxml2's loading routines
-	//http://xmlsoft.org/
-	//Tutorial: http://xmlsoft.org/tutorial/xmltutorial.pdf
-	xmlDocPtr doc;
-	xmlParserCtxtPtr context;
 
-	context =xmlNewParserCtxt();
+	//Load into a temporary state
+	// and if successful, transfer to full state
+	AnalysisState state;
+	bool result=state.load(cpFilename,errStream,merge);
 
-
-	if(!context)
-	{
-		errStream << TRANS("Failed to allocate parser") << std::endl;
+	if(!result)
 		return false;
-	}
-
-	//Open the XML file
-	doc = xmlCtxtReadFile(context, cpFilename, NULL,0);
-
-	if(!doc)
-		return false;
-	
-	//release the context
-	xmlFreeParserCtxt(context);
-	
-
-	//By default, lets not use relative paths
-	if(!merge)
-		useRelativePathsForSave=false;
-
-	//Lets do some parsing goodness
-	//ahh parsing - verbose and boring
-	FilterTree newFilterTree;
-	vector<Camera *> newCameraVec;
-	vector<Effect *> newEffectVec;
-	vector<pair<string,FilterTree > > newStashes;
-
-	std::string stateDir=onlyDir(cpFilename);
-	unsigned int activeCam;
-	try
-	{
-		std::stack<xmlNodePtr>  nodeStack;
-		//retrieve root node	
-		xmlNodePtr nodePtr = xmlDocGetRootElement(doc);
-
-		//Umm where is our root node guys?
-		if(!nodePtr)
-		{
-			errStream << TRANS("Unable to retrieve root node in input state file... Is this really a non-empty XML file?") <<  endl;
-			throw 1;
-		}
-		
-		//This *should* be an threeDepict state file
-		if(xmlStrcmp(nodePtr->name, (const xmlChar *)"threeDepictstate"))
-		{
-			errStream << TRANS("Base state node missing. Is this really a state XML file??") << endl;
-			throw 1;
-		}
-		//push root tag	
-		nodeStack.push(nodePtr);
-		
-		//Now in threeDepictstate tag
-		nodePtr = nodePtr->xmlChildrenNode;
-		xmlChar *xmlString;
-		//check for version tag & number
-		if(!XMLHelpFwdToElem(nodePtr,"writer"))
-		{
-			xmlString=xmlGetProp(nodePtr, (const xmlChar *)"version"); 
-
-			if(xmlString)
-			{
-				string tmpVer;
-				
-				tmpVer =(char *)xmlString;
-				//Check to see if only contains 0-9 period and "-" characters (valid version number)
-				if(tmpVer.find_first_not_of("0123456789.-")== std::string::npos)
-				{
-					//Check between the writer reported version, and the current program version
-					vector<string> vecStrs;
-					vecStrs.push_back(tmpVer);
-					vecStrs.push_back(PROGRAM_VERSION);
-
-					if(getMaxVerStr(vecStrs)!=PROGRAM_VERSION)
-					{
-						errStream << TRANS("State was created by a newer version of this program.. ")
-							<< TRANS("file reading will continue, but may fail.") << endl ;
-					}
-				}
-				else
-				{
-					errStream<< TRANS("Warning, unparseable version number in state file. File reading will continue, but may fail") << endl;
-				}
-				xmlFree(xmlString);
-			}
-		}
-		else
-		{
-			errStream<< TRANS("Unable to find the \"writer\" node") << endl;
-			throw 1;
-		}
-	
-
-		//Get the background colour
-		//====
-		float rTmp,gTmp,bTmp;
-		if(XMLHelpFwdToElem(nodePtr,"backcolour"))
-		{
-			errStream<< TRANS("Unable to find the \"backcolour\" node.") << endl;
-			throw 1;
-		}
-
-		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"r");
-		if(!xmlString)
-		{
-			errStream<< TRANS("\"backcolour\" node missing \"r\" value.") << endl;
-			throw 1;
-		}
-		if(stream_cast(rTmp,(char *)xmlString))
-		{
-			errStream<< TRANS("Unable to interpret \"backColour\" node's \"r\" value.") << endl;
-			throw 1;
-		}
-
-		xmlFree(xmlString);
-		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"g");
-		if(!xmlString)
-		{
-			errStream<< TRANS("\"backcolour\" node missing \"g\" value.") << endl;
-			throw 1;
-		}
-
-		if(stream_cast(gTmp,(char *)xmlString))
-		{
-			errStream<< TRANS("Unable to interpret \"backColour\" node's \"g\" value.") << endl;
-			throw 1;
-		}
 
-		xmlFree(xmlString);
-		xmlString=xmlGetProp(nodePtr,(const xmlChar *)"b");
-		if(!xmlString)
-		{
-			errStream<< TRANS("\"backcolour\" node missing \"b\" value.") << endl;
-			throw 1;
-		}
-
-		if(stream_cast(bTmp,(char *)xmlString))
-		{
-			errStream<< TRANS("Unable to interpret \"backColour\" node's \"b\" value.") << endl;
-			throw 1;
-		}
-
-		if(rTmp > 1.0 || gTmp>1.0 || bTmp > 1.0 || 
-			rTmp < 0.0 || gTmp < 0.0 || bTmp < 0.0)
-		{
-			errStream<< TRANS("\"backcolour\"s rgb values must be in range [0,1]") << endl;
-			throw 1;
-		}
-		if(!noUpdating)
-			targetScene->setBackgroundColour(rTmp,gTmp,bTmp);
-		xmlFree(xmlString);
-
-		nodeStack.push(nodePtr);
+	currentState=state;
 
+	//Synchronise scene and viscontrol components to 
+	// current state
 
-		if(!XMLHelpFwdToElem(nodePtr,"userelativepaths"))
-		{
-			useRelativePathsForSave=true;
-
-			//Try to load the original working directory, if possible
-			if(!XMLGetAttrib(nodePtr,workingDir,"origworkdir"))
-				workingDir.clear();
-		}
-		
-		nodePtr=nodeStack.top();
-
-		//====
-		
-		//Get the axis visibility
-		unsigned int axisIsVis;
-		if(!XMLGetNextElemAttrib(nodePtr,axisIsVis,"showaxis","value"))
-		{
-			errStream << TRANS("Unable to find or interpret \"showaxis\" node") << endl;
-			throw 1;
-		}
-		if(!noUpdating)
-			targetScene->setWorldAxisVisible(axisIsVis==1);
-
-		//find filtertree data
-		if(XMLHelpFwdToElem(nodePtr,"filtertree"))
-		{
-			errStream << TRANS("Unable to locate \"filtertree\" node.") << endl;
-			throw 1;
-		}
-
-		//Load the filter tree
-		if(newFilterTree.loadXML(nodePtr,errStream,stateDir))
-			throw 1;
-
-		//Read camera states, if present
-		nodeStack.push(nodePtr);
-		if(!XMLHelpFwdToElem(nodePtr,"cameras"))
-		{
-			//Move to camera active tag 
-			nodePtr=nodePtr->xmlChildrenNode;
-			if(XMLHelpFwdToElem(nodePtr,"active"))
-			{
-				errStream << TRANS("Cameras section missing \"active\" node.") << endl;
-				throw 1;
-			}
-
-			//read ID of active cam
-			xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
-			if(!xmlString)
-			{
-				errStream<< TRANS("Unable to find property \"value\"  for \"cameras->active\" node.") << endl;
-				throw 1;
-			}
-
-			if(stream_cast(activeCam,xmlString))
-			{
-				errStream<< TRANS("Unable to interpret property \"value\"  for \"cameras->active\" node.") << endl;
-				throw 1;
-			}
-
-		
-			//Spin through the list of each camera	
-			while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE))
-			{
-				std::string tmpStr;
-				tmpStr =(const char *)nodePtr->name;
-				Camera *thisCam;
-				thisCam=0;
-				
-				//work out the camera type
-				if(tmpStr == "persplookat")
-				{
-					thisCam = new CameraLookAt;
-					if(!thisCam->readState(nodePtr->xmlChildrenNode))
-					{
-						std::string s =TRANS("Failed to interpret camera state for camera : "); 
-
-						errStream<< s <<  newCameraVec.size() << endl;
-						throw 1;
-					}
-				}
-				else
-				{
-					errStream << TRANS("Unable to interpret the camera type for camera : ") << newCameraVec.size() <<  endl;
-					throw 1;
-				}
-
-				ASSERT(thisCam);
-				newCameraVec.push_back(thisCam);	
-			}
-
-			//Enforce active cam value validity
-			if(newCameraVec.size() < activeCam)
-				activeCam=0;
-
-		}
-		
-		nodePtr=nodeStack.top();
-		nodeStack.pop();
-		
-		nodeStack.push(nodePtr);
-		//Read stashes if present
-		if(!XMLHelpFwdToElem(nodePtr,"stashedfilters"))
-		{
-			nodeStack.push(nodePtr);
-
-			//Move to stashes 
-			nodePtr=nodePtr->xmlChildrenNode;
-
-			while(!XMLHelpFwdToElem(nodePtr,"stash"))
-			{
-				string stashName;
-				FilterTree newStashTree;
-				newStashTree.clear();
-
-				//read name of stash
-				xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name");
-				if(!xmlString)
-				{
-					errStream << TRANS("Unable to locate stash name for stash ") << newStashTree.size()+1 << endl;
-					throw 1;
-				}
-				stashName=(char *)xmlString;
-
-				if(!stashName.size())
-				{
-					errStream << TRANS("Empty stash name for stash ") << newStashTree.size()+1 << endl;
-					throw 1;
-				}
-
-				if(newStashTree.loadXML(nodePtr,errStream,stateDir))
-				{
-					errStream << TRANS("For stash ") << newStashTree.size()+1 << endl;
-					throw 1;
-				}
-				newStashes.push_back(make_pair(stashName,newStashTree));
-			}
-
-			nodePtr=nodeStack.top();
-			nodeStack.pop();
-		}
-		nodePtr=nodeStack.top();
-		nodeStack.pop();
+	//Grab the filter tree from the state
+	currentState.copyFilterTree(filterTree);
 	
-		//Read effects, if present
-		nodeStack.push(nodePtr);
-
-		//Read effects if present
-		if(!XMLHelpFwdToElem(nodePtr,"effects"))
-		{
-			std::string tmpStr;
-			nodePtr=nodePtr->xmlChildrenNode;
-			while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE))
-			{
-				tmpStr =(const char *)nodePtr->name;
-
-				Effect *e;
-				e = makeEffect(tmpStr);
-				if(!e)
-				{
-					errStream << TRANS("Unrecognised effect :") << tmpStr << endl;
-					throw 1;
-				}
-
-				//Check the effects are unique
-				for(unsigned int ui=0;ui<newEffectVec.size();ui++)
-				{
-					if(newEffectVec[ui]->getType()== e->getType())
-					{
-						delete e;
-						errStream << TRANS("Duplicate effect found") << tmpStr << TRANS(" cannot use.") << endl;
-						throw 1;
-					}
-
-				}
-
-				nodeStack.push(nodePtr);
-				//Parse the effect
-				if(!e->readState(nodePtr))
-				{
-					errStream << TRANS("Error reading effect : ") << e->getName() << std::endl;
-				
-					throw 1;
-				}
-				nodePtr=nodeStack.top();
-				nodeStack.pop();
-
-
-				newEffectVec.push_back(e);				
-			}
-		}
-		nodePtr=nodeStack.top();
-		nodeStack.pop();
-
-
-
-		nodeStack.push(nodePtr);
-	}
-	catch (int)
+	if(!noUpdating)
 	{
-		//Code threw an error, just say "bad parse" and be done with it
-		xmlFreeDoc(doc);
-		return false;
-	}
-	xmlFreeDoc(doc);	
+		// -- Set scene options --
+		float rBack,gBack,bBack;
+		currentState.getBackgroundColour(rBack,gBack,bBack);
+		targetScene->setBackgroundColour(rBack,gBack,bBack);
 
-	//Check that stashes are uniquely named
-	// do brute force search, as there are unlikely to be many stashes	
-	for(unsigned int ui=0;ui<newStashes.size();ui++)
-	{
-		for(unsigned int uj=0;uj<newStashes.size();uj++)
-		{
-			if(ui == uj)
-				continue;
-
-			//If these match, states not uniquely named,
-			//and thus statefile is invalid.
-			if(newStashes[ui].first == newStashes[uj].first)
-				return false;
+		targetScene->setWorldAxisVisible(currentState.getWorldAxisMode());
 
-		}
-	}
+		vector<const Camera *> cams;
+		currentState.copyCamsByRef(cams);
 
-	if(!merge)
-	{
-		//Erase any viscontrol data, seeing as we got this far	
-		clear(); 
-		//Now replace it with the new data
-		filterTree.swap(newFilterTree);
-		std::swap(stashedFilters,newStashes);
-	}
-	else
-	{
-		//If we are merging, then there is a chance
-		//of a name-clash. We avoid this by trying to append -merge continuously
-		for(unsigned int ui=0;ui<newStashes.size();ui++)
+		if(cams.size())
 		{
-			//protect against overload (very unlikely)
-			unsigned int maxCount;
-			maxCount=100;
-			while(hasFirstInPairVec(stashedFilters,newStashes[ui]) && --maxCount)
-				newStashes[ui].first+=TRANS("-merge");
-
-			if(maxCount)
-				stashedFilters.push_back(newStashes[ui]);
-			else
-				errStream << TRANS(" Unable to merge stashes correctly. This is improbable, so please report this.") << endl;
+			size_t activeCam=currentState.getActiveCam();
+			targetScene->setActiveCamByClone(cams[activeCam]);
 		}
 
-		filterTree.addFilterTree(newFilterTree,0);
-		undoFilterStack.clear();
-		redoFilterStack.clear();
-		filterMap.clear();
+		vector<Effect*> e;
+		currentState.copyEffects(e);
+		targetScene->setEffectVec(e);
+		//----
 	}
 
-	filterTree.initFilterTree();
-	
-	
-	//NOTE: We must be careful about :return: at this point
-	// as we now have mixed in the new filter data.
-
-	//Re-generate the ID mapping for the stashes
-	stashUniqueIDs.clear();
-	for(unsigned int ui=0;ui<stashedFilters.size();ui++)
-		stashUniqueIDs.genId(ui);
-
-	if(noUpdating)
-		return true;
 
-	//Wipe the existing cameras, and then put the new cameras in place
-	if(!merge)
-		targetScene->clearCams();
-	
-	//Set a default camera as needed. We don't need to track its unique ID, as this is
-	//"invisible" to the UI
-	if(!targetScene->getNumCams())
-	{
-		Camera *c=new CameraLookAt();
-		unsigned int id;
-		id=targetScene->addCam(c);
-		targetScene->setActiveCam(id);
-	}
 
-	if(newCameraVec.size())
-	{
-		for(unsigned int ui=0;ui<newCameraVec.size();ui++)
-		{
-			if(merge)
-			{
-				//Don't merge the default camera (which has no name)
-				if(newCameraVec[ui]->getUserString().empty())
-					continue;
-
-				//Keep trying new names appending "-merge" each time to obtain a new, and hopefully unique name
-				// Abort after many times
-				unsigned int maxCount;
-				maxCount=100;
-				while(targetScene->camNameExists(newCameraVec[ui]->getUserString()) && --maxCount)
-				{
-					newCameraVec[ui]->setUserString(newCameraVec[ui]->getUserString()+"-merge");
-				}
-
-				//If we have any attempts left, then it worked
-				if(maxCount)
-				{
-					unsigned int id;
-					id=targetScene->addCam(newCameraVec[ui]);
-					//Use the unique identifier to set the active cam,
-					//if this is the active camera.
-					if(ui == activeCam)
-						targetScene->setActiveCam(id);
-				}
-			}
-			else
-			{
-				//If there is no userstring, then its a  "default"
-				// camera (one that does not show up to the users,
-				// and cannot be erased from the scene)
-				// set it directly. Otherwise, its a user camera.
-				if(newCameraVec[ui]->getUserString().empty())
-				{
-					targetScene->setDefaultCam(newCameraVec[ui],
-							(ui==activeCam) );
-				}
-				else
-				{
-					unsigned int id;
-					id=targetScene->addCam(newCameraVec[ui]);
-					//Use the unique identifier to set the active cam,
-					//if this is the active camera.
-					if(ui == activeCam)
-						targetScene->setActiveCam(id);
-				}
-				
-			}
 
-		}
-	}
-	else
-	{
-		//If the user didn't specify any cameras,
-		// (as in some old versions of 3Depict < 0.0.13),
-		// then just set one that shows the scene
-		targetScene->ensureVisible(3);
-	}
+	fta.clear();
 
-	if(newEffectVec.size())
-	{
-		targetScene->clearEffects();
-		for(unsigned int ui=0;ui<newEffectVec.size();ui++)
-		{
-			targetScene->addEffect(newEffectVec[ui]);
-		}
-	}
+	filterTree.initFilterTree();
+		
+	//Try to restore the working directory as needed
+	std::string wd;
+	wd=currentState.getWorkingDir();
+	if(wd.size() && wxDirExists(wxStr(wd)))
+		wxSetWorkingDirectory(wxStr(currentState.getWorkingDir()));
 
-	//Perform sanitisation on results
+	currentState.setStateModified(false);
 	return true;
 }
 
-
 void VisController::clear()
 {
 	filterMap.clear();
-
 	filterTree.clear();
+	fta.clear();
 
-	undoFilterStack.clear();
+	currentState.setFilterTreeByClone(filterTree);
+	currentState.clearUndoRedoStacks();
 }
 
-void VisController::getCamData(std::vector<std::pair<unsigned int, std::string> > &camData) const
+void VisController::getCamData(std::vector<std::string>  &camData) const
 {
-	targetScene->getCameraIDs(camData);
+	vector<const Camera *> camRefs;
+	currentState.copyCamsByRef(camRefs);	
+	
+	camData.resize(camRefs.size());
+	for(size_t ui=0;ui<camRefs.size();ui++)
+	{
+		camData[ui]=camRefs[ui]->getUserString();
+	}
 }
 
 unsigned int VisController::getActiveCamId() const
 { 
-	return targetScene->getActiveCamId();
+	return currentState.getActiveCam();
 }
 
 unsigned int VisController::exportIonStreams(const std::vector<const FilterStreamData * > &selectedStreams,
@@ -1642,7 +1185,7 @@ unsigned int VisController::exportIonStreams(const std::vector<const FilterStrea
 					case IONFORMAT_POS:
 					{
 						//Append this ion stream to the posfile
-						appendPos(ionData->data,outFile.c_str());
+						IonHit::appendPos(ionData->data,outFile.c_str());
 
 						break;
 					}
@@ -1658,27 +1201,27 @@ unsigned int VisController::exportIonStreams(const std::vector<const FilterStrea
 }
 
 
-void VisController::addStashedToFilters(const Filter *parent, unsigned int stashId)
+void VisController::addStashedToFilters(const Filter *parentFilter, unsigned int stashOffset)
 {
-	ASSERT(stashId<stashedFilters.size());
-	
+	//Retrieve the specified stash
+	pair<string,FilterTree> f;
+
+	currentState.copyStashedTree(stashOffset,f);
+
+	filterTree.addFilterTree(f.second,parentFilter);
+	currentState.setFilterTreeByClone(filterTree);
+
 	//Save current filter state to undo stack
 	pushUndoStack();
 
-	filterTree.addFilterTree(stashedFilters[stashId].second,parent);
+	
 	filterTree.initFilterTree();
 }
 
-void VisController::deleteStash(unsigned int stashId)
+void VisController::eraseStash(unsigned int stashPos)
 {
-	unsigned int stashPos=stashUniqueIDs.getPos(stashId);
-
-	//swap out the one we wish to kill with the last element
-	if(stashPos != stashedFilters.size() -1)
-		swap(stashedFilters[stashedFilters.size()-1],stashedFilters[0]);
-
-	//nuke the tail
-	stashedFilters.pop_back();
+	//Remove viscontrol's mapping to this
+	currentState.eraseStash(stashPos);
 }
 
 unsigned int VisController::stashFilters(unsigned int filterId, const char *stashName)
@@ -1687,28 +1230,29 @@ unsigned int VisController::stashFilters(unsigned int filterId, const char *stas
 	
 	FilterTree fTree;
 	filterTree.cloneSubtree(fTree,target);
-	
-	stashedFilters.push_back(std::make_pair(string(stashName),fTree));
-	return stashUniqueIDs.genId(stashedFilters.size()-1); 
+
+	currentState.addStashedTree(std::make_pair(string(stashName),fTree));
+	return currentState.getStashCount()-1; 
 }
 
-void VisController::getStashTree(unsigned int stashId, FilterTree &f) const
+void VisController::getStashTree(unsigned int stashPos, FilterTree &f) const
 {
-	unsigned int pos = stashUniqueIDs.getPos(stashId);
-	f = stashedFilters[pos].second;
+	pair<string,FilterTree > stash;
+	currentState.copyStashedTree(stashPos,stash);
+	f=stash.second;
 }
 
+//TDOO: Drop pairm and just use string
 void VisController::getStashes(std::vector<std::pair<std::string,unsigned int > > &stashList) const
 {
 	ASSERT(stashList.empty()); // should be empty	
-	//Duplicate the stash list, but replace the filter tree ID
-	//with the ID value that corresponds to that position
-	stashList.reserve(stashedFilters.size());	
-	for(unsigned int ui=0;ui<stashedFilters.size(); ui++)
-	{
-		stashList.push_back(std::make_pair(stashedFilters[ui].first,
-					stashUniqueIDs.getId(ui)));
-	}
+
+	vector<pair<string,FilterTree> > tmp;
+	currentState.copyStashedTrees(tmp);
+	stashList.resize(tmp.size());
+
+	for(size_t ui=0;ui<tmp.size();ui++)
+		stashList[ui]= std::make_pair(tmp[ui].first,ui);
 }
 
 void VisController::updateRawGrid() const
@@ -1770,59 +1314,25 @@ void VisController::setCachePercent(unsigned int newCache)
 
 void VisController::pushUndoStack()
 {
-	FilterTree newTree;
-	newTree = filterTree;
-	if(undoFilterStack.size() > MAX_UNDO_SIZE)
-		undoFilterStack.pop_front();
-
-	undoFilterStack.push_back(newTree);
-	redoFilterStack.clear();
+	currentState.pushUndoStack();
 }
 
 void VisController::popUndoStack(bool restorePopped)
 {
-	ASSERT(undoFilterStack.size());
-
-	//Save the current filters to the redo stack.
-	// note that the copy constructor will generate a clone for us.
-	redoFilterStack.push_back(filterTree);
-
-	if(redoFilterStack.size() > MAX_UNDO_SIZE)
-		redoFilterStack.pop_front();
+	currentState.popUndoStack(restorePopped);
 
 	if(restorePopped)
 	{
-		//Swap the current filter cache out with the undo stack result
-		std::swap(filterTree,undoFilterStack.back());
-		
-		//Filter topology has changed. Update
+		currentState.copyFilterTree(filterTree);
 		filterTree.initFilterTree();
 	}
-
-	//Pop the undo stack
-	undoFilterStack.pop_back();
-	
-
 }
 
 void VisController::popRedoStack()
 {
-	//Push the current state back onto the undo stack
-	FilterTree newTree;
-
-	//Copy the iterators onto the new tree
-	//- due to copy const. We are modifying a clone, not the original
-	newTree = filterTree;
-	ASSERT(undoFilterStack.size() <=MAX_UNDO_SIZE);
-	undoFilterStack.push_back(newTree);
-
-	//Swap the current filter cache out with the redo stack result
-	std::swap(filterTree,redoFilterStack.back());
+	currentState.popRedoStack();
+	currentState.copyFilterTree(filterTree);
 	
-	//Pop the redo stack
-	redoFilterStack.pop_back();
-
-	//Filter topology has changed. Update
 	filterTree.initFilterTree();
 }
 
@@ -1863,13 +1373,26 @@ void VisController::setEffects(bool enable)
 
 bool VisController::hasHazardousContents() const
 {
+	//Filters can contain hazardous content - that is 
+	// content that can come from untrusted sources, and be used
+	// in a nefarious way. Check to see if any filter that
+	// could potentially be used in such a manner exists in our
+	// current state
+
+	//Check the stashed state
+	vector<pair<string, FilterTree > > stashedFilters;
+
+	currentState.copyStashedTrees(stashedFilters);
 	for(size_t ui=0;ui<stashedFilters.size();ui++)
 	{
 		if(stashedFilters[ui].second.hasHazardousContents())
 			return true;
 	}
 
-	return filterTree.hasHazardousContents();
+	//Check the active filter tree
+	FilterTree f;
+	currentState.copyFilterTree(f);	
+	return f.hasHazardousContents();
 }
 
 bool VisController::filterIsPureDataSource(size_t filterId) const
diff --git a/src/backend/viscontrol.h b/src/backend/viscontrol.h
index 04391e0..314b551 100644
--- a/src/backend/viscontrol.h
+++ b/src/backend/viscontrol.h
@@ -27,15 +27,13 @@ class wxGrid;
 class wxPropertyGrid;
 class wxTreeCtrl;
 
-#include "../gl/scene.h"
+class Scene;
 
 #include "filtertreeAnalyse.h"
 #include "backend/plot.h"
+#include "state.h"
 
-const unsigned int MAX_UNDO_SIZE=10;
-
-
-
+#include "backend/APT/APTFileIO.h"
 
 
 //!Visualisation controller
@@ -64,23 +62,20 @@ class VisController
 		wxListBox *plotSelList;
 
 
+
+
 		//--- Data storage ----
+		AnalysisState currentState;
+		
+		//TODO: Migrate to analyis state
 		//!Primary data storage for filter tree
 		FilterTree filterTree;
 	
 		//!Analysis results for last filter tree refresh
 		FilterTreeAnalyse fta;
-	
-		//!Undo filter tree stack 
-		std::deque<FilterTree> undoFilterStack,redoFilterStack;
-
-		//!Named, stored trees that can be put aside for secondary use
-		std::vector<std::pair<std::string,FilterTree> > stashedFilters;
-
-		//!Unique IDs for stash
-		UniqueIDHandler stashUniqueIDs;
 		//--------------------
 
+		
 		//!True if viscontrol should abort current operation
 		bool doProgressAbort;
 	
@@ -90,12 +85,11 @@ class VisController
 		//!True if there are pending updates from the user
 		bool pendingUpdates;
 
-		//!Have we implicitly used relative references when saving data files?
-		unsigned int useRelativePathsForSave;
-
 		//!Current progress
 		ProgressData curProg;
 
+		//!Maximum number of ions to pass to scene
+		size_t limitIonOutput;
 
 		void clear();
 	
@@ -117,8 +111,13 @@ class VisController
 		//!Update the console strings
 		void updateConsole(const std::vector<std::string> &v, const Filter *f) const;
 
+		
+		//!Limit the number of objects we are sending to the scene
+		void throttleSceneInput(std::list<vector<const FilterStreamData *> > &outputData) const;
+
 		//!Force an update to the scene. 
-		unsigned int updateScene(std::list<vector<const FilterStreamData *> > &outputData,bool releaseData=true);
+		unsigned int updateScene(std::list<vector<const FilterStreamData *> > &outputData,
+					std::vector<SelectionDevice *> &devices,bool releaseData=true);
 		
 		//!ID handler that assigns each filter its own ID that
 		// is guaranteed to be unique for the life of the filter in the filterTree	
@@ -128,8 +127,6 @@ class VisController
 		// the wxTree control
 		std::vector<const Filter *> persistentFilters;
 
-		//Working directory for filter tree file operations
-		std::string workingDir;
 
 	public:
 		VisController();
@@ -142,9 +139,9 @@ class VisController
 		unsigned int refreshFilterTree(bool doUpdateScene=true);
 
 		
-		
 		//!Force an update to the scene. 
-		unsigned int doUpdateScene(std::list<vector<const FilterStreamData *> > &outputData, bool releaseData=true);
+		unsigned int doUpdateScene(std::list<vector<const FilterStreamData *> > &outputData, 
+					std::vector<SelectionDevice *> &devices,bool releaseData=true);
 
 		//obtain the outputs from the filter tree's refresh. 
 		// The outputs *must* be deleted with safeDeleteFilterList
@@ -279,7 +276,7 @@ class VisController
 		unsigned int addCam(const std::string &camName);
 
 		//!Update a wxtGrid with the properties for a given filter
-		void updateCamPropertyGrid(wxPropertyGrid *g,unsigned int camUniqueId) const;
+		void updateCamPropertyGrid(wxPropertyGrid *g,unsigned int camId) const;
 		
 		//!Return the number of cameras
 		unsigned int numCams() const ;
@@ -287,7 +284,7 @@ class VisController
 		//!Set the properties using a key-value result (as obtaed from updatewxPropertyGrid)
 		/*! The return code tells whether to reject or accept the change. 
 		 */
-		bool setCamProperties(size_t camUniqueID, 
+		bool setCamProperties(size_t camId, 
 				unsigned int key, const std::string &value);
 
 
@@ -297,15 +294,15 @@ class VisController
 	
 
 		//!Return the current working directory for when loading/saving state file contents
-		std::string getWorkDir() const { return workingDir;};
+		std::string getWorkDir() const { return currentState.getWorkingDir();};
 		
 		//!Set current working dir used when saving state files
-		void setWorkDir(const std::string &wd) { workingDir=wd;};
+		void setWorkDir(const std::string &wd) { currentState.setWorkingDir(wd);};
 
 		
 		//!Save the viscontrol state: writes an XML file containing the viscontrol state
 		bool saveState(const char *filename, std::map<string,string> &fileMapping,
-					bool writePackage=false) const;
+					bool writePackage=false, bool resetModifyLevel=true) const;
 		
 		//!Save the viscontrol "package":this  writes an XML file containing the viscontrol state, altering the output of the filters to obtain the files it needs 
 		bool savePackage(const char *filename) const;
@@ -314,19 +311,28 @@ class VisController
 		bool loadState(const char *filename, std::ostream &f,bool merge=false,bool noUpdating=false);	
 
 		//!Are we currently using relative paths due to a previous load?
-		bool usingRelPaths() const { return useRelativePathsForSave;};
+		bool usingRelPaths() const { return currentState.getUseRelPaths();};
 
 		//!Set whether to use relative paths when saving
-		void setUseRelPaths(bool useRelPaths){ useRelativePathsForSave=useRelPaths;};
+		void setUseRelPaths(bool useRelPaths){ currentState.setUseRelPaths(useRelPaths);};
 
 		//!Get the camera ID-pair data TODO: this is kinda a halfway house between
 		//updating the camera data internally and passing in the dialog box and not
 		//should homogenise this...
-		void getCamData(std::vector<std::pair<unsigned int, std::string> > &camData) const;
+		void getCamData(std::vector<std::string> &camData) const;
 
 		//!Get the active camera ID
 		unsigned int getActiveCamId() const;
 
+		//Obtain updated camera from the scene and then commit it to the state
+		void getCameraUpdates();
+
+		//Set the maximum number of ions to allow the scene to display
+		void setIonDisplayLimit(size_t newLimit) { limitIonOutput=newLimit;}
+
+		size_t getIonDisplayLimit() const { return limitIonOutput;}
+
+
 		//!export given filterstream data pointers
 		static unsigned int exportIonStreams(const std::vector<const FilterStreamData *> &selected, 
 								const std::string &outFile, unsigned int format=IONFORMAT_POS);
@@ -352,7 +358,7 @@ class VisController
 		void addStashedToFilters(const Filter *parentFilter, unsigned int stashID);
 
 		//!Delete a stash using its uniqueID
-		void deleteStash(unsigned int stashID);
+		void eraseStash(unsigned int stashID);
 
 		//!Retreive the stash filters
 		void getStashes(std::vector<std::pair<std::string,unsigned int > > &stashes) const;
@@ -361,7 +367,7 @@ class VisController
 		void getStashTree(unsigned int stashId, FilterTree &) const;
 
 		//!Get the number of stashes
-		unsigned int getNumStashes() const { return stashedFilters.size();}
+		unsigned int getNumStashes() const { return currentState.getStashCount();}
 
 		//----
 
@@ -378,9 +384,9 @@ class VisController
 		void popRedoStack();
 
 		//!Get the size of the undo stack
-		unsigned int getUndoSize() const { return undoFilterStack.size();};
+		unsigned int getUndoSize() const { return currentState.getUndoSize();};
 		//!Get the size of the redo stack
-		unsigned int getRedoSize() const { return redoFilterStack.size();};
+		unsigned int getRedoSize() const { return currentState.getRedoSize();};
 
 		//!Get the current progress
 		ProgressData getProgress() const { return curProg;}
@@ -413,6 +419,16 @@ class VisController
 		//!Ask if a given filter is a pure data source
 		bool filterIsPureDataSource(size_t filterId) const ;  
 
+
+		//true if the state has been modified since last load/save.
+		int stateModifyLevel() const { return currentState.stateModifyLevel();};
+
+		bool hasStateData() const { return currentState.hasStateData(); }
+
+		//Return the current state's filename
+		string getFilename() const { return currentState.getFilename(); }
+		//Return the current state's filename
+		void setFilename(std::string &s) {currentState.setFilename(s); }
 #ifdef DEBUG
 		//Check that the tree conrol is synced up to the filter map correctly
 		void checkTree(wxTreeCtrl *t);
diff --git a/src/common/assertion.h b/src/common/assertion.h
index 35d7c09..c019461 100644
--- a/src/common/assertion.h
+++ b/src/common/assertion.h
@@ -25,19 +25,19 @@
 	
 	#include <sys/time.h>
 
-	void dh_assert(const char * const filename, const unsigned int lineNumber); 
-	void dh_warn(const char * const filename, const unsigned int lineNumber,
+	void userAskAssert(const char * const filename, const unsigned int lineNumber); 
+	void warnProgrammer(const char * const filename, const unsigned int lineNumber,
 							const char *message);
 
 	#ifndef ASSERT
-	#define ASSERT(f) if(!(f)) {dh_assert(__FILE__,__LINE__);}
+	#define ASSERT(f) {if(!(f)) { userAskAssert(__FILE__,__LINE__);}}
 	#endif
 
 	#ifndef WARN
-	#define WARN(f,g) if(!(f)) { dh_warn(__FILE__,__LINE__,g);}
+	#define WARN(f,g) { if(!(f)) { warnProgrammer(__FILE__,__LINE__,g);}}
 	#endif
 	
-	inline void dh_assert(const char * const filename, const unsigned int lineNumber) 
+	inline void userAskAssert(const char * const filename, const unsigned int lineNumber) 
 	{
 		std::cerr << "ASSERTION ERROR!" << std::endl;
 		std::cerr << "Filename: " << filename << std::endl;
@@ -52,7 +52,7 @@
 			exit(1);
 	}
 
-	inline void dh_warn(const char * const filename, const unsigned int lineNumber,const char *message) 
+	inline void warnProgrammer(const char * const filename, const unsigned int lineNumber,const char *message) 
 	{
 		std::cerr << "Warning to programmer." << std::endl;
 		std::cerr << "Filename: " << filename << std::endl;
@@ -65,18 +65,8 @@
 	#define DEBUG_TIME_END() timeval TIME_DEBUG_tend; gettimeofday(&TIME_DEBUG_tend,NULL); \
 	std::cerr << (TIME_DEBUG_tend.tv_sec - TIME_DEBUG_t.tv_sec) + ((float)TIME_DEBUG_tend.tv_usec-(float)TIME_DEBUG_t.tv_usec)/1.0e6 << std::endl;
 
-	//OpenGL debugging macro
-	#define glError() { \
-		GLenum err = glGetError(); \
-		while (err != GL_NO_ERROR) { \
-					fprintf(stderr, "glError: %s caught at %s:%u\n", (char *)gluErrorString(err), __FILE__, __LINE__); \
-					err = glGetError(); \
-				} \
-		std::cerr << "glErr Clean " << __FILE__ << ":" << __LINE__ << std::endl; \
-		}
-
 	#ifndef TEST
-	#define TEST(f,g) if(!(f)) { std::cerr << "Test fail :" << __FILE__ << ":" << __LINE__ << "\t"<< g << std::endl;return false;}
+	#define TEST(f,g) if(!(f)) { std::cerr << "Test fail :" << __FILE__ << ":" << __LINE__ << "\t"<< (g) << std::endl;return false;}
 	#endif
 
 	//A hack to generate compile time asserts (thanks Internet).
diff --git a/src/common/basics.cpp b/src/common/basics.cpp
index ab59505..53af351 100644
--- a/src/common/basics.cpp
+++ b/src/common/basics.cpp
@@ -44,7 +44,7 @@ const char *DTD_NAME="threeDepict-state.dtd";
 //Program name
 const char *PROGRAM_NAME = "3Depict";
 //Program version
-const char *PROGRAM_VERSION = "0.0.13";
+const char *PROGRAM_VERSION = "0.0.14";
 //Path to font for Default FTGL  font
 const char *FONT_FILE= "FreeSans.ttf";
 
@@ -328,7 +328,7 @@ void BoundCube::setBounds(const std::vector<Point3D> &points)
 #endif
 }
 
-void BoundCube::setInverseLimits()
+void BoundCube::setInverseLimits(bool setValid)
 {
 	bounds[0][0] = std::numeric_limits<float>::max();
 	bounds[1][0] = std::numeric_limits<float>::max();
@@ -338,13 +338,13 @@ void BoundCube::setInverseLimits()
 	bounds[1][1] = -std::numeric_limits<float>::max();
 	bounds[2][1] = -std::numeric_limits<float>::max();
 
-	valid[0][0] =false;
-	valid[1][0] =false;
-	valid[2][0] =false;
+	valid[0][0] =setValid;
+	valid[1][0] =setValid;
+	valid[2][0] =setValid;
 	
-	valid[0][1] =false;
-	valid[1][1] =false;
-	valid[2][1] =false;
+	valid[0][1] =setValid;
+	valid[1][1] =setValid;
+	valid[2][1] =setValid;
 }
 
 bool BoundCube::isValid() const
@@ -506,6 +506,12 @@ bool BoundCube::containsPt(const Point3D &p) const
 	return true;
 }
 
+bool BoundCube::contains(const BoundCube &b) const
+{
+	Point3D low,high;
+	b.getBounds(low,high);
+	return containsPt(low) && containsPt(high); 
+}
 float BoundCube::getSize(unsigned int dim) const
 {
 	ASSERT(dim < 3);
diff --git a/src/common/basics.h b/src/common/basics.h
index 09deb64..776b710 100644
--- a/src/common/basics.h
+++ b/src/common/basics.h
@@ -70,7 +70,47 @@ enum
 
 extern const char *TEXT_LOAD_ERR_STRINGS[];
 
-	
+//Perform a a<-b<-c<-a rotation of data
+template<class T>
+void rotate3(T &a, T &b, T &c)
+{
+	T tmp;
+	tmp=a;
+	a=b;
+	b=c;
+	c=tmp;
+}
+
+//Find the min/max value within an array
+//array must be nonzero sized
+template<class T>
+T maxValue(const T *t, size_t n)
+{
+	ASSERT(n);
+
+	T maxV=t[0];
+	for(size_t ui=1;ui<n;ui++)
+	{
+		maxV=std::max(t[ui],maxV);
+	}
+	return maxV;
+
+}
+
+template<class T>
+T minValue(const T *t, size_t n)
+{
+	ASSERT(n);
+
+	T minV=t[0];
+	for(size_t ui=1;ui<n;ui++)
+	{
+		minV=std::min(t[ui],minV);
+	}
+	return minV;
+
+}
+
 template<class T1, class T2>
 bool hasFirstInPairVec(const std::vector<std::pair<T1,T2> > &v, const std::pair<T1,T2> &r)
 {
@@ -255,7 +295,7 @@ public:
     }
 
     //Set the cube to be "inside out" at the limits of numeric results;
-    void setInverseLimits();
+    void setInverseLimits(bool setAsValid=false);
 
     void setBound(unsigned int bound, unsigned int minMax, float value) ;
 
@@ -292,6 +332,8 @@ public:
     //of the cube
     bool containsPt(const Point3D &pt) const;
 
+    bool contains(const BoundCube &b) const;
+
     //!Is this bounding cube completely contained within a sphere centred on pt of sqr size sqrRad?
     bool containedInSphere(const Point3D &pt, float sqrRad) const;
 
diff --git a/src/common/mathfuncs.cpp b/src/common/mathfuncs.cpp
index 970abe7..9a332d1 100644
--- a/src/common/mathfuncs.cpp
+++ b/src/common/mathfuncs.cpp
@@ -255,6 +255,48 @@ bool Point3D::orthogonalise(const Point3D &pt)
 	return true;
 }
 
+Point3D Point3D::centroid(const Point3D *p, unsigned int n)
+{
+	ASSERT(p);
+	Point3D centroid(0,0,0);
+
+	/* This code should work, but is not profiled. No caller uses
+	   this code at time of writing.
+#ifdef _OPENMP
+
+	//Parallel version
+	//--
+	vector<Point3D> centroids(omp_get_max_threads(),Point3D(0,0,0));
+#pragma omp parallel for 
+	for(size_t ui=0;ui<n;ui++)
+		centroids[omp_get_thread_num()]+=p[ui];
+
+	for(size_t ui=0;ui<centroids.size();ui++)
+		centroid+=centroids[ui];
+	//--
+#endif
+	*/
+	for(unsigned int ui=0;ui<n;ui++)
+		centroid+=p[ui];
+
+	centroid*=1.0f/(float)n;
+
+	return centroid;
+}
+
+Point3D Point3D::centroid(const std::vector<Point3D> &p)
+{
+	Point3D centroid(0,0,0);
+
+	for(unsigned int ui=0;ui<p.size();ui++)
+		centroid+=p[ui];
+
+	centroid*=1.0f/(float)p.size();
+
+	return centroid;
+}
+
+
 bool Point3D::parse(const std::string &str)
 {
 	//Needs to be at minimum #,#,#
@@ -509,7 +551,7 @@ void quat_pointmult(Point3f *result, const Quaternion *q1, const Quaternion *q2)
 //failure to do so will have weird results. 
 //For better performance on multiple rotations, use other function
 //Note result is stored in returned point
-void quat_rot(Point3f *point, Point3f *rotVec, float angle)
+void quat_rot(Point3f *point, const Point3f *rotVec, float angle)
 {
 	ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f < 
 			5.0f*sqrt(std::numeric_limits<float>::epsilon()));
@@ -548,8 +590,8 @@ void quat_rot(Point3f *point, Point3f *rotVec, float angle)
 }
 
 
-//Retrieve the quaternion for repeated rotation. pass to the quat_rot_apply_quats
-void quat_get_rot_quat(Point3f *rotVec, float angle,Quaternion *rotQuat) 
+//Retrieve the quaternion for repeated rotation. Pass to the quat_rot_apply_quats
+void quat_get_rot_quat(const Point3f *rotVec, float angle,Quaternion *rotQuat) 
 {
 	ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f < 
 			5.0f*sqrt(std::numeric_limits<float>::epsilon()));
diff --git a/src/common/mathfuncs.h b/src/common/mathfuncs.h
index 5ed223b..69640a4 100644
--- a/src/common/mathfuncs.h
+++ b/src/common/mathfuncs.h
@@ -21,6 +21,8 @@
 #include <cmath>
 #include <limits>
 #include <iostream>
+#include <vector>
+
 
 #include "endianTest.h"
 
@@ -140,6 +142,10 @@ class Point3D
 		//Perform a cross-product based orthogonalisation
 		//with the specified vector
 		bool orthogonalise(const Point3D &p);
+
+		static Point3D centroid(const Point3D *p, unsigned int n);
+		
+		static Point3D centroid(const std::vector<Point3D> &p); 
 #ifdef __LITTLE_ENDIAN__
                 //!Flip the endian state for data stored in this point
                 void switchEndian();
@@ -206,11 +212,11 @@ typedef struct
 //failure to do so will have weird results
 //Note result is stored in  point passed as argument
 //angle is in radians.
-void quat_rot(Point3f *point, Point3f *rotVec, float angle);
+void quat_rot(Point3f *point, const Point3f *rotVec, float angle);
 
 //Retrieve the quaternion for repeated rotations. Pass to the quat_rot_apply_quats.
 //angle is in radians
-void quat_get_rot_quat(Point3f *rotVec, float angle,  Quaternion *rotQuat);
+void quat_get_rot_quat(const Point3f *rotVec, float angle,  Quaternion *rotQuat);
 
 //Use previously generated quats from quat_get_rot_quats to rotate a point
 void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat);
diff --git a/src/pngread.c b/src/common/pngread.c
similarity index 100%
rename from src/pngread.c
rename to src/common/pngread.c
diff --git a/src/pngread.h b/src/common/pngread.h
similarity index 100%
rename from src/pngread.h
rename to src/common/pngread.h
diff --git a/src/common/stringFuncs.cpp b/src/common/stringFuncs.cpp
index da8a357..b797b76 100644
--- a/src/common/stringFuncs.cpp
+++ b/src/common/stringFuncs.cpp
@@ -20,6 +20,8 @@
 
 #include "common/basics.h"
 
+#include <sys/time.h>
+
 using std::string;
 using std::vector;
 
@@ -388,6 +390,11 @@ void genColString(unsigned char r, unsigned char g,
 //Strip "whitespace"
 std::string stripWhite(const std::string &str)
 {
+	return stripChars(str,"\f\n\r\t ");
+}
+
+std::string stripChars(const std::string &str, const char *chars)
+{
 	using std::string;
 
 	size_t start;
@@ -395,8 +402,8 @@ std::string stripWhite(const std::string &str)
 	if(!str.size())
 	      return str;
 
- 	start = str.find_first_not_of("\f\n\r\t ");
-	end = str.find_last_not_of("\f\n\r\t ");
+ 	start = str.find_first_not_of(chars);
+	end = str.find_last_not_of(chars);
 	if(start == string::npos) 
 		return string("");
 	else
diff --git a/src/common/stringFuncs.h b/src/common/stringFuncs.h
index 41daa29..a74b8fb 100644
--- a/src/common/stringFuncs.h
+++ b/src/common/stringFuncs.h
@@ -54,9 +54,10 @@ std::string getActiveChoice(const std::string &choiceString);
 std::string wxChoiceParamString(std::string choiceString);
 
 
-//Strip whitespace from a string
+//Strip given whitespace (\f,\n,\r,\t,\ )from a string
 std::string stripWhite(const std::string &str);
-
+//Strip specified chars from a string
+std::string stripChars(const std::string &Str, const char *chars);
 //!Return a lowercase version for a given string
 std::string lowercase(std::string s);
 
diff --git a/src/common/voxels.cpp b/src/common/voxels.cpp
index bf3921a..c21a671 100644
--- a/src/common/voxels.cpp
+++ b/src/common/voxels.cpp
@@ -21,6 +21,8 @@ using std::numeric_limits;
 const float FLOAT_SMALL=
 	sqrt(numeric_limits<float>::epsilon());
 
+#ifdef DEBUG
+
 bool testConvolve()
 {
 	{
@@ -164,14 +166,71 @@ bool basicTests()
 	TEST(xs == ys && ys == zs && zs == 2, "resizeKeepData");
 	TEST(f.max() == 1.0f,"resize keep data");
 	
+	//Test slice functions
+	//--
+	Voxels<float> v;
+	v.resize(2,2,2);
+	for(size_t ui=0;ui<8;ui++)
+		v.setData(ui&1, (ui & 2) >> 1, (ui &4)>>2, ui);
+
+	float *slice = new float[4];
+	//Test Z slice
+	v.getSlice(2,0,slice);
+	for(size_t ui=0;ui<4;ui++)
+	{
+		ASSERT(slice[ui] == ui);
+	}
+
+	//Expected results
+	float expResults[4];
+	//Test X slice
+	expResults[0]=0; expResults[1]=2;expResults[2]=4; expResults[3]=6;
+	v.getSlice(0,0,slice);
+	for(size_t ui=0;ui<4;ui++)
+	{
+		ASSERT(slice[ui] == expResults[ui]);
+	}
+
+	//Test Y slice
+	v.getSlice(1,1,slice);
+	expResults[0]=2; expResults[1]=3;expResults[2]=6; expResults[3]=7;
+	for(size_t ui=0;ui<4;ui++)
+	{
+		ASSERT(slice[ui] == expResults[ui]);
+	}
+
+	delete[] slice;
+
+	//-- try again with nonuniform voxels
+	v.resize(4,3,2);
+	for(size_t ui=0;ui<24;ui++)
+		v.setData(ui, ui);
+
+	slice = new float[12];
+	//Test Z slice
+	v.getSlice(2,1,slice);
+	for(size_t ui=0;ui<12;ui++)
+	{
+		ASSERT( slice[ui] >=12);
+	}
+
+	delete[] slice;
+	//--
+
 	return true;
 }
 
 
+
+
+
 bool runVoxelTests()
 {
+//	TEST(testCubeIntercepts(),"cube intercept test");
 	TEST(basicTests(),"basic voxel tests");
 	TEST(testConvolve()," voxel convolve");
 	TEST(simpleMath(), "voxel simple maths");	
 	return true;	
 }
+
+#endif
diff --git a/src/common/voxels.h b/src/common/voxels.h
index 4286b25..ee8c11b 100644
--- a/src/common/voxels.h
+++ b/src/common/voxels.h
@@ -50,6 +50,13 @@ enum{
 	BOUND_ENUM_END
 };
 
+//Interpolation mode for slice 
+enum
+{
+	SLICE_INTERP_NONE,
+	SLICE_INTERP_LINEAR,
+	SLICE_INTERP_ENUM_END
+};
 
 enum{
 	ADJ_ALL,
@@ -163,7 +170,15 @@ template<class T> class Voxels
 		void setData(size_t x, size_t y, size_t z, const T &val);
 		//!Set the value of nth point in the dataset
 		void setData(size_t n, const T &val);
-		
+
+
+		//get an interpolated slice from a section of the data
+		void getSlice(size_t normal, float offset, T *p, 
+			size_t interpMode=SLICE_INTERP_NONE, size_t boundMode=BOUND_MIRROR) const;
+
+		//Get a specific slice, from an integral offset in the data
+		void getSlice(size_t normal, size_t offset, 
+					T *p,size_t boundMode) const;
 		//!Get the size of the data field
 		void getSize(size_t &x, size_t &y, size_t &z) const;
 		size_t getSize() const {return voxels.size();};
@@ -228,10 +243,14 @@ template<class T> class Voxels
 		//!Get the bounding size
 		Point3D getMinBounds() const;
 		Point3D getMaxBounds() const;
+		//Obtain the ounds for a specified axis
+		void getAxisBounds(size_t axis, float &minV, float &maxV) const;
 		///! Get the spacing for a unit cell
 		Point3D getPitch() const;
 		//!Set the bounding size
 		void setBounds(const Point3D &pMin, const Point3D &pMax);
+		//!Get the bounding size
+		void getBounds(Point3D &pMin, Point3D &pMax) const { pMin=minBound;pMax=maxBound;}
 
 		//!Initialise the voxel storage
 		size_t init(size_t nX,size_t nY,size_t nZ, const BoundCube &bound);
@@ -340,7 +359,7 @@ template<class T> class Voxels
 		int histogram(std::vector<size_t> &v, size_t histBinCount) const;
 
 		//!Find the largest or smallest n objects
-		void findSorted(std::vector<size_t> &x, std::vector<size_t> &y, std::vector<size_t> &z, size_t n, bool largest=true) const;
+		void findNExtrema(std::vector<size_t> &x, std::vector<size_t> &y, std::vector<size_t> &z, size_t n, bool largest=true) const;
 
 		//!Generate a dataset that consists of the counts of points in a given voxel
 		/*! Ensure that the voxel scaling factors 
@@ -516,7 +535,7 @@ void Voxels<T>::getSize(size_t &x, size_t &y, size_t &z) const
 template<class T>
 size_t Voxels<T>::getEdgeIndex(size_t x,size_t y, size_t z, unsigned int index) const
 {
-	//This provides a reversable mapping of x,y,z 
+	//This provides a reversible mapping of x,y,z 
 	//X aligned edges are first
 	//Y second
 	//Z third
@@ -862,6 +881,13 @@ void Voxels<T>::getEdgeEndApproxVals(size_t edgeUniqId, float &a, float &b ) con
 }
 
 template<class T>
+void Voxels<T>::getAxisBounds(size_t axis, float &minV, float &maxV ) const
+{
+	maxV=maxBound[axis];
+	minV=minBound[axis];
+}
+
+template<class T>
 size_t Voxels<T>::resize(size_t x, size_t y, size_t z, const Point3D &newMinBound, const Point3D &newMaxBound) 
 {
 	voxels.clear();
@@ -1966,7 +1992,7 @@ void Voxels<T>::makeSphericalKernel(size_t sideLen, float bound, const T &val, u
 						}
 
 						//Level 0 corresponds to 1/8th of the original voxel. Level n = 1/(2^3(n+1)) 
-						//each voxel has side lenght L_v = originalLen/(2^(level+1))
+						//each voxel has side length L_v = originalLen/(2^(level+1))
 						while(!positionStack.empty())
 						{
 							unsigned int thisLevel;
@@ -2452,10 +2478,10 @@ int Voxels<T>::histogram(std::vector<size_t> &v, size_t histBinCount) const
 }
 
 template<class T>
-void Voxels<T>::findSorted(std::vector<size_t> &x, std::vector<size_t> &y, 
+void Voxels<T>::findNExtrema(std::vector<size_t> &x, std::vector<size_t> &y, 
 			std::vector<size_t> &z, size_t n, bool largest) const
 {
-	//Could be better if we didn't use indexed data aquisition (record opsition)
+	//Could be better if we didn't use indexed data acquisition (record position)
 	std::deque<size_t> bSx,bSy,bSz;
 
 	if(voxels.empty())
@@ -2538,6 +2564,168 @@ void Voxels<T>::findSorted(std::vector<size_t> &x, std::vector<size_t> &y,
 	}
 }
 
+
+//Obtain a slice of the voxel data. Data output will be in column order
+// p[posB*nA + posA]. Input slice must be sufficiently sized and allocated
+// to hold the output data
+template<class T>
+void Voxels<T>::getSlice(size_t normalAxis, size_t offset, T *p,size_t boundMode) const
+{
+	ASSERT(normalAxis < 3);
+
+	size_t dimA,dimB,nA;
+	switch(normalAxis)
+	{
+		case 0:
+		{
+			dimA=1;
+			dimB=2;
+			nA=binCount[dimA];
+			break;
+		}
+		case 1:
+		{	
+			dimA=0;
+			dimB=2;
+			nA=binCount[dimA];
+			break;
+		}
+		case 2:
+		{
+			dimA=0;
+			dimB=1;
+			nA=binCount[dimA];
+			break;
+		}
+		default:
+			ASSERT(false); //WTF - how did you get here??
+	}
+		
+
+	if(offset < binCount[normalAxis])
+	{
+		//We are within bounds, use normal access functions
+		switch(normalAxis)
+		{
+			case 0:
+			{
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getData(offset,ui,uj);
+				}
+				break;
+			}
+			case 1:
+			{	
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getData(ui,offset,uj);
+				}
+				break;
+			}
+			case 2:
+			{
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getData(ui,uj,offset);
+				}
+				break;
+			}
+			default:
+				ASSERT(false);
+		}
+	}
+	else
+	{
+		//We are outside the cube bounds, use the padded access functions
+		switch(normalAxis)
+		{
+			case 0:
+			{
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getPaddedData(offset,ui,uj,boundMode);
+				}
+				break;
+			}
+			case 1:
+			{	
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getPaddedData(ui,offset,uj,boundMode);
+				}
+				break;
+			}
+			case 2:
+			{
+				for(size_t ui=0;ui<binCount[dimA];ui++)
+				{
+					for(size_t uj=0;uj<binCount[dimB];uj++)
+						p[uj*nA + ui] =	getPaddedData(ui,uj,offset,boundMode);
+				}
+				break;
+			}
+			default:
+				ASSERT(false);
+		}
+	}
+}
+
+template<class T>
+void Voxels<T>::getSlice(size_t normal, float offset, 
+		T *p, size_t interpMode,size_t boundMode) const
+{
+	ASSERT(offset <=1.0f && offset >=0.0f);
+
+	//Obtain the appropriately interpolated slice
+	switch(interpMode)
+	{
+		case SLICE_INTERP_NONE:
+		{
+			size_t slicePos;
+			slicePos=roundf(offset*binCount[normal]);
+			getSlice(normal,slicePos,p,boundMode);
+			break;
+		}
+		case SLICE_INTERP_LINEAR:
+		{
+			//Find the upper and lower bounds
+			size_t sliceUpper,sliceLower;;
+			sliceUpper=ceilf(offset*binCount[normal]);
+			sliceLower=offset*binCount[normal];
+
+			{
+				T *pLower;
+				size_t numEntries=binCount[(normal+1)%3]*binCount[(normal+2)%3];
+				
+				pLower  = new T[numEntries];
+
+				getSlice(normal,sliceLower,pLower,boundMode);
+				getSlice(normal,sliceUpper,p,boundMode);
+
+				//Get the decimal part of the float
+				float integ;
+				float delta=modff(offset*binCount[normal],&integ);
+				for(size_t ui=0;ui<numEntries;ui++)
+					p[ui] = delta*(p[ui]-pLower[ui]) + pLower[ui];
+
+				delete[] pLower;
+			}
+			break;
+		}
+		default:
+			ASSERT(false);
+			
+	}
+
+}
+
+
 template<class T>
 void Voxels<T>::operator/=(const Voxels<T> &v)
 {
diff --git a/src/common/xmlHelper.h b/src/common/xmlHelper.h
index 732f66b..bc2055e 100644
--- a/src/common/xmlHelper.h
+++ b/src/common/xmlHelper.h
@@ -48,7 +48,7 @@ std::string escapeXML(const std::string &s);
 //Convert an xml escaped sequence into a normal string sequence
 std::string unescapeXML(const std::string &s);
 
-//!Jump to the next element of the given name and retreive the value for the specified attrip
+//!Jump to the next element of the given name and retrieve the value for the specified attrip
 //returns false on failure
 //NOTE: Do not use if your value may validly contain whitespace. stream_cast skips these cases
 template<class T> 
diff --git a/src/gl/cameras.cpp b/src/gl/cameras.cpp
index 1864b27..909a14c 100644
--- a/src/gl/cameras.cpp
+++ b/src/gl/cameras.cpp
@@ -50,7 +50,7 @@ enum
 
 
 
-Camera::Camera() : lock(false),origin(0.0f,0.0f,0.0f), viewDirection(0.0f,0.0f,-1.0f), upDirection(0.0f,0.0f,1.0f)
+Camera::Camera() : lock(false),origin(0.0f,0.0f,0.0f), viewDirection(0.0f,0.0f,-1.0f), upDirection(0.0f,0.0f,1.0f), orthoScale(1)
 {
 	
 }
@@ -915,7 +915,9 @@ bool CameraLookAt::readState(xmlNodePtr nodePtr)
 	if(!XMLGetNextElemAttrib(nodePtr,orthoScale,"orthoscale","value"))
 		return false;
 	if(orthoScale <=0 || std::isnan(orthoScale))
-		return false;
+	{
+		orthoScale=1.0f;
+	}
 
 	
 	float x,y,z;
diff --git a/src/gl/drawables.cpp b/src/gl/drawables.cpp
index f3d9f22..5b9bdf9 100644
--- a/src/gl/drawables.cpp
+++ b/src/gl/drawables.cpp
@@ -16,16 +16,28 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#if defined(WIN32) || defined(WIN64)
+#include <GL/glew.h>
+#endif
+
 #include "drawables.h"
 
 #include "common/colourmap.h"
 
 
+
+
 const float DEPTH_SORT_REORDER_EPSILON = 1e-2;
 
 //Static class variables
 //====
 const Camera *DrawableObj::curCamera = 0;
+bool DrawableObj::useAlphaBlend;
+TexturePool *DrawableObj::texPool;
+
+unsigned int DrawableObj::winX;
+unsigned int DrawableObj::winY;
+
 //==
 
 
@@ -94,6 +106,22 @@ void DrawableObj::explode(std::vector<DrawableObj *> &simpleObjects)
 	ASSERT(isExplodable());
 }
 
+void DrawableObj::setTexPool(TexturePool *t)
+{
+	if(texPool)
+		delete texPool;
+
+	texPool=t;
+
+}
+
+void DrawableObj::clearTexPool()
+{
+	ASSERT(texPool);
+	delete texPool;
+
+}
+
 Point3D DrawableObj::getCentroid() const
 {
 	ASSERT(!isExplodable());
@@ -136,7 +164,7 @@ void DrawPoint::draw() const
 {
 	glColor4f(r,g,b,a);
 	glBegin(GL_POINT);
-	glVertex3f(origin[0],origin[1],origin[2]);
+	glVertex3fv(origin.getValueArr());
 	glEnd();
 }
 
@@ -197,32 +225,23 @@ void DrawVector::draw() const
 
 	glLineWidth(lineSize);
 	glBegin(GL_LINES);
+	glVertex3fv(origin.getValueArr());
 	
 	if(arrowSize < sqrt(std::numeric_limits<float>::epsilon()) || !drawArrow)
 	{
-		glVertex3f(origin[0],origin[1],origin[2]);
 		glVertex3f(vector[0]+origin[0],vector[1]+origin[1],vector[2]+origin[2]);
 		glEnd();
-		
 		//restore the old line size
 		glLineWidth(oldLineWidth);
-		
 		glPopAttrib();
 		return ;
 	}
-	else
-	{
-
-		glVertex3f(origin[0],origin[1],origin[2]);
-
-		
-		glVertex3f(vector[0]+origin[0],vector[1]+origin[1],vector[2]+origin[2]);
-		glEnd();
-		//restore the old line size
-		glLineWidth(oldLineWidth);
-		
-		glPopAttrib();
-	}
+	glVertex3f(vector[0]+origin[0],vector[1]+origin[1],vector[2]+origin[2]);
+	glEnd();
+	//restore the old line size
+	glLineWidth(oldLineWidth);
+	
+	glPopAttrib();
 
 
 
@@ -318,15 +337,15 @@ void DrawVector::draw() const
 	
 	//Now, having the needed coords, we can draw the cone
 	glBegin(GL_TRIANGLE_FAN);
-	glNormal3f(axis[0],axis[1],axis[2]);
+	glNormal3fv(axis.getValueArr());
 	glVertex3f(0,0,0);
 	for(unsigned int ui=0; ui<NUM_CONE_SEGMENTS; ui++)
 	{
 		Point3D n;
 		n=ptArray[ui];
 		n.normalise();
-		glNormal3f(n[0],n[1],n[2]);
-		glVertex3f(ptArray[ui][0],ptArray[ui][1],ptArray[ui][2]);
+		glNormal3fv(n.getValueArr());
+		glVertex3fv(ptArray[ui].getValueArr());
 	}
 
 	glEnd();
@@ -336,7 +355,7 @@ void DrawVector::draw() const
 	glBegin(GL_TRIANGLE_FAN);
 	glNormal3f(-axis[0],-axis[1],-axis[2]);
 	for(unsigned int ui=NUM_CONE_SEGMENTS; ui--;) 
-		glVertex3f(ptArray[ui][0],ptArray[ui][1],ptArray[ui][2]);
+		glVertex3fv(ptArray[ui].getValueArr());
 	glEnd();
 
 	glPopMatrix();
@@ -406,15 +425,151 @@ void DrawTriangle::draw() const
 {
 	glColor4f(r,g,b,a);
 	glBegin(GL_TRIANGLES);
-		glVertex3f((vertices[0])[0],
-			(vertices[0])[1], (vertices[0])[2]);
-		glVertex3f((vertices[1])[0],
-			(vertices[1])[1], (vertices[1])[2]);
-		glVertex3f((vertices[2])[0],
-			(vertices[2])[1], (vertices[2])[2]);
+		for(size_t ui=0;ui<3;ui++)
+			glVertex3fv(vertices[ui].getValueArr());
 	glEnd();
 }
 
+void DrawQuad::getBoundingBox(BoundCube &b) const
+{
+	b.setBounds(vertices,4);
+}
+
+void DrawQuad::draw() const
+{
+	ASSERT(false);
+}
+
+void DrawQuad::setVertices(const Point3D *v) 
+{
+	for(size_t ui=0;ui<4;ui++)
+		vertices[ui]=v[ui];
+}
+
+Point3D DrawQuad::getOrigin() const
+{
+	return Point3D::centroid(vertices,4);
+}
+
+void DrawQuad::recomputeParams(const vector<Point3D> &vecs, 
+			const vector<float> &scalars, unsigned int mode)
+{
+	switch(mode)
+	{
+		case DRAW_QUAD_BIND_ORIGIN:
+		{
+			ASSERT(vecs.size() ==1 && scalars.size() ==0);
+			
+			Point3D curOrig=getOrigin();
+
+			Point3D delta = vecs[0]-curOrig;
+
+			for(size_t ui=0;ui<4;ui++)
+				vertices[ui]+=delta;
+
+
+			break;
+		}
+		default:
+			ASSERT(false);
+	}
+}
+
+DrawTexturedQuad::DrawTexturedQuad() :textureData(0), textureId((unsigned int)-1)
+{
+}
+
+DrawTexturedQuad::~DrawTexturedQuad()
+{
+	if(textureData)
+		delete[] textureData;
+
+	texPool->closeTexture(textureId);
+}
+
+void DrawTexturedQuad::draw() const
+{
+	ASSERT(glIsTexture(textureId));
+	
+	glEnable(GL_TEXTURE_2D);
+	glBindTexture(GL_TEXTURE_2D,textureId);
+	glPushAttrib(GL_CULL_FACE);
+	glDisable(GL_CULL_FACE);
+	
+	
+	glBindTexture(GL_TEXTURE_2D,textureId);
+
+	glColor4f(1.0f,1.0f,1.0f,1.0f);
+	const float COORD_SEQ_X[]={ 0,0,1,1};
+	const float COORD_SEQ_Y[]={ 0,1,1,0};
+	glBegin(GL_QUADS);
+		for(size_t ui=0;ui<4;ui++)
+		{
+			glTexCoord2f(COORD_SEQ_X[ui],COORD_SEQ_Y[ui]);
+			glVertex3fv(vertices[ui].getValueArr());
+		}
+	glEnd();
+
+	glPopAttrib();
+	glDisable(GL_TEXTURE_2D);	
+}
+
+//Call sequence
+// - resize destination for texture
+// - set texture by pixels
+// - rebind texture
+void DrawTexturedQuad::resize(size_t numX, size_t numY, 
+					unsigned int nChannels)
+{
+	//reallocate texture as required
+	if(textureData)
+	{
+		if( numX*numY*nChannels != nX*nY*channels)
+		{
+			delete[] textureData;
+			textureData = new unsigned char[numX*numY*nChannels];
+		}
+	}
+	else
+		textureData = new unsigned char[numX*numY*nChannels];
+
+	nX=numX;
+	nY=numY;
+	channels=nChannels;
+
+}
+
+void DrawTexturedQuad::rebindTexture()
+{
+	ASSERT(texPool);
+	ASSERT(textureData);
+	if(textureId == -1)
+		texPool->genTexID(textureId);
+	
+	//Construc the texture
+	glBindTexture(GL_TEXTURE_2D,textureId);
+	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 
+	ASSERT(channels == 3);
+
+	glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,nX,nY,
+		0,GL_RGB,GL_UNSIGNED_BYTE,textureData);
+
+
+
+}
+
+void DrawTexturedQuad::setData(size_t x, size_t y, unsigned char *entry)
+{
+	ASSERT(textureData);
+	ASSERT(channels == 3);
+
+	for(size_t ui=0;ui<channels;ui++)
+		textureData[(y*nX + x)*channels + ui] = entry[ui]; 	
+}
+
 
 DrawSphere::DrawSphere() : radius(1.0f), latSegments(8),longSegments(8)
 {
@@ -544,7 +699,7 @@ void DrawCylinder::draw() const
 	if(!q || !qCap[0] || !qCap[1])
 		return;
 
-	//Cross product desired direction with default
+	//Cross product desired drection with default
 	//direction to produce rotation vector
 	Point3D dir(0.0f,0.0f,1.0f);
 
@@ -687,8 +842,6 @@ DrawManyPoints::DrawManyPoints() : r(1.0f),g(1.0f),b(1.0f),a(1.0f), size(1.0f)
 
 DrawManyPoints::~DrawManyPoints() 
 {
-	wantsLight=false;
-	haveCachedBounds=false;
 }
 
 void DrawManyPoints::getBoundingBox(BoundCube &b) const
@@ -1068,7 +1221,7 @@ void DrawGLText::draw() const
 					//the text direction is now the x-axis
 					glTranslatef(advance/2.0f,halfHeight,0);
 					//spin text around its front direction 180 degrees
-					//no need to translate as text sits at its baseline
+					//no need to trnaslate as text sits at its baseline
 					glRotatef(180,0,0,1);
 					//move halfway along text, noting that 
 					//the text direction is now the x-axis
@@ -1329,15 +1482,13 @@ void DrawRectPrism::recomputeParams(const vector<Point3D> &vecs,
 	}
 }
 
-DrawTexturedQuadOverlay::DrawTexturedQuadOverlay() : texPool(0)
+DrawTexturedQuadOverlay::DrawTexturedQuadOverlay()  
 {
 }
 
 DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay()
 {
-#ifdef DEBUG
-	textureOK=false;
-#endif
+	texPool->closeTexture(textureId);
 }
 
 void DrawTexturedQuadOverlay::setSize(float s)
@@ -1364,6 +1515,7 @@ void DrawTexturedQuadOverlay::draw() const
 
 	glEnable(GL_TEXTURE_2D);
 	glBindTexture(GL_TEXTURE_2D,textureId);
+	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
 	
 	// Draw overlay quad 
 	glColor3f(1.0f,1.0f,1.0f);
@@ -1393,9 +1545,7 @@ void DrawTexturedQuadOverlay::draw() const
 bool DrawTexturedQuadOverlay::setTexture(const char *textureFile)
 {
 	ASSERT(texPool);	
-	unsigned int dummy;
-
-	textureOK= texPool->openTexture(textureFile,textureId,dummy);
+	textureOK= texPool->openTexture(textureFile,textureId);
 	return textureOK;
 }
 
@@ -1404,6 +1554,104 @@ void DrawTexturedQuadOverlay::getBoundingBox(BoundCube &b) const
 	b.setInvalid();
 }
 
+DrawAnimatedOverlay::DrawAnimatedOverlay()
+{
+	fadeIn=0.0f;
+	delayBeforeShow=0.0f;
+	textureOK=false;
+	resetTime();
+}
+
+DrawAnimatedOverlay::~DrawAnimatedOverlay()
+{
+}
+
+void DrawAnimatedOverlay::resetTime()
+{
+	gettimeofday(&animStartTime,NULL);
+}
+
+bool DrawAnimatedOverlay::setTexture(const vector<string> &texFiles,
+			float replayTime)
+{
+	repeatInterval=replayTime;
+
+	textureOK=texPool->openTexture3D(texFiles, textureId);
+	return textureOK;
+}
+
+void DrawAnimatedOverlay::setSize(float newLen)
+{
+	length=newLen;
+}
+
+
+void DrawAnimatedOverlay::draw() const
+{
+	if(!textureOK)
+		return;
+
+	float texCoordZ;
+	float alphaVal=1.0f;
+	{
+	timeval t;
+	gettimeofday(&t,NULL);
+	float animDeltaTime=(float)(t.tv_sec - animStartTime.tv_sec) +
+		(t.tv_usec-animStartTime.tv_usec)/1.0e6;
+
+	//Skip if we wish to show later
+	if(animDeltaTime < delayBeforeShow)
+		return;
+
+
+	if(fadeIn > 0.0f && (delayBeforeShow + fadeIn > animDeltaTime) ) 
+		alphaVal= (animDeltaTime - delayBeforeShow )/(fadeIn) ;
+
+	texCoordZ=fmod(animDeltaTime,repeatInterval);
+	texCoordZ/=repeatInterval;
+	}
+	ASSERT(glIsTexture(textureId));
+	
+	glMatrixMode(GL_PROJECTION);	
+	glPushMatrix();
+	glLoadIdentity();
+	gluOrtho2D(0, winX, winY, 0);
+
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadIdentity();
+
+	glEnable(GL_TEXTURE_3D);
+	glBindTexture(GL_TEXTURE_3D,textureId);
+	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MULT); 
+	
+	// Draw overlay quad 
+	glColor4f(1.0f,1.0f,1.0f,alphaVal);
+	glBegin(GL_QUADS);
+		glTexCoord3f(0.0f,0.0f,texCoordZ);
+		glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0);
+		glTexCoord3f(0.0f,1.0f,texCoordZ);
+		glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0);
+		glTexCoord3f(1.0f,1.0f,texCoordZ);
+		glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0);
+		glTexCoord3f(1.0f,0.0f,texCoordZ);
+		glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0);
+	glEnd();
+
+	glDisable(GL_TEXTURE_3D);	
+
+	glPopMatrix(); //Pop modelview matrix
+
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+
+	glMatrixMode(GL_MODELVIEW);
+}
+
+void DrawAnimatedOverlay::getBoundingBox(BoundCube &b) const
+{
+	b.setInvalid();
+}
 
 DrawColourBarOverlay::DrawColourBarOverlay() 
 {
@@ -1487,7 +1735,6 @@ void DrawColourBarOverlay::draw() const
 	//to 1 opengl unit by inversion 
 	const float FTGL_DEFAULT_UNIT_SCALE=1.0/72.0;
 
-	glColor3f(1.0f,1.0f,1.0f);	
 	font->FaceSize(3);
 	glDisable(GL_CULL_FACE);
 	glPushMatrix();
@@ -1627,7 +1874,7 @@ void DrawField3D::draw() const
 				ptsCacheOK=true;
 			}
 
-			if(alphaVal < 1.0f)
+			if(alphaVal < 1.0f && useAlphaBlend)
 			{
 				//We need to generate some points, then sort them by distance
 				//from eye (back to front), otherwise they will not blend properly
@@ -1662,7 +1909,7 @@ void DrawField3D::draw() const
 							((float)(ptsCache[idx].second.v[1]))/255.0f,
 							((float)(ptsCache[idx].second.v[2]))/255.0f, 
 							alphaVal);
-					glVertex3f(ptsCache[idx].first[0],ptsCache[idx].first[1],ptsCache[idx].first[2]);
+					glVertex3fv(ptsCache[idx].first.getValueArr());
 				}
 				glEnd();
 				glDepthMask(GL_TRUE);
@@ -1678,7 +1925,7 @@ void DrawField3D::draw() const
 							((float)(ptsCache[ui].second.v[1]))/255.0f,
 							((float)(ptsCache[ui].second.v[2]))/255.0f, 
 							1.0f);
-					glVertex3f(ptsCache[ui].first[0],ptsCache[ui].first[1],ptsCache[ui].first[2]);
+					glVertex3fv(ptsCache[ui].first.getValueArr());
 				}
 				glEnd();
 			}
@@ -1693,8 +1940,15 @@ void DrawField3D::draw() const
 	//Draw the bounding box as required
 	if(drawBoundBox)
 	{
+		float alphaUse;
+
+		if(useAlphaBlend)
+			alphaUse=boxColourA;
+		else
+			alphaUse=1.0f;
+		
 		drawBox(field->getMinBounds(),field->getMaxBounds(),
-			boxColourR, boxColourG,boxColourB,boxColourA);
+			boxColourR, boxColourG,boxColourB,alphaUse);
 	}
 	//Draw the projections
 }
@@ -1790,7 +2044,7 @@ void DrawIsoSurface::draw() const
 
 	//This could be optimised by using triangle strips
 	//rather than direct triangles.
-	if(a < 1.0f)
+	if(a < 1.0f && useAlphaBlend )
 	{
 		//We need to sort them by distance
 		//from eye (back to front), otherwise they will not blend properly
diff --git a/src/gl/drawables.h b/src/gl/drawables.h
index f8f2dbc..787083b 100644
--- a/src/gl/drawables.h
+++ b/src/gl/drawables.h
@@ -35,6 +35,8 @@
 	#include <GL/glu.h>
 #endif
 
+#include <sys/time.h>
+
 //TODO: Work out if there is any way of obtaining the maximum 
 //number of items that can be drawn in an opengl context
 //For now Max it out at 10 million (~120MB of vertex data)
@@ -42,7 +44,7 @@ const size_t MAX_NUM_DRAWABLE_POINTS=10;
 
 
 //OK, the new FTGL is fucked up. It actually uses defines from
-//freetype  as arguments to #includes. Wierd. So this sequence is important
+//freetype  as arguments to #includes. Weird. So this sequence is important
 #include <ft2build.h>
 #include <FTGL/ftgl.h>
 
@@ -96,11 +98,13 @@ enum
 	DRAW_TYPE_RECTPRISM,
 	DRAW_TYPE_COLOURBAR,
 	DRAW_TYPE_TEXTUREDOVERLAY,
+	DRAW_TYPE_ANIMATEDOVERLAY,
 	DRAW_TYPE_FIELD3D,
 	DRAW_TYPE_ISOSURFACE,
 	DRAW_TYPE_AXIS,
 };
 
+//TODO: It seems unneccesary to have multiple types for the bind
 
 //!Binding enums. Needed to bind drawable selection
 //to internal modification actions inside the drawable
@@ -118,6 +122,8 @@ enum
 	DRAW_RECT_BIND_TRANSLATE,
 	DRAW_RECT_BIND_CORNER_MOVE,
 	DRAW_TEXT_BIND_ORIGIN,
+
+	DRAW_QUAD_BIND_ORIGIN,
 	//DRAW_TEXT_BIND_TEXTDIR, //FIXME: Implement me for annotation todo.
 	//DRAW_TEXT_BIND_UPDIR,
 	DRAW_BIND_ENUM_END
@@ -125,6 +131,7 @@ enum
 
 
 
+
 //!An abstract bas class for drawing primitives
 class DrawableObj
 {
@@ -136,7 +143,12 @@ class DrawableObj
 		bool haveChanged;
 		//!Pointer to current scene camera
 		static const Camera *curCamera;	
+		//Pointer to texture pool object
+		static TexturePool *texPool;
+
+		static bool useAlphaBlend;
 	
+		static unsigned int winX,winY;
 	public: 
 		//!Can be selected from openGL viewport interactively?
 		bool canSelect;
@@ -144,6 +156,9 @@ class DrawableObj
 		//!Wants lighting calculations active during render?
 		bool wantsLight;
 
+
+		static void setUseAlphaBlending(bool willBlend) { useAlphaBlend =willBlend;}
+
 		//!Is this an overlay? By default, no
 		virtual bool isOverlay() const { return false;}
 
@@ -155,6 +170,7 @@ class DrawableObj
 		//!Do we need to do element based depth sorting?
 		virtual bool needsDepthSorting() const { return false; } ;
 
+	
 
 		//!Can we break this object down into constituent elements?
 		virtual bool isExplodable() const { return false;};
@@ -182,11 +198,14 @@ class DrawableObj
 		
 		//!Set the current camera
 		static void setCurCamera(const Camera *c){curCamera=c;};
+		//!Set the current camera
+		static void setTexPool(TexturePool *t);
+		static void clearTexPool();
 
 		//!Get the centre of the object. Only valid if object is simple
 		virtual Point3D getCentroid() const  ;
 
-	//	virtual DrawableObj *clone() const;
+		static void setWindowSize(unsigned int x, unsigned int y){winX=x;winY=y;};	
 
 };
 
@@ -372,6 +391,9 @@ class DrawTriangle : public DrawableObj
 class DrawQuad : public DrawableObj
 {
 	private:
+		//!Colours of the vertices (rgba colour model)
+		float r[4],g[4],b[4],a[4];
+	protected:
 		//!Vertices of the quad
 		Point3D vertices[4];
 
@@ -380,19 +402,21 @@ class DrawQuad : public DrawableObj
 		/*! Lighting for this class is per triangle only no
 		 * per vertex lighting */
 		Point3D normal;
-		//!Colours of the vertices (rgba colour model)
-		float r[4],g[4],b[4],a[4];
 	public:
 		//!Constructor
-		DrawQuad();
+		DrawQuad() {};
 		//!Destructor
-		virtual ~DrawQuad();
+		virtual ~DrawQuad() {};
 		
 		virtual unsigned int getType() const {return DRAW_TYPE_QUAD;};	
+
+		//!Get bounding cube
+		virtual void getBoundingBox(BoundCube &b) const ;
 		//!sets the vertices to defautl colours (r g b and white ) for each vertex respectively
 		void colourVerticies();
 		//!Set vertex's location
 		void setVertex(unsigned int, const Point3D &);
+		void setVertices(const Point3D *);
 		//!Set the colour of a vertex
 		void setColour(unsigned int, float r, float g, float b, float a);
 		//!Update the normal to the surface from vertices
@@ -401,8 +425,114 @@ class DrawQuad : public DrawableObj
 		void calcNormal();
 		//!Draw the triangle
 		void draw() const;
-		//!Get bounding cube
-		void getBoundingBox(BoundCube &b) const { return b.setBounds(vertices,4);}
+		
+		//!Gets the arrow axis direction
+		Point3D getOrigin() const;
+		
+		//!Recompute the internal parameters using the input vector information
+		// i.e. this is used for (eg) mouse interaction
+		void recomputeParams(const vector<Point3D> &vecs, 
+				const vector<float> &scalars, unsigned int mode);
+};
+
+class DrawTexturedQuad : public DrawQuad
+{
+	//TODO: Move this back
+	// into the texture pool
+		unsigned char *textureData;
+		size_t nX,nY;
+		size_t channels;
+		size_t displayMode;
+
+		//ID of the texture to use when drawing, -1 if not bound
+		// to opengl
+		unsigned int textureId;
+		
+	public:
+		DrawTexturedQuad();
+		~DrawTexturedQuad();
+
+		//Resize the texture contents, destroying any existing contents
+		void resize(size_t nx, size_t nY, unsigned int nChannels);
+		//Draw the texture
+		void draw() const;
+		//Set the specified pixel in the texture to this value 
+		void setData(size_t x, size_t y, unsigned char *entry);
+		//Send the texture to the video card. 
+		void rebindTexture();	
+};
+
+
+class DrawAnimatedOverlay : public DrawQuad
+{
+	private:
+		size_t nX,nY,nZ;
+
+		//ID of the texture to use when drawing, -1 if not bound
+		// to opengl
+		unsigned int textureId;
+
+		float position[2];
+
+		timeval animStartTime;
+
+		bool textureOK;
+
+		//Time delta before repeating animation
+		float repeatInterval;
+		
+		//Length to use for the quad to represent icon
+		float length;
+
+		//Time before showing the image
+		float delayBeforeShow;
+
+		//Time for fadein after show
+		float fadeIn;
+
+	public:
+		DrawAnimatedOverlay();
+		~DrawAnimatedOverlay();
+
+		virtual unsigned int getType() const {return DRAW_TYPE_ANIMATEDOVERLAY;}
+
+		//!This is an overlay
+		bool isOverlay() const {return true;};
+
+
+		//!Set the texture position in XY (z is ignored)
+		void setPos(float xp,float yp)
+		{
+			position[0]=xp;
+			position[1]=yp;
+		};
+
+		void setSize(float size);
+
+		//Set the time between repeats for the animation
+		void setRepeatTime(float timeV) { repeatInterval=timeV;}
+
+		//Set the time before the texture appears
+		void setShowDelayTime(float showDelayTime) 
+			{ ASSERT(showDelayTime >=0.0f);  delayBeforeShow = showDelayTime;}
+
+		//Set the time during which the alpha value will be ramped up.
+		// activated after the delay time (ie time before 100% visible is fadeInTime + 
+		//	delayTime.
+		void setFadeInTime(float fadeInTime)
+			{ ASSERT(fadeInTime >=0.0f); fadeIn=fadeInTime;}
+
+		//!Set the texture by name
+		bool setTexture(const vector<string> &textureFiles, float timeRepeat=1.0f);
+
+		void resetTime() ;
+
+		//!Draw object
+		void draw() const;
+
+		void getBoundingBox(BoundCube &b) const ;
+
+		bool isOK() const { return textureId != (unsigned int)-1; }
 };
 
 //!A sphere drawing 
@@ -798,11 +928,12 @@ class DrawColourBarOverlay : public DrawableObj
 class DrawTexturedQuadOverlay : public DrawableObj
 {
 	private:
-		TexturePool *texPool;
 		unsigned int textureId;
+		//Fractional coordinates for the 
 		float position[2];
+	
+		//Length of the rectangle to use for the icon
 		float length;
-		unsigned int winX,winY;
 
 		bool textureOK;
 	public:
@@ -814,7 +945,7 @@ class DrawTexturedQuadOverlay : public DrawableObj
 		//!This is an overlay
 		bool isOverlay() const {return true;};
 	
-		void setWindowSize(unsigned int x, unsigned int y){winX=x;winY=y;};	
+		static void setWindowSize(unsigned int x, unsigned int y){winX=x;winY=y;};	
 
 		//!Set the texture position in XY (z is ignored)
 		void setPos(float xp,float yp){position[0]=xp; position[1]=yp;};
@@ -824,8 +955,6 @@ class DrawTexturedQuadOverlay : public DrawableObj
 		//!Set the texture by name
 		bool setTexture(const char *textureFile);
 
-		//!Set the texture pool pointer
-		void setTexturePool(TexturePool *p) { texPool =p;};
 
 		//!Draw object
 		void draw() const;
diff --git a/src/gl/effect.cpp b/src/gl/effect.cpp
index b3168b2..0123625 100644
--- a/src/gl/effect.cpp
+++ b/src/gl/effect.cpp
@@ -25,6 +25,16 @@
 #include "common/stringFuncs.h"
 #include "common/constants.h"
 
+//OpenGL includes
+//MacOS is "special" and puts it elsewhere
+#ifdef __APPLE__ 
+	#include <OpenGL/glu.h>
+#else
+	#include <GL/glu.h>
+#endif
+
+
+
 Camera* Effect::curCam=0;
 BoundCube Effect::bc;
 float MIN_CROP_FRACTION=0.0001;
@@ -101,11 +111,20 @@ std::string Effect::getName() const
 	return EFFECT_NAMES[this->getType()];
 }
 
+
 BoxCropEffect::BoxCropEffect() : openGLIdStart(0), useCamCoordinates(false)
 {
 	effectType=EFFECT_BOX_CROP;
 }
 
+Effect *BoxCropEffect::clone() const
+{
+	Effect *e = new BoxCropEffect;
+
+	*e=*this;
+	return e;
+}
+
 void BoxCropEffect::enable(unsigned int pass) const
 {
 
@@ -481,6 +500,14 @@ AnaglyphEffect::AnaglyphEffect() : colourMode(ANAGLYPH_REDBLUE), eyeFlip(false),
 	effectType=EFFECT_ANAGLYPH;
 }
 
+Effect *AnaglyphEffect::clone() const
+{
+	Effect *e = new AnaglyphEffect;
+
+	*e=*this;
+	return e;
+}
+
 void AnaglyphEffect::enable(unsigned int passNumber) const
 {
 	if(passNumber >1 || curCam->type() !=CAM_LOOKAT) 
@@ -488,6 +515,7 @@ void AnaglyphEffect::enable(unsigned int passNumber) const
 
 	if(passNumber==0)
 	{
+		ASSERT(!oldCam);
 		oldCam=curCam->clone();
 		//Translate both the target, and the origin
 		curCam->translate(baseShift,0);
@@ -505,81 +533,34 @@ void AnaglyphEffect::enable(unsigned int passNumber) const
 		((CameraLookAt*)curCam)->setFrustumDistort(-baseShift);
 	}
 
-	if(colourMode<=ANAGLYPH_GREENMAGENTA)
-	{
-		//Different type of glasses use different colour masks.
-		const bool maskArray[][6] = { {true,false,false,false,false,true}, //Red-blue
-						{true,false,false,false,true,false}, //red-green
-						{true,false,false,false,true,true}, // red-cyan
-						{false,true,false,true,false,true} //green-magenta
-					};
-		
-		//Colour buffer masking method
-		if(passNumber == 0)
-		{
-			glClear(GL_COLOR_BUFFER_BIT );
-		}	
-		else
-			glClear(GL_DEPTH_BUFFER_BIT);
 
+	//Different type of glasses use different colour masks.
+	const bool maskArray[][6] = { {true,false,false,false,false,true}, //Red-blue
+					{true,false,false,false,true,false}, //red-green
+					{true,false,false,false,true,true}, // red-cyan
+					{false,true,false,true,false,true} //green-magenta
+				};
+	
+	//Colour buffer masking method
+	if(passNumber == 0)
+	{
+		glClear(GL_COLOR_BUFFER_BIT );
+	}	
+	else
+		glClear(GL_DEPTH_BUFFER_BIT);
 
-		//we flip either due to the pass, or because the user has
-		//back to front glasses.
-		unsigned int offset;
-		if(passNumber ^ eyeFlip)
-			offset=0;
-		else
-			offset=3;
-		unsigned int idx = colourMode-ANAGLYPH_REDBLUE;
 
-		glColorMask(maskArray[idx][offset],maskArray[idx][offset+1],
-				maskArray[idx][offset+2],true);
-	}
+	//we flip either due to the pass, or because the user has
+	//back to front glasses.
+	unsigned int offset;
+	if(passNumber ^ eyeFlip)
+		offset=0;
 	else
-	{
-		ASSERT(false);
-		//Accumulation mode
-		if(passNumber==0)
-		{
-			//clear accumulation buffer
-			glClear(GL_ACCUM_BUFFER_BIT);
-		}
-		else
-		{
-			//Set up a colour transfer matrix for the accumulation buffer
-			glMatrixMode(GL_COLOR);
+		offset=3;
+	unsigned int idx = colourMode-ANAGLYPH_REDBLUE;
 
-			float *leftEyeMatrix;
-			if(eyeFlip)
-				leftEyeMatrix=gbMatrix;
-			else
-			{
-				switch(colourMode)
-				{
-					case ANAGLYPH_MIXED:
-						leftEyeMatrix=mixedMatrix;
-						break;
-					case ANAGLYPH_HALF_COLOUR:
-						leftEyeMatrix=halfMatrix;
-						break;
-					default:
-						ASSERT(false);
-				}
-			}	
-
-			glPushMatrix();
-			glLoadMatrixf(leftEyeMatrix);
-
-			//Copy current draw matrix to the accumulation buffer
-			glAccum(GL_ACCUM,1.0);
-
-			glPopMatrix();
-			glMatrixMode(GL_MODELVIEW);
-
-			glClear(GL_DEPTH_BUFFER_BIT);
-		}
-	
-	}
+	glColorMask(maskArray[idx][offset],maskArray[idx][offset+1],
+			maskArray[idx][offset+2],true);
 
 	
 
@@ -594,59 +575,16 @@ void AnaglyphEffect::setMode(unsigned int mode)
 
 void AnaglyphEffect::disable() const
 {
-	if(colourMode<=ANAGLYPH_GREENMAGENTA)
-	{
-		//disable the colour mask
-		glColorMask(true,true,true,true);
-	}
-	else
-	{
-		ASSERT(false);
-		//FIXME: Does not work as advertised. You cannot retrieve
-		//the off-diagonal terms without using a shader, to the
-		//best of my knowledge. The on-diagonal terms can be altered
-		//however.
-	
-		//Mix with accumulation buffer, using the
-		//right hand colour mask then restore to 
-		//draw buffer
-		glMatrixMode(GL_COLOR);
-		glPushMatrix();
-
-		float *rightEyeMatrix=gbMatrix;
-		if(eyeFlip)
-		{
-			switch(colourMode)
-			{
-				case ANAGLYPH_MIXED:
-					rightEyeMatrix=mixedMatrix;
-					break;
-				case ANAGLYPH_HALF_COLOUR:
-					rightEyeMatrix=halfMatrix;
-					break;
-				default:
-					ASSERT(false);
-			}	
-
-		}
-		else
-			rightEyeMatrix=gbMatrix;	
-		
-		glLoadMatrixf(rightEyeMatrix);
-		//Mix result with accumulation buffer then restore
-		glAccum(GL_ACCUM,1.0);
-		glAccum(GL_RETURN,1.0);
-		//reset the colour matrix
-		glPopMatrix();
-
-		glMatrixMode(GL_MODELVIEW);
-		glClear(GL_ACCUM_BUFFER_BIT);
-	}
+	//disable the colour mask
+	glColorMask(true,true,true,true);
 
 
 	ASSERT(oldCam);
 	*curCam=*oldCam;
 	delete oldCam;
+#ifdef DEBUG
+	oldCam=0;
+#endif
 }
 
 bool AnaglyphEffect::writeState(std::ofstream &f, unsigned int format,unsigned int depth) const
diff --git a/src/gl/effect.h b/src/gl/effect.h
index 7b0e54c..0b1b22d 100644
--- a/src/gl/effect.h
+++ b/src/gl/effect.h
@@ -28,14 +28,6 @@
 	#undef ATTRIBUTE_PRINTF
 #endif
 
-//OpenGL includes
-//MacOS is "special" and puts it elsewhere
-#ifdef __APPLE__ 
-	#include <OpenGL/glu.h>
-#else
-	#include <GL/glu.h>
-#endif
-
 #include "cameras.h"
 
 //opengl allows up to 6 clipping planes
@@ -71,6 +63,8 @@ class Effect
 	public:
 		Effect();
 		virtual ~Effect() {};
+
+		virtual Effect *clone() const = 0;
 		virtual void enable(unsigned int pass=0) const =0;
 		virtual void disable() const=0;
 		std::string getName() const;
@@ -115,6 +109,10 @@ class BoxCropEffect : public Effect
 		BoxCropEffect();
 		virtual ~BoxCropEffect(){}; 
 
+
+		//Duplicate thi
+		Effect *clone() const;
+
 		//!Enable the clipping plane. Values *must* be set before calling
 		void enable(unsigned int pass) const;
 
@@ -159,6 +157,8 @@ class AnaglyphEffect : public Effect
 	public:
 		AnaglyphEffect();
 		~AnaglyphEffect(){}; 
+		//Duplicate thi
+		Effect *clone() const;
 
 		//!Enable the clipping plane. Values *must* be set before calling
 		void enable(unsigned int pass) const;
diff --git a/src/gl/isoSurface.cpp b/src/gl/isoSurface.cpp
index 33915af..0e4714b 100644
--- a/src/gl/isoSurface.cpp
+++ b/src/gl/isoSurface.cpp
@@ -492,7 +492,7 @@ void marchingCubes(const Voxels<float> &v,float isoValue, vector<TriangleWithVer
 
 	vector<TriangleWithIndexedVertices> indexedTriVec;
 
-	//Loop over the vertices, with the mesh such that the 
+	//Loop over the vertexs, with the mesh such that the 
 	//nominally cube centres are now on a grid that is dual
 	//to the original grid (excluding the external boundary of course)
 #pragma omp parallel for
diff --git a/src/gl/scene.cpp b/src/gl/scene.cpp
index abd38af..adf35d3 100644
--- a/src/gl/scene.cpp
+++ b/src/gl/scene.cpp
@@ -16,13 +16,26 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "scene.h"
+#if defined(WIN32) || defined(WIN64)
+#include <GL/glew.h>
+#endif
 
+#include "scene.h"
 
+#include "./backend/viscontrol.h"
+#include "./backend/filter.h"
 
 using std::vector;
 
-Scene::Scene() : tempCam(0), activeCam(0), cameraSet(false), outWinAspect(1.0f), r(0.0f), g(0.0f), b(0.0f)
+
+//
+const char ANIMATE_PROGRESS_BASENAME[] = {
+	"textures/animProgress"};
+unsigned int ANIMATE_PROGRESS_NUMFRAMES=3;
+
+
+
+Scene::Scene() : tempCam(0), cameraSet(true), outWinAspect(1.0f), r(0.0f), g(0.0f), b(0.0f)
 {
 	lastHovered=lastSelected=(unsigned int)(-1);
 	lockInteract=false;
@@ -32,21 +45,44 @@ Scene::Scene() : tempCam(0), activeCam(0), cameraSet(false), outWinAspect(1.0f),
 	useLighting=true;
 	useEffects=false;
 	showAxis=true;
+	attemptedLoadProgressAnim=false;
+	showProgressAnimation=false;
 
 	//default to black
 	rBack=gBack=bBack=0.0f;
 
+	activeCam = new CameraLookAt;
+
+	//Initialise GLEW
+#if defined(WIN32) || defined(WIN64)
+	if(glewInit())
+	{
+		cerr << "Opengl context could not be created, aborting." << endl;
+		//Blow up without opengl
+		exit(1);
+	}
+#endif
+
+
+	DrawableObj::setTexPool(new TexturePool);
+
 }
 
 Scene::~Scene()
 {
 	clearAll();
+	DrawableObj::clearTexPool();
 }
 
 unsigned int Scene::initDraw()
 {
 	glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);
 
+	//Will it blend? That is the question...
+	// let the objects know about this, so they
+	// can pick the right algorithm
+	DrawableObj::setUseAlphaBlending(useAlpha);
+	
 	if(useAlpha)
 		glEnable(GL_BLEND);
 	else
@@ -66,9 +102,6 @@ unsigned int Scene::initDraw()
 	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
 
 
-
-
-	glDisable(GL_LIGHTING);
 	//==
 	
 	//Use the active if set 
@@ -79,7 +112,27 @@ unsigned int Scene::initDraw()
 
 	}
 
+	//Attempt to load the progress animation, if we have not tried before
+	if(!attemptedLoadProgressAnim)
+	{
+		attemptedLoadProgressAnim=true;
 
+		//Load the animation textures
+		vector<string> animFiles;
+		animFiles.resize(ANIMATE_PROGRESS_NUMFRAMES);
+		string animFilename,tmpStr;
+		for(size_t ui=0;ui<ANIMATE_PROGRESS_NUMFRAMES;ui++)
+		{
+			animFilename=ANIMATE_PROGRESS_BASENAME;
+			stream_cast(tmpStr,ui);
+			animFilename+=tmpStr + string(".png");
+			animFiles[ui]=animFilename;
+		}
+
+		progressAnimTex.setTexture(animFiles);
+
+		updateProgressOverlay();
+	}
 
 	//Let the effects objects know about the scene
 	Effect::setBoundingCube(boundCube);
@@ -117,6 +170,18 @@ void Scene::updateCam(const Camera *camToUse) const
 
 }
 
+void Scene::updateProgressOverlay()
+{
+	progressAnimTex.setPos(0.9*winX,0.9*winY);
+	progressAnimTex.setSize(0.1*winX);
+	//Cycle every this many seconds
+	progressAnimTex.setRepeatTime(6.0f);
+	//Ramp opacity for this long (seconds)
+	progressAnimTex.setFadeInTime(1.0f);
+	//Don't show the animation until this many sceonds
+	progressAnimTex.setShowDelayTime(1.0f);
+}
+
 void Scene::draw() 
 {
 
@@ -127,12 +192,10 @@ void Scene::draw()
 	if(tempCam)
 		camToUse=tempCam;
 	else
-	{
-		ASSERT(activeCam < cameras.size());
-		camToUse=cameras[activeCam];
-	}
+		camToUse=activeCam;
 	//Inform text about current camera, so it can billboard if needed
 	DrawableObj::setCurCamera(camToUse);
+	DrawableObj::setWindowSize(winX,winY);
 	Effect::setCurCam(camToUse);
 
 
@@ -224,6 +287,9 @@ void Scene::draw()
 		drawHoverOverlay();
 	drawOverlays();
 
+	//Draw progress, if needed
+	drawProgressAnim();
+
 }
 
 void Scene::drawObjectVector(const vector<const DrawableObj*> &drawObjs, bool &lightsOn, bool drawOpaques) const
@@ -365,16 +431,8 @@ void Scene::drawHoverOverlay()
 
 
 		const float ICON_SIZE= 0.05;
-		binderIcons.setTexturePool(&texPool);
-		binderIcons.setWindowSize(winX,winY);	
 		binderIcons.setSize(ICON_SIZE*winY);
-		
-		mouseIcons.setTexturePool(&texPool);
-		mouseIcons.setWindowSize(winX,winY);	
 		mouseIcons.setSize(ICON_SIZE*winY);
-	
-		keyIcons.setTexturePool(&texPool);
-		keyIcons.setWindowSize(winX,winY);	
 		keyIcons.setSize(ICON_SIZE*winY);
 
 		unsigned int iconNum=0;
@@ -388,14 +446,14 @@ void Scene::drawHoverOverlay()
 				case BIND_MODE_FLOAT_SCALE:
 				case BIND_MODE_FLOAT_TRANSLATE:
 				case BIND_MODE_POINT3D_SCALE:
-					foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ENLARGE]);
+					foundIconTex=binderIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_ENLARGE]);
 					break;
 				case BIND_MODE_POINT3D_TRANSLATE:
-					foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_TRANSLATE]);
+					foundIconTex=binderIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_TRANSLATE]);
 					break;
 				case BIND_MODE_POINT3D_ROTATE:
 				case BIND_MODE_POINT3D_ROTATE_LOCK:
-					foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ROTATE]);
+					foundIconTex=binderIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_ROTATE]);
 				default:
 					break;
 			}
@@ -404,13 +462,13 @@ void Scene::drawHoverOverlay()
 			switch(binder[ui]->getMouseButtons())
 			{
 				case SELECT_BUTTON_LEFT:
-					foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_LEFT_CLICK]);
+					foundMouseTex=mouseIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_LEFT_CLICK]);
 					break;
 				case SELECT_BUTTON_MIDDLE:
-					foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_MIDDLE_CLICK]);
+					foundMouseTex=mouseIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_MIDDLE_CLICK]);
 					break;
 				case SELECT_BUTTON_RIGHT:
-					foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_RIGHT_CLICK]);
+					foundMouseTex=mouseIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_RIGHT_CLICK]);
 					break;
 				default:
 					//The flags are or'd together, so we can get other combinations
@@ -424,13 +482,13 @@ void Scene::drawHoverOverlay()
 			{
 				case FLAG_CMD:
 #ifdef __APPLE__
-					foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_COMMAND]);
+					foundKeyTex=keyIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_COMMAND]);
 #else
-					foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_CTRL]);
+					foundKeyTex=keyIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_CTRL]);
 #endif
 					break;
 				case FLAG_SHIFT:
-					foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_SHIFT]);
+					foundKeyTex=keyIcons.setTexture(TEXTURE_OVERLAY_PNG[TEXTURE_SHIFT]);
 					break;
 				default:
 					//The flags are or'd together, so we can get other combinations
@@ -473,11 +531,21 @@ void Scene::drawHoverOverlay()
 	glEnable(GL_DEPTH_TEST);
 }
 
+void Scene::drawProgressAnim() const
+{
+	if(!showProgressAnimation)
+		return;
+
+	if(!progressAnimTex.isOK())
+		return;
+
+	progressAnimTex.draw();
+}
 
 void Scene::commitTempCam()
 {
 	ASSERT(tempCam);
-	std::swap(cameras[activeCam], tempCam);
+	std::swap(activeCam, tempCam);
 	delete tempCam;
 	tempCam=0;
 }
@@ -493,9 +561,9 @@ void Scene::setTempCam()
 	//If a temporary camera is not set, set one.
 	//if it is set, update it from the active camera
 	if(!tempCam)
-		tempCam =cameras[activeCam]->clone();
+		tempCam =activeCam->clone();
 	else
-		*tempCam=*cameras[activeCam];
+		*tempCam=*activeCam;
 }
 
 void Scene::addDrawable(DrawableObj const *obj )
@@ -526,7 +594,6 @@ void Scene::clearAll()
 	clearObjs();
 	clearRefObjs();
 	clearBindings();	
-	clearCams();
 }
 
 void Scene::clearObjs()
@@ -545,47 +612,15 @@ void Scene::clearBindings()
 }
 
 
-void Scene::clearCams()
-{
-	for(unsigned int ui=0; ui<cameras.size(); ui++)
-		delete cameras[ui];
-
-	cameras.clear();
-	camIDs.clear();
-}
-
 void Scene::clearRefObjs()
 {
 	refObjects.clear();
 }
 
-
-unsigned int Scene::addCam(Camera *c)
-{
-	ASSERT(c);
-	ASSERT(cameras.size() == camIDs.size());
-	cameras.push_back(c);
-	unsigned int id = camIDs.genId(cameras.size()-1);
-
-	if(cameras.size() == 1)
-		setDefaultCam();
-	return id;
-}
-
-void Scene::removeCam(unsigned int camIDVal)
+void Scene::setShowProgress(bool show)
 {
-	unsigned int position = camIDs.getPos(camIDVal);
-	delete cameras[position];
-	cameras.erase(cameras.begin()+position);
-	camIDs.killByPos(position);
-
-	if(cameras.size())
-	{
-		activeCam=0;
-		cameraSet=true;
-	}
-	else
-		cameraSet=false;
+	showProgressAnimation=show;
+	progressAnimTex.resetTime();
 }
 
 
@@ -594,37 +629,12 @@ void Scene::setAspect(float newAspect)
 	outWinAspect=newAspect;
 }
 
-void Scene::setActiveCam(unsigned int idValue)
+void Scene::setActiveCamByClone(const Camera *c)
 {
-
 	if(tempCam)
 		discardTempCam();
 
-	unsigned int position = camIDs.getPos(idValue);
-	activeCam = position;
-	cameraSet=true;
-}
-
-void Scene::setDefaultCam(Camera *newCam, bool setAsActive)
-{
-	ASSERT(cameras.size() || newCam);
-
-	//If the scene is using a temporary camera
-	// (eg for animation or visual effects), discard it
-	if(tempCam)
-		discardTempCam();
-
-	//If we don't have a default camera, set one
-	if(cameras.size() && newCam)
-	{
-		if(newCam)
-			cameras[0] = newCam;
-	}
-	else if(newCam)
-		cameras.push_back(newCam);
-
-	if(setAsActive)
-		activeCam=0;
+	activeCam = c->clone();
 	cameraSet=true;
 }
 
@@ -633,7 +643,7 @@ void Scene::ensureVisible(unsigned int direction)
 {
 	computeSceneLimits();
 
-	cameras[activeCam]->ensureVisible(boundCube,direction);
+	activeCam->ensureVisible(boundCube,direction);
 }
 
 void Scene::computeSceneLimits()
@@ -668,7 +678,7 @@ void Scene::computeSceneLimits()
 		boundCube.setBounds(-0.5,-0.5,-0.5,
 					0.5,0.5,0.5);
 	}
-	//Now that we have a scene level bounding box,
+	//NOw that we have a scene level bounding box,
 	//we need to set the camera to ensure that
 	//this box is visible
 	ASSERT(boundCube.isValid());
@@ -687,8 +697,7 @@ void Scene::computeSceneLimits()
 
 Camera *Scene::getActiveCam()
 {
-	ASSERT(cameras.size());
-	return cameras[activeCam];
+	return activeCam;
 }
 
 Camera *Scene::getTempCam()
@@ -697,32 +706,6 @@ Camera *Scene::getTempCam()
 	return tempCam;
 }
 
-void Scene::getCamProperties(unsigned int uniqueID, CameraProperties &p) const
-{
-	unsigned int position=camIDs.getPos(uniqueID);
-	cameras[position]->getProperties(p);
-}
-
-void Scene::getCameraIDs(vector<std::pair<unsigned int, std::string> > &idVec) const
-{
-	std::vector<unsigned int> ids;
-	camIDs.getIds(ids);
-
-	idVec.resize(ids.size());
-	for(unsigned int ui=0;ui<ids.size(); ui++)
-	{
-		idVec[ui] = std::make_pair(ids[ui],
-			cameras[camIDs.getPos(ids[ui])]->getUserString());
-	}
-}
-
-bool Scene::setCamProperty(unsigned int uniqueID, unsigned int key,
-	       					const std::string &value) 
-{
-	unsigned int position=camIDs.getPos(uniqueID);
-	return cameras[position]->setProperty(key,value);
-}
-
 //Adapted from 
 //http://chadweisshaar.com/robotics/docs/html/_v_canvas_8cpp-source.html
 //GPLv3+ permission obtained by email inquiry.
@@ -734,7 +717,6 @@ unsigned int Scene::glSelect(bool storeSelected)
 	//Shouldn't be using a temporary camera.
 	//temporary cameras are only active during movement operations
 	ASSERT(!tempCam);
-	ASSERT(activeCam < cameras.size());
 	
 	
 	// Need to load a base name so that the other calls can replace it
@@ -749,7 +731,7 @@ unsigned int Scene::glSelect(bool storeSelected)
 	glPushMatrix();
 	//Apply the camera, but do NOT load the identity matrix, as
 	//we have set the pick matrix
-	cameras[activeCam]->apply(outWinAspect,boundCube,false);
+	activeCam->apply(outWinAspect,boundCube,false);
 
 	//Set up the objects. Only NON DISPLAYLIST items can be selected.
 	for(unsigned int ui=0; ui<objects.size(); ui++)
@@ -824,15 +806,15 @@ unsigned int Scene::glSelect(bool storeSelected)
 
 void Scene::finaliseCam()
 {
-	switch(cameras[activeCam]->type())
+	switch(activeCam->type())
 	{
 		case CAM_LOOKAT:
-			((CameraLookAt *)cameras[activeCam])->recomputeUpDirection();
+			((CameraLookAt *)activeCam)->recomputeUpDirection();
 			break;
 	}
 }
 
-void Scene::addSelectionDevices(const vector<SelectionDevice<Filter> *> &d)
+void Scene::addSelectionDevices(const vector<SelectionDevice *> &d)
 {
 	for(unsigned int ui=0;ui<d.size();ui++)
 	{
@@ -921,7 +903,7 @@ void Scene::applyDevice(float startX, float startY, float curX, float curY,
 	for(unsigned int ui=0;ui<activeBindings.size();ui++)
 	{
 		//Convert the mouse-XY coords into a world coordinate, depending upon mouse/
-		//key combinations
+		//key cobinations
 		Point3D worldVec;
 		Point3D vectorCoeffs[2];
 		activeBindings[ui]->computeWorldVectorCoeffs(mouseFlags,keyFlags,
@@ -952,16 +934,6 @@ void Scene::applyDevice(float startX, float startY, float curX, float curY,
 
 }
 
-unsigned int Scene::duplicateCameras(vector<Camera *> &cams) const
-{
-	cams.resize(cameras.size());
-
-	for(unsigned int ui=0;ui<cameras.size();ui++)	
-		cams[ui]=cameras[ui]->clone();
-
-	return activeCam;
-}	
-
 void Scene::getEffects(vector<const Effect *> &eff) const
 {
 	eff.resize(effects.size());
@@ -970,11 +942,6 @@ void Scene::getEffects(vector<const Effect *> &eff) const
 		eff[ui]=effects[ui];
 }	
 
-unsigned int Scene::getActiveCamId() const
-{
-	return camIDs.getId(activeCam);
-}
-
 
 void Scene::getModifiedBindings(std::vector<std::pair<const Filter *, SelectionBinding> > &bindings) const
 {
@@ -993,24 +960,17 @@ void Scene::restrictView(float xS, float yS, float xFin, float yFin)
 	viewRestrict=true;	
 }
 
-bool Scene::isDefaultCam() const
-{
-	return  activeCam==0;
-}
 
-bool Scene::camNameExists(const std::string &s) const
+void Scene::setEffectVec(vector<Effect *> &e)
 {
-	for(unsigned int ui=0;ui<cameras.size() ;ui++)
-	{
-		if(cameras[ui]->getUserString() == s)
-			return true;
-	}
+	clearEffects();
 
-	return false;
+	for(size_t ui=0;ui<e.size();ui++)
+		addEffect(e[ui]);
+	e.clear();
 }
 
 
-
 unsigned int Scene::addEffect(Effect *e)
 {
 	ASSERT(e);
@@ -1021,7 +981,6 @@ unsigned int Scene::addEffect(Effect *e)
 	return effectIDs.genId(effects.size()-1);
 }
 
-
 void Scene::removeEffect(unsigned int uniqueID)
 {
 	unsigned int position = effectIDs.getPos(uniqueID);
diff --git a/src/gl/scene.h b/src/gl/scene.h
index 5b8ced7..611bfac 100644
--- a/src/gl/scene.h
+++ b/src/gl/scene.h
@@ -20,11 +20,14 @@
 
 
 class Scene;
+class VisController;
+class Filter;
+class SelectionDevice;
+class SelectionBinding;
 
-//Custom includes
-#include "../backend/viscontrol.h"
+#include "drawables.h"
 
-#include "../backend/filter.h"
+//Custom includes
 #include "effect.h"
 
 //OpenGL debugging macro
@@ -67,13 +70,12 @@ class Scene
 
 
 		//!Bindings for interactive object properties
-		std::vector<SelectionDevice<Filter> *> selectionDevices;
+		std::vector<SelectionDevice *> selectionDevices;
 
 		//!Various OpenGL effects
 		std::vector<const Effect *> effects;
 
-		//!Vector of camera stats
-		std::vector<Camera *> cameras;
+		Camera *activeCam;
 
 		//!Temporary override camera
 		Camera *tempCam;
@@ -84,8 +86,6 @@ class Scene
 		//!Size of window in px (needed if doing 2D drawing)
 		unsigned int winX,winY;
 
-		//!Which camera are we using
-		unsigned int activeCam;
 		//!Is there a camera set?
 		bool cameraSet;
 		//!Aspect ratio of output window (x/y) -- needed for cams
@@ -94,10 +94,6 @@ class Scene
 		//!Blank canvas colour
 		float r,g,b;
 
-
-		//!Camera id storage and handling
-		UniqueIDHandler camIDs;
-
 		//!Effect ID handler
 		UniqueIDHandler effectIDs;
 
@@ -118,7 +114,8 @@ class Scene
 
 		float viewRestrictStart[2], viewRestrictEnd[2];
 			
-		//!Last selected object from call to glSelect(). -1 if last call failed to identify an item
+		//!Last selected object from call to glSelect(). -1 if last
+		// call failed to identify an item
 		unsigned int lastSelected;
 	
 		//!Last hoeverd object	
@@ -137,6 +134,14 @@ class Scene
 		//!Background colour
 		float rBack,gBack,bBack;
 
+		//!Should we a progress animation to the user in 3D?
+		bool showProgressAnimation;
+
+		//!Have we attempted to load the progress animation
+		bool attemptedLoadProgressAnim;
+
+		//texture to use for pgoress animation
+		DrawAnimatedOverlay progressAnimTex;
 
 		///!Draw the hover overlays
 		void drawHoverOverlay();
@@ -144,15 +149,21 @@ class Scene
 		//!Draw the normal overlays
 		void drawOverlays() const;
 
+		void drawProgressAnim() const;
+
 		//!initialise the drawing window
 		unsigned int initDraw();
 
 		void updateCam(const Camera *camToUse) const;
 
+		//reset the position of the overlay
+		void updateProgressOverlay(); 
 
 		//!Draw a specified vector of objects
 		void drawObjectVector(const std::vector<const DrawableObj*> &objects, bool &lightsOn, bool drawOpaques=true) const;
 
+		//!Disable copy constructor by making private
+		Scene &operator=(const Scene &);
 				
 	public:
 		//!Constructor
@@ -174,11 +185,10 @@ class Scene
 		void clearRefObjs();
 		//!Clear object bindings vector
 		void clearBindings();
-		//!Clear camera vector
-		void clearCams();
+		
 		//!Set the aspect ratio of the output window. Required.
 		void setAspect(float newAspect);
-		//!retreive aspect ratio (h/w) of output win
+		//!retrieve aspect ratio (h/w) of output win
 		float getAspect() const { return outWinAspect;};
 		
 		//!Add a drawable object 
@@ -188,30 +198,26 @@ class Scene
 		 */
 		void addDrawable(const DrawableObj *);
 		
-		//!Add a drawble to the refernce only section
-		/* Objects refferred to will not be modified or destroyed
-		 * by this class. It will onyl be used for drawing purposes
+		//!Add a drawable to the reference only section
+		/* Objects referred to will not be modified or destroyed
+		 * by this class. It will only be used for drawing purposes
 		 * It is up to the user to ensure that they are in a good state
 		 */
 		void addRefDrawable(const DrawableObj *);
-		
+	
 
-		//!remove a drawable object
-		void removeDrawable(unsigned int);
+		bool setProgressAnimation(const vector<string> &animFiles);
 
-		//!Add a camera 
-		/*!Pointer must be set to a valid (allocated) object.
-		 *!Scene will delete upon call to clearAll, clearCameras or
-		 *!upon destruction
-		 */
-		unsigned int addCam(Camera *);
-		
-		//!remove a camera object
-		void removeCam(unsigned int uniqueCamID);
+		void setShowProgress(bool show) ;
 
+		bool getShowProgress() const { return showProgressAnimation; }
 
+		//!remove a drawable object
+		void removeDrawable(unsigned int);
+
+		void setActiveCam();
 		//! set the active camera
-		void setActiveCam(unsigned int uniqueCamID);
+		void setActiveCamByClone(const Camera *c);
 
 		//! get the active camera
 		Camera *getActiveCam() ;
@@ -240,25 +246,12 @@ class Scene
 		bool haveTempCam() const { return tempCam!=0;};
 
 		//!Clone the active camera
-		Camera *cloneActiveCam() const { return cameras[activeCam]->clone(); };
-
-		//!Get the number of cameras (excluding tmp cam)
-		unsigned int getNumCams() const { return cameras.size(); } ;
+		Camera *cloneActiveCam() const { return activeCam->clone(); };
 
-		//!Get the camera properties for a given camera
-		void getCamProperties(unsigned int uniqueID, CameraProperties &p) const;
-		//!Set the camera properties for a given camera. returns true if property set is OK
-		bool setCamProperty(unsigned int uniqueID, unsigned int key,
-	       					const std::string &value);
-		//!Return ALL the camera unique IDs
-		void getCameraIDs(vector<std::pair<unsigned int, std::string> > &idVec) const;
 
 		//!Modify the active camera position to ensure that scene is visible 
 		void ensureVisible(unsigned int direction);
 
-		//!Set the active camera to the first entry. Only to be called if getNumCams > 0, or if a camera is passed in
-		void setDefaultCam(Camera *c=0,bool setAsActive=true);
-
 		//!Call if user has stopped interacting with camera briefly.
 		void finaliseCam();
 
@@ -268,7 +261,7 @@ class Scene
 		unsigned int glSelect(bool storeSelection=true);
 
 		//!Add selection devices to the scene.
-		void addSelectionDevices(const std::vector<SelectionDevice<Filter> *> &d);
+		void addSelectionDevices(const std::vector<SelectionDevice *> &d);
 
 		//!Clear the current selection devices 
 		void clearDevices();
@@ -303,9 +296,6 @@ class Scene
 		//!Get a copy of the effects pointers
 		void getEffects(std::vector<const Effect *> &effects) const; 
 
-		//!Return the unique ID of the active camera
-		unsigned int getActiveCamId() const;
-
 		//!Return any devices that have been modified since their creation
 		void getModifiedBindings(std::vector<std::pair<const Filter *,SelectionBinding > > &bindings) const;
 
@@ -314,9 +304,6 @@ class Scene
 		//!Disable view restriction
 		void unrestrictView() { viewRestrict=false;};
 
-		//!True if the current camera is the default (0th) camera
-		bool isDefaultCam() const; 
-
 		//!Set whether to use alpha blending
 		void setAlpha(bool newAlpha) { useAlpha=newAlpha;};
 
@@ -329,14 +316,11 @@ class Scene
 		bool getWorldAxisVisible() const { return showAxis;};
 
 		//!Set window size
-		void setWinSize(unsigned int x, unsigned int y) {winX=x;winY=y;}
+		void setWinSize(unsigned int x, unsigned int y) {winX=x;winY=y; updateProgressOverlay();}
 
 		//!Get the scene boundinng box
 		BoundCube getBound() const { return boundCube;}
 
-		//!Returns true if this camera name is already in use
-		bool camNameExists(const std::string &s) const;
-
 		//!Set the background colour
 		void setBackgroundColour(float newR,float newG,float newB) { rBack=newR;gBack=newG;bBack=newB;};
 
@@ -351,6 +335,13 @@ class Scene
 		//!Set whether to use effects or not
 		void setEffects(bool enable) {useEffects=enable;} 
 
+		//!Set the effect vector
+		/*! Pointers will become "owned" by scene
+		 * and will be deleted during destruction, clear, or next setEffectVec call
+		 * input vector will be cleared.
+		 */
+		void setEffectVec(vector<Effect *> &e);
+
 		//!Add an effect
 		unsigned int addEffect(Effect *e);
 		//!Remove a given effect
diff --git a/src/gl/select.cpp b/src/gl/select.cpp
index abbc405..7c1776f 100644
--- a/src/gl/select.cpp
+++ b/src/gl/select.cpp
@@ -16,7 +16,83 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+
+#include "common/mathfuncs.h"
+#include "common/assertion.h"
+#include "gl/drawables.h"
+
 #include "select.h"
+using std::vector;
+
+SelectionDevice::SelectionDevice(const Filter *p) : target(p)
+{
+}
+
+void SelectionDevice::addBinding(SelectionBinding b)
+{
+	bindingVec.push_back(b);
+}
+
+bool SelectionDevice::getBinding(const DrawableObj *d,unsigned int mouseFlags, 
+					unsigned int keyFlags,SelectionBinding* &b)
+{
+
+	unsigned int keyMask=0;
+
+
+	bool found=false;
+
+	for(unsigned int ui=0;ui<bindingVec.size();ui++)
+	{
+		if(bindingVec[ui].matchesDrawable(d,mouseFlags,keyFlags))
+		{
+			if(!found)
+			{
+				//we found one.
+				found=true;
+				b=&(bindingVec[ui]);
+				keyMask=b->getKeyFlags();
+				continue;
+			}
+
+			//OK, we already have one, but we can be "trumped"
+			//by a more complex keymask.
+			if( (keyMask & bindingVec[ui].getKeyFlags() )== keyMask)
+			{
+				b=&(bindingVec[ui]);
+				keyMask=b->getKeyFlags();
+			}
+		}
+	}
+
+
+	//This selection device does not match
+	//the targeted object.
+	return found;
+}
+
+void SelectionDevice::getModifiedBindings(vector<std::pair<const Filter *,SelectionBinding> > &bindings)
+{
+	ASSERT(target);
+	for(unsigned int ui=0;ui<bindingVec.size();ui++)
+	{
+		if(bindingVec[ui].modified())
+			bindings.push_back(std::make_pair(target,bindingVec[ui]));
+	}
+}
+
+bool SelectionDevice::getAvailBindings(const DrawableObj *d,vector<const SelectionBinding*> &b) const
+{
+	ASSERT(b.empty());
+	for(unsigned int ui=0;ui<bindingVec.size();ui++)
+	{
+		if(bindingVec[ui].matchesDrawable(d))
+			b.push_back(&(bindingVec[ui]));
+	}
+
+
+	return b.size();
+}
 
 
 SelectionBinding::SelectionBinding()
@@ -223,3 +299,4 @@ bool SelectionBinding::matchesDrawable(const DrawableObj *d) const
 	return (obj == d);
 }
 
+
diff --git a/src/gl/select.h b/src/gl/select.h
index 188b16e..c65d1ed 100644
--- a/src/gl/select.h
+++ b/src/gl/select.h
@@ -20,8 +20,11 @@
 #ifndef SELECT_H
 #define SELECT_H
 
-#include "drawables.h"
+#include <vector>
 
+class DrawableObj;
+class Filter;
+class Point3D;
 
 //Mouse button flags
 enum
@@ -157,14 +160,14 @@ class SelectionBinding
 		bool modified() const {return valModified;};
 };
 
-template<class T> class SelectionDevice
+class SelectionDevice
 {
 	private:
 		std::vector<SelectionBinding> bindingVec;
-		const T *target;
+		const Filter *target;
 public:
 		//!Create a new selection device
-		SelectionDevice(const T *p);
+		SelectionDevice(const Filter *p);
 
 		//!Copy constructor (not implemented)
 		SelectionDevice(const SelectionDevice &copySrc);
@@ -177,84 +180,11 @@ public:
 		bool getBinding(const DrawableObj *d, unsigned int mouseFlags, 
 				unsigned int keyFlags,	SelectionBinding* &b);
 
-		bool getAvailBindings(const DrawableObj *d, vector<const SelectionBinding*> &b) const;
-		void getModifiedBindings(vector<std::pair<const T *,SelectionBinding> > &bindings);
-};
-
-template<class T>
-SelectionDevice<T>::SelectionDevice(const T *p) : target(p)
-{
-}
-
-template<class T>
-void SelectionDevice<T>::addBinding(SelectionBinding b)
-{
-	bindingVec.push_back(b);
-}
-
-template<class T>
-bool SelectionDevice<T>::getBinding(const DrawableObj *d,unsigned int mouseFlags, 
-					unsigned int keyFlags,SelectionBinding* &b)
-{
-
-	unsigned int keyMask=0;
-
-
-	bool found=false;
-
-	for(unsigned int ui=0;ui<bindingVec.size();ui++)
-	{
-		if(bindingVec[ui].matchesDrawable(d,mouseFlags,keyFlags))
-		{
-			if(!found)
-			{
-				//we found one.
-				found=true;
-				b=&(bindingVec[ui]);
-				keyMask=b->getKeyFlags();
-				continue;
-			}
-
-			//OK, we already have one, but we can be "trumped"
-			//by a more complex keymask.
-			if( (keyMask & bindingVec[ui].getKeyFlags() )== keyMask)
-			{
-				b=&(bindingVec[ui]);
-				keyMask=b->getKeyFlags();
-			}
-		}
-	}
-
-
-	//This selection device does not match
-	//the targeted object.
-	return found;
-}
-
-template<class T>
-void SelectionDevice<T>::getModifiedBindings(vector<std::pair<const T *,SelectionBinding> > &bindings)
-{
-	ASSERT(target);
-	for(unsigned int ui=0;ui<bindingVec.size();ui++)
-	{
-		if(bindingVec[ui].modified())
-			bindings.push_back(std::make_pair(target,bindingVec[ui]));
-	}
-}
-
-template<class T>
-bool SelectionDevice<T>::getAvailBindings(const DrawableObj *d,vector<const SelectionBinding*> &b) const
-{
-	ASSERT(b.empty());
-	for(unsigned int ui=0;ui<bindingVec.size();ui++)
-	{
-		if(bindingVec[ui].matchesDrawable(d))
-			b.push_back(&(bindingVec[ui]));
-	}
-
+		bool getAvailBindings(const DrawableObj *d, std::vector<const SelectionBinding*> &b) const;
+		void getModifiedBindings(std::vector<std::pair<const Filter *,SelectionBinding> > &bindings);
 
-	return b.size();
-}
+		size_t getNumBindings() const { return bindingVec.size(); }
+};
 
 #endif
 
diff --git a/src/gl/textures.cpp b/src/gl/textures.cpp
index d521a37..f2aa789 100644
--- a/src/gl/textures.cpp
+++ b/src/gl/textures.cpp
@@ -16,13 +16,23 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "textures.h"
+#if defined(WIN32) || defined(WIN64)
+#include <GL/glew.h>
+#endif
 
-#include "pngread.h"
+#include "textures.h"
 
 #include "wxcommon.h"
+#include "common/pngread.h"
+
+#include <string>
 
-const char *TEST_OVERLAY_PNG[] = { 
+#include <iostream>
+
+using std::vector;
+using std::string;
+
+const char *TEXTURE_OVERLAY_PNG[] = { 
 				"textures/Left_clicked_mouse.png",
 				"textures/Left-Right-arrow.png",
 				"textures/Right_clicked_mouse.png",
@@ -43,19 +53,21 @@ TexturePool::~TexturePool()
 	closeAll();
 }
 
-bool TexturePool::openTexture(const char *texName,unsigned int &texID, unsigned int &uniqID)
+bool TexturePool::openTexture(const char *texName, unsigned int &texID)
 {
 	std::string texPath;
 
 	texPath = locateDataFile(texName);
-	
-	//See if we already have this texture (use abs. name)
+
+	if(texPath.empty())
+		return false;
+
+	//See if we already have this texture (use first frame as keyname)
 	for(unsigned int ui=0;ui<openTextures.size();ui++)
 	{
 		if(openTextures[ui].first == texPath)
 		{
-			texID = openTextures[ui].second.name;
-			uniqID = texUniqIds.getId(ui);
+			texID = openTextures[ui].second.glID;
 			return true;
 		}
 	}
@@ -63,17 +75,71 @@ bool TexturePool::openTexture(const char *texName,unsigned int &texID, unsigned
 
 	//Try to load the texture, as we don't have it
 	texture tex;	
-	if(!pngTexture2D(&tex,texPath.c_str()))
+	if(pngTexture2D(&tex,texPath.c_str()))
+		return false;
+
+	//record the texture in list of textures
+	openTextures.push_back(
+		make_pair(texPath,tex));
+
+	texID=tex.glID;
+	return true;
+}
+
+bool TexturePool::openTexture3D(const std::vector<std::string> &fileNames, unsigned int &texId) 
+{
+
+	vector<string> fullNames;
+	fullNames.resize(fileNames.size());
+	for(size_t ui=0;ui<fileNames.size();ui++)
 	{
-		uniqID=texUniqIds.genId(openTextures.size());
-		openTextures.push_back(
-			make_pair(texPath,tex));
+		std::string texPath;
+		texPath = locateDataFile(fileNames[ui].c_str());
 
-		texID=tex.name;
-		return true;
+		if(!texPath.size())
+			return false;
+		fullNames[ui]=texPath;
+	}
+	
+	//See if we already have this texture (use abs. name)
+	for(unsigned int ui=0;ui<openTextures.size();ui++)
+	{
+		//Use the first name of the file as the key
+		if(openTextures[ui].first == fullNames[0])
+		{
+			texId = openTextures[ui].second.glID;
+			return true;
+		}
 	}
-	else
+
+
+	//Try to load the texture, as we don't have it
+	texture tex;	
+	if(pngTexture3D(&tex,fullNames))
 		return false;
+	
+	//TODO: Better key storage method! (eg combined hash)
+	//Store the texture in the list of open textures,
+	// using the first frame of the sequence as the key
+	openTextures.push_back(
+		std::make_pair(fullNames[0],tex));
+
+
+	texId=tex.glID;
+	return true;
+}
+
+//TODO: Refactor to remove this routine
+void TexturePool::genTexID(unsigned int &texID, size_t texType) 
+{
+	texture tex;
+	tex.data=0;
+  
+	glGenTextures(1,&tex.glID);
+	texID = tex.glID;
+	
+	openTextures.push_back(
+		make_pair(std::string(""),tex));
 }
 
 
@@ -81,9 +147,9 @@ void TexturePool::closeTexture(unsigned int texId)
 {
 	for(unsigned int ui=0;ui<openTextures.size();ui++)
 	{
-		if(openTextures[ui].second.name== texId)
+		if(openTextures[ui].second.glID == texId)
 		{
-			texUniqIds.killByPos(ui);	
+			glDeleteTextures(1,&openTextures[ui].second.glID);
 			delete [] openTextures[ui].second.data;
 			openTextures.erase(openTextures.begin()+ui);
 			return;
@@ -95,64 +161,165 @@ void TexturePool::closeAll()
 {
 	for(unsigned int ui=0;ui<openTextures.size();ui++)
 	{
-		delete[] openTextures[ui].second.data;
-		glDeleteTextures(1,&openTextures[ui].second.name);	
+		if(openTextures[ui].second.data)
+		{
+			delete[] openTextures[ui].second.data;
+			glDeleteTextures(1,&openTextures[ui].second.glID);
+		}
 	}
 
-	texUniqIds.clear();
 	openTextures.clear();
 }
 
 
-int pngTexture(texture* dest, const char* filename, GLenum type) {
-  FILE *fp;
-  unsigned int x, y, z;
-  png_uint_32 width, height;
-  GLint curtex;
-  png_bytep *texture_rows;
-
-  if (!check_if_png((char *)filename, &fp, 8)) {
-    return(1); /* could not open, or was not a valid .png */
-  }
-
-  if (read_png(fp, 8, &texture_rows, &width, &height)) {
-    return(2); /* something is wrong with the .png */
-  }
-
-  z=0;
-  dest->width = width;
-  dest->height = height;
-  dest->data = new unsigned char[4*width*height];
-  for (y=0; y<height; y++) {
-    for (x=0; x<4*(width); x++) {
-      dest->data[z++] = texture_rows[y][x];
-    }
-    free(texture_rows[y]);
-  }
-  free(texture_rows);
-
-  if (type == GL_TEXTURE_1D) {
-    glGetIntegerv(GL_TEXTURE_BINDING_1D, &curtex);
-  } else {
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &curtex);
-  }
-  glGenTextures(1, &(dest->name));
-  glBindTexture(type, dest->name);
-  if (type == GL_TEXTURE_1D) {
-    glTexImage1D(type, 0, GL_RGBA, dest->width, 0, GL_RGBA, GL_UNSIGNED_BYTE, dest->data);
-  } else {
-    glTexImage2D(type, 0, GL_RGBA, dest->width, dest->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dest->data);
-  }
-  glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* other routines should override this later */
-  glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* if they don't want linear filtering */
-  glBindTexture(type, curtex);
-  return (0);
+int pngTexture(texture* dest, const char* filename, GLenum type) 
+{
+	FILE *fp;
+	unsigned int x, y, z;
+	png_uint_32 width, height;
+	GLint curtex;
+	png_bytep *texture_rows;
+
+	if (!check_if_png((char *)filename, &fp, 8))
+	{
+		if(fp)
+			fclose(fp);
+		return 1; // could not open, or was not a valid .png
+	}
+
+	if (read_png(fp, 8, &texture_rows, &width, &height))
+		return 2; // something is wrong with the .png 
+
+	z=0;
+	dest->width = width;
+	dest->height = height;
+	dest->data = new unsigned char[4*width*height];
+	for (y=0; y<height; y++)
+	{
+		for (x=0; x<4*(width); x++)
+		{
+			dest->data[z++] = texture_rows[y][x];
+		}
+		free(texture_rows[y]);
+	}
+	free(texture_rows);
+
+	//Retrieve the in-use texture, which we will reset later
+	if (type == GL_TEXTURE_1D)
+		glGetIntegerv(GL_TEXTURE_BINDING_1D, &curtex);
+	else 
+		glGetIntegerv(GL_TEXTURE_BINDING_2D, &curtex);
+	
+	glGenTextures(1, &(dest->glID));
+	glBindTexture(type, dest->glID);
+	
+	//Send texture to video card
+	if (type == GL_TEXTURE_1D)
+	{
+		glTexImage1D(type, 0, GL_RGBA, dest->width, 0, 
+					GL_RGBA, GL_UNSIGNED_BYTE, dest->data);
+	}
+	else 
+	{
+		glTexImage2D(type, 0, GL_RGBA, dest->width, dest->height, 0, 
+					GL_RGBA, GL_UNSIGNED_BYTE, dest->data);
+	}
+
+	//Sett scale-down 
+	// and scale-up interpolation to LINEAR
+	glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
+	glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	//Restore the current opengl texture
+	glBindTexture(type, curtex);
+
+	return (0);
+}
+
+int pngTexture3D(texture *dest, const vector<string> &fileNames)
+{
+	dest->depth=fileNames.size();
+
+	//Copy data from disk into temporary storage
+	vector<unsigned char> *dataArray=new vector<unsigned char>[fileNames.size()];
+	for(size_t ui=0; ui<fileNames.size(); ui++)
+	{
+		//Pointer is closed by readpng
+		FILE *fp;
+		png_bytep *texture_rows;
+		png_uint_32 width, height;
+		if (!check_if_png((char *)fileNames[ui].c_str(), &fp, 8)) 
+		{
+			if(fp)
+				fclose(fp);
+			delete[] dataArray;
+			return 1; 
+		}
+
+		/* something is wrong with the .png */
+		if (read_png(fp, 8, &texture_rows, &width, &height))
+		{
+			delete[] dataArray;
+			return 2;
+		}
+
+		if(ui)
+		{
+			//Check to see image is the same size
+			if(width != dest->width || height !=dest->height)
+			{
+				delete[] dataArray;
+				return 3;
+			}
+		}
+
+		dest->width = width;
+		dest->height = height;
+
+		dataArray[ui].resize(width*height*4);
+		size_t arrayDest;
+		arrayDest=0;
+		for (size_t y=0; y<height; y++)
+		{
+			for (size_t x=0; x<4*(width); x++)
+				dataArray[ui][arrayDest++] = texture_rows[y][x];
+		}
+	}
+
+	size_t offset=0;
+	//Copy data into cube that we will send to video card
+	dest->data = new unsigned char[4*dest->width*dest->height*dest->depth];
+	for(size_t ui=0;ui<dest->depth;ui++)
+	{
+		for(size_t uj=0;uj<dataArray[ui].size();uj++)
+		{
+			dest->data[offset++]=dataArray[ui][uj];
+		}
+	}
+
+	delete[] dataArray;
+	
+	glGenTextures(1, &(dest->glID));
+	glBindTexture(GL_TEXTURE_3D, dest->glID);
+	
+	//Send texture to video card
+	glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, dest->width, dest->height, dest->depth, 0,
+				GL_RGBA, GL_UNSIGNED_BYTE, dest->data);
+
+	//Sett scale-down 
+	// and scale-up interpolation to LINEAR
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	return 0;
 }
 
-int pngTexture2D(texture* dest, const char* filename) {
-  return (pngTexture(dest, filename, GL_TEXTURE_2D));
+int pngTexture2D(texture* dest, const char* filename)
+{
+	return (pngTexture(dest, filename, GL_TEXTURE_2D));
 }
 
-int pngTexture1D(texture* dest, const char* filename) {
-  return (pngTexture(dest, filename, GL_TEXTURE_1D));
+int pngTexture1D(texture* dest, const char* filename)
+{
+	return (pngTexture(dest, filename, GL_TEXTURE_1D));
 }
diff --git a/src/gl/textures.h b/src/gl/textures.h
index 936cd3d..7e7162a 100644
--- a/src/gl/textures.h
+++ b/src/gl/textures.h
@@ -30,6 +30,8 @@
 #include <GL/glu.h>
 #endif
 
+#include <vector>
+#include <string>
 
 
 //Named Textures
@@ -51,19 +53,20 @@ enum
 };
 
 //Paths to named textures
-extern const char *TEST_OVERLAY_PNG[]; 
+extern const char *TEXTURE_OVERLAY_PNG[]; 
 
 typedef struct {
-GLuint name; /* OpenGL name assigned by the thingy */
+GLuint glID; /* OpenGL name assigned by by glGenTexture*/
 GLuint width;
 GLuint height;
+GLuint depth;
 unsigned char *data;
 } texture;
 
 class TexturePool
 {
 private:
-		UniqueIDHandler texUniqIds;
+		//Filename of textures, or "" if using a generated texture, bound to the texture data
 		std::vector<std::pair<std::string,texture> > openTextures;
 
 	public:
@@ -72,9 +75,13 @@ private:
 		//Open the texture specified by the following file, and
 		//then return the texture ID; or just return the texture 
 		//if already loaded. Return true on success.
-		bool openTexture(const char *texName,unsigned int &texID, unsigned int &uniqID);
+		bool openTexture(const char *texName,unsigned int &texID);
+		//Open a set of identically sized images  into a 3D texture object
+		bool openTexture3D(const std::vector<std::string> &texName,unsigned int &texID);
 
-		//Close the specified texture, using its unique ID
+		void genTexID(unsigned int &textureID, size_t texType=GL_TEXTURE_2D)  ;
+
+		//Close the specified texture, using its texture ID 
 		void closeTexture(unsigned int texID);
 
 		//Close all textures
@@ -84,6 +91,10 @@ private:
 
 //!Type can be GL_TEXTURE_1D or GL_TEXTURE_2D
 int pngTexture(texture* dest, const char* filename, GLenum type);
+
+//Read a stack of equi-sized PNG images into a 3D opengl texture
+int pngTexture3D(texture*, const std::vector<std::string> &filenames);
+//read a single PNG image as an opengl texture
 int pngTexture2D(texture*, const char*);
 int pngTexture1D(texture*, const char*);
 
diff --git a/src/gui/cropPanel.cpp b/src/gui/cropPanel.cpp
index aa73af9..ee0897e 100644
--- a/src/gui/cropPanel.cpp
+++ b/src/gui/cropPanel.cpp
@@ -23,6 +23,8 @@
 
 #include "common/assertion.h"
 
+#include <limits>
+
 //Crop array indices
 enum
 {
@@ -214,12 +216,12 @@ unsigned int CropPanel::getBestCropWidget(float xMouse, float yMouse,unsigned in
 	
 	float meanPx = 1.0/(1.0/(w-2) + 1.0/(h-2));
 	unsigned int minIndex;
-	float minDist,x,y;
+	float minDist=std::numeric_limits<float>::max();
+	float tmpDist,x,y;
 	//work our way clockwise around the corners
 	//finding the minimum distance
 	for(unsigned int ui=0;ui<4;ui++)
 	{
-		float tmpDist;
 		//Check this corner
 		switch(ui)
 		{
@@ -249,7 +251,7 @@ unsigned int CropPanel::getBestCropWidget(float xMouse, float yMouse,unsigned in
 		}
 
 		tmpDist=(xMouse-x)*(xMouse-x) + (yMouse-y)*(yMouse-y);
-		if(!ui || tmpDist < minDist) //first pass - no data
+		if(tmpDist < minDist) 
 		{
 			minIndex=ui;
 			minDist=tmpDist;
diff --git a/src/gui/dialogs/ExportPos.cpp b/src/gui/dialogs/ExportPos.cpp
index 2e4d5d1..e4e82f9 100644
--- a/src/gui/dialogs/ExportPos.cpp
+++ b/src/gui/dialogs/ExportPos.cpp
@@ -151,7 +151,7 @@ void ExportPosDialog::initialiseData(FilterTree &f)
 
 	ProgressData p;
 	//TODO: Is trashing the devices a problem? do we have to restore them??
-	std::vector<SelectionDevice<Filter> *> dummyDevices;
+	std::vector<SelectionDevice *> dummyDevices;
 	std::vector<std::pair<const Filter *, string > > consoleStrings;
 	filterTree.refreshFilterTree(outputData,dummyDevices,consoleStrings,p,yieldCallback);
 
diff --git a/src/gui/dialogs/ExportPos.h b/src/gui/dialogs/ExportPos.h
index b191675..47bb091 100644
--- a/src/gui/dialogs/ExportPos.h
+++ b/src/gui/dialogs/ExportPos.h
@@ -32,7 +32,7 @@
 
 // end wxGlade
 
-#include "backend/viscontrol.h"
+#include "backend/filtertree.h"
 
 
 class ExportPosDialog: public wxDialog {
diff --git a/src/gui/dialogs/ExportRngDialog.h b/src/gui/dialogs/ExportRngDialog.h
index 78a5cf4..13859f4 100644
--- a/src/gui/dialogs/ExportRngDialog.h
+++ b/src/gui/dialogs/ExportRngDialog.h
@@ -1,6 +1,6 @@
 /*
  *	ExportRngDialog.h - Range data export dialog
- *	Copyright (C) 2012, D Haley 
+ *	Copyright (C) 2013, D Haley 
 
  *	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
@@ -22,11 +22,15 @@
 #include <wx/wx.h>
 // begin wxGlade: ::dependencies
 #include <wx/listctrl.h>
+#include <wx/grid.h>
 // end wxGlade
 
 #include <map>
+#include <vector>
+
+class VisController;
+class Filter;
 
-#include "backend/viscontrol.h"
 class ExportRngDialog: public wxDialog {
 public:
     // begin wxGlade: ExportRngDialog::ids
diff --git a/src/gui/dialogs/StashDialog.cpp b/src/gui/dialogs/StashDialog.cpp
index 2b8820f..f4c2efe 100644
--- a/src/gui/dialogs/StashDialog.cpp
+++ b/src/gui/dialogs/StashDialog.cpp
@@ -22,6 +22,7 @@
 #include "wxcomponents.h"
 #include "common/translation.h"
 
+#include "./backend/viscontrol.h"
 
 using std::pair;
 using std::string;
@@ -113,7 +114,7 @@ void StashDialog::OnListKeyDown(wxListEvent &event)
 				if ( item == -1 )
 					break;
 
-				visControl->deleteStash(listStashes->GetItemData(item));
+				visControl->eraseStash(listStashes->GetItemData(item));
 			}
 			
 			//Update the filter list
@@ -353,7 +354,7 @@ void StashDialog::OnBtnRemove(wxCommandEvent &event)
 		if ( item == -1 )
 			break;
 
-		visControl->deleteStash(listStashes->GetItemData(item));
+		visControl->eraseStash(listStashes->GetItemData(item));
 		updateList();
 		updateTree();
 		updateGrid();
diff --git a/src/gui/dialogs/StashDialog.h b/src/gui/dialogs/StashDialog.h
index 4caa358..d340776 100644
--- a/src/gui/dialogs/StashDialog.h
+++ b/src/gui/dialogs/StashDialog.h
@@ -24,10 +24,10 @@
 #include <wx/treectrl.h>
 #include <wx/grid.h>
 
-
-#include "backend/viscontrol.h"
 // end wxGlade
 
+#include "./backend/filtertree.h"
+class VisController;
 // begin wxGlade: ::extracode
 #include <wx/listctrl.h>
 // end wxGlade
diff --git a/src/gui/dialogs/prefDialog.h b/src/gui/dialogs/prefDialog.h
index 04c30f4..191c4c4 100644
--- a/src/gui/dialogs/prefDialog.h
+++ b/src/gui/dialogs/prefDialog.h
@@ -1,7 +1,7 @@
 // -*- C++ -*- generated by wxGlade HG on Fri Dec  3 22:26:29 2010
 /*
  * prefDialog.h  - program preferences management dialog
- * Copyright (C) 2013  D Haley
+ * Copyright (C) 2011  D Haley
  * 
  * 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
@@ -26,10 +26,7 @@
 #include "wxcomponents.h"
 // end wxGlade
 
-
-
-#include "backend/filter.h"
-#include "backend/viscontrol.h"
+class Filter;
 
 // begin wxGlade: ::extracode
 // end wxGlade
diff --git a/src/gui/glPane.cpp b/src/gui/glPane.cpp
index aa2ff56..ee9b852 100644
--- a/src/gui/glPane.cpp
+++ b/src/gui/glPane.cpp
@@ -22,6 +22,7 @@
 #include "wxcommon.h"
 
 #include "common/stringFuncs.h"
+#include "gl/select.h"
 #include "glPane.h"
 
 
@@ -159,7 +160,7 @@ unsigned int  BasicGLPane::selectionTest(const wxPoint &p,bool &shouldRedraw)
 	//if it has changed, we should redraw
 	shouldRedraw = (lastSelected !=selectedObject);
 
-	//Restore the previous matrix
+	//Restore the previous matirx
 	glPopMatrix();
 
 	//Restore the viewport
@@ -400,7 +401,7 @@ void BasicGLPane::mouseDown(wxMouseEvent& event)
 
 
 		//If the selected object is valid, then
-		//we did select an object. Treat this as a selection event
+		//we did select an object. Treat this as a seletion event
 		if(currentScene.getLastSelected() != (unsigned int)-1)
 		{
 			selectionMode=true;
@@ -729,8 +730,8 @@ bool BasicGLPane::prepare3DViewport(int tlx, int tly, int brx, int bry)
 	GLint dims[2]; 
 	glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); 
 
-	//Ensure that the opengGL function didn't tell us porkies,
-	// (well, check during debug builds)
+	//Ensure that the opengGL function didn't tell us porkies
+	//but double check for the non-debug bulds next line
 	ASSERT(dims[0] && dims[1]);
 
 	//check for exceeding max viewport and we have some space
diff --git a/src/gui/glPane.h b/src/gui/glPane.h
index 97cd8ee..87bff4f 100644
--- a/src/gui/glPane.h
+++ b/src/gui/glPane.h
@@ -18,10 +18,12 @@
 #ifndef GLPANE_H
 #define GLPANE_H
  
-#include <wx/glcanvas.h>
 
 #include "gl/scene.h"
 
+#include <wx/glcanvas.h>
+#include <wx/timer.h>
+#include <wx/statusbr.h>
 
 class BasicGLPane : public wxGLCanvas
 {
diff --git a/src/gui/glade-skeleton/mainWindow.wxg b/src/gui/glade-skeleton/mainWindow.wxg
index fb79994..6d588bd 100644
--- a/src/gui/glade-skeleton/mainWindow.wxg
+++ b/src/gui/glade-skeleton/mainWindow.wxg
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!-- generated by wxGlade HG on Wed Jan 12 22:00:42 2011 -->
+<!-- generated by wxGlade 0.6.5 on Sun Jun  9 13:07:46 2013 -->
 
 <application path="/home/user/Desktop/3Depict/src/glade-skeleton/3Depict.cpp" name="quick3d" class="quick3dApp" option="0" language="C++" top_window="MainFrame" encoding="ISO-8859-1" use_gettext="1" overwrite="1" use_new_namespace="1" for_version="2.8" is_template="0" indent_amount="4" indent_symbol="space" source_extension=".cpp" header_extension=".h">
     <object class="MainWindowFrame" name="MainFrame" base="EditFrame">
@@ -796,6 +796,15 @@
                                         <object class="wxBoxSizer" name="sizerTools" base="EditBoxSizer">
                                             <orient>wxVERTICAL</orient>
                                             <object class="sizeritem">
+                                                <flag>wxTOP</flag>
+                                                <border>3</border>
+                                                <option>0</option>
+                                                <object class="wxStaticText" name="labelAppearance" base="EditStaticText">
+                                                    <attribute>1</attribute>
+                                                    <label>Appearance</label>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem">
                                                 <flag>wxLEFT|wxTOP|wxBOTTOM</flag>
                                                 <border>5</border>
                                                 <option>0</option>
@@ -812,6 +821,24 @@
                                                 </object>
                                             </object>
                                             <object class="sizeritem">
+                                                <flag>wxEXPAND</flag>
+                                                <border>0</border>
+                                                <option>0</option>
+                                                <object class="wxStaticLine" name="static_line_1" base="EditStaticLine">
+                                                    <style>wxLI_HORIZONTAL</style>
+                                                    <attribute>1</attribute>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem">
+                                                <flag>wxTOP</flag>
+                                                <border>3</border>
+                                                <option>0</option>
+                                                <object class="wxStaticText" name="labelPerformance" base="EditStaticText">
+                                                    <attribute>1</attribute>
+                                                    <label>Performance</label>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem">
                                                 <flag>wxLEFT|wxTOP|wxBOTTOM</flag>
                                                 <border>5</border>
                                                 <option>0</option>
@@ -820,6 +847,35 @@
                                                 </object>
                                             </object>
                                             <object class="sizeritem">
+                                                <flag>wxLEFT|wxEXPAND</flag>
+                                                <border>5</border>
+                                                <option>0</option>
+                                                <object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
+                                                    <orient>wxHORIZONTAL</orient>
+                                                    <object class="sizeritem">
+                                                        <flag>wxRIGHT</flag>
+                                                        <border>3</border>
+                                                        <option>0</option>
+                                                        <object class="wxCheckBox" name="checkLimitOutput" base="EditCheckBox">
+                                                            <checked>1</checked>
+                                                            <label>Limit Output Pts</label>
+                                                            <tooltip>Limit the number of points in the 3D view</tooltip>
+                                                        </object>
+                                                    </object>
+                                                    <object class="sizeritem">
+                                                        <flag>wxLEFT</flag>
+                                                        <border>4</border>
+                                                        <option>0</option>
+                                                        <object class="wxTextCtrl" name="textLimitOutput" base="EditTextCtrl">
+                                                            <value>2000000</value>
+                                                            <events>
+                                                                <handler event="EVT_TEXT">OnTextLimitOutput</handler>
+                                                            </events>
+                                                        </object>
+                                                    </object>
+                                                </object>
+                                            </object>
+                                            <object class="sizeritem">
                                                 <flag>wxLEFT|wxTOP|wxBOTTOM</flag>
                                                 <border>5</border>
                                                 <option>0</option>
diff --git a/src/gui/mainFrame.cpp b/src/gui/mainFrame.cpp
index 6f1d7e2..caa65bd 100644
--- a/src/gui/mainFrame.cpp
+++ b/src/gui/mainFrame.cpp
@@ -1,21 +1,3 @@
-/*
- * 	3Depict.h - main program header
- * 	Copyright (C) 2013 D Haley
- *
- *	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 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 General Public License for more details.
-
- *	You should have received a copy of the GNU General Public License
- *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "mainFrame.h"
 
 #ifdef __APPLE__
@@ -96,6 +78,7 @@ const unsigned int MIN_WIN_WIDTH=100;
 const unsigned int MIN_WIN_HEIGHT=100;
 
 
+
 //!Number of pages in the panel at the bottom
 const unsigned int NOTE_CONSOLE_PAGE_OFFSET= 2;
 
@@ -253,6 +236,8 @@ enum {
     //Options panel
     ID_CHECK_ALPHA,
     ID_CHECK_LIGHTING,
+    ID_CHECK_LIMIT_POINT_OUT,
+    ID_TEXT_LIMIT_POINT_OUT,
     ID_CHECK_CACHING,
     ID_CHECK_WEAKRANDOM,
     ID_SPIN_CACHEPERCENT,
@@ -267,10 +252,18 @@ enum {
 
 };
 
+enum
+{
+	FILE_OPEN_TYPE_UNKNOWN=1,
+	FILE_OPEN_TYPE_XML=2,
+	FILE_OPEN_TYPE_POS=4,
+	FILE_OPEN_TYPE_TEXT=8
+};
+
 
 void setWxTreeImages(wxTreeCtrl *t, const map<size_t, wxArtID> &artFilters)
 {
-#if defined(__WIN32) || defined(__WIN64)
+#if defined(__WIN32) || defined(__WIN64) || defined(__APPLE__)
 	const int winTreeIconSize=9;
 	wxImageList *imList = new wxImageList(winTreeIconSize,winTreeIconSize);
 #else
@@ -283,7 +276,7 @@ void setWxTreeImages(wxTreeCtrl *t, const map<size_t, wxArtID> &artFilters)
 	//Construct an image list for the tree
 	for(map<size_t,wxArtID>::const_iterator it=artFilters.begin();it!=artFilters.end();++it)
 	{
-		#if defined(__WIN32) || defined(__WIN64)
+		#if defined(__WIN32) || defined(__WIN64) || defined(__APPLE__)
 
 			imList->Add(wxBitmap(wxBitmap(wxArtProvider::GetBitmap(it->second)).
 						ConvertToImage().Rescale(winTreeIconSize, winTreeIconSize)));
@@ -354,6 +347,8 @@ MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title
 	fullscreenState=0;
 	verCheckThread=0;
 	lastMessageType=MESSAGE_NONE;
+	lastProgressData.reset();
+
 	//Set up the program icon handler
 	wxArtProvider::Push(new MyArtProvider);
 	SetIcon(wxArtProvider::GetIcon(wxT("MY_ART_ID_ICON")));
@@ -399,12 +394,11 @@ MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title
     panelTop = new BasicGLPane(splitTopBottom);
 
 
-	bool glPanelOK;
 #if wxCHECK_VERSION(2,9,0)
 	glPanelOK = panelTop->displaySupported();
 #else
 	#if defined(__WXGTK20__) 
-		//I had to work this out by studying the constructor, and then testing simultaneously
+		//I had to work this out by studying the construtor, and then testing simultaneously
 		//on a broken and working Gl install. booyah.
 		glPanelOK=panelTop->m_glWidget;
 	#elif defined(__WIN32) || defined(__WIN64) || defined(__APPLE__)
@@ -621,12 +615,21 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
     bitmapFxStereoGlasses = new wxStaticBitmap(noteFxPanelStereo, wxID_ANY, wxNullBitmap);
     labelFxStereoBaseline = new wxStaticText(noteFxPanelStereo, wxID_ANY, wxTRANS("Baseline Separation"));
     sliderFxStereoBaseline = new wxSlider(noteFxPanelStereo,ID_EFFECT_STEREO_BASELINE_SLIDER, 20, 0, 100);
+    labelAppearance = new wxStaticText(noteTools, wxID_ANY, _("Appearance"));
     checkAlphaBlend = new wxCheckBox(noteTools,ID_CHECK_ALPHA , wxTRANS("Smooth && translucent objects"));
     checkAlphaBlend->SetValue(true);
     checkLighting = new wxCheckBox(noteTools, ID_CHECK_LIGHTING, wxTRANS("3D lighting"));
     checkLighting->SetValue(true);
+    static_line_1 = new wxStaticLine(noteTools, wxID_ANY);
+    labelPerformance = new wxStaticText(noteTools, wxID_ANY, wxTRANS("Performance"));
     checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, wxTRANS("Fast and weak randomisation."));
     checkWeakRandom->SetValue(true);
+    checkLimitOutput = new wxCheckBox(noteTools, ID_CHECK_LIMIT_POINT_OUT, wxTRANS("Limit Output Pts"));
+    checkLimitOutput->SetValue((visControl.getIonDisplayLimit() !=0));
+    std::string tmpStr;
+    stream_cast(tmpStr,visControl.getIonDisplayLimit());
+    textLimitOutput = new wxTextCtrl(noteTools, ID_TEXT_LIMIT_POINT_OUT, wxStr(tmpStr),
+		    	wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER );
     checkCaching = new wxCheckBox(noteTools, ID_CHECK_CACHING, wxTRANS("Filter caching"));
     checkCaching->SetValue(true);
     labelMaxRamUsage = new wxStaticText(noteTools, wxID_ANY, wxTRANS("Max. Ram usage (%)"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
@@ -764,7 +767,11 @@ MainWindowFrame::~MainWindowFrame()
 
 	//delete the file history  pointer
 	delete recentHistory;
-    
+   
+   	//Bindings did not get initialised, if glpane is not OK,
+	// so abort, rather than disconnecting
+   	if(!glPanelOK)
+		return; 
 
 	//wxwidgets can crash if objects are ->Connect-ed  in 
 	// wxWindowBase::DestroyChildren(), so Disconnect before destructing
@@ -870,6 +877,9 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
     EVT_CHECKBOX(ID_EFFECT_STEREO_LENSFLIP, MainWindowFrame::OnFxStereoLensFlip)
     EVT_COMBOBOX(ID_EFFECT_STEREO_COMBO, MainWindowFrame::OnFxStereoCombo)
     EVT_COMMAND_SCROLL(ID_EFFECT_STEREO_BASELINE_SLIDER, MainWindowFrame::OnFxStereoBaseline)
+    EVT_TEXT(ID_TEXT_LIMIT_POINT_OUT, MainWindowFrame::OnTextLimitOutput)
+    EVT_TEXT_ENTER(ID_TEXT_LIMIT_POINT_OUT, MainWindowFrame::OnTextLimitOutputEnter)
+    EVT_CHECKBOX(ID_CHECK_LIMIT_POINT_OUT, MainWindowFrame::OnCheckLimitOutput)
   
 
     EVT_COMMAND(wxID_ANY, RemoteUpdateAvailEvent, MainWindowFrame::OnCheckUpdatesThread)
@@ -877,6 +887,35 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
 END_EVENT_TABLE();
 
 
+unsigned int MainWindowFrame::guessFileType(const std::string &dataFile)
+{
+	
+	//Split the filename into chunks: path, volume, name and extension
+	//the format of this is OS dependant, but wxWidgets can deal with this.
+	wxFileName fname;
+	wxString volume,path,name,ext;
+	bool hasExt;
+	fname.SplitPath(wxStr(dataFile),&volume,
+			&path,&name,&ext, &hasExt);
+
+	//Test the extension to determine what we will do
+	//TODO: This is really lazy, and I should use something like libmagic.
+	std::string extStr;
+	extStr=stlStr(ext);
+
+	if( extStr == std::string("xml"))
+		return FILE_OPEN_TYPE_XML;
+	
+	if( extStr == std::string("txt"))
+		return FILE_OPEN_TYPE_TEXT;
+
+	if( extStr == std::string("pos"))
+		return FILE_OPEN_TYPE_POS;
+
+	return FILE_OPEN_TYPE_UNKNOWN;
+}
+
+
 bool MainWindowFrame::getTreeFilterId(const wxTreeItemId &tId, size_t &filterId) const
 {
 	if(!tId.IsOk())
@@ -892,6 +931,24 @@ bool MainWindowFrame::getTreeFilterId(const wxTreeItemId &tId, size_t &filterId)
 	return true;
 }
 
+void MainWindowFrame::checkAskSaveState()
+{
+
+	if(visControl.hasStateData() && visControl.stateModifyLevel() >=STATE_MODIFIED_ANCILLARY)
+	{
+		wxMessageDialog *wxD  =new wxMessageDialog(this,
+			wxTRANS("Current state has not been saved, would you like to save it now?")
+			,wxTRANS("State changed"),wxYES_NO|wxICON_QUESTION|wxYES_DEFAULT );
+		wxD->SetAffirmativeId(wxID_YES);
+		wxD->SetEscapeId(wxID_NO);
+
+		if ( wxD->ShowModal()== wxID_YES) 
+		{
+			wxCommandEvent event;
+			OnFileSave(event);
+		}
+	}
+}
 
 void MainWindowFrame::OnFileOpen(wxCommandEvent &event)
 {
@@ -899,6 +956,9 @@ void MainWindowFrame::OnFileOpen(wxCommandEvent &event)
 	if(currentlyUpdatingScene || visControl.isRefreshing())
 		return;
 
+
+
+
 	//Load a file, either a state file, or a new pos file
 	wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Select Data or State File..."), wxT(""),
 		wxT(""),wxTRANS("Readable files (*.xml, *.pos, *.txt,*.csv)|*.xml;*.pos;*.txt;*.csv|POS File (*.pos)|*.pos|XML State File (*.xml)|*.xml|Text Data Files (*.txt/csv)|*.txt;*.csv|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
@@ -907,6 +967,14 @@ void MainWindowFrame::OnFileOpen(wxCommandEvent &event)
 	if( (wxF->ShowModal() == wxID_CANCEL))
 		return;
 
+	//See if the user would like to save state, if we are opening a state file
+	// which will overwrite our current state
+	std::string filePath = stlStr(wxF->GetPath());
+	if(guessFileType(filePath) == FILE_TYPE_XML)
+		checkAskSaveState();
+		
+	
+	
 	textConsoleOut->Clear();
 	//Get vis controller to update tree control to match internal
 	// structure. Retain tree selection & visibility if we currently
@@ -963,6 +1031,8 @@ void MainWindowFrame::OnFileMerge(wxCommandEvent &event)
 	statusMessage(TRANS("Merged file."),MESSAGE_INFO);
 
 	panelTop->Refresh();
+
+	setSaveStatus();
 	
 	wxF->Destroy();
 }
@@ -1079,24 +1149,13 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 
 bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 {
-
 	//Don't try to alter viscontrol if we are refreshing. That would be bad.
 	ASSERT(!visControl.isRefreshing());
+	
 	std::string dataFile = stlStr(fileStr);
+	unsigned int fileType=guessFileType(dataFile);
 	
-	//Split the filename into chunks: path, volume, name and extension
-	//the format of this is OS dependant, but wxWidgets can deal with this.
-	wxFileName fname;
-	wxString volume,path,name,ext;
-	bool hasExt;
-	fname.SplitPath(fileStr,&volume,
-			&path,&name,&ext, &hasExt);
-
-	//Test the extension to determine what we will do
-	//TODO: This is really lazy, and I should use something like libmagic.
-	std::string extStr;
-	extStr=stlStr(ext);
-	if( extStr == std::string("xml"))
+	if(fileType == FILE_OPEN_TYPE_XML)
 	{
 		std::stringstream ss;
 		
@@ -1117,20 +1176,6 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 			return false;
 		}
 
-		//Try to restore the working directory as needed
-		if(!(visControl.getWorkDir().size()))
-		{
-			wxString wd;
-			wd = wxGetCwd();
-			visControl.setWorkDir(stlStr(wd));
-		}
-		else
-		{
-			if(wxDirExists(wxStr(visControl.getWorkDir())))
-				wxSetWorkingDirectory(wxStr(visControl.getWorkDir()));
-		}
-
-
 
 		if(visControl.hasHazardousContents())
 		{
@@ -1152,32 +1197,29 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 
 		checkViewWorldAxis->Check(visControl.getAxisVisible());
 
+		{
 		//Update the camera dropdown
-		vector<std::pair<unsigned int, std::string> > camData;
-		visControl.getCamData(camData);
+		vector<std::string > camNames;
+		visControl.getCamData(camNames);
 
 		comboCamera->Clear();
-		unsigned int uniqueID;
-		//Skip the first element, as it is a hidden camera.
-		for(unsigned int ui=1;ui<camData.size();ui++)
+		for(unsigned int ui=1;ui<camNames.size();ui++)
 		{
 			//Do not delete as this will be deleted by wx
-			comboCamera->Append(wxStr(camData[ui].second),
-					(wxClientData *)new wxListUint(camData[ui].first));	
+			comboCamera->Append(wxStr(camNames[ui]),
+					(wxClientData *)new wxListUint(ui));	
 			//If this is the active cam (1) set the selection and (2) remember
 			//the ID
-			if(camData[ui].first == visControl.getActiveCamId())
-			{
+			if(ui == visControl.getActiveCamId())
 				comboCamera->SetSelection(ui-1);
-				uniqueID=camData[ui].first;
-			}
 		}
 
 		//Only update the camera grid if we have a valid uniqueID
-		if(camData.size() > 1)
+		if(camNames.size() > 1)
 		{
 			//Use the remembered ID to update the grid.
-			visControl.updateCamPropertyGrid(gridCameraProperties,uniqueID);
+			visControl.updateCamPropertyGrid(gridCameraProperties,
+						visControl.getActiveCamId());
 		}
 		else
 		{
@@ -1185,6 +1227,7 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 			gridCameraProperties->clear();
 			comboCamera->SetValue(wxCStr(TRANS(cameraIntroString)));
 		}
+		}
 
 		//reset the stash combo box
 		comboStash->SetValue(wxCStr(TRANS(stashIntroString)));
@@ -1201,7 +1244,6 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 
 
 
-		currentFile =fileStr;
 		fileSave->Enable(true);
 
 		
@@ -1227,14 +1269,13 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 
 		FilterTree fTree;
 
-		Filter *posFilter,*downSampleFilter;
+		Filter *posFilter;
 		posFilter= configFile.getDefaultFilter(FILTER_TYPE_DATALOAD);
-		downSampleFilter= configFile.getDefaultFilter(FILTER_TYPE_IONDOWNSAMPLE);
 
 		//Bastardise the default settings such that it knows to use the correct
 		// file type, based upon file extension
 		unsigned int fileMode;
-		if(extStr == std::string("txt") || extStr == std::string("csv") )
+		if(fileType == FILE_OPEN_TYPE_TEXT)
 			fileMode=DATALOAD_TEXT_FILE;
 		else
 			fileMode=DATALOAD_FLOAT_FILE;
@@ -1251,10 +1292,8 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge)
 
 		//Append a new filter to the filter tree
 		fTree.addFilter(posFilter,0);
-		fTree.addFilter(downSampleFilter,posFilter);
 		visControl.addFilterTree(fTree,true,0);
 
-		currentFile.clear();
 	}	
 
 	visControl.updateWxTreeCtrl(treeFilters);
@@ -1282,15 +1321,21 @@ void MainWindowFrame::OnRecentFile(wxCommandEvent &event)
 		if(getTreeFilterId(treeFilters->GetSelection(),filterId))
 			visControl.setWxTreeFilterViewPersistence(filterId);
 
-
 		bool loadOK=false;
 		if(!wxFileExists(f))
 			statusMessage("File does not exist",MESSAGE_ERROR);
-		else if(loadFile(f))
+		else 
 		{
-			if(loadOK)
-				statusMessage(TRANS("Loaded file."),MESSAGE_INFO);
-			panelTop->Refresh();
+			//See if the user wants to save the current state
+			if(guessFileType(stlStr(f)) == FILE_TYPE_XML)
+				checkAskSaveState();
+		
+			if(loadFile(f))
+			{
+				if(loadOK)
+					statusMessage(TRANS("Loaded file."),MESSAGE_INFO);
+				panelTop->Refresh();
+			}
 		}
 		
 		if(!loadOK)
@@ -1300,44 +1345,44 @@ void MainWindowFrame::OnRecentFile(wxCommandEvent &event)
 			recentHistory->RemoveFileFromHistory(event.GetId()-wxID_FILE1);
 			configFile.removeRecentFile(stlStr(f));
 		}
+		
+		setSaveStatus();
 	}
+
 }
 
 void MainWindowFrame::OnFileSave(wxCommandEvent &event)
 {
-	if(!currentFile.length())
-		return;
+	std::string saveFilename=visControl.getFilename();
 
+	//Save menu should not be selectable if there is no file to save to.
+	ASSERT(!saveFilename.empty());
 	//If the file does not exist, use saveas instead
-	if(!wxFileExists(currentFile))
+	if( saveFilename.empty()  || !wxFileExists(wxStr(saveFilename)))
 	{
 		OnFileSaveAs(event);
-
 		return;
 	}
-
 	
 	std::map<string,string> dummyMap;
-	std::string dataFile = stlStr(currentFile);
-
 	//Try to save the viscontrol state
-	if(!visControl.saveState(dataFile.c_str(),dummyMap))
+	if(!visControl.saveState(saveFilename.c_str(),dummyMap))
 	{
 		wxErrMsg(this,TRANS("Save error"),TRANS("Unable to save. Check output destination can be written to."));
 	}
 	else
 	{
-		fileSave->Enable(true);
-
 		//Update the recent files, and the menu.
-		configFile.addRecentFile(dataFile);
-		recentHistory->AddFileToHistory(wxStr(dataFile));
-		
-		dataFile=std::string("Saved state: ") + dataFile;
-		statusMessage(dataFile.c_str(),MESSAGE_INFO);
+		configFile.addRecentFile(saveFilename);
+		recentHistory->AddFileToHistory(wxStr(saveFilename));
+	
+		std::string tmpStr;
+		tmpStr=	std::string("Saved state: ") + saveFilename;
+		statusMessage(tmpStr.c_str(),MESSAGE_INFO);
 
 	}
 
+	setSaveStatus();
 }
 
 void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event)
@@ -1621,10 +1666,19 @@ void MainWindowFrame::setLockUI(bool locking=true,
 			checkWeakRandom->Enable(!locking);
 			checkCaching->Enable(!locking);
 			spinCachePercent->Enable(!locking);
+			textLimitOutput->Enable(!locking);
+			checkLimitOutput->Enable(!locking);
 
 			fileMenu->Enable(ID_FILE_OPEN,!locking);
 			fileMenu->Enable(ID_FILE_MERGE,!locking);
-			fileMenu->Enable(ID_FILE_SAVE,!locking);
+
+			//Save menu needs to be handled specially in the case of an unlock
+			// as determining if it can be enabled needs work
+			if(!locking)
+				fileMenu->Enable(ID_FILE_SAVE,false);
+			else
+				setSaveStatus();
+
 			fileMenu->Enable(ID_FILE_SAVEAS,!locking);
 
 			for(size_t ui=0;ui<recentFilesMenu->GetMenuItemCount();ui++)
@@ -1657,9 +1711,16 @@ void MainWindowFrame::setLockUI(bool locking=true,
 
 			fileMenu->Enable(ID_FILE_OPEN,!locking);
 			fileMenu->Enable(ID_FILE_MERGE,!locking);
-			fileMenu->Enable(ID_FILE_SAVE,!locking);
 			fileMenu->Enable(ID_FILE_SAVEAS,!locking);
+			
+			//Save menu needs to be handled specially in the case of an unlock
+			// as determining if it can be enabled needs work
+			if(!locking)
+				fileMenu->Enable(ID_FILE_SAVE,false);
+			else
+				setSaveStatus();
 
+			//Lock/unlock all the recent files entries
 			for(size_t ui=0;ui<recentFilesMenu->GetMenuItemCount();ui++)
 			{
 				wxMenuItem *m;
@@ -1675,8 +1736,11 @@ void MainWindowFrame::setLockUI(bool locking=true,
 			//Locking of the tools pane
 			checkWeakRandom->Enable(!locking);
 			checkCaching->Enable(!locking);
+			checkLimitOutput->Enable(!locking);
+			textLimitOutput->Enable(!locking);
 			spinCachePercent->Enable(!locking);
 
+
 			//Lock panel spectra, so we cannot alter things like ranges
 			panelSpectra->limitInteraction(locking);
 			break;
@@ -1786,9 +1850,10 @@ void MainWindowFrame::OnFileExportFilterVideo(wxCommandEvent &event)
 			{
 				if(exportDialog->wantsImages())
 				{
+					vector<SelectionDevice *> dummy;
 					//update the output streams, but do not release
 					// the contents.
-					if(visControl.doUpdateScene(outStreams,false))
+					if(visControl.doUpdateScene(outStreams,dummy,false))
 					{
 						pair<string,string> errMsg;
 						string tmpStr;
@@ -2284,8 +2349,9 @@ void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 	}
 	else
 	{
-		currentFile = wxF->GetPath();
-		fileSave->Enable(true);
+		std::string tmpStr;
+		tmpStr=stlStr(wxF->GetPath());
+		visControl.setFilename(tmpStr);
 
 		//Update the recent files, and the menu.
 		configFile.addRecentFile(dataFile);
@@ -2297,6 +2363,8 @@ void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 
 	//Restore the relative path behaviour
 	visControl.setUseRelPaths(oldRelPath);
+	
+	setSaveStatus();
 }
 
 
@@ -3184,7 +3252,7 @@ void MainWindowFrame::OnTreeKeyDown(wxTreeEvent &event)
 	
 			//Force a scene update, independent of if autoUpdate is enabled. 
 			doSceneUpdate();	
-
+		
 			break;
 		}
 		default:
@@ -3234,7 +3302,7 @@ void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event)
 		clearWxTreeImages(treeFilters);
 
 	visControl.updateFilterPropGrid(gridFilterPropGroup,filterId);
-	
+
 	Layout();
 	programmaticEvent=false;
 }
@@ -3333,6 +3401,8 @@ void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event)
 		//refresh the camera property grid
 		visControl.updateCamPropertyGrid(gridCameraProperties ,l->value);
 
+		setSaveStatus();
+
 		//force redraw in 3D pane
 		panelTop->Refresh(false);
 		return ;
@@ -3350,6 +3420,8 @@ void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event)
 	visControl.setCam(u);
 	visControl.updateCamPropertyGrid(gridCameraProperties,u);
 	panelTop->Refresh(false);
+
+	setSaveStatus();
 }
 
 void MainWindowFrame::OnComboCamera(wxCommandEvent &event)
@@ -3367,6 +3439,8 @@ void MainWindowFrame::OnComboCamera(wxCommandEvent &event)
 	statusMessage(s.c_str(),MESSAGE_INFO);
 	
 	panelTop->Refresh(false);
+	
+	setSaveStatus();
 	return ;
 }
 
@@ -3510,6 +3584,7 @@ void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 		doSceneUpdate();
 
 	comboFilters->SetValue(wxT(""));
+	
 }
 
 bool MainWindowFrame::doSceneUpdate()
@@ -3522,6 +3597,7 @@ bool MainWindowFrame::doSceneUpdate()
 	progressTimer->Start(PROGRESS_TIMER_DELAY);		
 	currentlyUpdatingScene=true;
 	haveAborted=false;
+	panelTop->currentScene.setShowProgress(true);
 
 		
 	statusMessage("",MESSAGE_NONE);
@@ -3575,6 +3651,7 @@ bool MainWindowFrame::doSceneUpdate()
 
 	updateLastRefreshBox();
 
+	panelTop->currentScene.setShowProgress(false);
 
 	//Add (or hide) a little "Star" to inform the user there is some info available
 	if(textConsoleOut->IsEmpty() || noteDataView->GetSelection()==NOTE_CONSOLE_PAGE_OFFSET)
@@ -3593,6 +3670,8 @@ bool MainWindowFrame::doSceneUpdate()
 
 	visControl.updateRawGrid();
 
+	setSaveStatus();
+
 	//Return a value dependant upon whether we successfully loaded 
 	//the data or not
 	return errCode == 0;
@@ -3693,14 +3772,19 @@ void MainWindowFrame::OnAutosaveTimer(wxTimerEvent &event)
 	//Save to the autosave file
 	std::string s;
 	s=  stlStr(filePath);
-	std::map<string,string> dummyMap;
-	if(visControl.saveState(s.c_str(),dummyMap))
-		statusMessage(TRANS("Autosave complete."),MESSAGE_INFO);
-	else
+
+	//Only save if we have autosave data
+	if(visControl.hasStateData())
 	{
-		//The save failed, but may have left an incomplete file lying around
-		if(wxFileExists(filePath))
-			wxRemoveFile(filePath);
+		std::map<string,string> dummyMap;
+		if(visControl.saveState(s.c_str(),dummyMap,false,false))
+			statusMessage(TRANS("Autosave complete."),MESSAGE_INFO);
+		else
+		{
+			//The save failed, but may have left an incomplete file lying around
+			if(wxFileExists(filePath))
+				wxRemoveFile(filePath);
+		}
 	}
 
 
@@ -3763,8 +3847,8 @@ void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event)
 	{
 		//Use the current combobox value to determine which camera is the 
 		//current camera in the property grid
-		
-
+		visControl.getCameraUpdates();
+			
 		int n = comboCamera->FindString(comboCamera->GetValue());
 
 		if(n != wxNOT_FOUND)
@@ -3776,6 +3860,8 @@ void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event)
 		}
 
 		panelTop->clearCameraUpdates();
+
+		setSaveStatus();
 	}
 
 	if(plotUpdates)
@@ -3795,6 +3881,7 @@ void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event)
 
 	}
 
+
 	programmaticEvent=false;	
 }
 
@@ -3854,8 +3941,17 @@ void MainWindowFrame::updateProgressStatus()
 	}
 	else
 	{
+		//Check for new progress data
 		ProgressData p;
 		p=visControl.getProgress();
+
+		if(p == lastProgressData)
+			return;
+		lastProgressData=p;
+
+
+		//Update the text progress
+		{
 		ASSERT(p.totalProgress <= visControl.numFilters());
 		
 		if(p.filterProgress > 100)
@@ -3896,10 +3992,20 @@ void MainWindowFrame::updateProgressStatus()
 				progressString = totalProg + TRANS(" of ") + totalCount;
 		}
 
+
 		if( p.filterProgress != 100)
 			filterProg+=TRANS("\% Done (Esc aborts)");
 		else
 			filterProg+=TRANS("\% Done");
+		}
+
+		//Update the scene progress icon
+		if(panelTop->currentScene.getShowProgress())
+		{
+			wxPaintEvent wxP;
+			wxPostEvent(panelTop,wxP);
+		}
+
 
 	}
 
@@ -3907,6 +4013,7 @@ void MainWindowFrame::updateProgressStatus()
 	MainFrame_statusbar->SetStatusText(wxT(""),0);
 	MainFrame_statusbar->SetStatusText(wxStr(progressString),1);
 	MainFrame_statusbar->SetStatusText(wxStr(filterProg),2);
+
 }
 
 void MainWindowFrame::updatePostEffects()
@@ -4227,6 +4334,7 @@ void MainWindowFrame::OnButtonRefresh(wxCommandEvent &event)
 			statusMessage(TRANS("Tip: You can shift-click to force full refresh, if required"),MESSAGE_HINT);
 	}
 	doSceneUpdate();	
+	
 }
 
 void MainWindowFrame::OnRawDataUnsplit(wxSplitterEvent &event)
@@ -4370,6 +4478,8 @@ void MainWindowFrame::OnFilterGridCellEditorShow(wxGridEvent &event)
 		else
 			clearWxTreeImages(treeFilters);
 	}
+
+	setSaveStatus();
 }
 
 void MainWindowFrame::OnFilterGridCellEditorHide(wxGridEvent &event)
@@ -4464,7 +4574,8 @@ void MainWindowFrame::OnCameraGridCellEditorShow(wxGridEvent &event)
 	}
 
 	panelTop->Refresh(false);
-	
+
+	setSaveStatus();
 }
 
 void MainWindowFrame::OnButtonGridCopy(wxCommandEvent &event)
@@ -4516,6 +4627,61 @@ void MainWindowFrame::OnCheckWeakRandom(wxCommandEvent &event)
 	doSceneUpdate();
 }
 
+void MainWindowFrame::OnCheckLimitOutput(wxCommandEvent &event)
+{
+	size_t limitVal;
+	if(event.IsChecked())
+	{
+		bool isOK=validateTextAsStream(textLimitOutput,limitVal);
+
+		if(!isOK)
+			return;
+	}
+	else
+		limitVal=0;
+
+	visControl.setIonDisplayLimit(limitVal);
+	doSceneUpdate();
+	
+	configFile.setMaxPoints(limitVal);
+}
+
+void MainWindowFrame::OnTextLimitOutput(wxCommandEvent &event)
+{
+	size_t limitVal;
+	bool isOK=validateTextAsStream(textLimitOutput,limitVal);
+
+	if(!isOK)
+		return;
+
+	if(checkLimitOutput->IsChecked())
+	{
+		visControl.setIonDisplayLimit(limitVal);
+		configFile.setMaxPoints(limitVal);
+	}
+}
+
+void MainWindowFrame::OnTextLimitOutputEnter(wxCommandEvent &event)
+{
+	size_t limitVal;
+	bool isOK=validateTextAsStream(textLimitOutput,limitVal);
+
+	if(!isOK)
+		return;
+
+	if(checkLimitOutput->IsChecked())
+	{
+		visControl.setIonDisplayLimit(limitVal);
+		doSceneUpdate();
+	}
+
+	//If we set the limit to zero this is a special case
+	// that disables the limit, so untick the checkbox to make it clear to the
+	// user that we are not using this any more
+	if(limitVal == 0)
+		checkLimitOutput->SetValue(false);
+}
+
 void MainWindowFrame::OnCacheRamUsageSpin(wxSpinEvent &event)
 {
 	ASSERT(event.GetPosition() >= 0 &&event.GetPosition()<=100);
@@ -4547,7 +4713,10 @@ void MainWindowFrame::OnButtonRemoveCam(wxCommandEvent &event)
 		comboCamera->SetValue(wxT(""));
 		gridCameraProperties->clear();
 		programmaticEvent=false;
+
+		setSaveStatus();
 	}
+	
 }
 
 void MainWindowFrame::OnSpectraListbox(wxCommandEvent &event)
@@ -4611,7 +4780,7 @@ void MainWindowFrame::OnClose(wxCloseEvent &event)
 		// as we can't abort it anyway.
 		if(event.CanVeto())
 		{
-			if(visControl.numFilters() || visControl.numCams() > 1)
+			if(visControl.stateModifyLevel() >= STATE_MODIFIED_ANCILLARY)
 			{
 				//Prompt for close
 				wxMessageDialog *wxD  =new wxMessageDialog(this,
@@ -4708,6 +4877,8 @@ void MainWindowFrame::OnCheckPostProcess(wxCommandEvent &event)
 	noteFxPanelStereo->Enable(event.IsChecked());
 	visControl.setEffects(event.IsChecked());
 	updatePostEffects();
+		
+	setSaveStatus();
 	
 	panelTop->Refresh();
 }
@@ -4729,6 +4900,8 @@ void MainWindowFrame::OnFxCropCheck(wxCommandEvent &event)
 	labelFxCropDy->Enable(event.IsChecked());
 	labelFxCropDz->Enable(event.IsChecked());
 
+	setSaveStatus();
+
 	updatePostEffects();
 }
 
@@ -4859,6 +5032,19 @@ void MainWindowFrame::restoreConfigDefaults()
 
 	panelTop->setMouseZoomFactor((float)zoomRate/100.0f);
 	panelTop->setMouseMoveFactor((float)moveRate/100.0f);
+
+
+	//If the config file has a max points value stored, use it,
+	// but don't force a refresh, as we will do that later
+	if(configFile.getHaveMaxPoints())
+	{
+		std::string s;
+		stream_cast(s,configFile.getMaxPoints());
+
+		textLimitOutput->SetValue(wxStr(s));
+
+		visControl.setIonDisplayLimit(configFile.getMaxPoints());
+	}
 }
 
 void MainWindowFrame::restoreConfigPanelDefaults()
@@ -5099,8 +5285,10 @@ void MainWindowFrame::checkReloadAutosave()
 				requireFirstUpdate=true;
 				//Prevent the program from allowing save menu usage
 				//into autosave file
-				currentFile.clear();
-				fileSave->Enable(false);		
+				std::string tmpStr;
+				visControl.setFilename(tmpStr);
+
+				setSaveStatus();
 			}
 
 		
@@ -5163,8 +5351,8 @@ void MainWindowFrame::checkReloadAutosave()
 				{
 					//Prevent the program from allowing save menu usage
 					//into autosave file
-					currentFile.clear();
-					fileSave->Enable(false);
+					
+					
 					doErase=true;
 				}
 				else 
@@ -5228,11 +5416,18 @@ void MainWindowFrame::checkReloadAutosave()
 			wxFileName fileNaming(wxStr(removeFiles[ui]));
 			wxCopyFile(wxStr(removeFiles[ui]),wxtmpDir+fileNaming.GetFullName()); 
 		}
-		//if the copy works or not, just delete the autosave anyway
+		//if the copy works or not, just delete the autsave anyway
 		wxRemoveFile(wxStr(removeFiles[ui]));	
 	}
 }
 
+void MainWindowFrame::setSaveStatus()
+{
+	fileSave->Enable(
+		(visControl.stateModifyLevel() >=STATE_MODIFIED_ANCILLARY)
+			&& visControl.getFilename().size());
+}
+
 wxSize MainWindowFrame::getNiceWindowSize() const
 {
 	wxDisplay *disp=new wxDisplay;
@@ -5284,6 +5479,8 @@ void MainWindowFrame::set_properties()
     checkAlphaBlend->SetToolTip(wxTRANS("Enable/Disable \"Alpha blending\" (transparency) in rendering system. Blending is used to smooth objects (avoids artefacts known as \"jaggies\") and to make transparent surfaces. Disabling will provide faster rendering but look more blocky")); 
     checkLighting->SetToolTip(wxTRANS("Enable/Disable lighting calculations in rendering, for objects that request this. Lighting provides important depth cues for objects comprised of 3D surfaces. Disabling may allow faster rendering in complex scenes"));
     checkWeakRandom->SetToolTip(wxTRANS("Enable/Disable weak randomisation (Galois linear feedback shift register). Strong randomisation uses a much slower random selection method, but provides better protection against inadvertent correlations, and is recommended for final analyses"));
+
+    checkLimitOutput->SetToolTip(wxTRANS("Limit the number of points that can be displayed in the 3D  scene. Does not affect filter tree calculations. Disabling this can severely reduce performance, due to large numbers of points being visible at once."));
     checkCaching->SetToolTip(wxTRANS("Enable/Disable caching of intermediate results during filter updates. Disabling caching will use less system RAM, though changes to any filter property will cause the entire filter tree to be recomputed, greatly slowing computations"));
 
     gridFilterPropGroup->CreateGrid(0, 2);
@@ -5369,6 +5566,7 @@ void MainWindowFrame::do_layout()
     wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizerTools = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizerToolsRamUsage = new wxBoxSizer(wxHORIZONTAL);
+    wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL);
     wxBoxSizer* postProcessSizer = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizerFxStereo = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizerSetereoBaseline = new wxBoxSizer(wxHORIZONTAL);
@@ -5466,9 +5664,15 @@ void MainWindowFrame::do_layout()
     noteEffects->AddPage(noteFxPanelStereo, wxTRANS("Stereo"));
     postProcessSizer->Add(noteEffects, 1, wxEXPAND, 0);
     notePost->SetSizer(postProcessSizer);
+    sizerTools->Add(labelAppearance, 0, wxTOP, 3);
     sizerTools->Add(checkAlphaBlend, 0, wxLEFT|wxTOP|wxBOTTOM, 5);
     sizerTools->Add(checkLighting, 0, wxLEFT|wxTOP|wxBOTTOM, 6);
+    sizerTools->Add(static_line_1, 0, wxEXPAND, 0);
+    sizerTools->Add(labelPerformance, 0, wxTOP, 3);
     sizerTools->Add(checkWeakRandom, 0, wxLEFT|wxTOP|wxBOTTOM, 5);
+    sizer_1->Add(checkLimitOutput, 0, wxRIGHT, 3);
+    sizer_1->Add(textLimitOutput, 0, wxLEFT, 4);
+    sizerTools->Add(sizer_1, 0, wxLEFT|wxEXPAND, 5);
     sizerTools->Add(checkCaching, 0, wxLEFT|wxTOP|wxBOTTOM, 5);
     sizerToolsRamUsage->Add(labelMaxRamUsage, 0, wxRIGHT|wxALIGN_RIGHT, 5);
     sizerToolsRamUsage->Add(spinCachePercent, 0, 0, 5);
@@ -5503,6 +5707,7 @@ void MainWindowFrame::do_layout()
     splitLeftRight->SplitVertically(panelLeft, panelRight);
     topSizer->Add(splitLeftRight, 1, wxEXPAND, 0);
     SetSizer(topSizer);
+    topSizer->Fit(this);
     Layout();
     // end wxGlade
     //
diff --git a/src/gui/mainFrame.h b/src/gui/mainFrame.h
index 06b8d9d..c36bc04 100644
--- a/src/gui/mainFrame.h
+++ b/src/gui/mainFrame.h
@@ -102,6 +102,8 @@ private:
 
 	void setLockUI(bool amlocking,unsigned int lockMode);
 
+	//Did the opengl panel initialise correctly?
+	bool glPanelOK;
 	//!Scene - user interaction interface "visualisation control"
 	VisController visControl;
 
@@ -122,9 +124,6 @@ private:
 	//!source item when dragging a filter in the tree control
 	wxTreeItemId *filterTreeDragSource;
 
-	//!The current file if we are using an XML file
-	wxString currentFile;
-
 	//!Drag and drop functionality
 	FileDropTarget *dropTarget;
 	
@@ -144,10 +143,6 @@ private:
 	//Map to convert filter drop down choices to IDs
 	map<std::string,size_t> filterMap;
     
-
-#ifdef DEBUG
-    ofstream fs; // file for writing the event log
-#endif
 protected:
     wxTimer *statusTimer;
     wxTimer *progressTimer;
@@ -166,6 +161,7 @@ protected:
     wxMenu *fileMenu;
     wxMenu *fileExport;
     wxFileHistory *recentHistory;
+    ProgressData lastProgressData;
 
 
     // begin wxGlade: MainWindowFrame::attributes
@@ -173,6 +169,7 @@ protected:
     wxStaticText* lblSettings;
     wxComboBox* comboStash;
     wxButton* btnStashManage;
+    wxStaticLine* stashFilterStaticSep;
     wxStaticText* filteringLabel;
     wxComboBox* comboFilters;
     wxTreeCtrl* treeFilters;
@@ -197,11 +194,11 @@ protected:
     wxScrolledWindow* noteCamera;
     wxCheckBox* checkPostProcessing;
     wxCheckBox* checkFxCrop;
+    wxCheckBox* checkFxCropCameraFrame;
     wxComboBox* comboFxCropAxisOne;
     CropPanel* panelFxCropOne;
     wxComboBox* comboFxCropAxisTwo;
     CropPanel* panelFxCropTwo;
-    wxCheckBox* checkFxCropCameraFrame;
     wxStaticText* labelFxCropDx;
     wxTextCtrl* textFxCropDx;
     wxStaticText* labelFxCropDy;
@@ -210,18 +207,23 @@ protected:
     wxTextCtrl* textFxCropDz;
     wxPanel* noteFxPanelCrop;
     wxCheckBox* checkFxEnableStereo;
-    wxCheckBox* checkFxStereoLensFlip;
     wxStaticText* lblFxStereoMode;
     wxComboBox* comboFxStereoMode;
     wxStaticBitmap* bitmapFxStereoGlasses;
     wxStaticText* labelFxStereoBaseline;
     wxSlider* sliderFxStereoBaseline;
+    wxCheckBox* checkFxStereoLensFlip;
     wxPanel* noteFxPanelStereo;
     wxNotebook* noteEffects;
     wxPanel* notePost;
+    wxStaticText* labelAppearance;
     wxCheckBox* checkAlphaBlend;
     wxCheckBox* checkLighting;
+    wxStaticLine* static_line_1;
+    wxStaticText* labelPerformance;
     wxCheckBox* checkWeakRandom;
+    wxCheckBox* checkLimitOutput;
+    wxTextCtrl* textLimitOutput;
     wxCheckBox* checkCaching;
     wxStaticText* labelMaxRamUsage;
     wxSpinCtrl* spinCachePercent;
@@ -249,6 +251,9 @@ protected:
     wxStatusBar* MainFrame_statusbar;
     // end wxGlade
 
+    //Set the state for the state menu
+    void setSaveStatus();
+
     DECLARE_EVENT_TABLE();
 
 public:
@@ -256,6 +261,10 @@ public:
     virtual void OnFileMerge(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnFileSave(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnFileSaveAs(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnFileExportPlot(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnFileExportImage(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnFileExportIons(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnFileExportRange(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnFileExit(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnViewControlPane(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnViewRawDataPane(wxCommandEvent &event); // wxGlade: <event_handler>
@@ -301,6 +310,9 @@ public:
     virtual void OnCheckWeakRandom(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnCacheRamUsageSpin(wxSpinEvent &event); // wxGlade: <event_handler>
     virtual void OnSpectraListbox(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnCheckLimitOutput(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnTextLimitOutput(wxCommandEvent &event); // wxGlade: <event_handler>
+    virtual void OnTextLimitOutputEnter(wxCommandEvent &event); // wxGlade: <event_handler>
 
     virtual void OnComboFilterEnter(wxCommandEvent &event); // 
     virtual void OnComboFilter(wxCommandEvent &event); // 
@@ -332,10 +344,6 @@ public:
     virtual void OnNoteDataView(wxNotebookEvent &evt);
     virtual void OnGridCameraPropertyChange(wxGridEvent &event); // wxGlade: <event_handler>
 
-    virtual void OnFileExportPlot(wxCommandEvent &event); // wxGlade: <event_handler>
-    virtual void OnFileExportImage(wxCommandEvent &event); // wxGlade: <event_handler>
-    virtual void OnFileExportIons(wxCommandEvent &event); // wxGlade: <event_handler>
-    virtual void OnFileExportRange(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnFileExportVideo(wxCommandEvent &event);
     virtual void OnFileExportFilterVideo(wxCommandEvent &event);
     virtual void OnFileExportPackage(wxCommandEvent &event);
@@ -351,7 +359,12 @@ public:
     virtual void SetCommandLineFiles(wxArrayString &files);
     virtual void updateLastRefreshBox();
 
+    //return type of file, based upon heuristic check
+    static unsigned int guessFileType(const std::string &file);
 
+    //See if the user wants to save the current state
+    void checkAskSaveState();
+    
     //Check to see if we need to reload an autosave file (and reload it, as needed)
     void checkReloadAutosave();
 
diff --git a/src/gui/mathglPane.cpp b/src/gui/mathglPane.cpp
index 1180f95..4d76ce1 100644
--- a/src/gui/mathglPane.cpp
+++ b/src/gui/mathglPane.cpp
@@ -105,6 +105,12 @@ MathGLPane::~MathGLPane()
 }
 
 
+bool MathGLPane::readyForInput() const
+{
+	return (thePlot && gr && 
+		!thePlot->isInteractionLocked() && !thePlot->visibleEmpty());
+}
+
 unsigned int MathGLPane::getAxisMask(int x, int y) const
 {
 	
@@ -229,7 +235,7 @@ void MathGLPane::render(wxPaintEvent &event)
 
 
 	//If the plot has changed, been resized or is performing
-	// a mouse action that requires updating, we need to update it
+	// a mouse action that reuqires updating, we need to update it
 	//likewise if we don't have a plot, we need one.
 	if(!gr || hasChanged || hasResized || 
 		MOUSE_ACTION_NEEDS_REDRAW[mouseDragMode])
@@ -329,8 +335,8 @@ void MathGLPane::render(wxPaintEvent &event)
 
 			const int END_MARKER_SIZE=5;
 
-		//If the cursor is wholly below
-			//the axis, draw a line rather than a box
+			//If the cursor is wholly below
+			//the axis, draw a line rather than abox
 
 			unsigned int startMask, endMask;
 			startMask=getAxisMask(draggingStart.x, draggingStart.y);
@@ -412,8 +418,8 @@ void MathGLPane::updateMouseCursor()
 		return;
 
 	//Set cursor to normal by default
-		SetCursor(wxNullCursor);
-	if(!thePlot->getNumVisible())
+	SetCursor(wxNullCursor);
+	if(!readyForInput())
 		return;
 
 	//Update mouse cursor
@@ -462,7 +468,8 @@ bool MathGLPane::getRegionUnderCursor(const wxPoint  &mousePos, unsigned int &pl
 
 	//Convert the mouse coordinates to data coordinates.
 	mglPoint pMouse= gr->CalcXYZ(mousePos.x,mousePos.y);
-
+	if(!readyForInput())
+		return false;
 
 	//Only allow  range interaction within the plot bb
 #ifdef USE_MGL2
@@ -483,7 +490,7 @@ bool MathGLPane::getRegionUnderCursor(const wxPoint  &mousePos, unsigned int &pl
 void MathGLPane::mouseMoved(wxMouseEvent& event)
 {
 	leftWindow=false;
-	if(!thePlot || !gr || thePlot->isInteractionLocked() )
+	if(!readyForInput())
 	{
 		mouseDragMode=MOUSE_MODE_ENUM_END;
 		return;
@@ -526,7 +533,7 @@ void MathGLPane::mouseMoved(wxMouseEvent& event)
 
 void MathGLPane::mouseDoubleLeftClick(wxMouseEvent& event)
 {
-	if(!thePlot || !gr || thePlot->isInteractionLocked())
+	if(!readyForInput())
 		return;
 
 	//Cancel any mouse drag mode
@@ -623,7 +630,7 @@ void MathGLPane::oneDMouseDownAction(bool leftDown,bool middleDown,
 
 void MathGLPane::leftMouseDown(wxMouseEvent& event)
 {
-	if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked())
+	if(!readyForInput())
 		return;
 
 	int w,h;
@@ -652,7 +659,7 @@ void MathGLPane::leftMouseDown(wxMouseEvent& event)
 
 void MathGLPane::middleMouseDown(wxMouseEvent &event)
 {
-	if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked())
+	if(!readyForInput())
 		return;
 	
 	int w,h;
@@ -683,7 +690,7 @@ void MathGLPane::middleMouseDown(wxMouseEvent &event)
 void MathGLPane::mouseWheelMoved(wxMouseEvent& event)
 {
 	//If no valid plot, don't do anything
-	if(!thePlot || !gr || thePlot->isInteractionLocked() )
+	if(!readyForInput())
 		return;
 	
 	//no action if currently dragging
@@ -788,7 +795,7 @@ void MathGLPane::mouseWheelMoved(wxMouseEvent& event)
 void MathGLPane::leftMouseReleased(wxMouseEvent& event)
 {
 
-	if(!thePlot || !gr || thePlot->isInteractionLocked() )
+	if(!readyForInput())
 		return;
 
 	switch(mouseDragMode)
@@ -828,7 +835,7 @@ void MathGLPane::leftMouseReleased(wxMouseEvent& event)
 void MathGLPane::middleMouseReleased(wxMouseEvent& event)
 {
 
-	if(!gr || thePlot->isInteractionLocked())
+	if(!readyForInput())
 		return;
 
 	if(mouseDragMode == MOUSE_MODE_DRAG_PAN)
@@ -970,14 +977,14 @@ void MathGLPane::mouseLeftWindow(wxMouseEvent& event)
 
 void MathGLPane::keyPressed(wxKeyEvent& event) 
 {
-	if(!gr || thePlot->isInteractionLocked() )
+	if(!readyForInput())
 		return;
 	updateMouseCursor();
 }
 
 void MathGLPane::keyReleased(wxKeyEvent& event) 
 {
-	if(!gr || thePlot->isInteractionLocked() )
+	if(!readyForInput())
 		return;
 	updateMouseCursor();
 }
diff --git a/src/gui/mathglPane.h b/src/gui/mathglPane.h
index 46c17c2..60fc381 100644
--- a/src/gui/mathglPane.h
+++ b/src/gui/mathglPane.h
@@ -106,6 +106,8 @@ private:
 	//Action to perform when showing 1D plots and mouse down event occurs
 	void oneDMouseDownAction(bool leftDown,bool middleMouseDown,
 		bool alternateDown, int dragX,int dragY);
+
+	bool readyForInput() const;
 public:
 
 	MathGLPane(wxWindow* parent, int id);
diff --git a/src/testing.cpp b/src/testing.cpp
index 9ad7a16..7f7ee63 100644
--- a/src/testing.cpp
+++ b/src/testing.cpp
@@ -28,6 +28,7 @@
 #include "backend/filters/allFilter.h"
 #include "backend/configFile.h"
 
+
 #include "common/stringFuncs.h"
 #include "common/xmlHelper.h"
 
@@ -60,7 +61,7 @@ bool testFilterTree(const FilterTree &f)
 {
 	ASSERT(!f.hasHazardousContents());
 	std::list<std::pair<Filter *, std::vector<const FilterStreamData * > > > outData;
-	std::vector<SelectionDevice<Filter> *> devices;
+	std::vector<SelectionDevice *> devices;
 	std::vector<std::pair<const Filter *, string > > consoleMessages;
 
 	ProgressData prog;
@@ -151,9 +152,8 @@ bool basicFunctionTests()
 bool runUnitTests()
 {
 
-	if(!basicFunctionTests())
-		return false;
-	
+	cerr << "Running unit tests..." ;
+
 	if(!filterTests())
 		return false;
 
@@ -163,6 +163,10 @@ bool runUnitTests()
 	if(!rangeFileLoadTests())
 		return false;
 
+
+	if(!basicFunctionTests())
+		return false;
+	
 	if(!XMLTests())
 		return false;
 
@@ -172,13 +176,14 @@ bool runUnitTests()
 	if(!runVoxelTests())
 		return false;
 
+	cerr << " OK" << endl << endl;
+
 	return true;
 }
 
 bool filterTests()
 {
 	//Instantiate various filters, then run their unit tests
-	cerr << "Running per-filter unit tests...";
 	for(unsigned int ui=0; ui<FILTER_TYPE_ENUM_END; ui++)
 	{
 		Filter *f;
@@ -188,7 +193,6 @@ bool filterTests()
 
 		delete f;
 	}
-	cerr << "OK" <<endl;
 
 	if(!Filter::boolToggleTests())
 		return false;
@@ -215,7 +219,6 @@ bool filterCloneTests()
     	configFile.read();
 	
 	bool fileWarn=false;
-	cerr << "Running clone tests...";
 	for(unsigned int ui=0; ui<FILTER_TYPE_ENUM_END; ui++)
 	{
 		//Get the user's preferred, or the program
@@ -340,7 +343,6 @@ bool filterCloneTests()
 		delete f;
 		delete g;
 	}
-	cerr << "OK" << endl;
 	return true;
 }
 
@@ -369,7 +371,7 @@ bool rangeFileLoadTests()
 	testDir=testDir+wxT("rangefiles/");
 
 	wxArrayString arrayStr,tmpArr;
-	//Get all the files matching rng extentions
+	//Get all the files matching rng extensions
 	vector<string> rangeExts;
 	RangeFile::getAllExts(rangeExts);
 	for(unsigned int ui=0;ui<rangeExts.size();ui++)
@@ -389,7 +391,6 @@ bool rangeFileLoadTests()
 		return true;
 	}
 
-	cerr << "Range file loading...";
 
 	//Map names of file (without dir) to number of ions/range
 	map<string,unsigned int> ionCountMap;
@@ -411,6 +412,10 @@ bool rangeFileLoadTests()
 	failSet.insert("test6.rng");
 	ionCountMap["test7.rng"]=2; rangeCountMap["test7.rng"]=2;
 	ionCountMap["test8.rng"]=2; rangeCountMap["test8.rng"]=2;
+	ionCountMap["test9.rng"]=3; rangeCountMap["test9.rng"]=3;
+	ionCountMap["test10.rng"]=3; rangeCountMap["test10.rng"]=3;
+	ionCountMap["test11.rng"]=5; rangeCountMap["test11.rng"]=10;
+	ionCountMap["test12.rng"]=5; rangeCountMap["test12.rng"]=10;
 
 	ionCountMap["test1.rrng"]=1; rangeCountMap["test1.rrng"]=1;
 	ionCountMap["test2.rrng"]=3; rangeCountMap["test2.rrng"]=6; 
@@ -420,7 +425,6 @@ bool rangeFileLoadTests()
 	
 	ionCountMap["test1.env"]=1; rangeCountMap["test1.env"]=1; 
 
-	cerr << endl;
 	//Sort the array before we go any further, so that the output
 	//each time is the same, regardless of how the files were
 	//loaded into the dir. F.ex this makes diffing easier
@@ -437,7 +441,6 @@ bool rangeFileLoadTests()
 		fileShortname=stlStr(filename.GetFullName());
 		{
 			RangeFile f;
-			cerr << "\t" << fileShortname.c_str() << "...";
 
 			bool shouldSucceed;
 
@@ -445,43 +448,94 @@ bool rangeFileLoadTests()
 			// if its not in the set, it should load successfully
 			shouldSucceed=(failSet.find(fileShortname)==failSet.end());
 				
-			if((!f.openGuessFormat(fileLongname.c_str())) == shouldSucceed)
+			if(!(f.openGuessFormat(fileLongname.c_str()) == shouldSucceed))
 			{
+				cerr << "\t" << fileShortname.c_str() << "...";
 				cerr << f.getErrString() << endl;
 				TEST(false,"range file load test"); 
 			}
 
 
 			if(!shouldSucceed)
-			{
-				cerr << "OK" <<endl;
 				continue;
-			}
 
 			//Check against the hand-made map of ion and range counts
 			if(ionCountMap.find(fileShortname)!=ionCountMap.end())
 			{
-				TEST(ionCountMap[fileShortname] == f.getNumIons(),"ion count test");
+				std::string errMsg;
+				errMsg=string("ion count test : ") + fileShortname;
+				TEST(ionCountMap[fileShortname] == f.getNumIons(),errMsg.c_str());
 			}
 			else
 			{
+				cerr << "\t" << fileShortname.c_str() << "...";
 				WARN(false,"Did not know how many ions file was supposed to have. Test inconclusive");
 			}
 			
 			if(rangeCountMap.find(fileShortname)!=rangeCountMap.end())
 			{
-				TEST(rangeCountMap[fileShortname] == f.getNumRanges(),"range count test");
+				std::string errMsg;
+				errMsg=string("range count test : ") + fileShortname;
+				TEST(rangeCountMap[fileShortname] == f.getNumRanges(),errMsg.c_str());
 			}
 			else
 			{
+				cerr << "\t" << fileShortname.c_str() << "...";
 				WARN(false,"Did not know how many ranges file was supposed to have. Test inconclusive");
 			}
-
-			cerr << "OK" << endl;
 		}
 	}
 
-	cerr << "OK" << endl;
+
+
+	map<string,int> typeMapping;
+
+	typeMapping["test1.rng"]=RANGE_FORMAT_ORNL;
+	typeMapping["test2.rng"]=RANGE_FORMAT_ORNL; 
+	typeMapping["test3.rng"]=RANGE_FORMAT_ORNL;
+	typeMapping["test5.rng"]=RANGE_FORMAT_ORNL; 
+	typeMapping["test7.rng"]=RANGE_FORMAT_ORNL; 
+	typeMapping["test8.rng"]=RANGE_FORMAT_ORNL; 
+	typeMapping["test9.rng"]=RANGE_FORMAT_ORNL; 
+	typeMapping["test10.rng"]=RANGE_FORMAT_ORNL;
+	typeMapping["test11.rng"]=RANGE_FORMAT_ORNL;
+	typeMapping["test12.rng"]=RANGE_FORMAT_DBL_ORNL; 
+	typeMapping["test1.rrng"]=RANGE_FORMAT_RRNG;
+	typeMapping["test2.rrng"]=RANGE_FORMAT_RRNG;
+	typeMapping["test3.rrng"]=RANGE_FORMAT_RRNG;
+	typeMapping["test4.rrng"]=RANGE_FORMAT_RRNG;
+	typeMapping["test5.rrng"]=RANGE_FORMAT_RRNG;
+	typeMapping["test1.env"]=RANGE_FORMAT_ENV; 
+
+
+	for(unsigned int ui=0;ui<arrayStr.GetCount();ui++)
+	{
+		std::string fileLongname, fileShortname;
+		wxFileName filename;
+		
+		fileLongname=stlStr(arrayStr[ui]);
+		filename=wxStr(fileLongname);
+		fileShortname=stlStr(filename.GetFullName());
+
+		//Check to see that the auto-parser correctly identifies the type
+		if(typeMapping.find(fileShortname) != typeMapping.end())
+		{
+			std::string errString;
+			errString="Range type detection : ";
+			errString+=fileLongname;
+
+			if(!wxFileExists(wxStr(fileLongname)))
+			{
+				cerr << "File expected, but not found during test:" <<
+					fileLongname << endl;
+				continue;
+			}
+			
+
+			TEST(RangeFile::detectFileType(fileLongname.c_str()) == 
+					typeMapping[fileShortname], errString);
+		}
+	}
 	return true;
 }
 
diff --git a/src/winconsole.cpp b/src/winconsole.cpp
index a38f2f2..2f78e62 100644
--- a/src/winconsole.cpp
+++ b/src/winconsole.cpp
@@ -16,6 +16,9 @@
  *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+//Prevent 
+#if defined(__WIN32) || defined(__WIN64)
+
 // winconsole.cpp
 #include "winconsole.h"
 #include <cstdio>
@@ -53,3 +56,5 @@ winconsole::~winconsole()
   // remove the winconsole window
   FreeConsole();
 }
+
+#endif
diff --git a/src/winconsole.h b/src/winconsole.h
index 626b6c9..c7aeaf6 100644
--- a/src/winconsole.h
+++ b/src/winconsole.h
@@ -23,6 +23,7 @@
 
 #include <fstream>
 
+#if defined(__WIN32) || defined(__WIN64)
 class winconsole
 {
 private:
@@ -41,5 +42,5 @@ public:
   void hide();
   void show();
 };
-
+#endif
 #endif
diff --git a/src/wxcommon.cpp b/src/wxcommon.cpp
index c4737ff..4235cea 100644
--- a/src/wxcommon.cpp
+++ b/src/wxcommon.cpp
@@ -27,6 +27,10 @@
 	#include <wx/msw/registry.h>  
 #endif
 
+#ifdef __APPLE__
+#include "CoreFoundation/CoreFoundation.h"
+#endif
+
 //Auto update checking RSS URL
 const char *RSS_FEED_LOCATION="http://threedepict.sourceforge.net/rss.xml";
 
@@ -45,7 +49,7 @@ std::string locateDataFile(const char *name)
 	//Linux:
 	//	- Look in cwd & some common hard-coded install locations.
 	//Mac:
-	// 	- look in cwd
+	// 	- look in bundle
 	//Windows
 	//	- Locate a registry key that has the install path, which is preset by
 	//	  application installer
@@ -69,13 +73,16 @@ std::string locateDataFile(const char *name)
 		if(s.size() > 11)
 		{
 			s=s.substr(0,s.size()-11);			
-			return s + std::string(name);
+
+			s+=name;
+
+			if(wxFileExists(wxStr(s)))
+				return s;
 		}
 	}
 
-#endif	
-
-#ifdef __linux__
+	return std::string("");
+#elif defined( __linux__)
 
 	//Possible search paths. Must have trailing slash. will
 	//be searched in sequence.
@@ -97,13 +104,29 @@ std::string locateDataFile(const char *name)
 			return s;
 	}
 
-	//Give up and force cur working dir.
-	return std::string(name);
+	//Return empty string, as we cna't find it
+	return std::string("");
+#elif defined (__APPLE__)
+    CFBundleRef mainBundle = CFBundleGetMainBundle();
+    CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
+    char path[PATH_MAX];
+    if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
+    {
+        // error!
+	return std::string("");
+    }
+    CFRelease(resourcesURL);
+	std::string s=std::string(path) + "/" + name;
+		if(wxFileExists(wxStr(s)))
+			return s;
 #else
 
 	//E.g. Mac
 	//	- Look in cwd
-	return  std::string(name);
+	if(wxFileExists(wxCStr(name)))
+		return  std::string(name);
+	else
+		return std::string("");
 #endif
 }
 
diff --git a/src/wxcommon.h b/src/wxcommon.h
index 2cb631d..642d2d4 100644
--- a/src/wxcommon.h
+++ b/src/wxcommon.h
@@ -46,7 +46,7 @@ inline std::string stlStr(const wxString& s){
 
 //--------
 //Perform validation of a wx text control, adjusting appearance as needed
-// can pass an additonal constraint function that needs to be satistfied (return true)
+// can pass an additional constraint function that needs to be satisfied (return true)
 // in order for validation to succeed
 template<class T> 
 bool validateTextAsStream(wxTextCtrl *t, T &i, bool (*conditionFunc)(const T&))
@@ -122,7 +122,7 @@ bool validateTextAsStream(wxTextCtrl *t, T &i)
 void wxErrMsg(wxWindow *, const std::string &title,
 		const std::string &mesg);
 
-//locate the file we are looking for in OS specfic paths
+//locate the file we are looking for in OS specific paths. Returns empty string if file cannot be found
 std::string locateDataFile(const char *name);
 
 //Custom event for remote update thread posting
@@ -132,7 +132,7 @@ extern wxEventType RemoteUpdateAvailEvent;
 bool processMatchesName(size_t processID, const std::string &procName);
 
 
-//!Remote version thread checker, downloads rss file from remote system and then
+//!Remote version thread checker, downloads RSS file from remote system and then
 // parses the file for the latest remote version number
 class VersionCheckThread : public wxThread
 {
@@ -152,10 +152,10 @@ class VersionCheckThread : public wxThread
 		//Returns true upon completion of thread.
 		bool isComplete()  const { return complete; }
 
-		//Returns true if version string was retreived succesfully
+		//Returns true if version string was retrieved successfully
 		bool isRetrieveOK() const { return retrieveOK; }
 
-		//Return the maximal version string obtained from the remote rss feed
+		//Return the maximal version string obtained from the remote RSS feed
 		std::string getVerStr() {  return versionStr; }
 };
 #endif
diff --git a/src/wxcomponents.cpp b/src/wxcomponents.cpp
index 661681b..b0074f5 100644
--- a/src/wxcomponents.cpp
+++ b/src/wxcomponents.cpp
@@ -825,7 +825,7 @@ void CopyGrid::copyData()
 /*		else if(cells.size())
 		{
 			//FIXME: Needs more thought than I have time for right now. 
-			// the problem is that cells[] doesn't neccesarily sort tl->br,
+			// the problem is that cells[] doesn't necessarily sort tl->br,
 			// so you have to do this first
 			int lastRow=cells[0].GetRow();
 			int lastCol=cells[0].GetCol();
@@ -1103,7 +1103,7 @@ std::string TTFFinder::suggestFontName(unsigned int fontType, unsigned int index
 	return s;
 }
 
-std::string TTFFinder::getBestFontFile(unsigned int type) const
+std::string TTFFinder::getBestFontFile(unsigned int type) 
 {
 	unsigned int index=0;
 
diff --git a/src/wxcomponents.h b/src/wxcomponents.h
index a17d6e5..8080339 100644
--- a/src/wxcomponents.h
+++ b/src/wxcomponents.h
@@ -245,7 +245,7 @@ class TTFFinder
 
 		//!Returns a valid file that points to an installed ttf file, or an empty string
 		//NOTE: TTF file is not checked for content validity!
-		std::string getBestFontFile(unsigned int type) const ;
+		static std::string getBestFontFile(unsigned int type);
 };
 
 #endif
diff --git a/test/cppcheck.sh b/test/cppcheck.sh
deleted file mode 100755
index ddc3dd0..0000000
--- a/test/cppcheck.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-#How to use:
-#	* Download latest cppcheck git source
-#	* Build and install cppcheck
-#	* Run this script - you may need to customise it to your system
-
-
-if [ x`which cppcheck` == x"" ] ; then
-	echo "No cppcheck found. Please install into path."
-	exit 1
-fi
-
-#Default to 2 processes, otherwise
-# check system for number of processors
-# and thus use that as the number of processes
-NUM_PROCS=2
-if [ `uname` == Linux ] ; then
-	NUM_PROCS=`cat /proc/cpuinfo | grep processor |  wc -l`
-fi
-
-HG_ROOT=`hg root`
-
-cppcheck -q -j $NUM_PROCS --enable=all --inconclusive ${HG_ROOT}/src/. 2> ${HG_ROOT}/cpp-res
-cat ${HG_ROOT}/cpp-res | sort -n > tmp;
-
-#Strip output that is overly noisy/unhelpful to us
-echo 'does not have a constructor' > tmp-ignore
-echo '(information)' >> tmp-ignore
-echo 'is not initialized in the constructor' >> tmp-ignore
-echo 'C-style pointer casting' >> tmp-ignore
-grep -v -f tmp-ignore tmp  > ${HG_ROOT}/cpp-res
-rm tmp-ignore
-
-#Use the per-error message ignore file to filter the last of it
-if [ -f ${HG_ROOT}/cpp-ignore ] ; then
-	grep -v -f cpp-ignore ${HG_ROOT} cpp-res >tmp;
-	mv tmp ${HG_ROOT} > cpp-res
-	echo "Wrote cpp-res and cpp-res-delta (result - ignore) to ${HG_ROOT}."
-else
-	rm tmp
-	echo "No ignore file (cpp-ignore) found - please check entire cppcheck output"
-fi
diff --git a/test/rangefiles/test10.rng b/test/rangefiles/test10.rng
new file mode 100644
index 0000000..75b4903
--- /dev/null
+++ b/test/rangefiles/test10.rng
@@ -0,0 +1,12 @@
+3 3
+In-P
+Inside-Part 1 1 1
+Out-P
+Outside-Part 1 1 1
+Bd-P
+Border-Part 1 1 1
+----------------------In-P Out-P Bd-P
+. 1.0e7 4.0e7 1 0 0
+. 4.01e7 6.0e7 0 1 0
+. 6.01e7 1.0e8 0 0 1
+
diff --git a/test/rangefiles/test11.rng b/test/rangefiles/test11.rng
new file mode 100644
index 0000000..1968328
--- /dev/null
+++ b/test/rangefiles/test11.rng
@@ -0,0 +1,20 @@
+4 10
+Aa
+Aa 0.80 0.80 0.80
+Ab
+Ab 1.00 1.00 0.00
+Ac
+Ac 1.00 0.80 0.20
+Ad
+Ad 0.00 0.80 1.00
+------------------- Aa Ab Ac Ad
+. 1.1 1.2 1 0 0 0
+. 2.1 2.2 1 0 0 0
+. 3.1 3.2 1 0 0 0
+. 4.1 4.2 1 0 0 0
+. 5.1 5.2 1 0 0 0
+. 6.1 6.2 1 0 0 0
+. 7.1 7.2 0 1 0 0
+. 8.1 8.2 0 1 0 0
+. 9.1 9.2 0 0 1 0
+. 10.1 10.2 1 0 0 1
diff --git a/test/rangefiles/test12.rng b/test/rangefiles/test12.rng
new file mode 100644
index 0000000..f874de6
--- /dev/null
+++ b/test/rangefiles/test12.rng
@@ -0,0 +1,28 @@
+4 10
+Aa
+Aa 0.80 0.80 0.80
+Ab
+Ab 1.00 1.00 0.00
+Ac
+Ac 1.00 0.80 0.20
+Ad
+Ad 0.00 0.80 1.00
+------------------- Aa Ab Ac Ad
+. 13.8794 14.2981 1 0 0 0
+. 27.8655 28.2919 1 0 0 0
+. 14.4333 14.6733 1 0 0 0
+. 14.9400 15.2000 1 0 0 0
+. 28.9467 29.1733 1 0 0 0
+. 29.8867 30.1133 1 0 0 0
+. 68.7993 69.0600 0 1 0 0
+. 70.8533 71.1000 0 1 0 0
+. 196.8867 197.2867 0 0 1 0
+. 43.9400 44.0267 1 0 0 1
+
+
+--- polyatomic extension
+1 1
+AaAd
+AaAd 0.80 0.80 1.00
+----------------- AaAd
+. 43.9400 44.0267 1
diff --git a/test/rangefiles/test9.rng b/test/rangefiles/test9.rng
new file mode 100644
index 0000000..b5575bc
--- /dev/null
+++ b/test/rangefiles/test9.rng
@@ -0,0 +1,12 @@
+3 3
+In
+InsidePart 1 1 1
+Out
+OutsidePart 1 1 1
+Bd
+BorderPart 1 1 1
+----------------------In Out Bd
+. 1.0e7 4.0e7 1 0 0
+. 4.01e7 6.0e7 0 1 0
+. 6.01e7 1.0e8 0 0 1
+
diff --git a/test/spell-fixes.sh b/test/spell-fixes.sh
deleted file mode 100755
index 3c1e09f..0000000
--- a/test/spell-fixes.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-
-#!nasty hack script to fix some spelling errors in comments
-#Usage:
-#---
-# grep '^\s*//' *{cpp,h} > comments #Rudely extract (some) comments
-# cat comments | aspell list | sort | uniq > badwords #get a list of words with spelling errors
-#Manually slice down list of bad words
-# grep  -f badwords comments > errs
-#Manually slice down errs file, then correct spelling errs in that file
-# - then run this script
-#---
-SAVEIFS=$IFS
-
-IFS=$(echo -en "\n\b")
-for i in `cat errs`
-do
-	tre-agrep -4 --line-number $i `find ./ -name \*.cpp` `find ./ -name \*.h` > tmpRes;
-
-	if [ `wc -l tmpRes | awk '{print $1}'` -eq 0 ] ; then
-		echo "no match for :" $i
-		continue
-	fi
-
-	#Extract only the first occurrence
-	FILENAME=`cat tmpRes | awk  -F: '{print $1}' | head -n 1 `
-	LINE=`cat tmpRes | awk -F: '{print $2}' | head -n 1`
-
-	echo $FILENAME 
-	echo $LINE
-	awk -v line=$LINE -v new_content="$i" '{
-		if (NR == line) {
-			print new_content;
-		} else {
-			print $0;
-		}
-		}' $FILENAME  > tmpV
-	mv tmpV "$FILENAME"
-done
-
-
-IFS=$SAVEIFS
diff --git a/translations/3Depict_base.pot b/translations/3Depict_base.pot
index 9568e6e..5c909c0 100644
--- a/translations/3Depict_base.pot
+++ b/translations/3Depict_base.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-04-05 23:27+0200\n"
+"POT-Creation-Date: 2013-07-05 22:42+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -25,13 +25,13 @@ msgstr ""
 #: ../src/backend/filters/ionClip.cpp:545
 #: ../src/backend/filters/ionClip.cpp:567
 #: ../src/backend/filters/ionClip.cpp:607
-#: ../src/backend/filters/compositionProfile.cpp:931
-#: ../src/backend/filters/compositionProfile.cpp:972
+#: ../src/backend/filters/compositionProfile.cpp:940
+#: ../src/backend/filters/compositionProfile.cpp:981
 #: ../src/backend/filters/spatialAnalysis.cpp:593
-#: ../src/backend/filters/transform.cpp:1262
-#: ../src/backend/filters/transform.cpp:1289
-#: ../src/backend/filters/transform.cpp:1315
-#: ../src/backend/filters/annotation.cpp:557
+#: ../src/backend/filters/transform.cpp:1258
+#: ../src/backend/filters/transform.cpp:1285
+#: ../src/backend/filters/transform.cpp:1311
+#: ../src/backend/filters/annotation.cpp:569
 msgid "Origin"
 msgstr ""
 
@@ -73,8 +73,8 @@ msgstr ""
 #: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1109
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1134
-#: ../src/gui/dialogs/prefDialog.cpp:109 ../src/gui/mainFrame.cpp:5274
-#: ../src/gui/mainFrame.cpp:5279 ../src/backend/filters/dataLoad.cpp:484
+#: ../src/gui/dialogs/prefDialog.cpp:109 ../src/gui/mainFrame.cpp:5489
+#: ../src/gui/mainFrame.cpp:5494 ../src/backend/filters/dataLoad.cpp:486
 msgid "Value"
 msgstr ""
 
@@ -91,14 +91,14 @@ msgid "Error saving file. Check output dir is writable."
 msgstr ""
 
 #: ../src/wxcomponents.cpp:654 ../src/gui/dialogs/ExportRngDialog.cpp:170
-#: ../src/gui/mainFrame.cpp:1308 ../src/gui/mainFrame.cpp:1437
-#: ../src/gui/mainFrame.cpp:1482 ../src/gui/mainFrame.cpp:1565
-#: ../src/gui/mainFrame.cpp:2039 ../src/gui/mainFrame.cpp:2054
-#: ../src/gui/mainFrame.cpp:2147 ../src/gui/mainFrame.cpp:2264
+#: ../src/gui/mainFrame.cpp:1371 ../src/gui/mainFrame.cpp:1500
+#: ../src/gui/mainFrame.cpp:1545 ../src/gui/mainFrame.cpp:1628
+#: ../src/gui/mainFrame.cpp:2122 ../src/gui/mainFrame.cpp:2137
+#: ../src/gui/mainFrame.cpp:2230 ../src/gui/mainFrame.cpp:2347
 msgid "Save error"
 msgstr ""
 
-#: ../src/common/basics.cpp:52 ../src/backend/APT/APTClasses.cpp:54
+#: ../src/common/basics.cpp:52 ../src/backend/APT/APTFileIO.cpp:61
 msgid "Error opening file"
 msgstr ""
 
@@ -106,7 +106,7 @@ msgstr ""
 msgid "Error whilst reading file contents"
 msgstr ""
 
-#: ../src/common/basics.cpp:54 ../src/backend/APT/APTClasses.cpp:58
+#: ../src/common/basics.cpp:54 ../src/backend/APT/APTFileIO.cpp:65
 msgid "Error interpreting field in file"
 msgstr ""
 
@@ -250,37 +250,37 @@ msgstr ""
 msgid "Pseudo-Random"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:635
+#: ../src/gui/glPane.cpp:636
 msgid "Use shift/ctrl-space or double tap to alter reset axis"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:893
+#: ../src/gui/glPane.cpp:894
 msgid "Image progress"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:894
+#: ../src/gui/glPane.cpp:895
 msgid "Rendering tiles..."
 msgstr ""
 
-#: ../src/gui/glPane.cpp:910
+#: ../src/gui/glPane.cpp:911
 msgid "Tile "
 msgstr ""
 
-#: ../src/gui/glPane.cpp:910 ../src/gui/glPane.cpp:1077
-#: ../src/gui/mainFrame.cpp:3861 ../src/gui/mainFrame.cpp:3865
-#: ../src/gui/mainFrame.cpp:3878
+#: ../src/gui/glPane.cpp:911 ../src/gui/glPane.cpp:1078
+#: ../src/gui/mainFrame.cpp:3975 ../src/gui/mainFrame.cpp:3979
+#: ../src/gui/mainFrame.cpp:3992
 msgid " of "
 msgstr ""
 
-#: ../src/gui/glPane.cpp:1043
+#: ../src/gui/glPane.cpp:1044
 msgid "Animation progress"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:1044
+#: ../src/gui/glPane.cpp:1045
 msgid "Rendering sequence..."
 msgstr ""
 
-#: ../src/gui/glPane.cpp:1077
+#: ../src/gui/glPane.cpp:1078
 msgid "Saving Image "
 msgstr ""
 
@@ -301,7 +301,7 @@ msgid "Ions"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:55
-#: ../src/backend/filters/rangeFile.cpp:666
+#: ../src/backend/filters/rangeFile.cpp:721
 msgid "Ranges"
 msgstr ""
 
@@ -329,7 +329,7 @@ msgstr ""
 msgid "Range end"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2090
+#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2173
 msgid "Save pos..."
 msgstr ""
 
@@ -337,10 +337,10 @@ msgstr ""
 msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1308
-#: ../src/gui/mainFrame.cpp:1483 ../src/gui/mainFrame.cpp:1565
-#: ../src/gui/mainFrame.cpp:2040 ../src/gui/mainFrame.cpp:2148
-#: ../src/gui/mainFrame.cpp:2265
+#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1371
+#: ../src/gui/mainFrame.cpp:1546 ../src/gui/mainFrame.cpp:1628
+#: ../src/gui/mainFrame.cpp:2123 ../src/gui/mainFrame.cpp:2231
+#: ../src/gui/mainFrame.cpp:2348
 msgid "Unable to save. Check output destination can be written to."
 msgstr ""
 
@@ -368,8 +368,8 @@ msgstr ""
 msgid "Multiple autosave states were found; would you like to restore one?"
 msgstr ""
 
-#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:392
-#: ../src/backend/filter.cpp:395
+#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:388
+#: ../src/backend/filter.cpp:391
 msgid "Error"
 msgstr ""
 
@@ -382,43 +382,43 @@ msgstr ""
 msgid "Filter Errors"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:44
+#: ../src/gui/dialogs/StashDialog.cpp:45
 msgid "Stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:47
+#: ../src/gui/dialogs/StashDialog.cpp:48
 msgid "Stashed Tree"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:49
+#: ../src/gui/dialogs/StashDialog.cpp:50
 msgid "Properties"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:85
+#: ../src/gui/dialogs/StashDialog.cpp:86
 msgid "Stashed Trees"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:88
+#: ../src/gui/dialogs/StashDialog.cpp:89
 msgid "Erase stashed item"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:89
+#: ../src/gui/dialogs/StashDialog.cpp:90
 msgid "Filter view for current stash"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:90
+#: ../src/gui/dialogs/StashDialog.cpp:91
 msgid "Settings for selected filter in current stash"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:91
+#: ../src/gui/dialogs/StashDialog.cpp:92
 msgid "Available stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:152
+#: ../src/gui/dialogs/StashDialog.cpp:153
 msgid "Stash Name"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:153
+#: ../src/gui/dialogs/StashDialog.cpp:154
 msgid "Filter Count"
 msgstr ""
 
@@ -619,7 +619,7 @@ msgid "transition frame"
 msgstr ""
 
 #: ../src/gui/dialogs/animateFilterDialog.cpp:638
-#: ../src/gui/mainFrame.cpp:1538
+#: ../src/gui/mainFrame.cpp:1601
 msgid "Frame count"
 msgstr ""
 
@@ -662,7 +662,7 @@ msgstr ""
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1108
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1113
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1133
-#: ../src/gui/mainFrame.cpp:5273 ../src/gui/mainFrame.cpp:5278
+#: ../src/gui/mainFrame.cpp:5488 ../src/gui/mainFrame.cpp:5493
 msgid "Property"
 msgstr ""
 
@@ -676,8 +676,8 @@ msgid "Filter"
 msgstr ""
 
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1114
-#: ../src/backend/filters/transform.cpp:1180
-#: ../src/backend/filters/annotation.cpp:535
+#: ../src/backend/filters/transform.cpp:1176
+#: ../src/backend/filters/annotation.cpp:547
 msgid "Mode"
 msgstr ""
 
@@ -796,10 +796,10 @@ msgid "Index"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportPos.cpp:111 ../src/gui/dialogs/ExportPos.cpp:114
-#: ../src/backend/filters/compositionProfile.cpp:462
-#: ../src/backend/filters/spatialAnalysis.cpp:1656
-#: ../src/backend/filters/spatialAnalysis.cpp:1725
-#: ../src/backend/filters/spatialAnalysis.cpp:2659
+#: ../src/backend/filters/compositionProfile.cpp:466
+#: ../src/backend/filters/spatialAnalysis.cpp:1667
+#: ../src/backend/filters/spatialAnalysis.cpp:1736
+#: ../src/backend/filters/spatialAnalysis.cpp:2670
 #: ../src/backend/filters/spectrumPlot.cpp:240
 msgid "Count"
 msgstr ""
@@ -872,7 +872,7 @@ msgstr ""
 msgid "Raw Data Panel"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:618
+#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:639
 msgid "Plot List"
 msgstr ""
 
@@ -954,564 +954,580 @@ msgstr ""
 msgid "Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:88
+#: ../src/gui/mainFrame.cpp:89
 msgid "New camera name..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:89
+#: ../src/gui/mainFrame.cpp:90
 msgid "New stash name...."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:105 ../src/backend/filters/annotation.cpp:549
-#: ../src/backend/filters/annotation.cpp:651
-#: ../src/backend/filters/annotation.h:98
+#: ../src/gui/mainFrame.cpp:106 ../src/backend/filters/annotation.cpp:561
+#: ../src/backend/filters/annotation.cpp:663
+#: ../src/backend/filters/annotation.h:96
 msgid "Annotation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:106
+#: ../src/gui/mainFrame.cpp:107
 msgid "Bounding Box"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:107 ../src/backend/filters/ionClip.h:66
+#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/ionClip.h:66
 msgid "Clipping"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/clusterAnalysis.h:132
+#: ../src/gui/mainFrame.cpp:109 ../src/backend/filters/clusterAnalysis.h:132
 msgid "Cluster Analysis"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:109
+#: ../src/gui/mainFrame.cpp:110
 msgid "Compos. Profiles"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:110
+#: ../src/gui/mainFrame.cpp:111
 msgid "Downsampling"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:111
+#: ../src/gui/mainFrame.cpp:112
 msgid "Extern. Prog."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:112
+#: ../src/gui/mainFrame.cpp:113
 msgid "Ion Colour"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:113
+#: ../src/gui/mainFrame.cpp:114
 msgid "Ion Info"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:114
+#: ../src/gui/mainFrame.cpp:115
 msgid "Ion Transform"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:115 ../src/backend/filters/spectrumPlot.h:53
+#: ../src/gui/mainFrame.cpp:116 ../src/backend/filters/spectrumPlot.h:53
 msgid "Spectrum"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:116
+#: ../src/gui/mainFrame.cpp:117
 msgid "Range File"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:117 ../src/backend/filters/spatialAnalysis.h:142
+#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/spatialAnalysis.h:142
 msgid "Spat. Analysis"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/voxelise.h:89
+#: ../src/gui/mainFrame.cpp:119 ../src/backend/filters/voxelise.h:121
 msgid "Voxelisation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:403
+#: ../src/gui/mainFrame.cpp:415
 msgid "OpenGL Failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:404 ../src/gui/mainFrame.cpp:406
+#: ../src/gui/mainFrame.cpp:416 ../src/gui/mainFrame.cpp:418
 msgid ""
 "Unable to initialise the openGL (3D) panel. Program cannot start. Please "
 "check your video drivers."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:426
+#: ../src/gui/mainFrame.cpp:438
 msgid "&Open...\tCtrl+O"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:426
+#: ../src/gui/mainFrame.cpp:438
 msgid "Open state file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:427
+#: ../src/gui/mainFrame.cpp:439
 msgid "&Merge...\tCtrl+Shift+O"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:427
+#: ../src/gui/mainFrame.cpp:439
 msgid "Merge other file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:431
+#: ../src/gui/mainFrame.cpp:443
 msgid "&Recent"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:432
+#: ../src/gui/mainFrame.cpp:444
 msgid "&Save\tCtrl+S"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:432
+#: ../src/gui/mainFrame.cpp:444
 msgid "Save state to file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:434
+#: ../src/gui/mainFrame.cpp:446
 msgid "Save &As...\tCtrl+Shift+S"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:434
+#: ../src/gui/mainFrame.cpp:446
 msgid "Save current state to new file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:437
+#: ../src/gui/mainFrame.cpp:449
 msgid "&Plot...\tCtrl+P"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:437
+#: ../src/gui/mainFrame.cpp:449
 msgid "Export Current Plot"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:438
+#: ../src/gui/mainFrame.cpp:450
 msgid "&Image...\tCtrl+I"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:438
+#: ../src/gui/mainFrame.cpp:450
 msgid "Export Current 3D View"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:439
+#: ../src/gui/mainFrame.cpp:451
 msgid "Ion&s...\tCtrl+N"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:439
+#: ../src/gui/mainFrame.cpp:451
 msgid "Export Ion Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:440
+#: ../src/gui/mainFrame.cpp:452
 msgid "Ran&ges...\tCtrl+G"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:440
+#: ../src/gui/mainFrame.cpp:452
 msgid "Export Range Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:441
+#: ../src/gui/mainFrame.cpp:453
 msgid "&Animate Filters...\tCtrl+A"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:441
+#: ../src/gui/mainFrame.cpp:453
 msgid "Export Animated Filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:442
+#: ../src/gui/mainFrame.cpp:454
 msgid "Ani&mate Camera...\tCtrl+M"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:442
+#: ../src/gui/mainFrame.cpp:454
 msgid "Export Animated Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:443
+#: ../src/gui/mainFrame.cpp:455
 msgid "Pac&kage...\tCtrl+K"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:443
+#: ../src/gui/mainFrame.cpp:455
 msgid "Export analysis package"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:457
 msgid "&Export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:448
+#: ../src/gui/mainFrame.cpp:460
 msgid "&Quit\tCtrl+Q"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:448 ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:462
 msgid "Exit Program"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:462
 msgid "E&xit"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:464
 msgid "&File"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:468
 msgid "&Background Colour...\tCtrl+B"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:468
 msgid "Change background colour"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:472
 msgid "&Control Pane\tF3"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:472 ../src/gui/mainFrame.cpp:475
 msgid "Toggle left control pane"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:475
 msgid "&Control Pane\tAlt+C"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:469
+#: ../src/gui/mainFrame.cpp:481
 msgid "&Raw Data Pane\tF4"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:469 ../src/gui/mainFrame.cpp:472
+#: ../src/gui/mainFrame.cpp:481 ../src/gui/mainFrame.cpp:484
 msgid "Toggle raw data  pane (bottom)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:472
+#: ../src/gui/mainFrame.cpp:484
 msgid "&Raw Data Pane\tAlt+R"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:476
+#: ../src/gui/mainFrame.cpp:488
 msgid "&Plot List\tF5"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:476 ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:488 ../src/gui/mainFrame.cpp:490
 msgid "Toggle plot list"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:490
 msgid "&Plot List\tAlt+P"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:484
+#: ../src/gui/mainFrame.cpp:496
 msgid "&Legend\tCtrl+L"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:484
+#: ../src/gui/mainFrame.cpp:496
 msgid "Toggle Legend display"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:486
+#: ../src/gui/mainFrame.cpp:498
 msgid "P&lot..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:499
 msgid "&Axis\tCtrl+Shift+I"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:499
 msgid "Toggle World Axis display"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:492
+#: ../src/gui/mainFrame.cpp:504
 msgid "&Fullscreen mode\tF11"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:492 ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:504 ../src/gui/mainFrame.cpp:506
 msgid "Next fullscreen mode: with toolbars"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:506
 msgid "&Fullscreen mode\tCtrl+Shift+F"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:499
+#: ../src/gui/mainFrame.cpp:511
 msgid "&Undo\tCtrl+Z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:501
+#: ../src/gui/mainFrame.cpp:513
 msgid "&Redo\tCtrl+Y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:504
+#: ../src/gui/mainFrame.cpp:516
 msgid "&Preferences"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:506
+#: ../src/gui/mainFrame.cpp:518
 msgid "&Edit"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:509
+#: ../src/gui/mainFrame.cpp:521
 msgid "&View"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:511
+#: ../src/gui/mainFrame.cpp:523
 msgid "&Help...\tCtrl+H"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:511
+#: ../src/gui/mainFrame.cpp:523
 msgid "Show help files and documentation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:524
 msgid "&Contact..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:524
 msgid "Open contact page"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:514
+#: ../src/gui/mainFrame.cpp:526
 msgid "&About..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:514
+#: ../src/gui/mainFrame.cpp:526
 msgid "Information about this program"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:515
+#: ../src/gui/mainFrame.cpp:527
 msgid "&Help"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:517
+#: ../src/gui/mainFrame.cpp:529
 msgid "Stashed Filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:522
+#: ../src/gui/mainFrame.cpp:534
 msgid "Data Filtering"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:546
+#: ../src/gui/mainFrame.cpp:558
 msgid "Last Outputs"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:548
+#: ../src/gui/mainFrame.cpp:560
 msgid "Auto Refresh"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:554
+#: ../src/gui/mainFrame.cpp:566
 msgid "Filter settings"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:556
+#: ../src/gui/mainFrame.cpp:568
 msgid "Camera Name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:562
+#: ../src/gui/mainFrame.cpp:574
 msgid "3D Post-processing"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:564
+#: ../src/gui/mainFrame.cpp:576
 msgid "Enable Cropping"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:566 ../src/gui/mainFrame.cpp:577
+#: ../src/gui/mainFrame.cpp:578 ../src/gui/mainFrame.cpp:589
 msgid "x-y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:567 ../src/gui/mainFrame.cpp:578
+#: ../src/gui/mainFrame.cpp:579 ../src/gui/mainFrame.cpp:590
 msgid "x-z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:568 ../src/gui/mainFrame.cpp:579
+#: ../src/gui/mainFrame.cpp:580 ../src/gui/mainFrame.cpp:591
 msgid "y-x"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:569 ../src/gui/mainFrame.cpp:580
+#: ../src/gui/mainFrame.cpp:581 ../src/gui/mainFrame.cpp:592
 msgid "y-z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:570 ../src/gui/mainFrame.cpp:581
+#: ../src/gui/mainFrame.cpp:582 ../src/gui/mainFrame.cpp:593
 msgid "z-x"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:571 ../src/gui/mainFrame.cpp:582
+#: ../src/gui/mainFrame.cpp:583 ../src/gui/mainFrame.cpp:594
 msgid "z-y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:586
+#: ../src/gui/mainFrame.cpp:598
 msgid "Use camera coordinates"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:587
+#: ../src/gui/mainFrame.cpp:599
 msgid "dX"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:589
+#: ../src/gui/mainFrame.cpp:601
 msgid "dY"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:591
+#: ../src/gui/mainFrame.cpp:603
 msgid "dZ"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:593
+#: ../src/gui/mainFrame.cpp:605
 msgid "Enable Anaglyphic Stereo"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:594
+#: ../src/gui/mainFrame.cpp:606
 msgid "Flip Channels"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:595
+#: ../src/gui/mainFrame.cpp:607
 msgid "Anaglyph Mode"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:597
+#: ../src/gui/mainFrame.cpp:609
 msgid "Red-Blue"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:598
+#: ../src/gui/mainFrame.cpp:610
 msgid "Red-Green"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:599
+#: ../src/gui/mainFrame.cpp:611
 msgid "Red-Cyan"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:600
+#: ../src/gui/mainFrame.cpp:612
 msgid "Green-Magenta"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:604
+#: ../src/gui/mainFrame.cpp:616
 msgid "Baseline Separation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:606
+#: ../src/gui/mainFrame.cpp:619
 msgid "Smooth && translucent objects"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:608
+#: ../src/gui/mainFrame.cpp:621
 msgid "3D lighting"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:610
+#: ../src/gui/mainFrame.cpp:624
+msgid "Performance"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:625
 msgid "Fast and weak randomisation."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:612
+#: ../src/gui/mainFrame.cpp:627
+msgid "Limit Output Pts"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:633
 msgid "Filter caching"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:614
+#: ../src/gui/mainFrame.cpp:635
 msgid "Max. Ram usage (%)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:671
+#: ../src/gui/mainFrame.cpp:692
 msgid "Type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:672
+#: ../src/gui/mainFrame.cpp:693
 msgid "Num"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:683
+#: ../src/gui/mainFrame.cpp:704
 msgid "Warning: Your configuration file appears to be invalid:\n"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:684
+#: ../src/gui/mainFrame.cpp:705
 msgid "\tConfig Load: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:885 ../src/gui/mainFrame.cpp:933
+#: ../src/gui/mainFrame.cpp:940
+msgid "Current state has not been saved, would you like to save it now?"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:941
+msgid "State changed"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:963 ../src/gui/mainFrame.cpp:1019
 msgid "Select Data or State File..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:886
+#: ../src/gui/mainFrame.cpp:964
 msgid ""
 "Readable files (*.xml, *.pos, *.txt,*.csv)|*.xml;*.pos;*.txt;*.csv|POS File "
 "(*.pos)|*.pos|XML State File (*.xml)|*.xml|Text Data Files (*.txt/csv)|*.txt;"
 "*.csv|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:919 ../src/gui/mainFrame.cpp:1274
+#: ../src/gui/mainFrame.cpp:1005 ../src/gui/mainFrame.cpp:1336
 msgid "Loaded file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:934
+#: ../src/gui/mainFrame.cpp:1020
 msgid ""
 "3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|"
 "XML State File (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:945
+#: ../src/gui/mainFrame.cpp:1031
 msgid "Merged file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1047
+#: ../src/gui/mainFrame.cpp:1135
 msgid "Tip: You can use ⌘ (command) to merge"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1049
+#: ../src/gui/mainFrame.cpp:1137
 msgid "Tip: You can use ctrl to merge"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1097
+#: ../src/gui/mainFrame.cpp:1174
 msgid "Load error"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1098
+#: ../src/gui/mainFrame.cpp:1175
 msgid ""
 "Error loading state file.\n"
 "See console for more info."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1120
+#: ../src/gui/mainFrame.cpp:1183
 msgid ""
 "This state file contains filters that can be unsafe to run\n"
 "Do you wish to remove these before continuing?."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1121
+#: ../src/gui/mainFrame.cpp:1184
 msgid "Security warning"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1330 ../src/gui/mainFrame.cpp:1429
-#: ../src/gui/mainFrame.cpp:1792
+#: ../src/gui/mainFrame.cpp:1393 ../src/gui/mainFrame.cpp:1492
+#: ../src/gui/mainFrame.cpp:1875
 msgid "Unable to save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1331
+#: ../src/gui/mainFrame.cpp:1394
 msgid "No plot available. Please create a plot before exporting."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1335
+#: ../src/gui/mainFrame.cpp:1398
 msgid "Save plot..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1336
+#: ../src/gui/mainFrame.cpp:1399
 msgid ""
 "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*."
 "svg|PNG File (*.png)|*.png|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1392
+#: ../src/gui/mainFrame.cpp:1455
 msgid "Select type for save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1392
+#: ../src/gui/mainFrame.cpp:1455
 msgid "Choose file type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1414 ../src/gui/mainFrame.cpp:1457
-#: ../src/gui/mainFrame.cpp:1504
+#: ../src/gui/mainFrame.cpp:1477 ../src/gui/mainFrame.cpp:1520
+#: ../src/gui/mainFrame.cpp:1567
 msgid "Choose resolution"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1430
+#: ../src/gui/mainFrame.cpp:1493
 msgid "Unknown file extension. Please use \"svg\" or \"png\""
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1441
+#: ../src/gui/mainFrame.cpp:1504
 msgid "Saved plot: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1448 ../src/gui/mainFrame.cpp:1496
+#: ../src/gui/mainFrame.cpp:1511 ../src/gui/mainFrame.cpp:1559
 msgid "Save Image..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1449 ../src/gui/mainFrame.cpp:1497
+#: ../src/gui/mainFrame.cpp:1512 ../src/gui/mainFrame.cpp:1560
 msgid "PNG File (*.png)|*.png|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1472 ../src/gui/mainFrame.cpp:1521
+#: ../src/gui/mainFrame.cpp:1535 ../src/gui/mainFrame.cpp:1584
 msgid "Program limitation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1473
+#: ../src/gui/mainFrame.cpp:1536
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1519,11 +1535,11 @@ msgid ""
 " If this bothers you, please submit a bug."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1487 ../src/gui/mainFrame.cpp:1570
+#: ../src/gui/mainFrame.cpp:1550 ../src/gui/mainFrame.cpp:1633
 msgid "Saved 3D View :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1522
+#: ../src/gui/mainFrame.cpp:1585
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1531,389 +1547,389 @@ msgid ""
 " If this bothers, please submit a bug."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1538
+#: ../src/gui/mainFrame.cpp:1601
 msgid "Number of frames"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1678
+#: ../src/gui/mainFrame.cpp:1760
 msgid "Cannot animate with no filters."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1725
+#: ../src/gui/mainFrame.cpp:1807
 msgid "Filter property change failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1727
+#: ../src/gui/mainFrame.cpp:1809
 msgid "Filter change error"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1750
+#: ../src/gui/mainFrame.cpp:1832
 msgid "Refresh failed on frame :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1752
+#: ../src/gui/mainFrame.cpp:1834
 msgid "Refresh failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1778
+#: ../src/gui/mainFrame.cpp:1861
 msgid "Scene generation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1779
+#: ../src/gui/mainFrame.cpp:1862
 msgid "Unable to generate scene for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1793
+#: ../src/gui/mainFrame.cpp:1876
 msgid "Image save failed for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1818
+#: ../src/gui/mainFrame.cpp:1901
 msgid "Ion save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1819
+#: ../src/gui/mainFrame.cpp:1902
 msgid "Unable to save ions for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1850
+#: ../src/gui/mainFrame.cpp:1933
 msgid "Plot save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1851
+#: ../src/gui/mainFrame.cpp:1934
 msgid "Unable to save plot or frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1892
+#: ../src/gui/mainFrame.cpp:1975
 msgid "Range save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1893
+#: ../src/gui/mainFrame.cpp:1976
 msgid "Unable to save range for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1922
+#: ../src/gui/mainFrame.cpp:2005
 msgid "Voxel save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1923
+#: ../src/gui/mainFrame.cpp:2006
 msgid "Unable to save voxels for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1969 ../src/gui/mainFrame.cpp:2076
-#: ../src/gui/mainFrame.cpp:2173
+#: ../src/gui/mainFrame.cpp:2052 ../src/gui/mainFrame.cpp:2159
+#: ../src/gui/mainFrame.cpp:2256
 msgid "No filters means no data to export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1975
+#: ../src/gui/mainFrame.cpp:2058
 msgid "Package name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1976
+#: ../src/gui/mainFrame.cpp:2059
 msgid "Package directory name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1978
+#: ../src/gui/mainFrame.cpp:2061
 msgid "AnalysisPackage"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1990
+#: ../src/gui/mainFrame.cpp:2073
 msgid "Package folder already exists, won't overwrite."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1991
+#: ../src/gui/mainFrame.cpp:2074
 msgid "Not available"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2022
+#: ../src/gui/mainFrame.cpp:2105
 msgid ""
 "Package folder creation failed\n"
 "check writing to this location is possible."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2023
+#: ../src/gui/mainFrame.cpp:2106
 msgid "Folder creation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2045
+#: ../src/gui/mainFrame.cpp:2128
 msgid "Copying"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2046
+#: ../src/gui/mainFrame.cpp:2129
 msgid "Copying referenced files"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2054
+#: ../src/gui/mainFrame.cpp:2137
 msgid "Error copying file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2065
+#: ../src/gui/mainFrame.cpp:2148
 msgid "Saved package: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2086
+#: ../src/gui/mainFrame.cpp:2169
 msgid "Export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2091
+#: ../src/gui/mainFrame.cpp:2174
 msgid "POS Data (*.pos)|*.pos|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2119 ../src/gui/mainFrame.cpp:2218
+#: ../src/gui/mainFrame.cpp:2202 ../src/gui/mainFrame.cpp:2301
 msgid "File already exists, overwrite?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2120 ../src/gui/mainFrame.cpp:2219
-#: ../src/gui/mainFrame.cpp:2245
+#: ../src/gui/mainFrame.cpp:2203 ../src/gui/mainFrame.cpp:2302
+#: ../src/gui/mainFrame.cpp:2328
 msgid "Overwrite?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2152
+#: ../src/gui/mainFrame.cpp:2235
 msgid "Saved ions: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2177
+#: ../src/gui/mainFrame.cpp:2260
 msgid "Export Ranges"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2200
+#: ../src/gui/mainFrame.cpp:2283
 msgid "Save state..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2201
+#: ../src/gui/mainFrame.cpp:2284
 msgid "XML state file (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2244
+#: ../src/gui/mainFrame.cpp:2327
 msgid "Files have been referred to using relative paths. Keep relative paths?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2276
+#: ../src/gui/mainFrame.cpp:2360
 msgid "Saved state: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2612
+#: ../src/gui/mainFrame.cpp:2698
 msgid "Manual not found locally. Launching web browser"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2621
+#: ../src/gui/mainFrame.cpp:2707
 msgid "Opening contact page in external web browser"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2633
+#: ../src/gui/mainFrame.cpp:2719
 msgid "No filter stashes to edit."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2637
+#: ../src/gui/mainFrame.cpp:2723
 msgid "Filter Stashes"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2666
+#: ../src/gui/mainFrame.cpp:2752
 msgid "Quick and dirty analysis for point data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2676
+#: ../src/gui/mainFrame.cpp:2762
 msgid "Compiled with wx Version: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2697
+#: ../src/gui/mainFrame.cpp:2783
 msgid "Press enter to store new stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2703
+#: ../src/gui/mainFrame.cpp:2789
 msgid "Press enter to restore stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2738
+#: ../src/gui/mainFrame.cpp:2824
 msgid "Unable to create stash, selection invalid"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2746
+#: ../src/gui/mainFrame.cpp:2832
 msgid "Created new filter tree stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2868
+#: ../src/gui/mainFrame.cpp:2954
 msgid "Filter type not a data source - can't be at tree base"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3026
+#: ../src/gui/mainFrame.cpp:3112
 msgid "Moving - Hold ⌘ (command) to copy"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3028
+#: ../src/gui/mainFrame.cpp:3114
 msgid "Moving - Hold control to copy"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3284
+#: ../src/gui/mainFrame.cpp:3370
 msgid "Press enter to store new camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3286
+#: ../src/gui/mainFrame.cpp:3372
 msgid "Press enter to restore camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3311 ../src/gui/mainFrame.cpp:3348
+#: ../src/gui/mainFrame.cpp:3397 ../src/gui/mainFrame.cpp:3438
 msgid "Restored camera: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3329
+#: ../src/gui/mainFrame.cpp:3417
 msgid "Stored camera: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3406
+#: ../src/gui/mainFrame.cpp:3498
 msgid "Select an item from the filter tree before choosing a new filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3408
+#: ../src/gui/mainFrame.cpp:3500
 msgid "Load data source (file->open) before choosing a new filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3429
+#: ../src/gui/mainFrame.cpp:3521
 msgid "Select RNG File..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3430
+#: ../src/gui/mainFrame.cpp:3522
 msgid ""
 "Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
 "Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3450
+#: ../src/gui/mainFrame.cpp:3542
 msgid "Failed reading range file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3454
+#: ../src/gui/mainFrame.cpp:3546
 msgid "Error loading file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3510 ../src/gui/mainFrame.cpp:3563
-#: ../src/gui/mainFrame.cpp:4946 ../src/gui/mainFrame.cpp:5481
+#: ../src/gui/mainFrame.cpp:3604 ../src/gui/mainFrame.cpp:3658
+#: ../src/gui/mainFrame.cpp:5150 ../src/gui/mainFrame.cpp:5703
 msgid "Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3540
+#: ../src/gui/mainFrame.cpp:3634
 msgid "Refresh Aborted."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3567
+#: ../src/gui/mainFrame.cpp:3662
 msgid "*Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3569
+#: ../src/gui/mainFrame.cpp:3664
 msgid "§Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3680
+#: ../src/gui/mainFrame.cpp:3781
 msgid "Autosave complete."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3835
+#: ../src/gui/mainFrame.cpp:3940
 msgid "Aborted."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3876
+#: ../src/gui/mainFrame.cpp:3990
 msgid "Updated."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3882
+#: ../src/gui/mainFrame.cpp:3997
 msgid "\\% Done (Esc aborts)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3884
+#: ../src/gui/mainFrame.cpp:3999
 msgid "\\% Done"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4133 ../src/gui/mainFrame.cpp:4140
+#: ../src/gui/mainFrame.cpp:4258 ../src/gui/mainFrame.cpp:4265
 msgid "Next Fullscreen mode: none"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4136
+#: ../src/gui/mainFrame.cpp:4261
 msgid "Next Fullscreen mode: complete"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4144
+#: ../src/gui/mainFrame.cpp:4269
 msgid "Next Fullscreen mode: with toolbars"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4160
+#: ../src/gui/mainFrame.cpp:4285
 msgid "Next Mode: No fullscreen"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4164
+#: ../src/gui/mainFrame.cpp:4289
 msgid "Next Mode: fullscreen w/o toolbar"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4168
+#: ../src/gui/mainFrame.cpp:4293
 msgid "Next Mode: fullscreen with toolbar"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4209
+#: ../src/gui/mainFrame.cpp:4334
 msgid "Tip: You can shift-click to force full refresh, if required"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4461
+#: ../src/gui/mainFrame.cpp:4590
 msgid "No data to save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4572
+#: ../src/gui/mainFrame.cpp:4759
 msgid "Aborting..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4578
+#: ../src/gui/mainFrame.cpp:4765
 msgid ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4579 ../src/gui/mainFrame.cpp:4601
+#: ../src/gui/mainFrame.cpp:4766 ../src/gui/mainFrame.cpp:4788
 msgid "Confirmation request"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4600
+#: ../src/gui/mainFrame.cpp:4787
 msgid "Are you sure you wish to exit 3Depict?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4974
+#: ../src/gui/mainFrame.cpp:5178
 msgid "Update Notice: New version "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4974
+#: ../src/gui/mainFrame.cpp:5178
 msgid " found online."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4978
+#: ../src/gui/mainFrame.cpp:5182
 msgid "Online Check: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4978
+#: ../src/gui/mainFrame.cpp:5182
 msgid " is up-to-date."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5068
+#: ../src/gui/mainFrame.cpp:5272
 msgid "An auto-save state was found, would you like to restore it?."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5069
+#: ../src/gui/mainFrame.cpp:5273
 msgid "Autosave"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5076
+#: ../src/gui/mainFrame.cpp:5280
 msgid "Unable to load autosave file.."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5261
+#: ../src/gui/mainFrame.cpp:5474
 msgid "List of available filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5262
+#: ../src/gui/mainFrame.cpp:5475
 msgid "Tree of data filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5263
+#: ../src/gui/mainFrame.cpp:5476
 msgid ""
 "Enable/Disable automatic updates of data when filter change takes effect"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5266
+#: ../src/gui/mainFrame.cpp:5479
 msgid ""
 "Enable/Disable \"Alpha blending\" (transparency) in rendering system. "
 "Blending is used to smooth objects (avoids artefacts known as \"jaggies\") "
@@ -1921,14 +1937,14 @@ msgid ""
 "but look more blocky"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5267
+#: ../src/gui/mainFrame.cpp:5480
 msgid ""
 "Enable/Disable lighting calculations in rendering, for objects that request "
 "this. Lighting provides important depth cues for objects comprised of 3D "
 "surfaces. Disabling may allow faster rendering in complex scenes"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5268
+#: ../src/gui/mainFrame.cpp:5481
 msgid ""
 "Enable/Disable weak randomisation (Galois linear feedback shift register). "
 "Strong randomisation uses a much slower random selection method, but "
@@ -1936,7 +1952,14 @@ msgid ""
 "recommended for final analyses"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5269
+#: ../src/gui/mainFrame.cpp:5483
+msgid ""
+"Limit the number of points that can be displayed in the 3D  scene. Does not "
+"affect filter tree calculations. Disabling this can severely reduce "
+"performance, due to large numbers of points being visible at once."
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:5484
 msgid ""
 "Enable/Disable caching of intermediate results during filter updates. "
 "Disabling caching will use less system RAM, though changes to any filter "
@@ -1944,160 +1967,160 @@ msgid ""
 "computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5280
+#: ../src/gui/mainFrame.cpp:5495
 msgid "Camera data information"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5284
+#: ../src/gui/mainFrame.cpp:5499
 msgid "Enable/disable visual effects on final 3D output"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5286
+#: ../src/gui/mainFrame.cpp:5501
 msgid "Enable cropping post-process effect"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5289
+#: ../src/gui/mainFrame.cpp:5504
 msgid ""
 "Colour based 3D effect enable/disable - requires appropriate colour filter "
 "3D glasses."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5290
+#: ../src/gui/mainFrame.cpp:5505
 msgid "Glasses colour mode"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5292
+#: ../src/gui/mainFrame.cpp:5507
 msgid ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5296
+#: ../src/gui/mainFrame.cpp:5511
 msgid "X"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5297
+#: ../src/gui/mainFrame.cpp:5512
 msgid "Y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5298
+#: ../src/gui/mainFrame.cpp:5513
 msgid "Save raw data to file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5299
+#: ../src/gui/mainFrame.cpp:5514
 msgid "Copy raw data to clipboard"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5300
+#: ../src/gui/mainFrame.cpp:5515
 msgid "Manage \"stashed\" data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5301
+#: ../src/gui/mainFrame.cpp:5516
 msgid "Program text output"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5302
+#: ../src/gui/mainFrame.cpp:5517
 msgid "Select active camera, or type to create new named camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5303
+#: ../src/gui/mainFrame.cpp:5518
 msgid "Remove the selected camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5304
+#: ../src/gui/mainFrame.cpp:5519
 msgid "Perform cropping from coordinate frame of camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5305
+#: ../src/gui/mainFrame.cpp:5520
 msgid ""
 "Set the maximum amount of RAM to use in order to speed repeat computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5306
+#: ../src/gui/mainFrame.cpp:5521
 msgid "Collapse the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5307
+#: ../src/gui/mainFrame.cpp:5522
 msgid "Expand the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5308
+#: ../src/gui/mainFrame.cpp:5523
 msgid "Process the filter tree, hold shift to purge cached filter data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5447
+#: ../src/gui/mainFrame.cpp:5663
 msgid "Crop"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5448
+#: ../src/gui/mainFrame.cpp:5664
 msgid "Stereo"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5459
+#: ../src/gui/mainFrame.cpp:5681
 msgid "Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5460
+#: ../src/gui/mainFrame.cpp:5682
 msgid "Cam"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5461
+#: ../src/gui/mainFrame.cpp:5683
 msgid "Post"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5462
+#: ../src/gui/mainFrame.cpp:5684
 msgid "Tools"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5479 ../src/backend/filter.cpp:44
+#: ../src/gui/mainFrame.cpp:5701 ../src/backend/filter.cpp:44
 msgid "Plot"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5480
+#: ../src/gui/mainFrame.cpp:5702
 msgid "Raw"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:203
+#: ../src/gui/mathglPane.cpp:209
 msgid "No plots selected."
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1125
+#: ../src/gui/mathglPane.cpp:1134
 msgid ""
 "Unable to allocate requested memory.\n"
 " Try a lower resolution, or save as vector (SVG)."
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1127
+#: ../src/gui/mathglPane.cpp:1136
 msgid "Plotting functions returned an error:\n"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1129
+#: ../src/gui/mathglPane.cpp:1138
 msgid "File readback check failed"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1131
+#: ../src/gui/mathglPane.cpp:1140
 msgid "Filesize during readback appears to be zero."
 msgstr ""
 
-#: ../src/3Depict.cpp:77
+#: ../src/3Depict.cpp:78
 msgid "displays this message"
 msgstr ""
 
-#: ../src/3Depict.cpp:79
+#: ../src/3Depict.cpp:80
 msgid "inputfile"
 msgstr ""
 
-#: ../src/3Depict.cpp:88
+#: ../src/3Depict.cpp:89
 msgid ""
 "Run debug unit tests, returns nonzero on test failure, zero on success.\n"
 "\t\tXML files may be passed to run, instead of default tests"
 msgstr ""
 
-#: ../src/3Depict.cpp:374
+#: ../src/3Depict.cpp:375
 msgid "File : "
 msgstr ""
 
-#: ../src/3Depict.cpp:374
+#: ../src/3Depict.cpp:375
 msgid " does not exist. Skipping"
 msgstr ""
 
@@ -2113,17 +2136,18 @@ msgstr ""
 msgid "Unable to determine filter type in defaults listing."
 msgstr ""
 
-#: ../src/backend/configFile.cpp:568
+#: ../src/backend/configFile.cpp:577
 msgid "Online access for non win32/apple platforms is intentionally disabled, "
 msgstr ""
 
-#: ../src/backend/configFile.cpp:569
+#: ../src/backend/configFile.cpp:578
 msgid ""
 "regardless of the settings you use here. Use your package manager to keep up-"
 "to-date"
 msgstr ""
 
-#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:96
+#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:122
+#: ../src/backend/filters/voxelise.cpp:132
 msgid "None"
 msgstr ""
 
@@ -2151,240 +2175,103 @@ msgstr ""
 msgid "Points"
 msgstr ""
 
-#: ../src/backend/plot.cpp:619 ../src/backend/plot.cpp:627
+#: ../src/backend/plot.cpp:648 ../src/backend/plot.cpp:656
 msgid "Multiple data types"
 msgstr ""
 
-#: ../src/backend/plot.cpp:783
+#: ../src/backend/plot.cpp:808
 msgid "Mixed log/non-log:"
 msgstr ""
 
-#: ../src/backend/plot.cpp:1227
+#: ../src/backend/plot.cpp:1261
 msgid "error"
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:952
+#: ../src/backend/filtertree.cpp:951
 msgid "WARNING: Skipping node "
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:952
+#: ../src/backend/filtertree.cpp:951
 msgid " as it was not recognised"
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:990
+#: ../src/backend/filtertree.cpp:989
 msgid "Error processing node: "
 msgstr ""
 
-#: ../src/backend/viscontrol.cpp:951
-msgid ""
-"This file is a \"state\" file for the 3Depict program, and stores "
-"information about a particular analysis session. This file should be a valid "
-"\"XML\" file"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1089
-msgid "Failed to allocate parser"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1125
-msgid ""
-"Unable to retrieve root node in input state file... Is this really a non-"
-"empty XML file?"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1132
-msgid "Base state node missing. Is this really a state XML file??"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1161
-msgid "State was created by a newer version of this program.. "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1162
-msgid "file reading will continue, but may fail."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1167
-msgid ""
-"Warning, unparseable version number in state file. File reading will "
-"continue, but may fail"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1174
-msgid "Unable to find the \"writer\" node"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1184
-msgid "Unable to find the \"backcolour\" node."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1191
-msgid "\"backcolour\" node missing \"r\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1196
-msgid "Unable to interpret \"backColour\" node's \"r\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1204
-msgid "\"backcolour\" node missing \"g\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1210
-msgid "Unable to interpret \"backColour\" node's \"g\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1218
-msgid "\"backcolour\" node missing \"b\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1224
-msgid "Unable to interpret \"backColour\" node's \"b\" value."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1231
-msgid "\"backcolour\"s rgb values must be in range [0,1]"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1258
-msgid "Unable to find or interpret \"showaxis\" node"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1267
-msgid "Unable to locate \"filtertree\" node."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1283
-msgid "Cameras section missing \"active\" node."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1291
-msgid "Unable to find property \"value\"  for \"cameras->active\" node."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1297
-msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1317
-msgid "Failed to interpret camera state for camera : "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1325
-msgid "Unable to interpret the camera type for camera : "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1361
-msgid "Unable to locate stash name for stash "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1368
-msgid "Empty stash name for stash "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1374
-msgid "For stash "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1402
-msgid "Unrecognised effect :"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1412
-msgid "Duplicate effect found"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1412
-msgid " cannot use."
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1422
-msgid "Error reading effect : "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1483
-msgid "-merge"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1488
-msgid ""
-" Unable to merge stashes correctly. This is improbable, so please report "
-"this."
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:513
+#: ../src/backend/filters/externalProgram.cpp:515
 msgid "Command"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:516
+#: ../src/backend/filters/externalProgram.cpp:518
 msgid ""
 "Full command to send to operating system. See manual for escape sequence "
 "meanings"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:520
+#: ../src/backend/filters/externalProgram.cpp:522
 msgid "Work Dir"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:523
+#: ../src/backend/filters/externalProgram.cpp:525
 msgid "Directory to run the command in"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:533
+#: ../src/backend/filters/externalProgram.cpp:535
 msgid "Cleanup input"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:536
+#: ../src/backend/filters/externalProgram.cpp:538
 msgid "Erase input files when command completed"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:545
+#: ../src/backend/filters/externalProgram.cpp:547
 msgid "Cache"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:548
+#: ../src/backend/filters/externalProgram.cpp:550
 msgid ""
 "Assume program does not alter its output, unless inputs from 3Depict are "
 "altered"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:630
+#: ../src/backend/filters/externalProgram.cpp:632
 msgid "Error processing command line"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:632
+#: ../src/backend/filters/externalProgram.cpp:634
 msgid "Unable to set working directory"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:634
+#: ../src/backend/filters/externalProgram.cpp:636
 msgid "Error saving posfile result for external program"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:636
+#: ../src/backend/filters/externalProgram.cpp:638
 msgid "Error saving plot result for externalprogram"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:638
+#: ../src/backend/filters/externalProgram.cpp:640
 msgid "Error creating temporary directory"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:640
+#: ../src/backend/filters/externalProgram.cpp:642
 msgid "Detected unusable number of columns in plot"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:642
+#: ../src/backend/filters/externalProgram.cpp:644
 msgid "Unable to parse plot result from external program"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:644
+#: ../src/backend/filters/externalProgram.cpp:646
 msgid "Unable to load ions from external program"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:646
+#: ../src/backend/filters/externalProgram.cpp:648
 msgid "Unable to perform commandline substitution"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:648
+#: ../src/backend/filters/externalProgram.cpp:650
 msgid "Error executing external program"
 msgstr ""
 
@@ -2415,7 +2302,7 @@ msgid "Shape of clipping object"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:501
-#: ../src/backend/filters/compositionProfile.cpp:916
+#: ../src/backend/filters/compositionProfile.cpp:925
 msgid "Show Primitive"
 msgstr ""
 
@@ -2434,20 +2321,20 @@ msgid ""
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:526
-#: ../src/backend/filters/compositionProfile.cpp:975
+#: ../src/backend/filters/compositionProfile.cpp:984
 msgid "Position for centre of sphere"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:531
 #: ../src/backend/filters/ionClip.cpp:594
-#: ../src/backend/filters/compositionProfile.cpp:958
-#: ../src/backend/filters/compositionProfile.cpp:980
+#: ../src/backend/filters/compositionProfile.cpp:967
+#: ../src/backend/filters/compositionProfile.cpp:989
 #: ../src/backend/filters/spatialAnalysis.cpp:610
 msgid "Radius"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:534
-#: ../src/backend/filters/compositionProfile.cpp:983
+#: ../src/backend/filters/compositionProfile.cpp:992
 msgid "Radius of sphere"
 msgstr ""
 
@@ -2468,9 +2355,9 @@ msgid "Centre of cylinder"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:575
-#: ../src/backend/filters/compositionProfile.cpp:939
+#: ../src/backend/filters/compositionProfile.cpp:948
 #: ../src/backend/filters/spatialAnalysis.cpp:601
-#: ../src/backend/filters/transform.cpp:1323
+#: ../src/backend/filters/transform.cpp:1319
 msgid "Axis"
 msgstr ""
 
@@ -2479,7 +2366,7 @@ msgid "Positive vector for cylinder"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:586
-#: ../src/backend/filters/compositionProfile.cpp:950
+#: ../src/backend/filters/compositionProfile.cpp:959
 msgid "Lock Axis Mag."
 msgstr ""
 
@@ -2488,7 +2375,7 @@ msgid "Prevent changing length of cylinder during 3D interaction"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:597
-#: ../src/backend/filters/compositionProfile.cpp:961
+#: ../src/backend/filters/compositionProfile.cpp:970
 #: ../src/backend/filters/spatialAnalysis.cpp:613
 msgid "Radius of cylinder"
 msgstr ""
@@ -2681,7 +2568,7 @@ msgid "Create a plot showing chemistry for each cluster size"
 msgstr ""
 
 #: ../src/backend/filters/clusterAnalysis.cpp:1036
-#: ../src/backend/filters/compositionProfile.cpp:1023
+#: ../src/backend/filters/compositionProfile.cpp:1032
 #: ../src/backend/filters/ionInfo.cpp:419
 msgid "Normalise"
 msgstr ""
@@ -2770,10 +2657,10 @@ msgid "---------------------------------------------------------------------- "
 msgstr ""
 
 #: ../src/backend/filters/clusterAnalysis.cpp:1829
-#: ../src/backend/filters/spatialAnalysis.cpp:1458
-#: ../src/backend/filters/spatialAnalysis.cpp:1787
-#: ../src/backend/filters/spatialAnalysis.cpp:2083
-#: ../src/backend/filters/transform.cpp:1039
+#: ../src/backend/filters/spatialAnalysis.cpp:1469
+#: ../src/backend/filters/spatialAnalysis.cpp:1798
+#: ../src/backend/filters/spatialAnalysis.cpp:2094
+#: ../src/backend/filters/transform.cpp:1035
 msgid "Collate"
 msgstr ""
 
@@ -2819,396 +2706,455 @@ msgstr ""
 msgid "Composition"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:84
+#: ../src/backend/filters/voxelise.cpp:109
 msgid "None (Raw count)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:85
+#: ../src/backend/filters/voxelise.cpp:110
 msgid "Volume (Density)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:86
+#: ../src/backend/filters/voxelise.cpp:111
 msgid "All Ions (conc)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:87
+#: ../src/backend/filters/voxelise.cpp:112
 msgid "Ratio (Num/Denom)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:91
+#: ../src/backend/filters/voxelise.cpp:116
 msgid "Point Cloud"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:92
+#: ../src/backend/filters/voxelise.cpp:117
 msgid "Isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:97
+#: ../src/backend/filters/voxelise.cpp:118
+msgid "Axial slice"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:123
 msgid "Gaussian (2𝜎)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:101
+#: ../src/backend/filters/voxelise.cpp:127
 msgid "Zero"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:102
+#: ../src/backend/filters/voxelise.cpp:128
 msgid "Bounce"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:543
+#: ../src/backend/filters/voxelise.cpp:133
+msgid "Linear"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:604
 msgid "Voxel Limits (min,max): ("
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:592
+#: ../src/backend/filters/voxelise.cpp:754
 msgid "Fixed width"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:596
+#: ../src/backend/filters/voxelise.cpp:758
 msgid "If true, use fixed size voxels, otherwise use fixed count"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:602
+#: ../src/backend/filters/voxelise.cpp:764
 msgid "Bin width x"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:606
+#: ../src/backend/filters/voxelise.cpp:768
 msgid "Voxel size in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:610
+#: ../src/backend/filters/voxelise.cpp:772
 msgid "Bin width y"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:613
+#: ../src/backend/filters/voxelise.cpp:775
 msgid "Voxel size in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:619
+#: ../src/backend/filters/voxelise.cpp:781
 msgid "Bin width z"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:622
+#: ../src/backend/filters/voxelise.cpp:784
 msgid "Voxel size in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:629
+#: ../src/backend/filters/voxelise.cpp:791
 msgid "Num bins x"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:633
+#: ../src/backend/filters/voxelise.cpp:795
 msgid "Number of voxels to use in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:638
+#: ../src/backend/filters/voxelise.cpp:800
 msgid "Num bins y"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:641
+#: ../src/backend/filters/voxelise.cpp:803
 msgid "Number of voxels to use in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:647
+#: ../src/backend/filters/voxelise.cpp:809
 msgid "Num bins z"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:649
+#: ../src/backend/filters/voxelise.cpp:811
 msgid "Number of voxels to use in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:670
+#: ../src/backend/filters/voxelise.cpp:832
 msgid "Normalise by"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:673
+#: ../src/backend/filters/voxelise.cpp:835
 msgid "Method to use to normalise scalar value in each voxel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:676
+#: ../src/backend/filters/voxelise.cpp:838
 msgid "Computation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:683
+#: ../src/backend/filters/voxelise.cpp:845
 msgid "Numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:686
+#: ../src/backend/filters/voxelise.cpp:848
 msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:706
+#: ../src/backend/filters/voxelise.cpp:868
 msgid "Enable this ion for numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:717
+#: ../src/backend/filters/voxelise.cpp:879
 msgid "Denominator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:720
+#: ../src/backend/filters/voxelise.cpp:882
 msgid "Parameter \"b\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:736
+#: ../src/backend/filters/voxelise.cpp:898
 msgid "Enable this ion for denominator contribution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:757
-#: ../src/backend/filters/voxelise.cpp:792
+#: ../src/backend/filters/voxelise.cpp:919
+#: ../src/backend/filters/voxelise.cpp:954
 msgid "Filtering"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:761
+#: ../src/backend/filters/voxelise.cpp:923
 msgid "Smoothing method to use on voxels"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:764
+#: ../src/backend/filters/voxelise.cpp:926
 msgid "Processing"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:770
+#: ../src/backend/filters/voxelise.cpp:932
 msgid "Kernel Bins"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:774
+#: ../src/backend/filters/voxelise.cpp:936
 msgid "Number of bins in convolution kernel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:785
+#: ../src/backend/filters/voxelise.cpp:947
 msgid "Exterior values"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:788
+#: ../src/backend/filters/voxelise.cpp:950
 msgid "Method to use to treat boundaries of voxel data for convolution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:806
+#: ../src/backend/filters/voxelise.cpp:970
 msgid "Representation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:809
+#: ../src/backend/filters/voxelise.cpp:973
 msgid "3D display method"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:812
-#: ../src/backend/filters/compositionProfile.cpp:1070
+#: ../src/backend/filters/voxelise.cpp:981
+#: ../src/backend/filters/voxelise.cpp:1037
+#: ../src/backend/filters/compositionProfile.cpp:1079
 #: ../src/backend/filters/boundingBox.cpp:656
-#: ../src/backend/filters/dataLoad.cpp:565
+#: ../src/backend/filters/dataLoad.cpp:567
 msgid "Appearance"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:819
+#: ../src/backend/filters/voxelise.cpp:984
 msgid "Spot size"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:822
+#: ../src/backend/filters/voxelise.cpp:987
 msgid "Size of the spots to use for display"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:827
-#: ../src/backend/filters/voxelise.cpp:858
+#: ../src/backend/filters/voxelise.cpp:992
+#: ../src/backend/filters/voxelise.cpp:1030
 msgid "Transparency"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:830
+#: ../src/backend/filters/voxelise.cpp:995
 msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:838
+#: ../src/backend/filters/voxelise.cpp:1004
+msgid "Surf. param."
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1007
 msgid "Isovalue"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:841
+#: ../src/backend/filters/voxelise.cpp:1010
 msgid "Scalar value to show as isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:850
-#: ../src/backend/filters/compositionProfile.cpp:1061
-#: ../src/backend/filters/annotation.cpp:882
+#: ../src/backend/filters/voxelise.cpp:1022
+#: ../src/backend/filters/compositionProfile.cpp:1070
+#: ../src/backend/filters/annotation.cpp:903
 #: ../src/backend/filters/spectrumPlot.cpp:471
 msgid "Colour"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:853
+#: ../src/backend/filters/voxelise.cpp:1025
 msgid "Colour of isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:861
+#: ../src/backend/filters/voxelise.cpp:1033
 msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1264
-msgid "Voxelisation aborted"
+#: ../src/backend/filters/voxelise.cpp:1045
+msgid "Slice param."
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1266
-msgid "Out of memory"
+#: ../src/backend/filters/voxelise.cpp:1053
+msgid "Slice Axis"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1268
-msgid "Unable to perform filter convolution"
+#: ../src/backend/filters/voxelise.cpp:1056
+msgid "Normal for the planar slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1270
-msgid "Voxelisation bounds are invalid"
+#: ../src/backend/filters/voxelise.cpp:1063
+msgid "Slice Coord"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:289
-msgid "Colour Map"
+#: ../src/backend/filters/voxelise.cpp:1066
+msgid "Fractional coordinate that slice plane passes through"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1071
+msgid "Interp. Mode"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:293
+#: ../src/backend/filters/voxelise.cpp:1079
+msgid "Interpolation mode for direction normal to slice"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1094
+msgid "Colour mode"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1097
+#: ../src/backend/filters/ionColour.cpp:263
 msgid "Colour scheme used to assign points colours by value"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:301
+#: ../src/backend/filters/voxelise.cpp:1106
+#: ../src/backend/filters/ionColour.cpp:271
 msgid "Show Bar"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:308
-msgid "Num Colours"
+#: ../src/backend/filters/voxelise.cpp:1116
+msgid "Auto Bounds"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:310
-msgid "Number of unique colours to use in colour map"
+#: ../src/backend/filters/voxelise.cpp:1117
+msgid "Auto-compute min/max values in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:316
+#: ../src/backend/filters/voxelise.cpp:1127
+#: ../src/backend/filters/ionColour.cpp:286
 msgid "Map start"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:317
+#: ../src/backend/filters/voxelise.cpp:1128
+#: ../src/backend/filters/ionColour.cpp:287
 msgid "Assign points with this value to the first colour in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:324
+#: ../src/backend/filters/voxelise.cpp:1135
+#: ../src/backend/filters/ionColour.cpp:294
 msgid "Map end"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:325
+#: ../src/backend/filters/voxelise.cpp:1136
+#: ../src/backend/filters/ionColour.cpp:295
 msgid "Assign points with this value to the last colour in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:425
-#: ../src/backend/filters/transform.cpp:1577
+#: ../src/backend/filters/voxelise.cpp:1707
+msgid "Voxelisation aborted"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1709
+msgid "Out of memory"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1711
+msgid "Unable to perform filter convolution"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1713
+msgid "Voxelisation bounds are invalid"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:259
+msgid "Colour Map"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:278
+msgid "Num Colours"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:280
+msgid "Number of unique colours to use in colour map"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:395
+#: ../src/backend/filters/transform.cpp:1573
 #: ../src/backend/filters/ionInfo.cpp:548
 msgid "Aborted"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:449
+#: ../src/backend/filters/compositionProfile.cpp:453
 msgid "Distance"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:457
+#: ../src/backend/filters/compositionProfile.cpp:461
 msgid "Fraction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:459
+#: ../src/backend/filters/compositionProfile.cpp:463
 msgid "Density (\\#.len^3)"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:486
+#: ../src/backend/filters/compositionProfile.cpp:490
 msgid "Freq. Profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:584
+#: ../src/backend/filters/compositionProfile.cpp:588
 msgid "Too many bins in comp. profile."
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:586
+#: ../src/backend/filters/compositionProfile.cpp:590
 msgid "Not enough memory for comp. profile."
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:588
+#: ../src/backend/filters/compositionProfile.cpp:592
 msgid "Aborted composition prof."
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:905
+#: ../src/backend/filters/compositionProfile.cpp:914
 msgid "Primitive type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:909
+#: ../src/backend/filters/compositionProfile.cpp:918
 msgid "Basic shape to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:920
+#: ../src/backend/filters/compositionProfile.cpp:929
 msgid "Display the 3D composition profile interaction object"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:934
+#: ../src/backend/filters/compositionProfile.cpp:943
 #: ../src/backend/filters/spatialAnalysis.cpp:596
 msgid "Position for centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:942
+#: ../src/backend/filters/compositionProfile.cpp:951
 msgid "Vector between ends of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:953
+#: ../src/backend/filters/compositionProfile.cpp:962
 msgid "Prevent length of cylinder changing during interaction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:993
+#: ../src/backend/filters/compositionProfile.cpp:1002
 msgid "Fixed Bin Num"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:996
+#: ../src/backend/filters/compositionProfile.cpp:1005
 msgid ""
 "If true, use a fixed number of bins for profile, otherwise use fixed step "
 "size"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1002
+#: ../src/backend/filters/compositionProfile.cpp:1011
 #: ../src/backend/filters/spatialAnalysis.cpp:420
 #: ../src/backend/filters/spatialAnalysis.cpp:569
 msgid "Num Bins"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1007
+#: ../src/backend/filters/compositionProfile.cpp:1016
 msgid "Number of bins to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1012
+#: ../src/backend/filters/compositionProfile.cpp:1021
 #: ../src/backend/filters/spectrumPlot.cpp:395
 msgid "Bin width"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1018
+#: ../src/backend/filters/compositionProfile.cpp:1027
 msgid "Size of each bin in profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1027
+#: ../src/backend/filters/compositionProfile.cpp:1036
 msgid "Convert bin counts into relative frequencies in each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1048
+#: ../src/backend/filters/compositionProfile.cpp:1057
 #: ../src/backend/filters/spectrumPlot.cpp:458
 msgid "Plot Type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1051
+#: ../src/backend/filters/compositionProfile.cpp:1060
 msgid "Visual style for plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1064
+#: ../src/backend/filters/compositionProfile.cpp:1073
 msgid "Colour of plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1080
+#: ../src/backend/filters/compositionProfile.cpp:1089
 msgid "Err. Estimator"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1083
+#: ../src/backend/filters/compositionProfile.cpp:1092
 msgid "Method of estimating error associated with each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1090
+#: ../src/backend/filters/compositionProfile.cpp:1099
 msgid "Avg. Window"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1093
+#: ../src/backend/filters/compositionProfile.cpp:1102
 msgid "Number of bins to include in moving average filter"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1097
+#: ../src/backend/filters/compositionProfile.cpp:1106
 msgid "Error analysis"
 msgstr ""
 
@@ -3341,97 +3287,97 @@ msgstr ""
 msgid "Alg. Params."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1016
+#: ../src/backend/filters/spatialAnalysis.cpp:1022
 msgid "Spatial analysis aborted by user"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1018
+#: ../src/backend/filters/spatialAnalysis.cpp:1024
 msgid "Insufficient data to complete analysis."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1492
-#: ../src/backend/filters/spatialAnalysis.cpp:1546
-#: ../src/backend/filters/spatialAnalysis.cpp:1793
-#: ../src/backend/filters/spatialAnalysis.cpp:2089
-#: ../src/backend/filters/spatialAnalysis.cpp:2578
+#: ../src/backend/filters/spatialAnalysis.cpp:1503
+#: ../src/backend/filters/spatialAnalysis.cpp:1557
+#: ../src/backend/filters/spatialAnalysis.cpp:1804
+#: ../src/backend/filters/spatialAnalysis.cpp:2100
+#: ../src/backend/filters/spatialAnalysis.cpp:2589
 msgid "Build"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1504
-#: ../src/backend/filters/spatialAnalysis.cpp:1558
+#: ../src/backend/filters/spatialAnalysis.cpp:1515
+#: ../src/backend/filters/spatialAnalysis.cpp:1569
 msgid "Surface"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1598
-#: ../src/backend/filters/spatialAnalysis.cpp:1820
-#: ../src/backend/filters/spatialAnalysis.cpp:2116
+#: ../src/backend/filters/spatialAnalysis.cpp:1609
+#: ../src/backend/filters/spatialAnalysis.cpp:1831
+#: ../src/backend/filters/spatialAnalysis.cpp:2127
 msgid "Analyse"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1655
-#: ../src/backend/filters/spatialAnalysis.cpp:1724
+#: ../src/backend/filters/spatialAnalysis.cpp:1666
+#: ../src/backend/filters/spatialAnalysis.cpp:1735
 msgid "Radial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1659
+#: ../src/backend/filters/spatialAnalysis.cpp:1670
 msgid "NN Freq."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1715
+#: ../src/backend/filters/spatialAnalysis.cpp:1726
 msgid "Warning, "
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1716
+#: ../src/backend/filters/spatialAnalysis.cpp:1727
 msgid ""
 " points were unable to find neighbour points that exceeded the search "
 "radius, and thus terminated prematurely"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1726
+#: ../src/backend/filters/spatialAnalysis.cpp:1737
 msgid " RDF"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2016
-#: ../src/backend/filters/spatialAnalysis.cpp:2322
+#: ../src/backend/filters/spatialAnalysis.cpp:2027
+#: ../src/backend/filters/spatialAnalysis.cpp:2333
 msgid "Number Density (\\#/Vol^3)"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2043
-#: ../src/backend/filters/spatialAnalysis.cpp:2347
+#: ../src/backend/filters/spatialAnalysis.cpp:2054
+#: ../src/backend/filters/spatialAnalysis.cpp:2358
 msgid "Warning,"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2044
-#: ../src/backend/filters/spatialAnalysis.cpp:2348
+#: ../src/backend/filters/spatialAnalysis.cpp:2055
+#: ../src/backend/filters/spatialAnalysis.cpp:2359
 msgid " points were un-analysable. These have been dropped"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2066
-#: ../src/backend/filters/spatialAnalysis.cpp:2370
+#: ../src/backend/filters/spatialAnalysis.cpp:2077
+#: ../src/backend/filters/spatialAnalysis.cpp:2381
 msgid "And so on..."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2450
+#: ../src/backend/filters/spatialAnalysis.cpp:2461
 msgid "Extract"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2501
+#: ../src/backend/filters/spatialAnalysis.cpp:2512
 msgid "Reduce"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2595
+#: ../src/backend/filters/spatialAnalysis.cpp:2606
 msgid "Compute"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2620
+#: ../src/backend/filters/spatialAnalysis.cpp:2631
 msgid "Insufficient points to complete analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2658
+#: ../src/backend/filters/spatialAnalysis.cpp:2669
 msgid "Axial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2660
+#: ../src/backend/filters/spatialAnalysis.cpp:2671
 msgid " 1D Dist. Func."
 msgstr ""
 
@@ -3475,122 +3421,122 @@ msgstr ""
 msgid "Mass Centre"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1058
+#: ../src/backend/filters/transform.cpp:1054
 msgid "Mass-to-Charge (amu/e)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1112
+#: ../src/backend/filters/transform.cpp:1108
 msgid "Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1128
+#: ../src/backend/filters/transform.cpp:1124
 msgid "Splice"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1183
+#: ../src/backend/filters/transform.cpp:1179
 msgid "Algorithm to use to transform point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1199
+#: ../src/backend/filters/transform.cpp:1195
 msgid "Origin mode"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1202
+#: ../src/backend/filters/transform.cpp:1198
 msgid "Select how transform origin is computed"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1207
+#: ../src/backend/filters/transform.cpp:1203
 msgid "Show marker"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1211
+#: ../src/backend/filters/transform.cpp:1207
 msgid "Display an interactive object to set transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1213
+#: ../src/backend/filters/transform.cpp:1209
 msgid "Display a small marker to denote transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1229
+#: ../src/backend/filters/transform.cpp:1225
 msgid "Translation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1232
+#: ../src/backend/filters/transform.cpp:1228
 msgid "Translation vector for transform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1244
+#: ../src/backend/filters/transform.cpp:1240
 msgid "Offset"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1248
+#: ../src/backend/filters/transform.cpp:1244
 msgid "Scalar to use to offset each point's associated value"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1265
-#: ../src/backend/filters/transform.cpp:1292
+#: ../src/backend/filters/transform.cpp:1261
+#: ../src/backend/filters/transform.cpp:1288
 msgid "Origin of scale trasnform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1272
-#: ../src/backend/filters/transform.cpp:1299
+#: ../src/backend/filters/transform.cpp:1268
+#: ../src/backend/filters/transform.cpp:1295
 msgid "Scale Fact."
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1275
-#: ../src/backend/filters/transform.cpp:1302
+#: ../src/backend/filters/transform.cpp:1271
+#: ../src/backend/filters/transform.cpp:1298
 msgid "Enlargement factor for scaling around origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1318
+#: ../src/backend/filters/transform.cpp:1314
 msgid "Origin of rotation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1326
+#: ../src/backend/filters/transform.cpp:1322
 msgid "Axis around which to revolve"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1331
+#: ../src/backend/filters/transform.cpp:1327
 msgid "Angle (deg)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1334
+#: ../src/backend/filters/transform.cpp:1330
 msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1351
+#: ../src/backend/filters/transform.cpp:1347
 msgid "Noise Type"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1354
+#: ../src/backend/filters/transform.cpp:1350
 msgid "Method to use to degrade point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1361
+#: ../src/backend/filters/transform.cpp:1357
 msgid "Noise level"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1363
+#: ../src/backend/filters/transform.cpp:1359
 msgid "Standard dev."
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1371
+#: ../src/backend/filters/transform.cpp:1367
 msgid "Amplitude of noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1383
+#: ../src/backend/filters/transform.cpp:1379
 msgid "Transform Params"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1580
+#: ../src/backend/filters/transform.cpp:1576
 msgid "Unable to allocate memory"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1759
+#: ../src/backend/filters/transform.cpp:1755
 msgid "White"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1761
+#: ../src/backend/filters/transform.cpp:1757
 msgid "Gaussian"
 msgstr ""
 
@@ -3697,7 +3643,7 @@ msgid "Thickness of the lines used to draw the box"
 msgstr ""
 
 #: ../src/backend/filters/boundingBox.cpp:650
-#: ../src/backend/filters/annotation.cpp:833
+#: ../src/backend/filters/annotation.cpp:845
 msgid "Font Size"
 msgstr ""
 
@@ -3705,219 +3651,229 @@ msgstr ""
 msgid "Relative size for text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:67
+#: ../src/backend/filters/annotation.cpp:68
 msgid "Arrow"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:68
+#: ../src/backend/filters/annotation.cpp:69
 msgid "Text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:69
+#: ../src/backend/filters/annotation.cpp:70
 msgid "Arrow+Text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:70
+#: ../src/backend/filters/annotation.cpp:71
 msgid "Angle"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:71
+#: ../src/backend/filters/annotation.cpp:72
 msgid "Ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:538
+#: ../src/backend/filters/annotation.cpp:526
+msgid "Enable"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:529
+msgid "Enable/disable annotation"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:550
 msgid "Type or style of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:553
-#: ../src/backend/filters/annotation.cpp:655
+#: ../src/backend/filters/annotation.cpp:565
+#: ../src/backend/filters/annotation.cpp:667
 msgid "Text of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:561
+#: ../src/backend/filters/annotation.cpp:573
 msgid "Position of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:565
-#: ../src/backend/filters/annotation.cpp:669
-#: ../src/backend/filters/annotation.cpp:727
-#: ../src/backend/filters/annotation.cpp:816
+#: ../src/backend/filters/annotation.cpp:577
+#: ../src/backend/filters/annotation.cpp:681
+#: ../src/backend/filters/annotation.cpp:739
+#: ../src/backend/filters/annotation.cpp:828
 msgid "Up dir"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:569
-#: ../src/backend/filters/annotation.cpp:820
+#: ../src/backend/filters/annotation.cpp:581
+#: ../src/backend/filters/annotation.cpp:832
 msgid "Vector for up direction of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:573
-#: ../src/backend/filters/annotation.cpp:676
-#: ../src/backend/filters/annotation.cpp:719
-#: ../src/backend/filters/annotation.cpp:824
+#: ../src/backend/filters/annotation.cpp:585
+#: ../src/backend/filters/annotation.cpp:688
+#: ../src/backend/filters/annotation.cpp:731
+#: ../src/backend/filters/annotation.cpp:836
 msgid "Across dir"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:577
-#: ../src/backend/filters/annotation.cpp:828
+#: ../src/backend/filters/annotation.cpp:589
+#: ../src/backend/filters/annotation.cpp:840
 msgid "Reading direction for annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:582
-#: ../src/backend/filters/annotation.cpp:661
-#: ../src/backend/filters/annotation.cpp:754
+#: ../src/backend/filters/annotation.cpp:594
+#: ../src/backend/filters/annotation.cpp:673
+#: ../src/backend/filters/annotation.cpp:766
 msgid "Text size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:586
-#: ../src/backend/filters/annotation.cpp:665
-#: ../src/backend/filters/annotation.cpp:836
+#: ../src/backend/filters/annotation.cpp:598
+#: ../src/backend/filters/annotation.cpp:677
+#: ../src/backend/filters/annotation.cpp:848
 msgid "Relative size of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:594
-#: ../src/backend/filters/annotation.cpp:633
-#: ../src/backend/filters/annotation.cpp:800
+#: ../src/backend/filters/annotation.cpp:606
+#: ../src/backend/filters/annotation.cpp:645
+#: ../src/backend/filters/annotation.cpp:812
 msgid "Start"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:598
-#: ../src/backend/filters/annotation.cpp:637
+#: ../src/backend/filters/annotation.cpp:610
+#: ../src/backend/filters/annotation.cpp:649
 msgid "3D position for tail of arrow"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:602
-#: ../src/backend/filters/annotation.cpp:642
-#: ../src/backend/filters/annotation.cpp:808
+#: ../src/backend/filters/annotation.cpp:614
+#: ../src/backend/filters/annotation.cpp:654
+#: ../src/backend/filters/annotation.cpp:820
 msgid "End"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:606
-#: ../src/backend/filters/annotation.cpp:646
+#: ../src/backend/filters/annotation.cpp:618
+#: ../src/backend/filters/annotation.cpp:658
 msgid "3D Position to which arrow points"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:612
-#: ../src/backend/filters/annotation.cpp:683
+#: ../src/backend/filters/annotation.cpp:624
+#: ../src/backend/filters/annotation.cpp:695
 msgid "Tip radius"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:616
+#: ../src/backend/filters/annotation.cpp:628
 msgid "Size of the arrow head"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:620
+#: ../src/backend/filters/annotation.cpp:632
 msgid "Line size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:624
+#: ../src/backend/filters/annotation.cpp:636
 msgid "Thickness of line used to draw arrow stem"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:693
+#: ../src/backend/filters/annotation.cpp:705
 msgid "Position A"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:697
+#: ../src/backend/filters/annotation.cpp:709
 msgid "Location of first non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:701
+#: ../src/backend/filters/annotation.cpp:713
 msgid "Origin "
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:705
+#: ../src/backend/filters/annotation.cpp:717
 msgid "Location of central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:709
+#: ../src/backend/filters/annotation.cpp:721
 msgid "Position B"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:713
+#: ../src/backend/filters/annotation.cpp:725
 msgid "Location of second non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:723
+#: ../src/backend/filters/annotation.cpp:735
 msgid "Reading direction for angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:728
+#: ../src/backend/filters/annotation.cpp:740
 msgid "Vector for up direction of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:736
+#: ../src/backend/filters/annotation.cpp:748
 msgid "Reflexive"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:739
+#: ../src/backend/filters/annotation.cpp:751
 msgid "Measure interor (enabled) or exterior angle (disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:744
+#: ../src/backend/filters/annotation.cpp:756
 msgid "Show Angle"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:748
+#: ../src/backend/filters/annotation.cpp:760
 msgid "Display angle text (when enabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:758
+#: ../src/backend/filters/annotation.cpp:770
 msgid "Size of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:776
+#: ../src/backend/filters/annotation.cpp:788
 msgid "Digit format"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:780
+#: ../src/backend/filters/annotation.cpp:792
 msgid ""
 "Format of angle text; # for numeral position, '.' for separator, eg ##.## "
 "gives 12.34"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:786
+#: ../src/backend/filters/annotation.cpp:798
+#: ../src/backend/filters/annotation.cpp:886
 msgid "Sphere size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:790
+#: ../src/backend/filters/annotation.cpp:802
+#: ../src/backend/filters/annotation.cpp:890
 msgid "Marker sphere size for manipulating tool"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:804
+#: ../src/backend/filters/annotation.cpp:816
 msgid "Ruler beginning 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:812
+#: ../src/backend/filters/annotation.cpp:824
 msgid "Ruler finish 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:845
+#: ../src/backend/filters/annotation.cpp:857
 msgid "Fixed ticks"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:848
+#: ../src/backend/filters/annotation.cpp:860
 msgid ""
 "Use fixed (enabled) number of text markers, or one every fixed distance "
 "(disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:855
+#: ../src/backend/filters/annotation.cpp:867
 msgid "Num Ticks"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:858
+#: ../src/backend/filters/annotation.cpp:870
 msgid "Number of tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:865
+#: ../src/backend/filters/annotation.cpp:877
 msgid "Tick Spacing"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:868
+#: ../src/backend/filters/annotation.cpp:880
 msgid "Distance between tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:885
+#: ../src/backend/filters/annotation.cpp:906
 msgid "Colour for ruler and ticks"
 msgstr ""
 
@@ -4069,149 +4025,149 @@ msgstr ""
 msgid "Bug? Problem with qhull library, cannot run convex hull."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:45
+#: ../src/backend/filters/dataLoad.cpp:47
 msgid "POS Data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:46
+#: ../src/backend/filters/dataLoad.cpp:48
 msgid "Text Data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:225
+#: ../src/backend/filters/dataLoad.cpp:227
 msgid " does not exist"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:262
-#: ../src/backend/filters/dataLoad.cpp:273
-#: ../src/backend/filters/dataLoad.cpp:293
-#: ../src/backend/filters/dataLoad.cpp:305
+#: ../src/backend/filters/dataLoad.cpp:264
+#: ../src/backend/filters/dataLoad.cpp:275
+#: ../src/backend/filters/dataLoad.cpp:295
+#: ../src/backend/filters/dataLoad.cpp:307
 msgid "Error loading file: "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:319
+#: ../src/backend/filters/dataLoad.cpp:321
 msgid "Data file contained incorrect number of columns -- should be 4, was "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:372
+#: ../src/backend/filters/dataLoad.cpp:374
 msgid ""
 "Warning:One or more bounds of the loaded data approaches the limits of "
 "numerical stability for the internal data type(magnitude too large). "
 "Consider rescaling data before loading"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:379
+#: ../src/backend/filters/dataLoad.cpp:381
 msgid "Loaded "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:379
+#: ../src/backend/filters/dataLoad.cpp:381
 msgid " Points"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:407
-#: ../src/backend/filters/rangeFile.cpp:504
+#: ../src/backend/filters/dataLoad.cpp:409
+#: ../src/backend/filters/rangeFile.cpp:559
 msgid "File"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:408
+#: ../src/backend/filters/dataLoad.cpp:410
 msgid "File from which to load data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:419
+#: ../src/backend/filters/dataLoad.cpp:421
 msgid "File type"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:421
+#: ../src/backend/filters/dataLoad.cpp:423
 msgid "Type of file to be loaded"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:435
+#: ../src/backend/filters/dataLoad.cpp:437
 msgid "Entries per point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:436
+#: ../src/backend/filters/dataLoad.cpp:438
 msgid "Number of decimal values in file per 3D point (normally 4)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:464
+#: ../src/backend/filters/dataLoad.cpp:466
 msgid "Relative offset of each entry in file for point's X position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:472
+#: ../src/backend/filters/dataLoad.cpp:474
 msgid "Relative offset of each entry in file for point's Y position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:480
+#: ../src/backend/filters/dataLoad.cpp:482
 msgid "Relative offset of each entry in file for point's Z position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:488
+#: ../src/backend/filters/dataLoad.cpp:490
 msgid ""
 "Relative offset of each entry in file to use for scalar value of 3D point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:491
+#: ../src/backend/filters/dataLoad.cpp:493
 msgid "Value Label"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:495
+#: ../src/backend/filters/dataLoad.cpp:497
 msgid "Name for the scalar value associated with each point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:498
+#: ../src/backend/filters/dataLoad.cpp:500
 msgid "Format params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:504
+#: ../src/backend/filters/dataLoad.cpp:506
 msgid "Enabled"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:508
+#: ../src/backend/filters/dataLoad.cpp:510
 msgid "Load this file?"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:516
+#: ../src/backend/filters/dataLoad.cpp:518
 msgid "Sample data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:519
+#: ../src/backend/filters/dataLoad.cpp:521
 msgid ""
 "Perform random selection on file contents, instead of loading entire file"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:526
+#: ../src/backend/filters/dataLoad.cpp:528
 msgid "Load Limit (MB)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:529
+#: ../src/backend/filters/dataLoad.cpp:531
 msgid "Limit for size of data to load"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:535
+#: ../src/backend/filters/dataLoad.cpp:537
 msgid "Monitor"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:539
+#: ../src/backend/filters/dataLoad.cpp:541
 msgid ""
 "Watch file timestamp to track changes to file contents from other programs"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:541
+#: ../src/backend/filters/dataLoad.cpp:543
 msgid "Load params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:551
+#: ../src/backend/filters/dataLoad.cpp:553
 msgid "Default colour "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:554
+#: ../src/backend/filters/dataLoad.cpp:556
 msgid "Default colour for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:559
+#: ../src/backend/filters/dataLoad.cpp:561
 msgid "Draw Size"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:562
+#: ../src/backend/filters/dataLoad.cpp:564
 msgid "Default size for points, if not overridden by other filters"
 msgstr ""
 
@@ -4279,291 +4235,456 @@ msgstr ""
 msgid "Bad bincount value in spectrum filter."
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:146
+#: ../src/backend/filters/rangeFile.cpp:143
 msgid "Pre-Allocate"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:260 ../src/backend/filter.cpp:46
+#: ../src/backend/filters/rangeFile.cpp:274 ../src/backend/filter.cpp:46
 msgid "Range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:506
+#: ../src/backend/filters/rangeFile.cpp:561
 msgid "File to use for range data"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:518
+#: ../src/backend/filters/rangeFile.cpp:573
 msgid "Drop unranged"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:520
+#: ../src/backend/filters/rangeFile.cpp:575
 msgid "Remove unranged points when generating output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:540
+#: ../src/backend/filters/rangeFile.cpp:595
 msgid "All Ions"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:541
+#: ../src/backend/filters/rangeFile.cpp:596
 msgid "Enable/disable all ions at once"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:549
+#: ../src/backend/filters/rangeFile.cpp:604
 msgid "Species"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:556
+#: ../src/backend/filters/rangeFile.cpp:611
 msgid "IonID "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:557
+#: ../src/backend/filters/rangeFile.cpp:612
 msgid "Enable/disable specified ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:570
+#: ../src/backend/filters/rangeFile.cpp:625
 msgid "Active Ion "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:572
+#: ../src/backend/filters/rangeFile.cpp:627
 msgid "If true, ion is used in output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:586
+#: ../src/backend/filters/rangeFile.cpp:641
 msgid "Colour "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:589
+#: ../src/backend/filters/rangeFile.cpp:644
 msgid "Colour used to represent ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:613
+#: ../src/backend/filters/rangeFile.cpp:668
 msgid "All Ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:614
+#: ../src/backend/filters/rangeFile.cpp:669
 msgid "Enable/disable all ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:632
+#: ../src/backend/filters/rangeFile.cpp:687
 msgid "Active Rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:635
+#: ../src/backend/filters/rangeFile.cpp:690
 msgid ""
 "Enable/disable specified range (ion must also be enabled to activiate range)"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:639
+#: ../src/backend/filters/rangeFile.cpp:694
 msgid "Ion "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:642
+#: ../src/backend/filters/rangeFile.cpp:697
 msgid "Name of ion associate to this range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:651
+#: ../src/backend/filters/rangeFile.cpp:706
 msgid "Start rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:654
+#: ../src/backend/filters/rangeFile.cpp:709
 msgid "Start value for range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:659
+#: ../src/backend/filters/rangeFile.cpp:714
 msgid "End rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:662
+#: ../src/backend/filters/rangeFile.cpp:717
 msgid "Stopping value for range`"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:966
+#: ../src/backend/filters/rangeFile.cpp:1021
 msgid "Ranging aborted by user"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:968
+#: ../src/backend/filters/rangeFile.cpp:1023
 msgid "Insufficient memory for range"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:93
+#: ../src/backend/state.cpp:120
+msgid ""
+"This file is a \"state\" file for the 3Depict program, and stores "
+"information about a particular analysis session. This file should be a valid "
+"\"XML\" file"
+msgstr ""
+
+#: ../src/backend/state.cpp:248
+msgid "Failed to allocate parser"
+msgstr ""
+
+#: ../src/backend/state.cpp:283
+msgid ""
+"Unable to retrieve root node in input state file... Is this really a non-"
+"empty XML file?"
+msgstr ""
+
+#: ../src/backend/state.cpp:290
+msgid "Base state node missing. Is this really a state XML file??"
+msgstr ""
+
+#: ../src/backend/state.cpp:319
+msgid "State was created by a newer version of this program.. "
+msgstr ""
+
+#: ../src/backend/state.cpp:320
+msgid "file reading will continue, but may fail."
+msgstr ""
+
+#: ../src/backend/state.cpp:325
+msgid ""
+"Warning, unparseable version number in state file. File reading will "
+"continue, but may fail"
+msgstr ""
+
+#: ../src/backend/state.cpp:332
+msgid "Unable to find the \"writer\" node"
+msgstr ""
+
+#: ../src/backend/state.cpp:342
+msgid "Unable to find the \"backcolour\" node."
+msgstr ""
+
+#: ../src/backend/state.cpp:349
+msgid "\"backcolour\" node missing \"r\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:354
+msgid "Unable to interpret \"backColour\" node's \"r\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:362
+msgid "\"backcolour\" node missing \"g\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:368
+msgid "Unable to interpret \"backColour\" node's \"g\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:376
+msgid "\"backcolour\" node missing \"b\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:382
+msgid "Unable to interpret \"backColour\" node's \"b\" value."
+msgstr ""
+
+#: ../src/backend/state.cpp:389
+msgid "\"backcolour\"s rgb values must be in range [0,1]"
+msgstr ""
+
+#: ../src/backend/state.cpp:417
+msgid "Unable to find or interpret \"showaxis\" node"
+msgstr ""
+
+#: ../src/backend/state.cpp:424
+msgid "Unable to locate \"filtertree\" node."
+msgstr ""
+
+#: ../src/backend/state.cpp:440
+msgid "Cameras section missing \"active\" node."
+msgstr ""
+
+#: ../src/backend/state.cpp:448
+msgid "Unable to find property \"value\"  for \"cameras->active\" node."
+msgstr ""
+
+#: ../src/backend/state.cpp:454
+msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
+msgstr ""
+
+#: ../src/backend/state.cpp:473
+msgid "Failed to interpret camera state for camera : "
+msgstr ""
+
+#: ../src/backend/state.cpp:481
+msgid "Unable to interpret the camera type for camera : "
+msgstr ""
+
+#: ../src/backend/state.cpp:517
+msgid "Unable to locate stash name for stash "
+msgstr ""
+
+#: ../src/backend/state.cpp:524
+msgid "Empty stash name for stash "
+msgstr ""
+
+#: ../src/backend/state.cpp:533
+msgid "No filter tree for stash:"
+msgstr ""
+
+#: ../src/backend/state.cpp:539
+msgid "For stash "
+msgstr ""
+
+#: ../src/backend/state.cpp:570
+msgid "Unrecognised effect :"
+msgstr ""
+
+#: ../src/backend/state.cpp:580
+msgid "Duplicate effect found"
+msgstr ""
+
+#: ../src/backend/state.cpp:580
+msgid " cannot use."
+msgstr ""
+
+#: ../src/backend/state.cpp:590
+msgid "Error reading effect : "
+msgstr ""
+
+#: ../src/backend/state.cpp:651
+msgid "-merge"
+msgstr ""
+
+#: ../src/backend/state.cpp:656
+msgid ""
+" Unable to merge stashes correctly. This is improbable, so please report "
+"this."
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:198
 msgid ""
 "Parent filter has no output, but filter requires input -- there is no point "
 "in placing a child filter here."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:94
+#: ../src/backend/filtertreeAnalyse.cpp:199
 msgid "Leaf-only filter with child"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:104
+#: ../src/backend/filtertreeAnalyse.cpp:209
 msgid ""
 "Parent filters' output will be blocked by child, without use. Parent results "
 "will be dropped."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:105
-#: ../src/backend/filtertreeAnalyse.cpp:119
+#: ../src/backend/filtertreeAnalyse.cpp:210
+#: ../src/backend/filtertreeAnalyse.cpp:224
 msgid "Bad parent->child pair"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:118
+#: ../src/backend/filtertreeAnalyse.cpp:223
 msgid ""
 "First filter does not output anything useable by child filter. Child filter "
 "not useful."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:291
+#: ../src/backend/filtertreeAnalyse.cpp:303
 msgid "Spatial results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:292
+#: ../src/backend/filtertreeAnalyse.cpp:304
 msgid ""
 "Filters and settings selected that could alter reported results that depend "
 "upon density. Check to see if spatial sampling may be happening in the "
 "filter tree - this warning is provisional only."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:453
+#: ../src/backend/filtertreeAnalyse.cpp:372
+msgid "Filter needs parent \""
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:373
+msgid ""
+"\" but does not have one. Filter may not function correctly until this "
+"parent is given."
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:374
+msgid "Filter missing needed parent"
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:553
 msgid "Composition results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:454
+#: ../src/backend/filtertreeAnalyse.cpp:554
 msgid ""
 "Filters and settings selected that could bias reported composition. Check to "
 "see if species biasing may occcur in the filter tree - this warning is "
 "provisional only."
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:32
+#: ../src/backend/APT/APTFileIO.cpp:39
 msgid "Memory allocation failure on POS load"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:33
+#: ../src/backend/APT/APTFileIO.cpp:40
 msgid "Error opening pos file"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:34
+#: ../src/backend/APT/APTFileIO.cpp:41
 msgid "Pos file empty"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:35
+#: ../src/backend/APT/APTFileIO.cpp:42
 msgid "Pos file size appears to have non-integer number of entries"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:36
+#: ../src/backend/APT/APTFileIO.cpp:43
 msgid "Error reading from pos file (after open)"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:37
+#: ../src/backend/APT/APTFileIO.cpp:44
 msgid "Error - Found NaN in pos file"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:38
+#: ../src/backend/APT/APTFileIO.cpp:45
 msgid "Pos load aborted by interrupt."
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:55
+#: ../src/backend/APT/APTFileIO.cpp:62
 msgid "No numerical data found"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:56
+#: ../src/backend/APT/APTFileIO.cpp:63
 msgid "Error re-opening file, after first scan"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:57
+#: ../src/backend/APT/APTFileIO.cpp:64
 msgid "Unable to read file contents after open"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:59
+#: ../src/backend/APT/APTFileIO.cpp:66
 msgid "Incorrect number of fields in file"
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:60
+#: ../src/backend/APT/APTFileIO.cpp:67
 msgid "Unable to allocate memory to store data"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:42
+#: ../src/backend/APT/APTRanges.cpp:46
 msgid "Error opening file, check name and permissions."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:43
+#: ../src/backend/APT/APTRanges.cpp:47
 msgid ""
 "Error interpreting range file header, expecting ion count and range count, "
 "respectively."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:44
+#: ../src/backend/APT/APTRanges.cpp:48
 msgid ""
 "Range file appears to be empty, check file is a proper range file and is not "
 "empty."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:45
+#: ../src/backend/APT/APTRanges.cpp:49
 msgid "Error reading the long name for ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:46
+#: ../src/backend/APT/APTRanges.cpp:50
 msgid "Error reading the short name for ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:47
+#: ../src/backend/APT/APTRanges.cpp:51
 msgid ""
 "Error reading colour data in the file, expecting 3 decimal values, space "
 "separated."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:48
+#: ../src/backend/APT/APTRanges.cpp:52
 msgid ""
 "Tried skipping to table separator line (line with dashes), but did not find "
 "it."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:49
+#: ../src/backend/APT/APTRanges.cpp:53
+msgid ""
+"Number of ions in the table header did not match the number specified at the "
+"start of the file"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:54
 msgid ""
 "Unexpected failure whilst trying to skip over range lead-in data (bit before "
 "range start value)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:50
+#: ../src/backend/APT/APTRanges.cpp:55
 msgid ""
 "Range table had an incorrect number of entries, should be 2 or 3 + number of "
 "ranges"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:51
+#: ../src/backend/APT/APTRanges.cpp:56
 msgid "Unable to read range start and end values"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:52
+#: ../src/backend/APT/APTRanges.cpp:57
 msgid "Unable to read range table entry"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:53
+#: ../src/backend/APT/APTRanges.cpp:58
 msgid ""
 "Error reading file, unexpected format, are you sure it is a proper range "
 "file?"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:54
+#: ../src/backend/APT/APTRanges.cpp:59
 msgid ""
 "Too many ranges appeared to have range entries with no usable data (eg, all "
 "blank)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:55
+#: ../src/backend/APT/APTRanges.cpp:60
 msgid ""
 "Range file appears to contain malformed data, check things like start and "
 "ends of m/c are not equal or flipped."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:56
+#: ../src/backend/APT/APTRanges.cpp:61
 msgid "Range file appears to be inconsistent (eg, overlapping ranges)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:57
+#: ../src/backend/APT/APTRanges.cpp:62
 msgid "No ion name mapping found  for multiple ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:811
+#: ../src/backend/APT/APTRanges.cpp:63
+msgid "Polyatomic extension range matches multiple masses in first section"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:1273
 msgid ""
 "Range headings do not match order of the ions listed in the name "
 "specifications. The name specification ordering will be used when reading "
@@ -4584,7 +4705,7 @@ msgstr ""
 msgid "Ion. Transform"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.h:60
+#: ../src/backend/filters/ionColour.h:59
 msgid "Spectral Colour"
 msgstr ""
 
@@ -4608,7 +4729,7 @@ msgstr ""
 msgid "Ext. Program"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.h:79
+#: ../src/backend/filters/rangeFile.h:89
 msgid "Ranging"
 msgstr ""
 
diff --git a/translations/3Depict_de_DE.mo b/translations/3Depict_de_DE.mo
index 6a08e10..e9ff0b8 100644
Binary files a/translations/3Depict_de_DE.mo and b/translations/3Depict_de_DE.mo differ
diff --git a/translations/3Depict_de_DE.po b/translations/3Depict_de_DE.po
index 94dfa2e..d2b47ba 100644
--- a/translations/3Depict_de_DE.po
+++ b/translations/3Depict_de_DE.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: 3Depict\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-04-05 23:27+0200\n"
+"POT-Creation-Date: 2013-07-05 22:42+0200\n"
 "PO-Revision-Date: 2012-07-09 08:21+0000\n"
 "Last-Translator: epix1234 <erich_s at gmx.de>\n"
 "Language-Team: German (Germany) (http://www.transifex.com/projects/p/3depict/"
@@ -29,13 +29,13 @@ msgstr "Sperren"
 #: ../src/backend/filters/ionClip.cpp:545
 #: ../src/backend/filters/ionClip.cpp:567
 #: ../src/backend/filters/ionClip.cpp:607
-#: ../src/backend/filters/compositionProfile.cpp:931
-#: ../src/backend/filters/compositionProfile.cpp:972
+#: ../src/backend/filters/compositionProfile.cpp:940
+#: ../src/backend/filters/compositionProfile.cpp:981
 #: ../src/backend/filters/spatialAnalysis.cpp:593
-#: ../src/backend/filters/transform.cpp:1262
-#: ../src/backend/filters/transform.cpp:1289
-#: ../src/backend/filters/transform.cpp:1315
-#: ../src/backend/filters/annotation.cpp:557
+#: ../src/backend/filters/transform.cpp:1258
+#: ../src/backend/filters/transform.cpp:1285
+#: ../src/backend/filters/transform.cpp:1311
+#: ../src/backend/filters/annotation.cpp:569
 msgid "Origin"
 msgstr "Ursprung"
 
@@ -77,8 +77,8 @@ msgstr "Param."
 #: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1109
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1134
-#: ../src/gui/dialogs/prefDialog.cpp:109 ../src/gui/mainFrame.cpp:5274
-#: ../src/gui/mainFrame.cpp:5279 ../src/backend/filters/dataLoad.cpp:484
+#: ../src/gui/dialogs/prefDialog.cpp:109 ../src/gui/mainFrame.cpp:5489
+#: ../src/gui/mainFrame.cpp:5494 ../src/backend/filters/dataLoad.cpp:486
 msgid "Value"
 msgstr "Wert"
 
@@ -97,14 +97,14 @@ msgstr ""
 "Zielverzeichnis nicht schreibgeschüzt ist."
 
 #: ../src/wxcomponents.cpp:654 ../src/gui/dialogs/ExportRngDialog.cpp:170
-#: ../src/gui/mainFrame.cpp:1308 ../src/gui/mainFrame.cpp:1437
-#: ../src/gui/mainFrame.cpp:1482 ../src/gui/mainFrame.cpp:1565
-#: ../src/gui/mainFrame.cpp:2039 ../src/gui/mainFrame.cpp:2054
-#: ../src/gui/mainFrame.cpp:2147 ../src/gui/mainFrame.cpp:2264
+#: ../src/gui/mainFrame.cpp:1371 ../src/gui/mainFrame.cpp:1500
+#: ../src/gui/mainFrame.cpp:1545 ../src/gui/mainFrame.cpp:1628
+#: ../src/gui/mainFrame.cpp:2122 ../src/gui/mainFrame.cpp:2137
+#: ../src/gui/mainFrame.cpp:2230 ../src/gui/mainFrame.cpp:2347
 msgid "Save error"
 msgstr "Fehler speichern"
 
-#: ../src/common/basics.cpp:52 ../src/backend/APT/APTClasses.cpp:54
+#: ../src/common/basics.cpp:52 ../src/backend/APT/APTFileIO.cpp:61
 msgid "Error opening file"
 msgstr "Fehler beim Öffnen der Datei"
 
@@ -112,7 +112,7 @@ msgstr "Fehler beim Öffnen der Datei"
 msgid "Error whilst reading file contents"
 msgstr "Fehler beim Lesen des Dateiinhaltes"
 
-#: ../src/common/basics.cpp:54 ../src/backend/APT/APTClasses.cpp:58
+#: ../src/common/basics.cpp:54 ../src/backend/APT/APTFileIO.cpp:65
 msgid "Error interpreting field in file"
 msgstr "Fehler beim Interpretieren eine Feldes in der Datei"
 
@@ -256,39 +256,39 @@ msgstr "Blau"
 msgid "Pseudo-Random"
 msgstr "Pseudo-Random"
 
-#: ../src/gui/glPane.cpp:635
+#: ../src/gui/glPane.cpp:636
 msgid "Use shift/ctrl-space or double tap to alter reset axis"
 msgstr ""
 "Verwenden Sie Shift / ⌘-Leertaste oder doppeltippen, um Achsen "
 "zurückzusetzen oder zu verändern"
 
-#: ../src/gui/glPane.cpp:893
+#: ../src/gui/glPane.cpp:894
 msgid "Image progress"
 msgstr "Bild Fortschritt"
 
-#: ../src/gui/glPane.cpp:894
+#: ../src/gui/glPane.cpp:895
 msgid "Rendering tiles..."
 msgstr "Rendering tiles..."
 
-#: ../src/gui/glPane.cpp:910
+#: ../src/gui/glPane.cpp:911
 msgid "Tile "
 msgstr "Tile "
 
-#: ../src/gui/glPane.cpp:910 ../src/gui/glPane.cpp:1077
-#: ../src/gui/mainFrame.cpp:3861 ../src/gui/mainFrame.cpp:3865
-#: ../src/gui/mainFrame.cpp:3878
+#: ../src/gui/glPane.cpp:911 ../src/gui/glPane.cpp:1078
+#: ../src/gui/mainFrame.cpp:3975 ../src/gui/mainFrame.cpp:3979
+#: ../src/gui/mainFrame.cpp:3992
 msgid " of "
 msgstr " von "
 
-#: ../src/gui/glPane.cpp:1043
+#: ../src/gui/glPane.cpp:1044
 msgid "Animation progress"
 msgstr "Animation-Fortschritt"
 
-#: ../src/gui/glPane.cpp:1044
+#: ../src/gui/glPane.cpp:1045
 msgid "Rendering sequence..."
 msgstr "Renderreihenfolge..."
 
-#: ../src/gui/glPane.cpp:1077
+#: ../src/gui/glPane.cpp:1078
 msgid "Saving Image "
 msgstr "Speichere Bild "
 
@@ -309,7 +309,7 @@ msgid "Ions"
 msgstr "Ionen"
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:55
-#: ../src/backend/filters/rangeFile.cpp:666
+#: ../src/backend/filters/rangeFile.cpp:721
 msgid "Ranges"
 msgstr "Ranges"
 
@@ -337,7 +337,7 @@ msgstr "Range Anfang"
 msgid "Range end"
 msgstr "Range Ende"
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2090
+#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2173
 msgid "Save pos..."
 msgstr "pos speichern..."
 
@@ -345,10 +345,10 @@ msgstr "pos speichern..."
 msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*"
 msgstr "ORNL Format RNG (*.rng)|*.rng|Alle Dateien (*)|*"
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1308
-#: ../src/gui/mainFrame.cpp:1483 ../src/gui/mainFrame.cpp:1565
-#: ../src/gui/mainFrame.cpp:2040 ../src/gui/mainFrame.cpp:2148
-#: ../src/gui/mainFrame.cpp:2265
+#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1371
+#: ../src/gui/mainFrame.cpp:1546 ../src/gui/mainFrame.cpp:1628
+#: ../src/gui/mainFrame.cpp:2123 ../src/gui/mainFrame.cpp:2231
+#: ../src/gui/mainFrame.cpp:2348
 msgid "Unable to save. Check output destination can be written to."
 msgstr ""
 "Speichern nicht möglich. Bitte überprüfen Sie ob der Ausgabepfad "
@@ -378,8 +378,8 @@ msgstr ""
 msgid "Multiple autosave states were found; would you like to restore one?"
 msgstr ""
 
-#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:392
-#: ../src/backend/filter.cpp:395
+#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:388
+#: ../src/backend/filter.cpp:391
 msgid "Error"
 msgstr ""
 
@@ -392,43 +392,43 @@ msgstr ""
 msgid "Filter Errors"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:44
+#: ../src/gui/dialogs/StashDialog.cpp:45
 msgid "Stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:47
+#: ../src/gui/dialogs/StashDialog.cpp:48
 msgid "Stashed Tree"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:49
+#: ../src/gui/dialogs/StashDialog.cpp:50
 msgid "Properties"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:85
+#: ../src/gui/dialogs/StashDialog.cpp:86
 msgid "Stashed Trees"
 msgstr "Stashed Trees"
 
-#: ../src/gui/dialogs/StashDialog.cpp:88
+#: ../src/gui/dialogs/StashDialog.cpp:89
 msgid "Erase stashed item"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:89
+#: ../src/gui/dialogs/StashDialog.cpp:90
 msgid "Filter view for current stash"
 msgstr "Filteransicht für den aktuellen Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:90
+#: ../src/gui/dialogs/StashDialog.cpp:91
 msgid "Settings for selected filter in current stash"
 msgstr "Einstellungen für den ausgewählten Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:91
+#: ../src/gui/dialogs/StashDialog.cpp:92
 msgid "Available stashes"
 msgstr "Verfügbare Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:152
+#: ../src/gui/dialogs/StashDialog.cpp:153
 msgid "Stash Name"
 msgstr "Stash Name"
 
-#: ../src/gui/dialogs/StashDialog.cpp:153
+#: ../src/gui/dialogs/StashDialog.cpp:154
 msgid "Filter Count"
 msgstr "Filter Count"
 
@@ -629,7 +629,7 @@ msgid "transition frame"
 msgstr ""
 
 #: ../src/gui/dialogs/animateFilterDialog.cpp:638
-#: ../src/gui/mainFrame.cpp:1538
+#: ../src/gui/mainFrame.cpp:1601
 msgid "Frame count"
 msgstr "Bildanzahl"
 
@@ -672,7 +672,7 @@ msgstr ""
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1108
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1113
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1133
-#: ../src/gui/mainFrame.cpp:5273 ../src/gui/mainFrame.cpp:5278
+#: ../src/gui/mainFrame.cpp:5488 ../src/gui/mainFrame.cpp:5493
 msgid "Property"
 msgstr "Eigenschaft"
 
@@ -686,8 +686,8 @@ msgid "Filter"
 msgstr ""
 
 #: ../src/gui/dialogs/animateFilterDialog.cpp:1114
-#: ../src/backend/filters/transform.cpp:1180
-#: ../src/backend/filters/annotation.cpp:535
+#: ../src/backend/filters/transform.cpp:1176
+#: ../src/backend/filters/annotation.cpp:547
 msgid "Mode"
 msgstr ""
 
@@ -806,10 +806,10 @@ msgid "Index"
 msgstr "Index"
 
 #: ../src/gui/dialogs/ExportPos.cpp:111 ../src/gui/dialogs/ExportPos.cpp:114
-#: ../src/backend/filters/compositionProfile.cpp:462
-#: ../src/backend/filters/spatialAnalysis.cpp:1656
-#: ../src/backend/filters/spatialAnalysis.cpp:1725
-#: ../src/backend/filters/spatialAnalysis.cpp:2659
+#: ../src/backend/filters/compositionProfile.cpp:466
+#: ../src/backend/filters/spatialAnalysis.cpp:1667
+#: ../src/backend/filters/spatialAnalysis.cpp:1736
+#: ../src/backend/filters/spatialAnalysis.cpp:2670
 #: ../src/backend/filters/spectrumPlot.cpp:240
 msgid "Count"
 msgstr "Anzahl"
@@ -882,7 +882,7 @@ msgstr "Kontrollfenster"
 msgid "Raw Data Panel"
 msgstr "Rohdatenfenster"
 
-#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:618
+#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:639
 msgid "Plot List"
 msgstr "Plotliste"
 
@@ -968,77 +968,77 @@ msgstr "Startup"
 msgid "Camera"
 msgstr "Kamera"
 
-#: ../src/gui/mainFrame.cpp:88
+#: ../src/gui/mainFrame.cpp:89
 msgid "New camera name..."
 msgstr "Neuer Kameraname..."
 
-#: ../src/gui/mainFrame.cpp:89
+#: ../src/gui/mainFrame.cpp:90
 msgid "New stash name...."
 msgstr "Neuer Stashname..."
 
-#: ../src/gui/mainFrame.cpp:105 ../src/backend/filters/annotation.cpp:549
-#: ../src/backend/filters/annotation.cpp:651
-#: ../src/backend/filters/annotation.h:98
+#: ../src/gui/mainFrame.cpp:106 ../src/backend/filters/annotation.cpp:561
+#: ../src/backend/filters/annotation.cpp:663
+#: ../src/backend/filters/annotation.h:96
 msgid "Annotation"
 msgstr "Kommentar"
 
-#: ../src/gui/mainFrame.cpp:106
+#: ../src/gui/mainFrame.cpp:107
 msgid "Bounding Box"
 msgstr "Begrenzungs-Box"
 
-#: ../src/gui/mainFrame.cpp:107 ../src/backend/filters/ionClip.h:66
+#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/ionClip.h:66
 msgid "Clipping"
 msgstr "Zuschneiden"
 
-#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/clusterAnalysis.h:132
+#: ../src/gui/mainFrame.cpp:109 ../src/backend/filters/clusterAnalysis.h:132
 msgid "Cluster Analysis"
 msgstr "Clusteranalyse"
 
-#: ../src/gui/mainFrame.cpp:109
+#: ../src/gui/mainFrame.cpp:110
 msgid "Compos. Profiles"
 msgstr "Konz.Profil"
 
-#: ../src/gui/mainFrame.cpp:110
+#: ../src/gui/mainFrame.cpp:111
 msgid "Downsampling"
 msgstr "Datenreduktion"
 
-#: ../src/gui/mainFrame.cpp:111
+#: ../src/gui/mainFrame.cpp:112
 msgid "Extern. Prog."
 msgstr "Ext. Progr."
 
-#: ../src/gui/mainFrame.cpp:112
+#: ../src/gui/mainFrame.cpp:113
 msgid "Ion Colour"
 msgstr "Ionenfarbe"
 
-#: ../src/gui/mainFrame.cpp:113
+#: ../src/gui/mainFrame.cpp:114
 msgid "Ion Info"
 msgstr "Ion Info"
 
-#: ../src/gui/mainFrame.cpp:114
+#: ../src/gui/mainFrame.cpp:115
 msgid "Ion Transform"
 msgstr "Ionentransform."
 
-#: ../src/gui/mainFrame.cpp:115 ../src/backend/filters/spectrumPlot.h:53
+#: ../src/gui/mainFrame.cpp:116 ../src/backend/filters/spectrumPlot.h:53
 msgid "Spectrum"
 msgstr "Spektrum"
 
-#: ../src/gui/mainFrame.cpp:116
+#: ../src/gui/mainFrame.cpp:117
 msgid "Range File"
 msgstr "Rangedatei"
 
-#: ../src/gui/mainFrame.cpp:117 ../src/backend/filters/spatialAnalysis.h:142
+#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/spatialAnalysis.h:142
 msgid "Spat. Analysis"
 msgstr "Räumliche Analyse"
 
-#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/voxelise.h:89
+#: ../src/gui/mainFrame.cpp:119 ../src/backend/filters/voxelise.h:121
 msgid "Voxelisation"
 msgstr "Voxelisation"
 
-#: ../src/gui/mainFrame.cpp:403
+#: ../src/gui/mainFrame.cpp:415
 msgid "OpenGL Failed"
 msgstr "OpenGL fehlgeschlagen"
 
-#: ../src/gui/mainFrame.cpp:404 ../src/gui/mainFrame.cpp:406
+#: ../src/gui/mainFrame.cpp:416 ../src/gui/mainFrame.cpp:418
 msgid ""
 "Unable to initialise the openGL (3D) panel. Program cannot start. Please "
 "check your video drivers."
@@ -1046,389 +1046,405 @@ msgstr ""
 "Kann das OpenGL (3D)-Panel nicht initialisieren. Das Programm kann nicht "
 "gestartet werden. Bitte überprüfen Sie Ihren Video-Treiber."
 
-#: ../src/gui/mainFrame.cpp:426
+#: ../src/gui/mainFrame.cpp:438
 msgid "&Open...\tCtrl+O"
 msgstr "&Öffnen...\tCtrl+O"
 
-#: ../src/gui/mainFrame.cpp:426
+#: ../src/gui/mainFrame.cpp:438
 msgid "Open state file"
 msgstr "Statusdatei öffnen"
 
-#: ../src/gui/mainFrame.cpp:427
+#: ../src/gui/mainFrame.cpp:439
 msgid "&Merge...\tCtrl+Shift+O"
 msgstr "&Zusammenführen...\tCtrl+Shift+O"
 
-#: ../src/gui/mainFrame.cpp:427
+#: ../src/gui/mainFrame.cpp:439
 msgid "Merge other file"
 msgstr "Merge other file"
 
-#: ../src/gui/mainFrame.cpp:431
+#: ../src/gui/mainFrame.cpp:443
 msgid "&Recent"
 msgstr "&Letzte"
 
-#: ../src/gui/mainFrame.cpp:432
+#: ../src/gui/mainFrame.cpp:444
 msgid "&Save\tCtrl+S"
 msgstr "&Speichern\tCtrl+S"
 
-#: ../src/gui/mainFrame.cpp:432
+#: ../src/gui/mainFrame.cpp:444
 msgid "Save state to file"
 msgstr "Status in Datei speichern"
 
-#: ../src/gui/mainFrame.cpp:434
+#: ../src/gui/mainFrame.cpp:446
 msgid "Save &As...\tCtrl+Shift+S"
 msgstr "Speichern &als...\tCtrl+Shift+S"
 
-#: ../src/gui/mainFrame.cpp:434
+#: ../src/gui/mainFrame.cpp:446
 msgid "Save current state to new file"
 msgstr "Aktuellen Status als neue Datei speichern"
 
-#: ../src/gui/mainFrame.cpp:437
+#: ../src/gui/mainFrame.cpp:449
 msgid "&Plot...\tCtrl+P"
 msgstr "&Plot...\tCtrl+P"
 
-#: ../src/gui/mainFrame.cpp:437
+#: ../src/gui/mainFrame.cpp:449
 msgid "Export Current Plot"
 msgstr "Aktuellen Plot exportieren"
 
-#: ../src/gui/mainFrame.cpp:438
+#: ../src/gui/mainFrame.cpp:450
 msgid "&Image...\tCtrl+I"
 msgstr "&Bild...\tCtrl+I"
 
-#: ../src/gui/mainFrame.cpp:438
+#: ../src/gui/mainFrame.cpp:450
 msgid "Export Current 3D View"
 msgstr "Aktuelle 3D Ansicht exportieren"
 
-#: ../src/gui/mainFrame.cpp:439
+#: ../src/gui/mainFrame.cpp:451
 msgid "Ion&s...\tCtrl+N"
 msgstr "Ion&en...\tCtrl+N"
 
-#: ../src/gui/mainFrame.cpp:439
+#: ../src/gui/mainFrame.cpp:451
 msgid "Export Ion Data"
 msgstr "Ionendaten exportieren"
 
-#: ../src/gui/mainFrame.cpp:440
+#: ../src/gui/mainFrame.cpp:452
 msgid "Ran&ges...\tCtrl+G"
 msgstr "Ran&ges...\tCtrl+G"
 
-#: ../src/gui/mainFrame.cpp:440
+#: ../src/gui/mainFrame.cpp:452
 msgid "Export Range Data"
 msgstr "Rangedaten exportieren"
 
-#: ../src/gui/mainFrame.cpp:441
+#: ../src/gui/mainFrame.cpp:453
 msgid "&Animate Filters...\tCtrl+A"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:441
+#: ../src/gui/mainFrame.cpp:453
 msgid "Export Animated Filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:442
+#: ../src/gui/mainFrame.cpp:454
 msgid "Ani&mate Camera...\tCtrl+M"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:442
+#: ../src/gui/mainFrame.cpp:454
 msgid "Export Animated Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:443
+#: ../src/gui/mainFrame.cpp:455
 msgid "Pac&kage...\tCtrl+K"
 msgstr "Pa&ket...\tCtrl+K"
 
-#: ../src/gui/mainFrame.cpp:443
+#: ../src/gui/mainFrame.cpp:455
 msgid "Export analysis package"
 msgstr "Analysepaket exportieren"
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:457
 msgid "&Export"
 msgstr "&Exportieren"
 
-#: ../src/gui/mainFrame.cpp:448
+#: ../src/gui/mainFrame.cpp:460
 msgid "&Quit\tCtrl+Q"
 msgstr "&Beenden\tCtrl+Q"
 
-#: ../src/gui/mainFrame.cpp:448 ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:462
 msgid "Exit Program"
 msgstr "Programm beenden"
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:462
 msgid "E&xit"
 msgstr "E&xit"
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:464
 msgid "&File"
 msgstr "&Datei"
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:468
 msgid "&Background Colour...\tCtrl+B"
 msgstr "&Hintergrundfarbe...\tCtrl+B"
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:468
 msgid "Change background colour"
 msgstr "Hintergrundfarbe ändern"
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:472
 msgid "&Control Pane\tF3"
 msgstr "&Kontrollfenster\tF3"
 
-#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:472 ../src/gui/mainFrame.cpp:475
 msgid "Toggle left control pane"
 msgstr "Linkes Kontrollfenster ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:475
 msgid "&Control Pane\tAlt+C"
 msgstr "&Kontrollfenster\tAlt+C"
 
-#: ../src/gui/mainFrame.cpp:469
+#: ../src/gui/mainFrame.cpp:481
 msgid "&Raw Data Pane\tF4"
 msgstr "&Rohdatenfenster\tF4"
 
-#: ../src/gui/mainFrame.cpp:469 ../src/gui/mainFrame.cpp:472
+#: ../src/gui/mainFrame.cpp:481 ../src/gui/mainFrame.cpp:484
 msgid "Toggle raw data  pane (bottom)"
 msgstr "Rohdatenfenster (unten)"
 
-#: ../src/gui/mainFrame.cpp:472
+#: ../src/gui/mainFrame.cpp:484
 msgid "&Raw Data Pane\tAlt+R"
 msgstr "&Rohdatenfenster\tAlt+R"
 
-#: ../src/gui/mainFrame.cpp:476
+#: ../src/gui/mainFrame.cpp:488
 msgid "&Plot List\tF5"
 msgstr "&Plot Liste\tF5"
 
-#: ../src/gui/mainFrame.cpp:476 ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:488 ../src/gui/mainFrame.cpp:490
 msgid "Toggle plot list"
 msgstr "Plotliste ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:490
 msgid "&Plot List\tAlt+P"
 msgstr "&Plot Liste\tAlt+P"
 
-#: ../src/gui/mainFrame.cpp:484
+#: ../src/gui/mainFrame.cpp:496
 msgid "&Legend\tCtrl+L"
 msgstr "&Legende\tCtrl+L"
 
-#: ../src/gui/mainFrame.cpp:484
+#: ../src/gui/mainFrame.cpp:496
 msgid "Toggle Legend display"
 msgstr "Legende anzeigen ein/aus"
 
-#: ../src/gui/mainFrame.cpp:486
+#: ../src/gui/mainFrame.cpp:498
 msgid "P&lot..."
 msgstr "P&lot..."
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:499
 msgid "&Axis\tCtrl+Shift+I"
 msgstr "&Achsen\tCtrl+Shift+I"
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:499
 msgid "Toggle World Axis display"
 msgstr "Hauptachsen ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:492
+#: ../src/gui/mainFrame.cpp:504
 msgid "&Fullscreen mode\tF11"
 msgstr "&Vollbildmodus\tF11"
 
-#: ../src/gui/mainFrame.cpp:492 ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:504 ../src/gui/mainFrame.cpp:506
 msgid "Next fullscreen mode: with toolbars"
 msgstr "Nächster Vollbildmodus: ohne Werkzeugleisten"
 
-#: ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:506
 msgid "&Fullscreen mode\tCtrl+Shift+F"
 msgstr "&Vollbildmodus\tCtrl+Shift+F"
 
-#: ../src/gui/mainFrame.cpp:499
+#: ../src/gui/mainFrame.cpp:511
 msgid "&Undo\tCtrl+Z"
 msgstr "&Zurück\tCtrl+Z"
 
-#: ../src/gui/mainFrame.cpp:501
+#: ../src/gui/mainFrame.cpp:513
 msgid "&Redo\tCtrl+Y"
 msgstr "&Wiederholen\tCtrl+Y"
 
-#: ../src/gui/mainFrame.cpp:504
+#: ../src/gui/mainFrame.cpp:516
 msgid "&Preferences"
 msgstr "&Voreinstellungen"
 
-#: ../src/gui/mainFrame.cpp:506
+#: ../src/gui/mainFrame.cpp:518
 msgid "&Edit"
 msgstr "&Bearbeiten"
 
-#: ../src/gui/mainFrame.cpp:509
+#: ../src/gui/mainFrame.cpp:521
 msgid "&View"
 msgstr "&Ansicht"
 
-#: ../src/gui/mainFrame.cpp:511
+#: ../src/gui/mainFrame.cpp:523
 msgid "&Help...\tCtrl+H"
 msgstr "&Hilfe...\tCtrl+H"
 
-#: ../src/gui/mainFrame.cpp:511
+#: ../src/gui/mainFrame.cpp:523
 msgid "Show help files and documentation"
 msgstr "Hilfedateien und Dokumentation anzeigen"
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:524
 msgid "&Contact..."
 msgstr "&Kontakt..."
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:524
 msgid "Open contact page"
 msgstr "Kontaktseite öffnen"
 
-#: ../src/gui/mainFrame.cpp:514
+#: ../src/gui/mainFrame.cpp:526
 msgid "&About..."
 msgstr "Über 3Depict..."
 
-#: ../src/gui/mainFrame.cpp:514
+#: ../src/gui/mainFrame.cpp:526
 msgid "Information about this program"
 msgstr "Informationen zu diesem Programm"
 
-#: ../src/gui/mainFrame.cpp:515
+#: ../src/gui/mainFrame.cpp:527
 msgid "&Help"
 msgstr "&Hilfe"
 
-#: ../src/gui/mainFrame.cpp:517
+#: ../src/gui/mainFrame.cpp:529
 msgid "Stashed Filters"
 msgstr "Zwischengelagerte Filter"
 
-#: ../src/gui/mainFrame.cpp:522
+#: ../src/gui/mainFrame.cpp:534
 msgid "Data Filtering"
 msgstr "Daten filtern"
 
-#: ../src/gui/mainFrame.cpp:546
+#: ../src/gui/mainFrame.cpp:558
 msgid "Last Outputs"
 msgstr "Letzte Ausgabe"
 
-#: ../src/gui/mainFrame.cpp:548
+#: ../src/gui/mainFrame.cpp:560
 msgid "Auto Refresh"
 msgstr ""
 "Autom.\n"
 "aktualisieren"
 
-#: ../src/gui/mainFrame.cpp:554
+#: ../src/gui/mainFrame.cpp:566
 msgid "Filter settings"
 msgstr "Filtereinstellungen"
 
-#: ../src/gui/mainFrame.cpp:556
+#: ../src/gui/mainFrame.cpp:568
 msgid "Camera Name"
 msgstr "Kameraname"
 
-#: ../src/gui/mainFrame.cpp:562
+#: ../src/gui/mainFrame.cpp:574
 msgid "3D Post-processing"
 msgstr "3D Nachbearbeitung"
 
-#: ../src/gui/mainFrame.cpp:564
+#: ../src/gui/mainFrame.cpp:576
 msgid "Enable Cropping"
 msgstr "Zuschneiden aktivieren"
 
-#: ../src/gui/mainFrame.cpp:566 ../src/gui/mainFrame.cpp:577
+#: ../src/gui/mainFrame.cpp:578 ../src/gui/mainFrame.cpp:589
 msgid "x-y"
 msgstr "x-y"
 
-#: ../src/gui/mainFrame.cpp:567 ../src/gui/mainFrame.cpp:578
+#: ../src/gui/mainFrame.cpp:579 ../src/gui/mainFrame.cpp:590
 msgid "x-z"
 msgstr "x-z"
 
-#: ../src/gui/mainFrame.cpp:568 ../src/gui/mainFrame.cpp:579
+#: ../src/gui/mainFrame.cpp:580 ../src/gui/mainFrame.cpp:591
 msgid "y-x"
 msgstr "y-x"
 
-#: ../src/gui/mainFrame.cpp:569 ../src/gui/mainFrame.cpp:580
+#: ../src/gui/mainFrame.cpp:581 ../src/gui/mainFrame.cpp:592
 msgid "y-z"
 msgstr "y-z"
 
-#: ../src/gui/mainFrame.cpp:570 ../src/gui/mainFrame.cpp:581
+#: ../src/gui/mainFrame.cpp:582 ../src/gui/mainFrame.cpp:593
 msgid "z-x"
 msgstr "z-x"
 
-#: ../src/gui/mainFrame.cpp:571 ../src/gui/mainFrame.cpp:582
+#: ../src/gui/mainFrame.cpp:583 ../src/gui/mainFrame.cpp:594
 msgid "z-y"
 msgstr "z-y"
 
-#: ../src/gui/mainFrame.cpp:586
+#: ../src/gui/mainFrame.cpp:598
 msgid "Use camera coordinates"
 msgstr "Verwende Kamerakoordinaten"
 
-#: ../src/gui/mainFrame.cpp:587
+#: ../src/gui/mainFrame.cpp:599
 msgid "dX"
 msgstr "dX"
 
-#: ../src/gui/mainFrame.cpp:589
+#: ../src/gui/mainFrame.cpp:601
 msgid "dY"
 msgstr "dY"
 
-#: ../src/gui/mainFrame.cpp:591
+#: ../src/gui/mainFrame.cpp:603
 msgid "dZ"
 msgstr "dZ"
 
-#: ../src/gui/mainFrame.cpp:593
+#: ../src/gui/mainFrame.cpp:605
 msgid "Enable Anaglyphic Stereo"
 msgstr "Anaglyphic Stereo aktivieren"
 
-#: ../src/gui/mainFrame.cpp:594
+#: ../src/gui/mainFrame.cpp:606
 msgid "Flip Channels"
 msgstr "Kanäle tauschen"
 
-#: ../src/gui/mainFrame.cpp:595
+#: ../src/gui/mainFrame.cpp:607
 msgid "Anaglyph Mode"
 msgstr "Anaglyphmodus"
 
-#: ../src/gui/mainFrame.cpp:597
+#: ../src/gui/mainFrame.cpp:609
 msgid "Red-Blue"
 msgstr "Rot-Blau"
 
-#: ../src/gui/mainFrame.cpp:598
+#: ../src/gui/mainFrame.cpp:610
 msgid "Red-Green"
 msgstr "Rot-Grün"
 
-#: ../src/gui/mainFrame.cpp:599
+#: ../src/gui/mainFrame.cpp:611
 msgid "Red-Cyan"
 msgstr "Rot-Zyan"
 
-#: ../src/gui/mainFrame.cpp:600
+#: ../src/gui/mainFrame.cpp:612
 msgid "Green-Magenta"
 msgstr "Grün-Magenta"
 
-#: ../src/gui/mainFrame.cpp:604
+#: ../src/gui/mainFrame.cpp:616
 msgid "Baseline Separation"
 msgstr "Basislinienabstand"
 
-#: ../src/gui/mainFrame.cpp:606
+#: ../src/gui/mainFrame.cpp:619
 msgid "Smooth && translucent objects"
 msgstr "Glatte && durchsichtige Objekte"
 
-#: ../src/gui/mainFrame.cpp:608
+#: ../src/gui/mainFrame.cpp:621
 msgid "3D lighting"
 msgstr "3D Beleuchtung"
 
-#: ../src/gui/mainFrame.cpp:610
+#: ../src/gui/mainFrame.cpp:624
+msgid "Performance"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:625
 msgid "Fast and weak randomisation."
 msgstr "Schnelle aber schwache Randomisierung"
 
-#: ../src/gui/mainFrame.cpp:612
+#: ../src/gui/mainFrame.cpp:627
+msgid "Limit Output Pts"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:633
 msgid "Filter caching"
 msgstr "Filter zwischenspeichern"
 
-#: ../src/gui/mainFrame.cpp:614
+#: ../src/gui/mainFrame.cpp:635
 msgid "Max. Ram usage (%)"
 msgstr "Max. RAM-Nutzung (%)"
 
-#: ../src/gui/mainFrame.cpp:671
+#: ../src/gui/mainFrame.cpp:692
 msgid "Type"
 msgstr "Type"
 
-#: ../src/gui/mainFrame.cpp:672
+#: ../src/gui/mainFrame.cpp:693
 msgid "Num"
 msgstr "Num"
 
-#: ../src/gui/mainFrame.cpp:683
+#: ../src/gui/mainFrame.cpp:704
 msgid "Warning: Your configuration file appears to be invalid:\n"
 msgstr "Warnung: Ihre Konfigurationsdatei scheint ungültig zu sein.\n"
 
-#: ../src/gui/mainFrame.cpp:684
+#: ../src/gui/mainFrame.cpp:705
 msgid "\tConfig Load: "
 msgstr "\tConfig Load: "
 
-#: ../src/gui/mainFrame.cpp:885 ../src/gui/mainFrame.cpp:933
+#: ../src/gui/mainFrame.cpp:940
+msgid "Current state has not been saved, would you like to save it now?"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:941
+msgid "State changed"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:963 ../src/gui/mainFrame.cpp:1019
 msgid "Select Data or State File..."
 msgstr "Daten oder Statusdatei auswählen..."
 
-#: ../src/gui/mainFrame.cpp:886
+#: ../src/gui/mainFrame.cpp:964
 msgid ""
 "Readable files (*.xml, *.pos, *.txt,*.csv)|*.xml;*.pos;*.txt;*.csv|POS File "
 "(*.pos)|*.pos|XML State File (*.xml)|*.xml|Text Data Files (*.txt/csv)|*.txt;"
@@ -1438,11 +1454,11 @@ msgstr ""
 "Datei (*.pos)|*.pos|XML Status Datei (*.xml)|*.xml|Text Dateien (*.txt/csv)|"
 "*.txt;*.csv|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:919 ../src/gui/mainFrame.cpp:1274
+#: ../src/gui/mainFrame.cpp:1005 ../src/gui/mainFrame.cpp:1336
 msgid "Loaded file."
 msgstr "Loaded file."
 
-#: ../src/gui/mainFrame.cpp:934
+#: ../src/gui/mainFrame.cpp:1020
 msgid ""
 "3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|"
 "XML State File (*.xml)|*.xml|All Files (*)|*"
@@ -1450,23 +1466,23 @@ msgstr ""
 "3Depictdateien (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS Datei (*.pos)|*."
 "pos|XML Status Datei (*.xml)|*.xml|All Files (*)|*"
 
-#: ../src/gui/mainFrame.cpp:945
+#: ../src/gui/mainFrame.cpp:1031
 msgid "Merged file."
 msgstr "Datei zusammengeführt."
 
-#: ../src/gui/mainFrame.cpp:1047
+#: ../src/gui/mainFrame.cpp:1135
 msgid "Tip: You can use ⌘ (command) to merge"
 msgstr "Tip: Sie können ⌘ (command) zum Zusammenführen verwenden"
 
-#: ../src/gui/mainFrame.cpp:1049
+#: ../src/gui/mainFrame.cpp:1137
 msgid "Tip: You can use ctrl to merge"
 msgstr "Tip: Sie können strg zum Zusammen führen verwenden"
 
-#: ../src/gui/mainFrame.cpp:1097
+#: ../src/gui/mainFrame.cpp:1174
 msgid "Load error"
 msgstr "Fehler beim Laden"
 
-#: ../src/gui/mainFrame.cpp:1098
+#: ../src/gui/mainFrame.cpp:1175
 msgid ""
 "Error loading state file.\n"
 "See console for more info."
@@ -1474,7 +1490,7 @@ msgstr ""
 "Fehler beim Laden der Statusdatei.\n"
 "Konsole für mehr Informationen."
 
-#: ../src/gui/mainFrame.cpp:1120
+#: ../src/gui/mainFrame.cpp:1183
 msgid ""
 "This state file contains filters that can be unsafe to run\n"
 "Do you wish to remove these before continuing?."
@@ -1482,24 +1498,24 @@ msgstr ""
 "Diese Statusdatei enthält Filter deren Anwendung möglicherweise unsicher "
 "ist. Wollen Sie diese entfernen."
 
-#: ../src/gui/mainFrame.cpp:1121
+#: ../src/gui/mainFrame.cpp:1184
 msgid "Security warning"
 msgstr "Sicherheitswarnung"
 
-#: ../src/gui/mainFrame.cpp:1330 ../src/gui/mainFrame.cpp:1429
-#: ../src/gui/mainFrame.cpp:1792
+#: ../src/gui/mainFrame.cpp:1393 ../src/gui/mainFrame.cpp:1492
+#: ../src/gui/mainFrame.cpp:1875
 msgid "Unable to save"
 msgstr "Speichern nicht möglich"
 
-#: ../src/gui/mainFrame.cpp:1331
+#: ../src/gui/mainFrame.cpp:1394
 msgid "No plot available. Please create a plot before exporting."
 msgstr "Kein Plot vefügbar. Plot muss vor dem Exportieren erzeugt werden."
 
-#: ../src/gui/mainFrame.cpp:1335
+#: ../src/gui/mainFrame.cpp:1398
 msgid "Save plot..."
 msgstr "Plot speichern..."
 
-#: ../src/gui/mainFrame.cpp:1336
+#: ../src/gui/mainFrame.cpp:1399
 msgid ""
 "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*."
 "svg|PNG File (*.png)|*.png|All Files (*)|*"
@@ -1507,40 +1523,40 @@ msgstr ""
 "Dateierweiterung (svg,png)|*.svg;*.png|Skalierbare Vektorgrafik (*.svg)|*."
 "svg|PNG Datei (*.png)|*.png|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:1392
+#: ../src/gui/mainFrame.cpp:1455
 msgid "Select type for save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1392
+#: ../src/gui/mainFrame.cpp:1455
 msgid "Choose file type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1414 ../src/gui/mainFrame.cpp:1457
-#: ../src/gui/mainFrame.cpp:1504
+#: ../src/gui/mainFrame.cpp:1477 ../src/gui/mainFrame.cpp:1520
+#: ../src/gui/mainFrame.cpp:1567
 msgid "Choose resolution"
 msgstr "Auflösung auswählen"
 
-#: ../src/gui/mainFrame.cpp:1430
+#: ../src/gui/mainFrame.cpp:1493
 msgid "Unknown file extension. Please use \"svg\" or \"png\""
 msgstr "Unbekannte Dateierweiterung. Bitte verwenden Sie \"svg\" oder \"png\""
 
-#: ../src/gui/mainFrame.cpp:1441
+#: ../src/gui/mainFrame.cpp:1504
 msgid "Saved plot: "
 msgstr "Gespeicherter Plot:"
 
-#: ../src/gui/mainFrame.cpp:1448 ../src/gui/mainFrame.cpp:1496
+#: ../src/gui/mainFrame.cpp:1511 ../src/gui/mainFrame.cpp:1559
 msgid "Save Image..."
 msgstr "Speichere Bild..."
 
-#: ../src/gui/mainFrame.cpp:1449 ../src/gui/mainFrame.cpp:1497
+#: ../src/gui/mainFrame.cpp:1512 ../src/gui/mainFrame.cpp:1560
 msgid "PNG File (*.png)|*.png|All Files (*)|*"
 msgstr "PNG Datei (*.png)|*.png|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:1472 ../src/gui/mainFrame.cpp:1521
+#: ../src/gui/mainFrame.cpp:1535 ../src/gui/mainFrame.cpp:1584
 msgid "Program limitation"
 msgstr "Programmeinschränkung"
 
-#: ../src/gui/mainFrame.cpp:1473
+#: ../src/gui/mainFrame.cpp:1536
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1548,11 +1564,11 @@ msgid ""
 " If this bothers you, please submit a bug."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1487 ../src/gui/mainFrame.cpp:1570
+#: ../src/gui/mainFrame.cpp:1550 ../src/gui/mainFrame.cpp:1633
 msgid "Saved 3D View :"
 msgstr "Gespeicherte 3D Ansicht"
 
-#: ../src/gui/mainFrame.cpp:1522
+#: ../src/gui/mainFrame.cpp:1585
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1564,100 +1580,100 @@ msgstr ""
 "kleiner als die ursprünglichen Werte sind. Sollte Sie dies stören, melden "
 "Sie bitte einen Bug."
 
-#: ../src/gui/mainFrame.cpp:1538
+#: ../src/gui/mainFrame.cpp:1601
 msgid "Number of frames"
 msgstr "Bilderanzahl"
 
-#: ../src/gui/mainFrame.cpp:1678
+#: ../src/gui/mainFrame.cpp:1760
 msgid "Cannot animate with no filters."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1725
+#: ../src/gui/mainFrame.cpp:1807
 msgid "Filter property change failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1727
+#: ../src/gui/mainFrame.cpp:1809
 msgid "Filter change error"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1750
+#: ../src/gui/mainFrame.cpp:1832
 msgid "Refresh failed on frame :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1752
+#: ../src/gui/mainFrame.cpp:1834
 msgid "Refresh failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1778
+#: ../src/gui/mainFrame.cpp:1861
 msgid "Scene generation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1779
+#: ../src/gui/mainFrame.cpp:1862
 msgid "Unable to generate scene for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1793
+#: ../src/gui/mainFrame.cpp:1876
 msgid "Image save failed for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1818
+#: ../src/gui/mainFrame.cpp:1901
 msgid "Ion save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1819
+#: ../src/gui/mainFrame.cpp:1902
 msgid "Unable to save ions for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1850
+#: ../src/gui/mainFrame.cpp:1933
 msgid "Plot save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1851
+#: ../src/gui/mainFrame.cpp:1934
 msgid "Unable to save plot or frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1892
+#: ../src/gui/mainFrame.cpp:1975
 msgid "Range save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1893
+#: ../src/gui/mainFrame.cpp:1976
 msgid "Unable to save range for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1922
+#: ../src/gui/mainFrame.cpp:2005
 msgid "Voxel save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1923
+#: ../src/gui/mainFrame.cpp:2006
 msgid "Unable to save voxels for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1969 ../src/gui/mainFrame.cpp:2076
-#: ../src/gui/mainFrame.cpp:2173
+#: ../src/gui/mainFrame.cpp:2052 ../src/gui/mainFrame.cpp:2159
+#: ../src/gui/mainFrame.cpp:2256
 msgid "No filters means no data to export"
 msgstr "Keine Filter bedeutet keine Daten zum Exportieren"
 
-#: ../src/gui/mainFrame.cpp:1975
+#: ../src/gui/mainFrame.cpp:2058
 msgid "Package name"
 msgstr "Paketname"
 
-#: ../src/gui/mainFrame.cpp:1976
+#: ../src/gui/mainFrame.cpp:2059
 msgid "Package directory name"
 msgstr "Paketverzeichnis"
 
-#: ../src/gui/mainFrame.cpp:1978
+#: ../src/gui/mainFrame.cpp:2061
 msgid "AnalysisPackage"
 msgstr "Analysepaket"
 
-#: ../src/gui/mainFrame.cpp:1990
+#: ../src/gui/mainFrame.cpp:2073
 msgid "Package folder already exists, won't overwrite."
 msgstr "Paketverzeichnis existiert bereits. Werde es nicht überschreiben."
 
-#: ../src/gui/mainFrame.cpp:1991
+#: ../src/gui/mainFrame.cpp:2074
 msgid "Not available"
 msgstr "Nicht verfügbar"
 
-#: ../src/gui/mainFrame.cpp:2022
+#: ../src/gui/mainFrame.cpp:2105
 msgid ""
 "Package folder creation failed\n"
 "check writing to this location is possible."
@@ -1665,151 +1681,151 @@ msgstr ""
 "Anlegen des Paketverzeichnisses fehlgeschlagen\n"
 "Überprüfen Sie ob der angegenbene Ort schreibgeschützt ist."
 
-#: ../src/gui/mainFrame.cpp:2023
+#: ../src/gui/mainFrame.cpp:2106
 msgid "Folder creation failed"
 msgstr "Anlegen des Ordners ist fehlgeschlagen"
 
-#: ../src/gui/mainFrame.cpp:2045
+#: ../src/gui/mainFrame.cpp:2128
 msgid "Copying"
 msgstr "kopiere"
 
-#: ../src/gui/mainFrame.cpp:2046
+#: ../src/gui/mainFrame.cpp:2129
 msgid "Copying referenced files"
 msgstr "Copying referenced files"
 
-#: ../src/gui/mainFrame.cpp:2054
+#: ../src/gui/mainFrame.cpp:2137
 msgid "Error copying file"
 msgstr "Fehler beim Kopieren der Datei"
 
-#: ../src/gui/mainFrame.cpp:2065
+#: ../src/gui/mainFrame.cpp:2148
 msgid "Saved package: "
 msgstr "Gespeicherte Pakete: "
 
-#: ../src/gui/mainFrame.cpp:2086
+#: ../src/gui/mainFrame.cpp:2169
 msgid "Export"
 msgstr "Exportieren"
 
-#: ../src/gui/mainFrame.cpp:2091
+#: ../src/gui/mainFrame.cpp:2174
 msgid "POS Data (*.pos)|*.pos|All Files (*)|*"
 msgstr "POS-Daten (*.pos)|*.pos|All Files (*)|*"
 
-#: ../src/gui/mainFrame.cpp:2119 ../src/gui/mainFrame.cpp:2218
+#: ../src/gui/mainFrame.cpp:2202 ../src/gui/mainFrame.cpp:2301
 msgid "File already exists, overwrite?"
 msgstr "Datei existiert bereits. Überschreiben?"
 
-#: ../src/gui/mainFrame.cpp:2120 ../src/gui/mainFrame.cpp:2219
-#: ../src/gui/mainFrame.cpp:2245
+#: ../src/gui/mainFrame.cpp:2203 ../src/gui/mainFrame.cpp:2302
+#: ../src/gui/mainFrame.cpp:2328
 msgid "Overwrite?"
 msgstr "Überschreiben?"
 
-#: ../src/gui/mainFrame.cpp:2152
+#: ../src/gui/mainFrame.cpp:2235
 msgid "Saved ions: "
 msgstr "Gespeicherte Ionen:"
 
-#: ../src/gui/mainFrame.cpp:2177
+#: ../src/gui/mainFrame.cpp:2260
 msgid "Export Ranges"
 msgstr "Range exportieren"
 
-#: ../src/gui/mainFrame.cpp:2200
+#: ../src/gui/mainFrame.cpp:2283
 msgid "Save state..."
 msgstr "Speichere Status..."
 
-#: ../src/gui/mainFrame.cpp:2201
+#: ../src/gui/mainFrame.cpp:2284
 msgid "XML state file (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2244
+#: ../src/gui/mainFrame.cpp:2327
 msgid "Files have been referred to using relative paths. Keep relative paths?"
 msgstr ""
 "Auf Dateien wurde mit relativen Pfaden verwiesen. Relative Pfade beibehalten?"
 
-#: ../src/gui/mainFrame.cpp:2276
+#: ../src/gui/mainFrame.cpp:2360
 msgid "Saved state: "
 msgstr "Gespeicherter Status: "
 
-#: ../src/gui/mainFrame.cpp:2612
+#: ../src/gui/mainFrame.cpp:2698
 msgid "Manual not found locally. Launching web browser"
 msgstr "Anleitung konnte lokal nicht gefunden werden. Starte Webbrowser"
 
-#: ../src/gui/mainFrame.cpp:2621
+#: ../src/gui/mainFrame.cpp:2707
 msgid "Opening contact page in external web browser"
 msgstr "Öffne Kontaktseite in externem Browser"
 
-#: ../src/gui/mainFrame.cpp:2633
+#: ../src/gui/mainFrame.cpp:2719
 msgid "No filter stashes to edit."
 msgstr "Keine Filterstashes zum Bearbeiten."
 
-#: ../src/gui/mainFrame.cpp:2637
+#: ../src/gui/mainFrame.cpp:2723
 msgid "Filter Stashes"
 msgstr "Filter Stashes"
 
-#: ../src/gui/mainFrame.cpp:2666
+#: ../src/gui/mainFrame.cpp:2752
 msgid "Quick and dirty analysis for point data."
 msgstr "\"Quick and dirty\" Analyse von Punktdaten."
 
-#: ../src/gui/mainFrame.cpp:2676
+#: ../src/gui/mainFrame.cpp:2762
 msgid "Compiled with wx Version: "
 msgstr "Kompiliert mit wx Version: "
 
-#: ../src/gui/mainFrame.cpp:2697
+#: ../src/gui/mainFrame.cpp:2783
 msgid "Press enter to store new stash"
 msgstr "Eingabe drücken um neuen Filterstash zu speichern"
 
-#: ../src/gui/mainFrame.cpp:2703
+#: ../src/gui/mainFrame.cpp:2789
 msgid "Press enter to restore stash"
 msgstr "Eingabe drücken um Stash wiederherzustellen"
 
-#: ../src/gui/mainFrame.cpp:2738
+#: ../src/gui/mainFrame.cpp:2824
 msgid "Unable to create stash, selection invalid"
 msgstr "Stash kann nicht erstellt werden, Auswahl ungültig"
 
-#: ../src/gui/mainFrame.cpp:2746
+#: ../src/gui/mainFrame.cpp:2832
 msgid "Created new filter tree stash"
 msgstr "Neuer Filterstash wurde erzeugt"
 
-#: ../src/gui/mainFrame.cpp:2868
+#: ../src/gui/mainFrame.cpp:2954
 msgid "Filter type not a data source - can't be at tree base"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3026
+#: ../src/gui/mainFrame.cpp:3112
 msgid "Moving - Hold ⌘ (command) to copy"
 msgstr "Verschieben - Halte ⌘ (command) um zu kopieren"
 
-#: ../src/gui/mainFrame.cpp:3028
+#: ../src/gui/mainFrame.cpp:3114
 msgid "Moving - Hold control to copy"
 msgstr "Verschieben - Halte Strg zum kopieren"
 
-#: ../src/gui/mainFrame.cpp:3284
+#: ../src/gui/mainFrame.cpp:3370
 msgid "Press enter to store new camera"
 msgstr "Eingabe drücken um neue Kamera zu speichern"
 
-#: ../src/gui/mainFrame.cpp:3286
+#: ../src/gui/mainFrame.cpp:3372
 msgid "Press enter to restore camera"
 msgstr "Eingabe drücken um Kamera wiederherzustellen"
 
-#: ../src/gui/mainFrame.cpp:3311 ../src/gui/mainFrame.cpp:3348
+#: ../src/gui/mainFrame.cpp:3397 ../src/gui/mainFrame.cpp:3438
 msgid "Restored camera: "
 msgstr "Wiederhergestellte Kamera: "
 
-#: ../src/gui/mainFrame.cpp:3329
+#: ../src/gui/mainFrame.cpp:3417
 msgid "Stored camera: "
 msgstr "Gespeicherte Kamera: "
 
-#: ../src/gui/mainFrame.cpp:3406
+#: ../src/gui/mainFrame.cpp:3498
 msgid "Select an item from the filter tree before choosing a new filter"
 msgstr ""
 "Aktivieren Sie zuerst ein Punkt aus dem Filterverlauf bevor Sie einen neuen "
 "Filter auswählen"
 
-#: ../src/gui/mainFrame.cpp:3408
+#: ../src/gui/mainFrame.cpp:3500
 msgid "Load data source (file->open) before choosing a new filter"
 msgstr "Lade Datenquelle (Datei->öffnen) vor dem Auswählen eines neuen Filters"
 
-#: ../src/gui/mainFrame.cpp:3429
+#: ../src/gui/mainFrame.cpp:3521
 msgid "Select RNG File..."
 msgstr "RNG Datei auswählen..."
 
-#: ../src/gui/mainFrame.cpp:3430
+#: ../src/gui/mainFrame.cpp:3522
 msgid ""
 "Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
 "Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"
@@ -1817,88 +1833,88 @@ msgstr ""
 "Rangedatei (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
 "Environment Datei (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:3450
+#: ../src/gui/mainFrame.cpp:3542
 msgid "Failed reading range file."
 msgstr "Fehler beim Lesen der Rangedatei."
 
-#: ../src/gui/mainFrame.cpp:3454
+#: ../src/gui/mainFrame.cpp:3546
 msgid "Error loading file"
 msgstr "Fehler beim Laden der Datei"
 
-#: ../src/gui/mainFrame.cpp:3510 ../src/gui/mainFrame.cpp:3563
-#: ../src/gui/mainFrame.cpp:4946 ../src/gui/mainFrame.cpp:5481
+#: ../src/gui/mainFrame.cpp:3604 ../src/gui/mainFrame.cpp:3658
+#: ../src/gui/mainFrame.cpp:5150 ../src/gui/mainFrame.cpp:5703
 msgid "Cons."
 msgstr "Kons."
 
-#: ../src/gui/mainFrame.cpp:3540
+#: ../src/gui/mainFrame.cpp:3634
 msgid "Refresh Aborted."
 msgstr "Aktualisieren abgebrochen"
 
-#: ../src/gui/mainFrame.cpp:3567
+#: ../src/gui/mainFrame.cpp:3662
 msgid "*Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3569
+#: ../src/gui/mainFrame.cpp:3664
 msgid "§Cons."
 msgstr "§Kons."
 
-#: ../src/gui/mainFrame.cpp:3680
+#: ../src/gui/mainFrame.cpp:3781
 msgid "Autosave complete."
 msgstr "Autosave beendet."
 
-#: ../src/gui/mainFrame.cpp:3835
+#: ../src/gui/mainFrame.cpp:3940
 msgid "Aborted."
 msgstr "Abgebrochen"
 
-#: ../src/gui/mainFrame.cpp:3876
+#: ../src/gui/mainFrame.cpp:3990
 msgid "Updated."
 msgstr "Updated."
 
-#: ../src/gui/mainFrame.cpp:3882
+#: ../src/gui/mainFrame.cpp:3997
 msgid "\\% Done (Esc aborts)"
 msgstr "\\% fertig (Esc abbrechen)"
 
-#: ../src/gui/mainFrame.cpp:3884
+#: ../src/gui/mainFrame.cpp:3999
 msgid "\\% Done"
 msgstr "\\% fertig"
 
-#: ../src/gui/mainFrame.cpp:4133 ../src/gui/mainFrame.cpp:4140
+#: ../src/gui/mainFrame.cpp:4258 ../src/gui/mainFrame.cpp:4265
 msgid "Next Fullscreen mode: none"
 msgstr "Nächster Vollbildmodus: keiner"
 
-#: ../src/gui/mainFrame.cpp:4136
+#: ../src/gui/mainFrame.cpp:4261
 msgid "Next Fullscreen mode: complete"
 msgstr "Nächster Vollbildmodus: vollständig"
 
-#: ../src/gui/mainFrame.cpp:4144
+#: ../src/gui/mainFrame.cpp:4269
 msgid "Next Fullscreen mode: with toolbars"
 msgstr "Nächster Vollbildmodus: mit Werkzeugleisten"
 
-#: ../src/gui/mainFrame.cpp:4160
+#: ../src/gui/mainFrame.cpp:4285
 msgid "Next Mode: No fullscreen"
 msgstr "Nächster Modus: Kein Vollbild"
 
-#: ../src/gui/mainFrame.cpp:4164
+#: ../src/gui/mainFrame.cpp:4289
 msgid "Next Mode: fullscreen w/o toolbar"
 msgstr "Nächster Modus: Vollbild ohne Werkzeugleiste"
 
-#: ../src/gui/mainFrame.cpp:4168
+#: ../src/gui/mainFrame.cpp:4293
 msgid "Next Mode: fullscreen with toolbar"
 msgstr "Nächster Modus: Vollbild mit Werkzeugleiste"
 
-#: ../src/gui/mainFrame.cpp:4209
+#: ../src/gui/mainFrame.cpp:4334
 msgid "Tip: You can shift-click to force full refresh, if required"
 msgstr "Tipp: Verwende shift-click um komplettes Aktualisieren zu erzwingen"
 
-#: ../src/gui/mainFrame.cpp:4461
+#: ../src/gui/mainFrame.cpp:4590
 msgid "No data to save"
 msgstr "Keine Daten zum Sichern"
 
-#: ../src/gui/mainFrame.cpp:4572
+#: ../src/gui/mainFrame.cpp:4759
 msgid "Aborting..."
 msgstr "Abbrechen..."
 
-#: ../src/gui/mainFrame.cpp:4578
+#: ../src/gui/mainFrame.cpp:4765
 msgid ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
@@ -1906,70 +1922,70 @@ msgstr ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
 
-#: ../src/gui/mainFrame.cpp:4579 ../src/gui/mainFrame.cpp:4601
+#: ../src/gui/mainFrame.cpp:4766 ../src/gui/mainFrame.cpp:4788
 msgid "Confirmation request"
 msgstr "Bestätigungsabfrage"
 
-#: ../src/gui/mainFrame.cpp:4600
+#: ../src/gui/mainFrame.cpp:4787
 msgid "Are you sure you wish to exit 3Depict?"
 msgstr "Sind Sie sicher, dass Sie 3Depict beenden wollen?"
 
-#: ../src/gui/mainFrame.cpp:4974
+#: ../src/gui/mainFrame.cpp:5178
 msgid "Update Notice: New version "
 msgstr "Updatenotiz: Neue Version "
 
-#: ../src/gui/mainFrame.cpp:4974
+#: ../src/gui/mainFrame.cpp:5178
 msgid " found online."
 msgstr " online gefunden."
 
-#: ../src/gui/mainFrame.cpp:4978
+#: ../src/gui/mainFrame.cpp:5182
 msgid "Online Check: "
 msgstr "Überprüfe online:"
 
-#: ../src/gui/mainFrame.cpp:4978
+#: ../src/gui/mainFrame.cpp:5182
 msgid " is up-to-date."
 msgstr "ist up-to-date."
 
-#: ../src/gui/mainFrame.cpp:5068
+#: ../src/gui/mainFrame.cpp:5272
 msgid "An auto-save state was found, would you like to restore it?."
 msgstr "Ein auto-save Status wurde gefunden. Wollen Sie ihn wiederherstellen?"
 
-#: ../src/gui/mainFrame.cpp:5069
+#: ../src/gui/mainFrame.cpp:5273
 msgid "Autosave"
 msgstr "Automatisch speichern"
 
-#: ../src/gui/mainFrame.cpp:5076
+#: ../src/gui/mainFrame.cpp:5280
 msgid "Unable to load autosave file.."
 msgstr "Kann Autosavedatei nicht laden.."
 
-#: ../src/gui/mainFrame.cpp:5261
+#: ../src/gui/mainFrame.cpp:5474
 msgid "List of available filters"
 msgstr "Liste der verfügbaren Filter"
 
-#: ../src/gui/mainFrame.cpp:5262
+#: ../src/gui/mainFrame.cpp:5475
 msgid "Tree of data filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5263
+#: ../src/gui/mainFrame.cpp:5476
 msgid ""
 "Enable/Disable automatic updates of data when filter change takes effect"
 msgstr ""
 "Ein/Ausschalten vom automatischen Aktualisieren der Daten wenn Änderungen am "
 "Filter wirksam werden"
 
-#: ../src/gui/mainFrame.cpp:5266
+#: ../src/gui/mainFrame.cpp:5479
 msgid ""
 "Enable/Disable \"Alpha blending\" (transparency) in rendering system. "
 "Blending is used to smooth objects (avoids artefacts known as \"jaggies\") "
 "and to make transparent surfaces. Disabling will provide faster rendering "
 "but look more blocky"
 msgstr ""
-"Ein/Ausschalten des \"Alpha blending\" (Transparenz) im Rendersystem. "
-"Dieses wird verwendet um ebene Objekte (vermeidet Artefakte bekannt als "
-"jaggies) und transparente Oberflächen zu generieren. Ausschalten erlaubt "
-"schnelleres Renden führt jedoch zu blockigerer Darstellung."
+"Ein/Ausschalten des \"Alpha blending\" (Transparenz) im Rendersystem. Dieses "
+"wird verwendet um ebene Objekte (vermeidet Artefakte bekannt als jaggies) "
+"und transparente Oberflächen zu generieren. Ausschalten erlaubt schnelleres "
+"Renden führt jedoch zu blockigerer Darstellung."
 
-#: ../src/gui/mainFrame.cpp:5267
+#: ../src/gui/mainFrame.cpp:5480
 msgid ""
 "Enable/Disable lighting calculations in rendering, for objects that request "
 "this. Lighting provides important depth cues for objects comprised of 3D "
@@ -1980,7 +1996,7 @@ msgstr ""
 "umrandete Objekte. Deaktivieren erlaubt u.U. schnelleres Rendern bei "
 "komplizierten Szenen."
 
-#: ../src/gui/mainFrame.cpp:5268
+#: ../src/gui/mainFrame.cpp:5481
 msgid ""
 "Enable/Disable weak randomisation (Galois linear feedback shift register). "
 "Strong randomisation uses a much slower random selection method, but "
@@ -1992,41 +2008,49 @@ msgstr ""
 "Auswahlmethode bietet dafür aber einen besseren Schutz gegen unbeabsichtigte "
 "Korrelationen und wird für die endgültige Analyse empfohlen."
 
-#: ../src/gui/mainFrame.cpp:5269
+#: ../src/gui/mainFrame.cpp:5483
+msgid ""
+"Limit the number of points that can be displayed in the 3D  scene. Does not "
+"affect filter tree calculations. Disabling this can severely reduce "
+"performance, due to large numbers of points being visible at once."
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:5484
 msgid ""
 "Enable/Disable caching of intermediate results during filter updates. "
 "Disabling caching will use less system RAM, though changes to any filter "
 "property will cause the entire filter tree to be recomputed, greatly slowing "
 "computations"
-msgstr "Ein/Ausschalten des Zwischenspeicherns von Ergebnissen während "
-"Filteraktualisierungen. Dies verbraucht weniger RAM, führt jedoch dazu, "
-"dass bei Änderungen der Filterparameter der ganze Filterbaum neu "
-"berechnet wird. Dies erhöht den Rechenaufwand deutlich."
+msgstr ""
+"Ein/Ausschalten des Zwischenspeicherns von Ergebnissen während "
+"Filteraktualisierungen. Dies verbraucht weniger RAM, führt jedoch dazu, dass "
+"bei Änderungen der Filterparameter der ganze Filterbaum neu berechnet wird. "
+"Dies erhöht den Rechenaufwand deutlich."
 
-#: ../src/gui/mainFrame.cpp:5280
+#: ../src/gui/mainFrame.cpp:5495
 msgid "Camera data information"
 msgstr "Kamerainformation"
 
-#: ../src/gui/mainFrame.cpp:5284
+#: ../src/gui/mainFrame.cpp:5499
 msgid "Enable/disable visual effects on final 3D output"
 msgstr "Ein/Ausschalten von visuellen Effekten in der finalen 3D Ausgabe."
 
-#: ../src/gui/mainFrame.cpp:5286
+#: ../src/gui/mainFrame.cpp:5501
 msgid "Enable cropping post-process effect"
 msgstr "Cropping post-Prozess Effect einschalten"
 
-#: ../src/gui/mainFrame.cpp:5289
+#: ../src/gui/mainFrame.cpp:5504
 msgid ""
 "Colour based 3D effect enable/disable - requires appropriate colour filter "
 "3D glasses."
 msgstr ""
 "Farbbasierte 3D-Effekte ein/ausschalten - erfordert geeignete 3D-Brillen"
 
-#: ../src/gui/mainFrame.cpp:5290
+#: ../src/gui/mainFrame.cpp:5505
 msgid "Glasses colour mode"
 msgstr "Brillenfarbmodus"
 
-#: ../src/gui/mainFrame.cpp:5292
+#: ../src/gui/mainFrame.cpp:5507
 msgid ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
@@ -2034,96 +2058,96 @@ msgstr ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
 
-#: ../src/gui/mainFrame.cpp:5296
+#: ../src/gui/mainFrame.cpp:5511
 msgid "X"
 msgstr "X"
 
-#: ../src/gui/mainFrame.cpp:5297
+#: ../src/gui/mainFrame.cpp:5512
 msgid "Y"
 msgstr "Y"
 
-#: ../src/gui/mainFrame.cpp:5298
+#: ../src/gui/mainFrame.cpp:5513
 msgid "Save raw data to file"
 msgstr "Speichere Rohdaten in Datei"
 
-#: ../src/gui/mainFrame.cpp:5299
+#: ../src/gui/mainFrame.cpp:5514
 msgid "Copy raw data to clipboard"
 msgstr "Kopiere Rohdaten in die Zwischenablage"
 
-#: ../src/gui/mainFrame.cpp:5300
+#: ../src/gui/mainFrame.cpp:5515
 msgid "Manage \"stashed\" data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5301
+#: ../src/gui/mainFrame.cpp:5516
 msgid "Program text output"
 msgstr "Programm Textausgabe"
 
-#: ../src/gui/mainFrame.cpp:5302
+#: ../src/gui/mainFrame.cpp:5517
 msgid "Select active camera, or type to create new named camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5303
+#: ../src/gui/mainFrame.cpp:5518
 msgid "Remove the selected camera"
 msgstr "Ausgewählte Kamera entfernen"
 
-#: ../src/gui/mainFrame.cpp:5304
+#: ../src/gui/mainFrame.cpp:5519
 msgid "Perform cropping from coordinate frame of camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5305
+#: ../src/gui/mainFrame.cpp:5520
 msgid ""
 "Set the maximum amount of RAM to use in order to speed repeat computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5306
+#: ../src/gui/mainFrame.cpp:5521
 msgid "Collapse the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5307
+#: ../src/gui/mainFrame.cpp:5522
 msgid "Expand the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5308
+#: ../src/gui/mainFrame.cpp:5523
 msgid "Process the filter tree, hold shift to purge cached filter data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5447
+#: ../src/gui/mainFrame.cpp:5663
 msgid "Crop"
 msgstr "Zuschneiden"
 
-#: ../src/gui/mainFrame.cpp:5448
+#: ../src/gui/mainFrame.cpp:5664
 msgid "Stereo"
 msgstr "Stereo"
 
-#: ../src/gui/mainFrame.cpp:5459
+#: ../src/gui/mainFrame.cpp:5681
 msgid "Data"
 msgstr "Daten"
 
-#: ../src/gui/mainFrame.cpp:5460
+#: ../src/gui/mainFrame.cpp:5682
 msgid "Cam"
 msgstr "Cam"
 
-#: ../src/gui/mainFrame.cpp:5461
+#: ../src/gui/mainFrame.cpp:5683
 msgid "Post"
 msgstr "Post"
 
-#: ../src/gui/mainFrame.cpp:5462
+#: ../src/gui/mainFrame.cpp:5684
 msgid "Tools"
 msgstr "Werkz."
 
-#: ../src/gui/mainFrame.cpp:5479 ../src/backend/filter.cpp:44
+#: ../src/gui/mainFrame.cpp:5701 ../src/backend/filter.cpp:44
 msgid "Plot"
 msgstr "Plot"
 
-#: ../src/gui/mainFrame.cpp:5480
+#: ../src/gui/mainFrame.cpp:5702
 msgid "Raw"
 msgstr "Roh"
 
-#: ../src/gui/mathglPane.cpp:203
+#: ../src/gui/mathglPane.cpp:209
 msgid "No plots selected."
 msgstr "Kein Plot ausgewählt."
 
-#: ../src/gui/mathglPane.cpp:1125
+#: ../src/gui/mathglPane.cpp:1134
 msgid ""
 "Unable to allocate requested memory.\n"
 " Try a lower resolution, or save as vector (SVG)."
@@ -2131,37 +2155,37 @@ msgstr ""
 "Kann den notwendigen Speicher nicht zuordnen. Versuche eine geringer "
 "Auflösung oder speichere als Vektografik (svg)."
 
-#: ../src/gui/mathglPane.cpp:1127
+#: ../src/gui/mathglPane.cpp:1136
 msgid "Plotting functions returned an error:\n"
 msgstr "Plot-Funktion meldete einen Fehler:\n"
 
-#: ../src/gui/mathglPane.cpp:1129
+#: ../src/gui/mathglPane.cpp:1138
 msgid "File readback check failed"
 msgstr "File readback check failed"
 
-#: ../src/gui/mathglPane.cpp:1131
+#: ../src/gui/mathglPane.cpp:1140
 msgid "Filesize during readback appears to be zero."
 msgstr "Filesize during readback appears to be zero."
 
-#: ../src/3Depict.cpp:77
+#: ../src/3Depict.cpp:78
 msgid "displays this message"
 msgstr "zeigt diese Nachricht"
 
-#: ../src/3Depict.cpp:79
+#: ../src/3Depict.cpp:80
 msgid "inputfile"
 msgstr "Eingabedatei"
 
-#: ../src/3Depict.cpp:88
+#: ../src/3Depict.cpp:89
 msgid ""
 "Run debug unit tests, returns nonzero on test failure, zero on success.\n"
 "\t\tXML files may be passed to run, instead of default tests"
 msgstr ""
 
-#: ../src/3Depict.cpp:374
+#: ../src/3Depict.cpp:375
 msgid "File : "
 msgstr "Datei : "
 
-#: ../src/3Depict.cpp:374
+#: ../src/3Depict.cpp:375
 msgid " does not exist. Skipping"
 msgstr " existiert nicht. Überspringe"
 
@@ -2177,12 +2201,12 @@ msgstr "Kann den letzten Dateieintrag nicht interpretieren"
 msgid "Unable to determine filter type in defaults listing."
 msgstr "Kann den Filtertyp im Defaultslisting nicht bestimmen."
 
-#: ../src/backend/configFile.cpp:568
+#: ../src/backend/configFile.cpp:577
 msgid "Online access for non win32/apple platforms is intentionally disabled, "
 msgstr ""
 "Onlinezugang für nicht Win32/apple systeme wurde absichtlich deaktiviert."
 
-#: ../src/backend/configFile.cpp:569
+#: ../src/backend/configFile.cpp:578
 msgid ""
 "regardless of the settings you use here. Use your package manager to keep up-"
 "to-date"
@@ -2190,7 +2214,8 @@ msgstr ""
 "Nutzen Sie Ihren Paketmanager um up-to-date zu sein unabhängig von den "
 "Einstellungen die Sie hier verwenden"
 
-#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:96
+#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:122
+#: ../src/backend/filters/voxelise.cpp:132
 msgid "None"
 msgstr "Keiner"
 
@@ -2218,248 +2243,103 @@ msgstr "Stem"
 msgid "Points"
 msgstr "Punkte"
 
-#: ../src/backend/plot.cpp:619 ../src/backend/plot.cpp:627
+#: ../src/backend/plot.cpp:648 ../src/backend/plot.cpp:656
 msgid "Multiple data types"
 msgstr ""
 
-#: ../src/backend/plot.cpp:783
+#: ../src/backend/plot.cpp:808
 msgid "Mixed log/non-log:"
 msgstr "Gemischt log/nicht-log"
 
-#: ../src/backend/plot.cpp:1227
+#: ../src/backend/plot.cpp:1261
 msgid "error"
 msgstr "Fehler"
 
-#: ../src/backend/filtertree.cpp:952
+#: ../src/backend/filtertree.cpp:951
 msgid "WARNING: Skipping node "
 msgstr "WARNUNG: Skipping node "
 
-#: ../src/backend/filtertree.cpp:952
+#: ../src/backend/filtertree.cpp:951
 msgid " as it was not recognised"
 msgstr " wurde nicht erkannt."
 
-#: ../src/backend/filtertree.cpp:990
+#: ../src/backend/filtertree.cpp:989
 msgid "Error processing node: "
 msgstr "Fehler beim Verarbeiten von Node: "
 
-#: ../src/backend/viscontrol.cpp:951
-msgid ""
-"This file is a \"state\" file for the 3Depict program, and stores "
-"information about a particular analysis session. This file should be a valid "
-"\"XML\" file"
-msgstr ""
-"Diese Datei ist ein \"Status\" Datei für das Programm 3Depict. Sie speichert "
-"Informationen über die jeweiligen Analysesitzung. Dies sollte ein gültige "
-"\"XML\" Datei sein."
-
-#: ../src/backend/viscontrol.cpp:1089
-msgid "Failed to allocate parser"
-msgstr "Kann Parser nicht zuordnen"
-
-#: ../src/backend/viscontrol.cpp:1125
-msgid ""
-"Unable to retrieve root node in input state file... Is this really a non-"
-"empty XML file?"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1132
-msgid "Base state node missing. Is this really a state XML file??"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1161
-msgid "State was created by a newer version of this program.. "
-msgstr "Status wurde von einer neueren Version dieses Programmes erstellt.. "
-
-#: ../src/backend/viscontrol.cpp:1162
-msgid "file reading will continue, but may fail."
-msgstr "Datei wird weiter eingelesen kann aber unter Umständen fehlschlagen."
-
-#: ../src/backend/viscontrol.cpp:1167
-msgid ""
-"Warning, unparseable version number in state file. File reading will "
-"continue, but may fail"
-msgstr ""
-"Warnung: Nicht lesbare Versionsnummer in Statusdatei. Datei wird weiter "
-"eingelesen kann aber unter Umständen fehlschlagen."
-
-#: ../src/backend/viscontrol.cpp:1174
-msgid "Unable to find the \"writer\" node"
-msgstr "Kann \"writer\" node nicht finden"
-
-#: ../src/backend/viscontrol.cpp:1184
-msgid "Unable to find the \"backcolour\" node."
-msgstr "Unable to find the \"backcolour\" node."
-
-#: ../src/backend/viscontrol.cpp:1191
-msgid "\"backcolour\" node missing \"r\" value."
-msgstr "\"backcolour\" node fehlt \"r\" Wert."
-
-#: ../src/backend/viscontrol.cpp:1196
-msgid "Unable to interpret \"backColour\" node's \"r\" value."
-msgstr "Kann \"backColour\" node's \"r\" Wert nicht interpretieren."
-
-#: ../src/backend/viscontrol.cpp:1204
-msgid "\"backcolour\" node missing \"g\" value."
-msgstr "\"backcolour\" node fehlt \"g\" Wert."
-
-#: ../src/backend/viscontrol.cpp:1210
-msgid "Unable to interpret \"backColour\" node's \"g\" value."
-msgstr "Kann \"backColour\" node's \"g\" Wert nicht interpretieren."
-
-#: ../src/backend/viscontrol.cpp:1218
-msgid "\"backcolour\" node missing \"b\" value."
-msgstr "\"backcolour\" node fehlt \"b\" Wert."
-
-#: ../src/backend/viscontrol.cpp:1224
-msgid "Unable to interpret \"backColour\" node's \"b\" value."
-msgstr "Kann \"backColour\" node's \"b\" Wert nicht interpretieren."
-
-#: ../src/backend/viscontrol.cpp:1231
-msgid "\"backcolour\"s rgb values must be in range [0,1]"
-msgstr "\"backcolour\"s rgb Wert muss im Bereich [0,1] liegen"
-
-#: ../src/backend/viscontrol.cpp:1258
-msgid "Unable to find or interpret \"showaxis\" node"
-msgstr "Kann \"showaxis\" node nicht interpretieren"
-
-#: ../src/backend/viscontrol.cpp:1267
-msgid "Unable to locate \"filtertree\" node."
-msgstr "Kann \"filtertree\" node nicht finden."
-
-#: ../src/backend/viscontrol.cpp:1283
-msgid "Cameras section missing \"active\" node."
-msgstr "Cameras section fehlt \"active\" node."
-
-#: ../src/backend/viscontrol.cpp:1291
-msgid "Unable to find property \"value\"  for \"cameras->active\" node."
-msgstr "Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht finden."
-
-#: ../src/backend/viscontrol.cpp:1297
-msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
-msgstr ""
-"Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht interpretieren."
-
-#: ../src/backend/viscontrol.cpp:1317
-msgid "Failed to interpret camera state for camera : "
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1325
-msgid "Unable to interpret the camera type for camera : "
-msgstr "Kann den Kameratype nicht interpretieren für :"
-
-#: ../src/backend/viscontrol.cpp:1361
-msgid "Unable to locate stash name for stash "
-msgstr "Kann den Stashnamen für Stash  nicht finden"
-
-#: ../src/backend/viscontrol.cpp:1368
-msgid "Empty stash name for stash "
-msgstr "Leerer Stashname für Stash"
-
-#: ../src/backend/viscontrol.cpp:1374
-msgid "For stash "
-msgstr "Für Stash "
-
-#: ../src/backend/viscontrol.cpp:1402
-msgid "Unrecognised effect :"
-msgstr "Nichterkannter Effekt :"
-
-#: ../src/backend/viscontrol.cpp:1412
-msgid "Duplicate effect found"
-msgstr "Doppelter Effekt gefunden"
-
-#: ../src/backend/viscontrol.cpp:1412
-msgid " cannot use."
-msgstr "kann nicht   verwenden."
-
-#: ../src/backend/viscontrol.cpp:1422
-msgid "Error reading effect : "
-msgstr "Fehler beim Lesen:"
-
-#: ../src/backend/viscontrol.cpp:1483
-msgid "-merge"
-msgstr ""
-
-#: ../src/backend/viscontrol.cpp:1488
-msgid ""
-" Unable to merge stashes correctly. This is improbable, so please report "
-"this."
-msgstr ""
-" Kann stashes nicht korrekt zusammenführen. Dies ist nicht möglich bitte "
-"melden Sie das."
-
-#: ../src/backend/filters/externalProgram.cpp:513
+#: ../src/backend/filters/externalProgram.cpp:515
 msgid "Command"
 msgstr "Befehl"
 
-#: ../src/backend/filters/externalProgram.cpp:516
+#: ../src/backend/filters/externalProgram.cpp:518
 msgid ""
 "Full command to send to operating system. See manual for escape sequence "
 "meanings"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:520
+#: ../src/backend/filters/externalProgram.cpp:522
 msgid "Work Dir"
 msgstr "Arbeitsverzeichnis"
 
-#: ../src/backend/filters/externalProgram.cpp:523
+#: ../src/backend/filters/externalProgram.cpp:525
 msgid "Directory to run the command in"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:533
+#: ../src/backend/filters/externalProgram.cpp:535
 msgid "Cleanup input"
 msgstr "Bereinige Eingabe"
 
-#: ../src/backend/filters/externalProgram.cpp:536
+#: ../src/backend/filters/externalProgram.cpp:538
 msgid "Erase input files when command completed"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:545
+#: ../src/backend/filters/externalProgram.cpp:547
 msgid "Cache"
 msgstr "Zwischenspeicher"
 
-#: ../src/backend/filters/externalProgram.cpp:548
+#: ../src/backend/filters/externalProgram.cpp:550
 msgid ""
 "Assume program does not alter its output, unless inputs from 3Depict are "
 "altered"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:630
+#: ../src/backend/filters/externalProgram.cpp:632
 msgid "Error processing command line"
 msgstr "Fehler beim Ausführen der Kommandozeile"
 
-#: ../src/backend/filters/externalProgram.cpp:632
+#: ../src/backend/filters/externalProgram.cpp:634
 msgid "Unable to set working directory"
 msgstr "Kann Arbeitsverzeichnis nicht festlegen"
 
-#: ../src/backend/filters/externalProgram.cpp:634
+#: ../src/backend/filters/externalProgram.cpp:636
 msgid "Error saving posfile result for external program"
 msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
 
-#: ../src/backend/filters/externalProgram.cpp:636
+#: ../src/backend/filters/externalProgram.cpp:638
 msgid "Error saving plot result for externalprogram"
 msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
 
-#: ../src/backend/filters/externalProgram.cpp:638
+#: ../src/backend/filters/externalProgram.cpp:640
 msgid "Error creating temporary directory"
 msgstr "Fehler beim Anlegen des temporären Verzeichnisses"
 
-#: ../src/backend/filters/externalProgram.cpp:640
+#: ../src/backend/filters/externalProgram.cpp:642
 msgid "Detected unusable number of columns in plot"
 msgstr "Detected unusable number of columns in plot"
 
-#: ../src/backend/filters/externalProgram.cpp:642
+#: ../src/backend/filters/externalProgram.cpp:644
 msgid "Unable to parse plot result from external program"
 msgstr "Unable to parse plot result from external program"
 
-#: ../src/backend/filters/externalProgram.cpp:644
+#: ../src/backend/filters/externalProgram.cpp:646
 msgid "Unable to load ions from external program"
 msgstr "Kann Ionen von externem Programm nicht laden"
 
-#: ../src/backend/filters/externalProgram.cpp:646
+#: ../src/backend/filters/externalProgram.cpp:648
 msgid "Unable to perform commandline substitution"
 msgstr "Unable to perform commandline substitution"
 
-#: ../src/backend/filters/externalProgram.cpp:648
+#: ../src/backend/filters/externalProgram.cpp:650
 msgid "Error executing external program"
 msgstr "Fehler beim Ausführen von externem Programm"
 
@@ -2490,7 +2370,7 @@ msgid "Shape of clipping object"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:501
-#: ../src/backend/filters/compositionProfile.cpp:916
+#: ../src/backend/filters/compositionProfile.cpp:925
 msgid "Show Primitive"
 msgstr "Zeige Primitiv"
 
@@ -2509,20 +2389,20 @@ msgid ""
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:526
-#: ../src/backend/filters/compositionProfile.cpp:975
+#: ../src/backend/filters/compositionProfile.cpp:984
 msgid "Position for centre of sphere"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:531
 #: ../src/backend/filters/ionClip.cpp:594
-#: ../src/backend/filters/compositionProfile.cpp:958
-#: ../src/backend/filters/compositionProfile.cpp:980
+#: ../src/backend/filters/compositionProfile.cpp:967
+#: ../src/backend/filters/compositionProfile.cpp:989
 #: ../src/backend/filters/spatialAnalysis.cpp:610
 msgid "Radius"
 msgstr "Radius"
 
 #: ../src/backend/filters/ionClip.cpp:534
-#: ../src/backend/filters/compositionProfile.cpp:983
+#: ../src/backend/filters/compositionProfile.cpp:992
 msgid "Radius of sphere"
 msgstr ""
 
@@ -2543,9 +2423,9 @@ msgid "Centre of cylinder"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:575
-#: ../src/backend/filters/compositionProfile.cpp:939
+#: ../src/backend/filters/compositionProfile.cpp:948
 #: ../src/backend/filters/spatialAnalysis.cpp:601
-#: ../src/backend/filters/transform.cpp:1323
+#: ../src/backend/filters/transform.cpp:1319
 msgid "Axis"
 msgstr "Achse"
 
@@ -2554,7 +2434,7 @@ msgid "Positive vector for cylinder"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:586
-#: ../src/backend/filters/compositionProfile.cpp:950
+#: ../src/backend/filters/compositionProfile.cpp:959
 msgid "Lock Axis Mag."
 msgstr "Achsen Vergr. sperren"
 
@@ -2563,7 +2443,7 @@ msgid "Prevent changing length of cylinder during 3D interaction"
 msgstr ""
 
 #: ../src/backend/filters/ionClip.cpp:597
-#: ../src/backend/filters/compositionProfile.cpp:961
+#: ../src/backend/filters/compositionProfile.cpp:970
 #: ../src/backend/filters/spatialAnalysis.cpp:613
 msgid "Radius of cylinder"
 msgstr ""
@@ -2760,7 +2640,7 @@ msgid "Create a plot showing chemistry for each cluster size"
 msgstr ""
 
 #: ../src/backend/filters/clusterAnalysis.cpp:1036
-#: ../src/backend/filters/compositionProfile.cpp:1023
+#: ../src/backend/filters/compositionProfile.cpp:1032
 #: ../src/backend/filters/ionInfo.cpp:419
 msgid "Normalise"
 msgstr "Normalisieren"
@@ -2859,10 +2739,10 @@ msgid "---------------------------------------------------------------------- "
 msgstr "---------------------------------------------------------------------- "
 
 #: ../src/backend/filters/clusterAnalysis.cpp:1829
-#: ../src/backend/filters/spatialAnalysis.cpp:1458
-#: ../src/backend/filters/spatialAnalysis.cpp:1787
-#: ../src/backend/filters/spatialAnalysis.cpp:2083
-#: ../src/backend/filters/transform.cpp:1039
+#: ../src/backend/filters/spatialAnalysis.cpp:1469
+#: ../src/backend/filters/spatialAnalysis.cpp:1798
+#: ../src/backend/filters/spatialAnalysis.cpp:2094
+#: ../src/backend/filters/transform.cpp:1035
 msgid "Collate"
 msgstr "Abgleichen"
 
@@ -2908,396 +2788,455 @@ msgstr ""
 msgid "Composition"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:84
+#: ../src/backend/filters/voxelise.cpp:109
 msgid "None (Raw count)"
 msgstr "Keine (Roh count)"
 
-#: ../src/backend/filters/voxelise.cpp:85
+#: ../src/backend/filters/voxelise.cpp:110
 msgid "Volume (Density)"
 msgstr "Volumen (Dichte)"
 
-#: ../src/backend/filters/voxelise.cpp:86
+#: ../src/backend/filters/voxelise.cpp:111
 msgid "All Ions (conc)"
 msgstr "Alle Ionen (Konz)"
 
-#: ../src/backend/filters/voxelise.cpp:87
+#: ../src/backend/filters/voxelise.cpp:112
 msgid "Ratio (Num/Denom)"
 msgstr "Verhältnis (Zähler/Nenner)"
 
-#: ../src/backend/filters/voxelise.cpp:91
+#: ../src/backend/filters/voxelise.cpp:116
 msgid "Point Cloud"
 msgstr "Punktwolke"
 
-#: ../src/backend/filters/voxelise.cpp:92
+#: ../src/backend/filters/voxelise.cpp:117
 msgid "Isosurface"
 msgstr "Isosurface"
 
-#: ../src/backend/filters/voxelise.cpp:97
+#: ../src/backend/filters/voxelise.cpp:118
+msgid "Axial slice"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:123
 msgid "Gaussian (2𝜎)"
 msgstr "Gauss (2𝜎)"
 
-#: ../src/backend/filters/voxelise.cpp:101
+#: ../src/backend/filters/voxelise.cpp:127
 msgid "Zero"
 msgstr "Null"
 
-#: ../src/backend/filters/voxelise.cpp:102
+#: ../src/backend/filters/voxelise.cpp:128
 msgid "Bounce"
 msgstr "Bounce"
 
-#: ../src/backend/filters/voxelise.cpp:543
+#: ../src/backend/filters/voxelise.cpp:133
+msgid "Linear"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:604
 msgid "Voxel Limits (min,max): ("
 msgstr "Voxel Grenzen (min,max): ("
 
-#: ../src/backend/filters/voxelise.cpp:592
+#: ../src/backend/filters/voxelise.cpp:754
 msgid "Fixed width"
 msgstr "Fixe Breite"
 
-#: ../src/backend/filters/voxelise.cpp:596
+#: ../src/backend/filters/voxelise.cpp:758
 msgid "If true, use fixed size voxels, otherwise use fixed count"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:602
+#: ../src/backend/filters/voxelise.cpp:764
 msgid "Bin width x"
 msgstr "Bin-Breite x"
 
-#: ../src/backend/filters/voxelise.cpp:606
+#: ../src/backend/filters/voxelise.cpp:768
 msgid "Voxel size in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:610
+#: ../src/backend/filters/voxelise.cpp:772
 msgid "Bin width y"
 msgstr "Bin-Breite y"
 
-#: ../src/backend/filters/voxelise.cpp:613
+#: ../src/backend/filters/voxelise.cpp:775
 msgid "Voxel size in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:619
+#: ../src/backend/filters/voxelise.cpp:781
 msgid "Bin width z"
 msgstr "Bin-Breite Z"
 
-#: ../src/backend/filters/voxelise.cpp:622
+#: ../src/backend/filters/voxelise.cpp:784
 msgid "Voxel size in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:629
+#: ../src/backend/filters/voxelise.cpp:791
 msgid "Num bins x"
 msgstr "Anzahl Bins x"
 
-#: ../src/backend/filters/voxelise.cpp:633
+#: ../src/backend/filters/voxelise.cpp:795
 msgid "Number of voxels to use in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:638
+#: ../src/backend/filters/voxelise.cpp:800
 msgid "Num bins y"
 msgstr "Anzahl Bins y"
 
-#: ../src/backend/filters/voxelise.cpp:641
+#: ../src/backend/filters/voxelise.cpp:803
 msgid "Number of voxels to use in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:647
+#: ../src/backend/filters/voxelise.cpp:809
 msgid "Num bins z"
 msgstr "Anzahl Bins z"
 
-#: ../src/backend/filters/voxelise.cpp:649
+#: ../src/backend/filters/voxelise.cpp:811
 msgid "Number of voxels to use in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:670
+#: ../src/backend/filters/voxelise.cpp:832
 msgid "Normalise by"
 msgstr "Normalisieren mit"
 
-#: ../src/backend/filters/voxelise.cpp:673
+#: ../src/backend/filters/voxelise.cpp:835
 msgid "Method to use to normalise scalar value in each voxel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:676
+#: ../src/backend/filters/voxelise.cpp:838
 msgid "Computation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:683
+#: ../src/backend/filters/voxelise.cpp:845
 msgid "Numerator"
 msgstr "Zähler"
 
-#: ../src/backend/filters/voxelise.cpp:686
+#: ../src/backend/filters/voxelise.cpp:848
 msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:706
+#: ../src/backend/filters/voxelise.cpp:868
 msgid "Enable this ion for numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:717
+#: ../src/backend/filters/voxelise.cpp:879
 msgid "Denominator"
 msgstr "Nenner"
 
-#: ../src/backend/filters/voxelise.cpp:720
+#: ../src/backend/filters/voxelise.cpp:882
 msgid "Parameter \"b\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:736
+#: ../src/backend/filters/voxelise.cpp:898
 msgid "Enable this ion for denominator contribution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:757
-#: ../src/backend/filters/voxelise.cpp:792
+#: ../src/backend/filters/voxelise.cpp:919
+#: ../src/backend/filters/voxelise.cpp:954
 msgid "Filtering"
 msgstr "Filtern"
 
-#: ../src/backend/filters/voxelise.cpp:761
+#: ../src/backend/filters/voxelise.cpp:923
 msgid "Smoothing method to use on voxels"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:764
+#: ../src/backend/filters/voxelise.cpp:926
 msgid "Processing"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:770
+#: ../src/backend/filters/voxelise.cpp:932
 msgid "Kernel Bins"
 msgstr "Kernel Bins"
 
-#: ../src/backend/filters/voxelise.cpp:774
+#: ../src/backend/filters/voxelise.cpp:936
 msgid "Number of bins in convolution kernel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:785
+#: ../src/backend/filters/voxelise.cpp:947
 msgid "Exterior values"
 msgstr "Exterior values"
 
-#: ../src/backend/filters/voxelise.cpp:788
+#: ../src/backend/filters/voxelise.cpp:950
 msgid "Method to use to treat boundaries of voxel data for convolution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:806
+#: ../src/backend/filters/voxelise.cpp:970
 msgid "Representation"
 msgstr "Representation"
 
-#: ../src/backend/filters/voxelise.cpp:809
+#: ../src/backend/filters/voxelise.cpp:973
 msgid "3D display method"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:812
-#: ../src/backend/filters/compositionProfile.cpp:1070
+#: ../src/backend/filters/voxelise.cpp:981
+#: ../src/backend/filters/voxelise.cpp:1037
+#: ../src/backend/filters/compositionProfile.cpp:1079
 #: ../src/backend/filters/boundingBox.cpp:656
-#: ../src/backend/filters/dataLoad.cpp:565
+#: ../src/backend/filters/dataLoad.cpp:567
 msgid "Appearance"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:819
+#: ../src/backend/filters/voxelise.cpp:984
 msgid "Spot size"
 msgstr "Spot size"
 
-#: ../src/backend/filters/voxelise.cpp:822
+#: ../src/backend/filters/voxelise.cpp:987
 msgid "Size of the spots to use for display"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:827
-#: ../src/backend/filters/voxelise.cpp:858
+#: ../src/backend/filters/voxelise.cpp:992
+#: ../src/backend/filters/voxelise.cpp:1030
 msgid "Transparency"
 msgstr "Transparenz"
 
-#: ../src/backend/filters/voxelise.cpp:830
+#: ../src/backend/filters/voxelise.cpp:995
 msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:838
+#: ../src/backend/filters/voxelise.cpp:1004
+msgid "Surf. param."
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1007
 msgid "Isovalue"
 msgstr "Isovalue"
 
-#: ../src/backend/filters/voxelise.cpp:841
+#: ../src/backend/filters/voxelise.cpp:1010
 msgid "Scalar value to show as isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:850
-#: ../src/backend/filters/compositionProfile.cpp:1061
-#: ../src/backend/filters/annotation.cpp:882
+#: ../src/backend/filters/voxelise.cpp:1022
+#: ../src/backend/filters/compositionProfile.cpp:1070
+#: ../src/backend/filters/annotation.cpp:903
 #: ../src/backend/filters/spectrumPlot.cpp:471
 msgid "Colour"
 msgstr "Farbe"
 
-#: ../src/backend/filters/voxelise.cpp:853
+#: ../src/backend/filters/voxelise.cpp:1025
 msgid "Colour of isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:861
+#: ../src/backend/filters/voxelise.cpp:1033
 msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1264
-msgid "Voxelisation aborted"
-msgstr "Voxelisation abgebrochen"
+#: ../src/backend/filters/voxelise.cpp:1045
+msgid "Slice param."
+msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1266
-msgid "Out of memory"
-msgstr "Zu wenig Speicher"
+#: ../src/backend/filters/voxelise.cpp:1053
+msgid "Slice Axis"
+msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1268
-msgid "Unable to perform filter convolution"
-msgstr "Kann Filter convolution nicht durchführen"
+#: ../src/backend/filters/voxelise.cpp:1056
+msgid "Normal for the planar slice"
+msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1270
-msgid "Voxelisation bounds are invalid"
-msgstr "Voxelisation Grenzen sin ungültig"
+#: ../src/backend/filters/voxelise.cpp:1063
+msgid "Slice Coord"
+msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:289
-msgid "Colour Map"
-msgstr "Farbtabelle"
+#: ../src/backend/filters/voxelise.cpp:1066
+msgid "Fractional coordinate that slice plane passes through"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1071
+msgid "Interp. Mode"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1079
+msgid "Interpolation mode for direction normal to slice"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1094
+msgid "Colour mode"
+msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:293
+#: ../src/backend/filters/voxelise.cpp:1097
+#: ../src/backend/filters/ionColour.cpp:263
 msgid "Colour scheme used to assign points colours by value"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:301
+#: ../src/backend/filters/voxelise.cpp:1106
+#: ../src/backend/filters/ionColour.cpp:271
 msgid "Show Bar"
 msgstr "Zeige Balken"
 
-#: ../src/backend/filters/ionColour.cpp:308
-msgid "Num Colours"
+#: ../src/backend/filters/voxelise.cpp:1116
+msgid "Auto Bounds"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:310
-msgid "Number of unique colours to use in colour map"
+#: ../src/backend/filters/voxelise.cpp:1117
+msgid "Auto-compute min/max values in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:316
+#: ../src/backend/filters/voxelise.cpp:1127
+#: ../src/backend/filters/ionColour.cpp:286
 msgid "Map start"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:317
+#: ../src/backend/filters/voxelise.cpp:1128
+#: ../src/backend/filters/ionColour.cpp:287
 msgid "Assign points with this value to the first colour in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:324
+#: ../src/backend/filters/voxelise.cpp:1135
+#: ../src/backend/filters/ionColour.cpp:294
 msgid "Map end"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:325
+#: ../src/backend/filters/voxelise.cpp:1136
+#: ../src/backend/filters/ionColour.cpp:295
 msgid "Assign points with this value to the last colour in map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:425
-#: ../src/backend/filters/transform.cpp:1577
+#: ../src/backend/filters/voxelise.cpp:1707
+msgid "Voxelisation aborted"
+msgstr "Voxelisation abgebrochen"
+
+#: ../src/backend/filters/voxelise.cpp:1709
+msgid "Out of memory"
+msgstr "Zu wenig Speicher"
+
+#: ../src/backend/filters/voxelise.cpp:1711
+msgid "Unable to perform filter convolution"
+msgstr "Kann Filter convolution nicht durchführen"
+
+#: ../src/backend/filters/voxelise.cpp:1713
+msgid "Voxelisation bounds are invalid"
+msgstr "Voxelisation Grenzen sin ungültig"
+
+#: ../src/backend/filters/ionColour.cpp:259
+msgid "Colour Map"
+msgstr "Farbtabelle"
+
+#: ../src/backend/filters/ionColour.cpp:278
+msgid "Num Colours"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:280
+msgid "Number of unique colours to use in colour map"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:395
+#: ../src/backend/filters/transform.cpp:1573
 #: ../src/backend/filters/ionInfo.cpp:548
 msgid "Aborted"
 msgstr "Abgebrochen"
 
-#: ../src/backend/filters/compositionProfile.cpp:449
+#: ../src/backend/filters/compositionProfile.cpp:453
 msgid "Distance"
 msgstr "Abstand"
 
-#: ../src/backend/filters/compositionProfile.cpp:457
+#: ../src/backend/filters/compositionProfile.cpp:461
 msgid "Fraction"
 msgstr "Anteil"
 
-#: ../src/backend/filters/compositionProfile.cpp:459
+#: ../src/backend/filters/compositionProfile.cpp:463
 msgid "Density (\\#.len^3)"
 msgstr "Dichte (\\#.len^3)"
 
-#: ../src/backend/filters/compositionProfile.cpp:486
+#: ../src/backend/filters/compositionProfile.cpp:490
 msgid "Freq. Profile"
 msgstr "Häufigkeitsprofil"
 
-#: ../src/backend/filters/compositionProfile.cpp:584
+#: ../src/backend/filters/compositionProfile.cpp:588
 msgid "Too many bins in comp. profile."
 msgstr "Zu viele Bins im Konzentrationsprofil."
 
-#: ../src/backend/filters/compositionProfile.cpp:586
+#: ../src/backend/filters/compositionProfile.cpp:590
 msgid "Not enough memory for comp. profile."
 msgstr "Nicht genug Speicher für Konz.-Profil."
 
-#: ../src/backend/filters/compositionProfile.cpp:588
+#: ../src/backend/filters/compositionProfile.cpp:592
 msgid "Aborted composition prof."
 msgstr "Konzentrationspr. abgebr."
 
-#: ../src/backend/filters/compositionProfile.cpp:905
+#: ../src/backend/filters/compositionProfile.cpp:914
 msgid "Primitive type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:909
+#: ../src/backend/filters/compositionProfile.cpp:918
 msgid "Basic shape to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:920
+#: ../src/backend/filters/compositionProfile.cpp:929
 msgid "Display the 3D composition profile interaction object"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:934
+#: ../src/backend/filters/compositionProfile.cpp:943
 #: ../src/backend/filters/spatialAnalysis.cpp:596
 msgid "Position for centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:942
+#: ../src/backend/filters/compositionProfile.cpp:951
 msgid "Vector between ends of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:953
+#: ../src/backend/filters/compositionProfile.cpp:962
 msgid "Prevent length of cylinder changing during interaction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:993
+#: ../src/backend/filters/compositionProfile.cpp:1002
 msgid "Fixed Bin Num"
 msgstr "Fix. Bin-Anz."
 
-#: ../src/backend/filters/compositionProfile.cpp:996
+#: ../src/backend/filters/compositionProfile.cpp:1005
 msgid ""
 "If true, use a fixed number of bins for profile, otherwise use fixed step "
 "size"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1002
+#: ../src/backend/filters/compositionProfile.cpp:1011
 #: ../src/backend/filters/spatialAnalysis.cpp:420
 #: ../src/backend/filters/spatialAnalysis.cpp:569
 msgid "Num Bins"
 msgstr "Bin-Anz."
 
-#: ../src/backend/filters/compositionProfile.cpp:1007
+#: ../src/backend/filters/compositionProfile.cpp:1016
 msgid "Number of bins to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1012
+#: ../src/backend/filters/compositionProfile.cpp:1021
 #: ../src/backend/filters/spectrumPlot.cpp:395
 msgid "Bin width"
 msgstr "Bin-Breite"
 
-#: ../src/backend/filters/compositionProfile.cpp:1018
+#: ../src/backend/filters/compositionProfile.cpp:1027
 msgid "Size of each bin in profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1027
+#: ../src/backend/filters/compositionProfile.cpp:1036
 msgid "Convert bin counts into relative frequencies in each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1048
+#: ../src/backend/filters/compositionProfile.cpp:1057
 #: ../src/backend/filters/spectrumPlot.cpp:458
 msgid "Plot Type"
 msgstr "Plot Type"
 
-#: ../src/backend/filters/compositionProfile.cpp:1051
+#: ../src/backend/filters/compositionProfile.cpp:1060
 msgid "Visual style for plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1064
+#: ../src/backend/filters/compositionProfile.cpp:1073
 msgid "Colour of plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1080
+#: ../src/backend/filters/compositionProfile.cpp:1089
 msgid "Err. Estimator"
 msgstr "Fehlerschätzer"
 
-#: ../src/backend/filters/compositionProfile.cpp:1083
+#: ../src/backend/filters/compositionProfile.cpp:1092
 msgid "Method of estimating error associated with each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1090
+#: ../src/backend/filters/compositionProfile.cpp:1099
 msgid "Avg. Window"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1093
+#: ../src/backend/filters/compositionProfile.cpp:1102
 msgid "Number of bins to include in moving average filter"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1097
+#: ../src/backend/filters/compositionProfile.cpp:1106
 msgid "Error analysis"
 msgstr ""
 
@@ -3430,47 +3369,47 @@ msgstr ""
 msgid "Alg. Params."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1016
+#: ../src/backend/filters/spatialAnalysis.cpp:1022
 msgid "Spatial analysis aborted by user"
 msgstr "Spatial analysis aborted by user"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1018
+#: ../src/backend/filters/spatialAnalysis.cpp:1024
 msgid "Insufficient data to complete analysis."
 msgstr "Ungenügend Daten zum Fertigstellen der Analyse."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1492
-#: ../src/backend/filters/spatialAnalysis.cpp:1546
-#: ../src/backend/filters/spatialAnalysis.cpp:1793
-#: ../src/backend/filters/spatialAnalysis.cpp:2089
-#: ../src/backend/filters/spatialAnalysis.cpp:2578
+#: ../src/backend/filters/spatialAnalysis.cpp:1503
+#: ../src/backend/filters/spatialAnalysis.cpp:1557
+#: ../src/backend/filters/spatialAnalysis.cpp:1804
+#: ../src/backend/filters/spatialAnalysis.cpp:2100
+#: ../src/backend/filters/spatialAnalysis.cpp:2589
 msgid "Build"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1504
-#: ../src/backend/filters/spatialAnalysis.cpp:1558
+#: ../src/backend/filters/spatialAnalysis.cpp:1515
+#: ../src/backend/filters/spatialAnalysis.cpp:1569
 msgid "Surface"
 msgstr "Oberfläche"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1598
-#: ../src/backend/filters/spatialAnalysis.cpp:1820
-#: ../src/backend/filters/spatialAnalysis.cpp:2116
+#: ../src/backend/filters/spatialAnalysis.cpp:1609
+#: ../src/backend/filters/spatialAnalysis.cpp:1831
+#: ../src/backend/filters/spatialAnalysis.cpp:2127
 msgid "Analyse"
 msgstr "Analyse"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1655
-#: ../src/backend/filters/spatialAnalysis.cpp:1724
+#: ../src/backend/filters/spatialAnalysis.cpp:1666
+#: ../src/backend/filters/spatialAnalysis.cpp:1735
 msgid "Radial Distance"
 msgstr "Radialer Abstand"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1659
+#: ../src/backend/filters/spatialAnalysis.cpp:1670
 msgid "NN Freq."
 msgstr "NN Freq."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1715
+#: ../src/backend/filters/spatialAnalysis.cpp:1726
 msgid "Warning, "
 msgstr "Warnung, "
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1716
+#: ../src/backend/filters/spatialAnalysis.cpp:1727
 msgid ""
 " points were unable to find neighbour points that exceeded the search "
 "radius, and thus terminated prematurely"
@@ -3478,51 +3417,51 @@ msgstr ""
 " Punkte konnten keine Nachbapunkte die den Suchradius überschritten finden "
 "und beendeten vorzeitig."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1726
+#: ../src/backend/filters/spatialAnalysis.cpp:1737
 msgid " RDF"
 msgstr " RDF"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2016
-#: ../src/backend/filters/spatialAnalysis.cpp:2322
+#: ../src/backend/filters/spatialAnalysis.cpp:2027
+#: ../src/backend/filters/spatialAnalysis.cpp:2333
 msgid "Number Density (\\#/Vol^3)"
 msgstr "Number Density (\\#/Vol^3)"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2043
-#: ../src/backend/filters/spatialAnalysis.cpp:2347
+#: ../src/backend/filters/spatialAnalysis.cpp:2054
+#: ../src/backend/filters/spatialAnalysis.cpp:2358
 msgid "Warning,"
 msgstr "Warnung,"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2044
-#: ../src/backend/filters/spatialAnalysis.cpp:2348
+#: ../src/backend/filters/spatialAnalysis.cpp:2055
+#: ../src/backend/filters/spatialAnalysis.cpp:2359
 msgid " points were un-analysable. These have been dropped"
 msgstr " points were un-analysable. These have been dropped"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2066
-#: ../src/backend/filters/spatialAnalysis.cpp:2370
+#: ../src/backend/filters/spatialAnalysis.cpp:2077
+#: ../src/backend/filters/spatialAnalysis.cpp:2381
 msgid "And so on..."
 msgstr "Und so weiter..."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2450
+#: ../src/backend/filters/spatialAnalysis.cpp:2461
 msgid "Extract"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2501
+#: ../src/backend/filters/spatialAnalysis.cpp:2512
 msgid "Reduce"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2595
+#: ../src/backend/filters/spatialAnalysis.cpp:2606
 msgid "Compute"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2620
+#: ../src/backend/filters/spatialAnalysis.cpp:2631
 msgid "Insufficient points to complete analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2658
+#: ../src/backend/filters/spatialAnalysis.cpp:2669
 msgid "Axial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2660
+#: ../src/backend/filters/spatialAnalysis.cpp:2671
 msgid " 1D Dist. Func."
 msgstr ""
 
@@ -3566,122 +3505,122 @@ msgstr "Boundbox Zentrum"
 msgid "Mass Centre"
 msgstr "Massen-Zentrum"
 
-#: ../src/backend/filters/transform.cpp:1058
+#: ../src/backend/filters/transform.cpp:1054
 msgid "Mass-to-Charge (amu/e)"
 msgstr "Masse-zu-Ladung (amu/e)"
 
-#: ../src/backend/filters/transform.cpp:1112
+#: ../src/backend/filters/transform.cpp:1108
 msgid "Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1128
+#: ../src/backend/filters/transform.cpp:1124
 msgid "Splice"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1183
+#: ../src/backend/filters/transform.cpp:1179
 msgid "Algorithm to use to transform point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1199
+#: ../src/backend/filters/transform.cpp:1195
 msgid "Origin mode"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1202
+#: ../src/backend/filters/transform.cpp:1198
 msgid "Select how transform origin is computed"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1207
+#: ../src/backend/filters/transform.cpp:1203
 msgid "Show marker"
 msgstr "Zeige Markierung"
 
-#: ../src/backend/filters/transform.cpp:1211
+#: ../src/backend/filters/transform.cpp:1207
 msgid "Display an interactive object to set transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1213
+#: ../src/backend/filters/transform.cpp:1209
 msgid "Display a small marker to denote transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1229
+#: ../src/backend/filters/transform.cpp:1225
 msgid "Translation"
 msgstr "Translation"
 
-#: ../src/backend/filters/transform.cpp:1232
+#: ../src/backend/filters/transform.cpp:1228
 msgid "Translation vector for transform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1244
+#: ../src/backend/filters/transform.cpp:1240
 msgid "Offset"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1248
+#: ../src/backend/filters/transform.cpp:1244
 msgid "Scalar to use to offset each point's associated value"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1265
-#: ../src/backend/filters/transform.cpp:1292
+#: ../src/backend/filters/transform.cpp:1261
+#: ../src/backend/filters/transform.cpp:1288
 msgid "Origin of scale trasnform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1272
-#: ../src/backend/filters/transform.cpp:1299
+#: ../src/backend/filters/transform.cpp:1268
+#: ../src/backend/filters/transform.cpp:1295
 msgid "Scale Fact."
 msgstr "Skalierungsfaktor"
 
-#: ../src/backend/filters/transform.cpp:1275
-#: ../src/backend/filters/transform.cpp:1302
+#: ../src/backend/filters/transform.cpp:1271
+#: ../src/backend/filters/transform.cpp:1298
 msgid "Enlargement factor for scaling around origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1318
+#: ../src/backend/filters/transform.cpp:1314
 msgid "Origin of rotation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1326
+#: ../src/backend/filters/transform.cpp:1322
 msgid "Axis around which to revolve"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1331
+#: ../src/backend/filters/transform.cpp:1327
 msgid "Angle (deg)"
 msgstr "Winkel (deg)"
 
-#: ../src/backend/filters/transform.cpp:1334
+#: ../src/backend/filters/transform.cpp:1330
 msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1351
+#: ../src/backend/filters/transform.cpp:1347
 msgid "Noise Type"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1354
+#: ../src/backend/filters/transform.cpp:1350
 msgid "Method to use to degrade point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1361
+#: ../src/backend/filters/transform.cpp:1357
 msgid "Noise level"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1363
+#: ../src/backend/filters/transform.cpp:1359
 msgid "Standard dev."
 msgstr "Standardabweichung"
 
-#: ../src/backend/filters/transform.cpp:1371
+#: ../src/backend/filters/transform.cpp:1367
 msgid "Amplitude of noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1383
+#: ../src/backend/filters/transform.cpp:1379
 msgid "Transform Params"
 msgstr "Transformationsparameter"
 
-#: ../src/backend/filters/transform.cpp:1580
+#: ../src/backend/filters/transform.cpp:1576
 msgid "Unable to allocate memory"
 msgstr "Kann Speicher nicht zuweisen"
 
-#: ../src/backend/filters/transform.cpp:1759
+#: ../src/backend/filters/transform.cpp:1755
 msgid "White"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1761
+#: ../src/backend/filters/transform.cpp:1757
 msgid "Gaussian"
 msgstr ""
 
@@ -3788,7 +3727,7 @@ msgid "Thickness of the lines used to draw the box"
 msgstr ""
 
 #: ../src/backend/filters/boundingBox.cpp:650
-#: ../src/backend/filters/annotation.cpp:833
+#: ../src/backend/filters/annotation.cpp:845
 msgid "Font Size"
 msgstr "Schriftgröße"
 
@@ -3796,219 +3735,229 @@ msgstr "Schriftgröße"
 msgid "Relative size for text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:67
+#: ../src/backend/filters/annotation.cpp:68
 msgid "Arrow"
 msgstr "Pfeil"
 
-#: ../src/backend/filters/annotation.cpp:68
+#: ../src/backend/filters/annotation.cpp:69
 msgid "Text"
 msgstr "Text"
 
-#: ../src/backend/filters/annotation.cpp:69
+#: ../src/backend/filters/annotation.cpp:70
 msgid "Arrow+Text"
 msgstr "Pfeil+Text"
 
-#: ../src/backend/filters/annotation.cpp:70
+#: ../src/backend/filters/annotation.cpp:71
 msgid "Angle"
 msgstr "Winkel"
 
-#: ../src/backend/filters/annotation.cpp:71
+#: ../src/backend/filters/annotation.cpp:72
 msgid "Ruler"
 msgstr "Lineal"
 
-#: ../src/backend/filters/annotation.cpp:538
+#: ../src/backend/filters/annotation.cpp:526
+msgid "Enable"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:529
+msgid "Enable/disable annotation"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:550
 msgid "Type or style of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:553
-#: ../src/backend/filters/annotation.cpp:655
+#: ../src/backend/filters/annotation.cpp:565
+#: ../src/backend/filters/annotation.cpp:667
 msgid "Text of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:561
+#: ../src/backend/filters/annotation.cpp:573
 msgid "Position of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:565
-#: ../src/backend/filters/annotation.cpp:669
-#: ../src/backend/filters/annotation.cpp:727
-#: ../src/backend/filters/annotation.cpp:816
+#: ../src/backend/filters/annotation.cpp:577
+#: ../src/backend/filters/annotation.cpp:681
+#: ../src/backend/filters/annotation.cpp:739
+#: ../src/backend/filters/annotation.cpp:828
 msgid "Up dir"
 msgstr "Up dir"
 
-#: ../src/backend/filters/annotation.cpp:569
-#: ../src/backend/filters/annotation.cpp:820
+#: ../src/backend/filters/annotation.cpp:581
+#: ../src/backend/filters/annotation.cpp:832
 msgid "Vector for up direction of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:573
-#: ../src/backend/filters/annotation.cpp:676
-#: ../src/backend/filters/annotation.cpp:719
-#: ../src/backend/filters/annotation.cpp:824
+#: ../src/backend/filters/annotation.cpp:585
+#: ../src/backend/filters/annotation.cpp:688
+#: ../src/backend/filters/annotation.cpp:731
+#: ../src/backend/filters/annotation.cpp:836
 msgid "Across dir"
 msgstr "Across dir"
 
-#: ../src/backend/filters/annotation.cpp:577
-#: ../src/backend/filters/annotation.cpp:828
+#: ../src/backend/filters/annotation.cpp:589
+#: ../src/backend/filters/annotation.cpp:840
 msgid "Reading direction for annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:582
-#: ../src/backend/filters/annotation.cpp:661
-#: ../src/backend/filters/annotation.cpp:754
+#: ../src/backend/filters/annotation.cpp:594
+#: ../src/backend/filters/annotation.cpp:673
+#: ../src/backend/filters/annotation.cpp:766
 msgid "Text size"
 msgstr "Textgröße"
 
-#: ../src/backend/filters/annotation.cpp:586
-#: ../src/backend/filters/annotation.cpp:665
-#: ../src/backend/filters/annotation.cpp:836
+#: ../src/backend/filters/annotation.cpp:598
+#: ../src/backend/filters/annotation.cpp:677
+#: ../src/backend/filters/annotation.cpp:848
 msgid "Relative size of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:594
-#: ../src/backend/filters/annotation.cpp:633
-#: ../src/backend/filters/annotation.cpp:800
+#: ../src/backend/filters/annotation.cpp:606
+#: ../src/backend/filters/annotation.cpp:645
+#: ../src/backend/filters/annotation.cpp:812
 msgid "Start"
 msgstr "Anfang"
 
-#: ../src/backend/filters/annotation.cpp:598
-#: ../src/backend/filters/annotation.cpp:637
+#: ../src/backend/filters/annotation.cpp:610
+#: ../src/backend/filters/annotation.cpp:649
 msgid "3D position for tail of arrow"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:602
-#: ../src/backend/filters/annotation.cpp:642
-#: ../src/backend/filters/annotation.cpp:808
+#: ../src/backend/filters/annotation.cpp:614
+#: ../src/backend/filters/annotation.cpp:654
+#: ../src/backend/filters/annotation.cpp:820
 msgid "End"
 msgstr "Ende"
 
-#: ../src/backend/filters/annotation.cpp:606
-#: ../src/backend/filters/annotation.cpp:646
+#: ../src/backend/filters/annotation.cpp:618
+#: ../src/backend/filters/annotation.cpp:658
 msgid "3D Position to which arrow points"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:612
-#: ../src/backend/filters/annotation.cpp:683
+#: ../src/backend/filters/annotation.cpp:624
+#: ../src/backend/filters/annotation.cpp:695
 msgid "Tip radius"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:616
+#: ../src/backend/filters/annotation.cpp:628
 msgid "Size of the arrow head"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:620
+#: ../src/backend/filters/annotation.cpp:632
 msgid "Line size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:624
+#: ../src/backend/filters/annotation.cpp:636
 msgid "Thickness of line used to draw arrow stem"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:693
+#: ../src/backend/filters/annotation.cpp:705
 msgid "Position A"
 msgstr "Position A"
 
-#: ../src/backend/filters/annotation.cpp:697
+#: ../src/backend/filters/annotation.cpp:709
 msgid "Location of first non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:701
+#: ../src/backend/filters/annotation.cpp:713
 msgid "Origin "
 msgstr "Ursprung "
 
-#: ../src/backend/filters/annotation.cpp:705
+#: ../src/backend/filters/annotation.cpp:717
 msgid "Location of central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:709
+#: ../src/backend/filters/annotation.cpp:721
 msgid "Position B"
 msgstr "Position B"
 
-#: ../src/backend/filters/annotation.cpp:713
+#: ../src/backend/filters/annotation.cpp:725
 msgid "Location of second non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:723
+#: ../src/backend/filters/annotation.cpp:735
 msgid "Reading direction for angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:728
+#: ../src/backend/filters/annotation.cpp:740
 msgid "Vector for up direction of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:736
+#: ../src/backend/filters/annotation.cpp:748
 msgid "Reflexive"
 msgstr "Reflexive"
 
-#: ../src/backend/filters/annotation.cpp:739
+#: ../src/backend/filters/annotation.cpp:751
 msgid "Measure interor (enabled) or exterior angle (disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:744
+#: ../src/backend/filters/annotation.cpp:756
 msgid "Show Angle"
 msgstr "Zeige Winkel"
 
-#: ../src/backend/filters/annotation.cpp:748
+#: ../src/backend/filters/annotation.cpp:760
 msgid "Display angle text (when enabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:758
+#: ../src/backend/filters/annotation.cpp:770
 msgid "Size of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:776
+#: ../src/backend/filters/annotation.cpp:788
 msgid "Digit format"
 msgstr "Zahlenformat"
 
-#: ../src/backend/filters/annotation.cpp:780
+#: ../src/backend/filters/annotation.cpp:792
 msgid ""
 "Format of angle text; # for numeral position, '.' for separator, eg ##.## "
 "gives 12.34"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:786
+#: ../src/backend/filters/annotation.cpp:798
+#: ../src/backend/filters/annotation.cpp:886
 msgid "Sphere size"
 msgstr "Kugelgröße"
 
-#: ../src/backend/filters/annotation.cpp:790
+#: ../src/backend/filters/annotation.cpp:802
+#: ../src/backend/filters/annotation.cpp:890
 msgid "Marker sphere size for manipulating tool"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:804
+#: ../src/backend/filters/annotation.cpp:816
 msgid "Ruler beginning 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:812
+#: ../src/backend/filters/annotation.cpp:824
 msgid "Ruler finish 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:845
+#: ../src/backend/filters/annotation.cpp:857
 msgid "Fixed ticks"
 msgstr "Fixe Marker"
 
-#: ../src/backend/filters/annotation.cpp:848
+#: ../src/backend/filters/annotation.cpp:860
 msgid ""
 "Use fixed (enabled) number of text markers, or one every fixed distance "
 "(disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:855
+#: ../src/backend/filters/annotation.cpp:867
 msgid "Num Ticks"
 msgstr "Anzahl Marker"
 
-#: ../src/backend/filters/annotation.cpp:858
+#: ../src/backend/filters/annotation.cpp:870
 msgid "Number of tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:865
+#: ../src/backend/filters/annotation.cpp:877
 msgid "Tick Spacing"
 msgstr "Markerabstand"
 
-#: ../src/backend/filters/annotation.cpp:868
+#: ../src/backend/filters/annotation.cpp:880
 msgid "Distance between tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:885
+#: ../src/backend/filters/annotation.cpp:906
 msgid "Colour for ruler and ticks"
 msgstr ""
 
@@ -4160,30 +4109,30 @@ msgstr "Nicht genügend Speicher für Operation"
 msgid "Bug? Problem with qhull library, cannot run convex hull."
 msgstr "Bug? Problem mit qhull Bibliothek. Kann convex hull nicht ausführen."
 
-#: ../src/backend/filters/dataLoad.cpp:45
+#: ../src/backend/filters/dataLoad.cpp:47
 msgid "POS Data"
 msgstr "Pos-Daten"
 
-#: ../src/backend/filters/dataLoad.cpp:46
+#: ../src/backend/filters/dataLoad.cpp:48
 msgid "Text Data"
 msgstr "Text-Daten"
 
-#: ../src/backend/filters/dataLoad.cpp:225
+#: ../src/backend/filters/dataLoad.cpp:227
 msgid " does not exist"
 msgstr " existiert nicht"
 
-#: ../src/backend/filters/dataLoad.cpp:262
-#: ../src/backend/filters/dataLoad.cpp:273
-#: ../src/backend/filters/dataLoad.cpp:293
-#: ../src/backend/filters/dataLoad.cpp:305
+#: ../src/backend/filters/dataLoad.cpp:264
+#: ../src/backend/filters/dataLoad.cpp:275
+#: ../src/backend/filters/dataLoad.cpp:295
+#: ../src/backend/filters/dataLoad.cpp:307
 msgid "Error loading file: "
 msgstr "Fehler beim Laden der Datei: "
 
-#: ../src/backend/filters/dataLoad.cpp:319
+#: ../src/backend/filters/dataLoad.cpp:321
 msgid "Data file contained incorrect number of columns -- should be 4, was "
 msgstr "Datei enthielt falsche Anzahl von Spalten - sollte 4 sein, war "
 
-#: ../src/backend/filters/dataLoad.cpp:372
+#: ../src/backend/filters/dataLoad.cpp:374
 msgid ""
 "Warning:One or more bounds of the loaded data approaches the limits of "
 "numerical stability for the internal data type(magnitude too large). "
@@ -4193,119 +4142,119 @@ msgstr ""
 "der numerischen Stabilität des internen Datentyps (Größenordnung zu groß). "
 "Erwägen Sie die Daten vor dem Laden zu skalieren. "
 
-#: ../src/backend/filters/dataLoad.cpp:379
+#: ../src/backend/filters/dataLoad.cpp:381
 msgid "Loaded "
 msgstr "Geladen "
 
-#: ../src/backend/filters/dataLoad.cpp:379
+#: ../src/backend/filters/dataLoad.cpp:381
 msgid " Points"
 msgstr " Punkte"
 
-#: ../src/backend/filters/dataLoad.cpp:407
-#: ../src/backend/filters/rangeFile.cpp:504
+#: ../src/backend/filters/dataLoad.cpp:409
+#: ../src/backend/filters/rangeFile.cpp:559
 msgid "File"
 msgstr "Datei"
 
-#: ../src/backend/filters/dataLoad.cpp:408
+#: ../src/backend/filters/dataLoad.cpp:410
 msgid "File from which to load data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:419
+#: ../src/backend/filters/dataLoad.cpp:421
 msgid "File type"
 msgstr "Dateityp"
 
-#: ../src/backend/filters/dataLoad.cpp:421
+#: ../src/backend/filters/dataLoad.cpp:423
 msgid "Type of file to be loaded"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:435
+#: ../src/backend/filters/dataLoad.cpp:437
 msgid "Entries per point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:436
+#: ../src/backend/filters/dataLoad.cpp:438
 msgid "Number of decimal values in file per 3D point (normally 4)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:464
+#: ../src/backend/filters/dataLoad.cpp:466
 msgid "Relative offset of each entry in file for point's X position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:472
+#: ../src/backend/filters/dataLoad.cpp:474
 msgid "Relative offset of each entry in file for point's Y position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:480
+#: ../src/backend/filters/dataLoad.cpp:482
 msgid "Relative offset of each entry in file for point's Z position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:488
+#: ../src/backend/filters/dataLoad.cpp:490
 msgid ""
 "Relative offset of each entry in file to use for scalar value of 3D point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:491
+#: ../src/backend/filters/dataLoad.cpp:493
 msgid "Value Label"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:495
+#: ../src/backend/filters/dataLoad.cpp:497
 msgid "Name for the scalar value associated with each point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:498
+#: ../src/backend/filters/dataLoad.cpp:500
 msgid "Format params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:504
+#: ../src/backend/filters/dataLoad.cpp:506
 msgid "Enabled"
 msgstr "Aktiviert"
 
-#: ../src/backend/filters/dataLoad.cpp:508
+#: ../src/backend/filters/dataLoad.cpp:510
 msgid "Load this file?"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:516
+#: ../src/backend/filters/dataLoad.cpp:518
 msgid "Sample data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:519
+#: ../src/backend/filters/dataLoad.cpp:521
 msgid ""
 "Perform random selection on file contents, instead of loading entire file"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:526
+#: ../src/backend/filters/dataLoad.cpp:528
 msgid "Load Limit (MB)"
 msgstr "Ladelimit (MB)"
 
-#: ../src/backend/filters/dataLoad.cpp:529
+#: ../src/backend/filters/dataLoad.cpp:531
 msgid "Limit for size of data to load"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:535
+#: ../src/backend/filters/dataLoad.cpp:537
 msgid "Monitor"
 msgstr "Monitor"
 
-#: ../src/backend/filters/dataLoad.cpp:539
+#: ../src/backend/filters/dataLoad.cpp:541
 msgid ""
 "Watch file timestamp to track changes to file contents from other programs"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:541
+#: ../src/backend/filters/dataLoad.cpp:543
 msgid "Load params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:551
+#: ../src/backend/filters/dataLoad.cpp:553
 msgid "Default colour "
 msgstr "Bevorzugte Farbe "
 
-#: ../src/backend/filters/dataLoad.cpp:554
+#: ../src/backend/filters/dataLoad.cpp:556
 msgid "Default colour for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:559
+#: ../src/backend/filters/dataLoad.cpp:561
 msgid "Draw Size"
 msgstr "Draw Size"
 
-#: ../src/backend/filters/dataLoad.cpp:562
+#: ../src/backend/filters/dataLoad.cpp:564
 msgid "Default size for points, if not overridden by other filters"
 msgstr ""
 
@@ -4373,221 +4322,384 @@ msgstr "Nicht genügend Speicher für Spektrumfilter"
 msgid "Bad bincount value in spectrum filter."
 msgstr "Falsche Binanzahl im Spektrumfilter."
 
-#: ../src/backend/filters/rangeFile.cpp:146
+#: ../src/backend/filters/rangeFile.cpp:143
 msgid "Pre-Allocate"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:260 ../src/backend/filter.cpp:46
+#: ../src/backend/filters/rangeFile.cpp:274 ../src/backend/filter.cpp:46
 msgid "Range"
 msgstr "Range"
 
-#: ../src/backend/filters/rangeFile.cpp:506
+#: ../src/backend/filters/rangeFile.cpp:561
 msgid "File to use for range data"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:518
+#: ../src/backend/filters/rangeFile.cpp:573
 msgid "Drop unranged"
 msgstr "Nicht gerangete ausschalten"
 
-#: ../src/backend/filters/rangeFile.cpp:520
+#: ../src/backend/filters/rangeFile.cpp:575
 msgid "Remove unranged points when generating output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:540
+#: ../src/backend/filters/rangeFile.cpp:595
 msgid "All Ions"
 msgstr "Alle Ionen"
 
-#: ../src/backend/filters/rangeFile.cpp:541
+#: ../src/backend/filters/rangeFile.cpp:596
 msgid "Enable/disable all ions at once"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:549
+#: ../src/backend/filters/rangeFile.cpp:604
 msgid "Species"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:556
+#: ../src/backend/filters/rangeFile.cpp:611
 msgid "IonID "
 msgstr "IonID "
 
-#: ../src/backend/filters/rangeFile.cpp:557
+#: ../src/backend/filters/rangeFile.cpp:612
 msgid "Enable/disable specified ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:570
+#: ../src/backend/filters/rangeFile.cpp:625
 msgid "Active Ion "
 msgstr "Actives Ion "
 
-#: ../src/backend/filters/rangeFile.cpp:572
+#: ../src/backend/filters/rangeFile.cpp:627
 msgid "If true, ion is used in output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:586
+#: ../src/backend/filters/rangeFile.cpp:641
 msgid "Colour "
 msgstr "Farbe"
 
-#: ../src/backend/filters/rangeFile.cpp:589
+#: ../src/backend/filters/rangeFile.cpp:644
 msgid "Colour used to represent ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:613
+#: ../src/backend/filters/rangeFile.cpp:668
 msgid "All Ranges"
 msgstr "Alle Range"
 
-#: ../src/backend/filters/rangeFile.cpp:614
+#: ../src/backend/filters/rangeFile.cpp:669
 msgid "Enable/disable all ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:632
+#: ../src/backend/filters/rangeFile.cpp:687
 msgid "Active Rng "
 msgstr "Activer Rng "
 
-#: ../src/backend/filters/rangeFile.cpp:635
+#: ../src/backend/filters/rangeFile.cpp:690
 msgid ""
 "Enable/disable specified range (ion must also be enabled to activiate range)"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:639
+#: ../src/backend/filters/rangeFile.cpp:694
 msgid "Ion "
 msgstr "Ion "
 
-#: ../src/backend/filters/rangeFile.cpp:642
+#: ../src/backend/filters/rangeFile.cpp:697
 msgid "Name of ion associate to this range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:651
+#: ../src/backend/filters/rangeFile.cpp:706
 msgid "Start rng "
 msgstr "Start rng "
 
-#: ../src/backend/filters/rangeFile.cpp:654
+#: ../src/backend/filters/rangeFile.cpp:709
 msgid "Start value for range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:659
+#: ../src/backend/filters/rangeFile.cpp:714
 msgid "End rng "
 msgstr "End rng "
 
-#: ../src/backend/filters/rangeFile.cpp:662
+#: ../src/backend/filters/rangeFile.cpp:717
 msgid "Stopping value for range`"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:966
+#: ../src/backend/filters/rangeFile.cpp:1021
 msgid "Ranging aborted by user"
 msgstr "Ranging durch User abgebrochen"
 
-#: ../src/backend/filters/rangeFile.cpp:968
+#: ../src/backend/filters/rangeFile.cpp:1023
 msgid "Insufficient memory for range"
 msgstr "Nicht genug Speicher für Range"
 
-#: ../src/backend/filtertreeAnalyse.cpp:93
+#: ../src/backend/state.cpp:120
+msgid ""
+"This file is a \"state\" file for the 3Depict program, and stores "
+"information about a particular analysis session. This file should be a valid "
+"\"XML\" file"
+msgstr ""
+"Diese Datei ist ein \"Status\" Datei für das Programm 3Depict. Sie speichert "
+"Informationen über die jeweiligen Analysesitzung. Dies sollte ein gültige "
+"\"XML\" Datei sein."
+
+#: ../src/backend/state.cpp:248
+msgid "Failed to allocate parser"
+msgstr "Kann Parser nicht zuordnen"
+
+#: ../src/backend/state.cpp:283
+msgid ""
+"Unable to retrieve root node in input state file... Is this really a non-"
+"empty XML file?"
+msgstr ""
+
+#: ../src/backend/state.cpp:290
+msgid "Base state node missing. Is this really a state XML file??"
+msgstr ""
+
+#: ../src/backend/state.cpp:319
+msgid "State was created by a newer version of this program.. "
+msgstr "Status wurde von einer neueren Version dieses Programmes erstellt.. "
+
+#: ../src/backend/state.cpp:320
+msgid "file reading will continue, but may fail."
+msgstr "Datei wird weiter eingelesen kann aber unter Umständen fehlschlagen."
+
+#: ../src/backend/state.cpp:325
+msgid ""
+"Warning, unparseable version number in state file. File reading will "
+"continue, but may fail"
+msgstr ""
+"Warnung: Nicht lesbare Versionsnummer in Statusdatei. Datei wird weiter "
+"eingelesen kann aber unter Umständen fehlschlagen."
+
+#: ../src/backend/state.cpp:332
+msgid "Unable to find the \"writer\" node"
+msgstr "Kann \"writer\" node nicht finden"
+
+#: ../src/backend/state.cpp:342
+msgid "Unable to find the \"backcolour\" node."
+msgstr "Unable to find the \"backcolour\" node."
+
+#: ../src/backend/state.cpp:349
+msgid "\"backcolour\" node missing \"r\" value."
+msgstr "\"backcolour\" node fehlt \"r\" Wert."
+
+#: ../src/backend/state.cpp:354
+msgid "Unable to interpret \"backColour\" node's \"r\" value."
+msgstr "Kann \"backColour\" node's \"r\" Wert nicht interpretieren."
+
+#: ../src/backend/state.cpp:362
+msgid "\"backcolour\" node missing \"g\" value."
+msgstr "\"backcolour\" node fehlt \"g\" Wert."
+
+#: ../src/backend/state.cpp:368
+msgid "Unable to interpret \"backColour\" node's \"g\" value."
+msgstr "Kann \"backColour\" node's \"g\" Wert nicht interpretieren."
+
+#: ../src/backend/state.cpp:376
+msgid "\"backcolour\" node missing \"b\" value."
+msgstr "\"backcolour\" node fehlt \"b\" Wert."
+
+#: ../src/backend/state.cpp:382
+msgid "Unable to interpret \"backColour\" node's \"b\" value."
+msgstr "Kann \"backColour\" node's \"b\" Wert nicht interpretieren."
+
+#: ../src/backend/state.cpp:389
+msgid "\"backcolour\"s rgb values must be in range [0,1]"
+msgstr "\"backcolour\"s rgb Wert muss im Bereich [0,1] liegen"
+
+#: ../src/backend/state.cpp:417
+msgid "Unable to find or interpret \"showaxis\" node"
+msgstr "Kann \"showaxis\" node nicht interpretieren"
+
+#: ../src/backend/state.cpp:424
+msgid "Unable to locate \"filtertree\" node."
+msgstr "Kann \"filtertree\" node nicht finden."
+
+#: ../src/backend/state.cpp:440
+msgid "Cameras section missing \"active\" node."
+msgstr "Cameras section fehlt \"active\" node."
+
+#: ../src/backend/state.cpp:448
+msgid "Unable to find property \"value\"  for \"cameras->active\" node."
+msgstr "Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht finden."
+
+#: ../src/backend/state.cpp:454
+msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
+msgstr ""
+"Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht interpretieren."
+
+#: ../src/backend/state.cpp:473
+msgid "Failed to interpret camera state for camera : "
+msgstr ""
+
+#: ../src/backend/state.cpp:481
+msgid "Unable to interpret the camera type for camera : "
+msgstr "Kann den Kameratype nicht interpretieren für :"
+
+#: ../src/backend/state.cpp:517
+msgid "Unable to locate stash name for stash "
+msgstr "Kann den Stashnamen für Stash  nicht finden"
+
+#: ../src/backend/state.cpp:524
+msgid "Empty stash name for stash "
+msgstr "Leerer Stashname für Stash"
+
+#: ../src/backend/state.cpp:533
+msgid "No filter tree for stash:"
+msgstr ""
+
+#: ../src/backend/state.cpp:539
+msgid "For stash "
+msgstr "Für Stash "
+
+#: ../src/backend/state.cpp:570
+msgid "Unrecognised effect :"
+msgstr "Nichterkannter Effekt :"
+
+#: ../src/backend/state.cpp:580
+msgid "Duplicate effect found"
+msgstr "Doppelter Effekt gefunden"
+
+#: ../src/backend/state.cpp:580
+msgid " cannot use."
+msgstr "kann nicht   verwenden."
+
+#: ../src/backend/state.cpp:590
+msgid "Error reading effect : "
+msgstr "Fehler beim Lesen:"
+
+#: ../src/backend/state.cpp:651
+msgid "-merge"
+msgstr ""
+
+#: ../src/backend/state.cpp:656
+msgid ""
+" Unable to merge stashes correctly. This is improbable, so please report "
+"this."
+msgstr ""
+" Kann stashes nicht korrekt zusammenführen. Dies ist nicht möglich bitte "
+"melden Sie das."
+
+#: ../src/backend/filtertreeAnalyse.cpp:198
 msgid ""
 "Parent filter has no output, but filter requires input -- there is no point "
 "in placing a child filter here."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:94
+#: ../src/backend/filtertreeAnalyse.cpp:199
 msgid "Leaf-only filter with child"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:104
+#: ../src/backend/filtertreeAnalyse.cpp:209
 msgid ""
 "Parent filters' output will be blocked by child, without use. Parent results "
 "will be dropped."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:105
-#: ../src/backend/filtertreeAnalyse.cpp:119
+#: ../src/backend/filtertreeAnalyse.cpp:210
+#: ../src/backend/filtertreeAnalyse.cpp:224
 msgid "Bad parent->child pair"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:118
+#: ../src/backend/filtertreeAnalyse.cpp:223
 msgid ""
 "First filter does not output anything useable by child filter. Child filter "
 "not useful."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:291
+#: ../src/backend/filtertreeAnalyse.cpp:303
 msgid "Spatial results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:292
+#: ../src/backend/filtertreeAnalyse.cpp:304
 msgid ""
 "Filters and settings selected that could alter reported results that depend "
 "upon density. Check to see if spatial sampling may be happening in the "
 "filter tree - this warning is provisional only."
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:453
+#: ../src/backend/filtertreeAnalyse.cpp:372
+msgid "Filter needs parent \""
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:373
+msgid ""
+"\" but does not have one. Filter may not function correctly until this "
+"parent is given."
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:374
+msgid "Filter missing needed parent"
+msgstr ""
+
+#: ../src/backend/filtertreeAnalyse.cpp:553
 msgid "Composition results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:454
+#: ../src/backend/filtertreeAnalyse.cpp:554
 msgid ""
 "Filters and settings selected that could bias reported composition. Check to "
 "see if species biasing may occcur in the filter tree - this warning is "
 "provisional only."
 msgstr ""
 
-#: ../src/backend/APT/APTClasses.cpp:32
+#: ../src/backend/APT/APTFileIO.cpp:39
 msgid "Memory allocation failure on POS load"
 msgstr "Speicherzuweisungsfeher beim Laden der pos-Datei"
 
-#: ../src/backend/APT/APTClasses.cpp:33
+#: ../src/backend/APT/APTFileIO.cpp:40
 msgid "Error opening pos file"
 msgstr "Fehler beim Öffnen der pos-Datei"
 
-#: ../src/backend/APT/APTClasses.cpp:34
+#: ../src/backend/APT/APTFileIO.cpp:41
 msgid "Pos file empty"
 msgstr "Pos-Datei ist leer"
 
-#: ../src/backend/APT/APTClasses.cpp:35
+#: ../src/backend/APT/APTFileIO.cpp:42
 msgid "Pos file size appears to have non-integer number of entries"
 msgstr ""
 "Pos-Dateigröße scheint eine nicht ganzzahlige Anzahl an Einträgen zu haben"
 
-#: ../src/backend/APT/APTClasses.cpp:36
+#: ../src/backend/APT/APTFileIO.cpp:43
 msgid "Error reading from pos file (after open)"
 msgstr "Fehler beim Lesen aus pos-Datei (nach dem öffnen)"
 
-#: ../src/backend/APT/APTClasses.cpp:37
+#: ../src/backend/APT/APTFileIO.cpp:44
 msgid "Error - Found NaN in pos file"
 msgstr "Fehler - Fand NaN in pos-Datei"
 
-#: ../src/backend/APT/APTClasses.cpp:38
+#: ../src/backend/APT/APTFileIO.cpp:45
 msgid "Pos load aborted by interrupt."
 msgstr "Pos laden durch Interrupt abgebrochen."
 
-#: ../src/backend/APT/APTClasses.cpp:55
+#: ../src/backend/APT/APTFileIO.cpp:62
 msgid "No numerical data found"
 msgstr "Keine numerischen Daten gefunden"
 
-#: ../src/backend/APT/APTClasses.cpp:56
+#: ../src/backend/APT/APTFileIO.cpp:63
 msgid "Error re-opening file, after first scan"
 msgstr "Fehler beim nochmaligen Öffnen der Datei nach dem ersten Scan"
 
-#: ../src/backend/APT/APTClasses.cpp:57
+#: ../src/backend/APT/APTFileIO.cpp:64
 msgid "Unable to read file contents after open"
 msgstr "Kann den Dateiinhalt nach dem Öffnen nich lesen"
 
-#: ../src/backend/APT/APTClasses.cpp:59
+#: ../src/backend/APT/APTFileIO.cpp:66
 msgid "Incorrect number of fields in file"
 msgstr "Die Datei enthält eine falsche Anzahl von Feldern"
 
-#: ../src/backend/APT/APTClasses.cpp:60
+#: ../src/backend/APT/APTFileIO.cpp:67
 msgid "Unable to allocate memory to store data"
 msgstr "Kann Speicher nicht zuordnen"
 
-#: ../src/backend/APT/APTRanges.cpp:42
+#: ../src/backend/APT/APTRanges.cpp:46
 msgid "Error opening file, check name and permissions."
 msgstr "Fehler beim Öffnen der Datei, überprüfe Namen und Berechtigungen."
 
-#: ../src/backend/APT/APTRanges.cpp:43
+#: ../src/backend/APT/APTRanges.cpp:47
 msgid ""
 "Error interpreting range file header, expecting ion count and range count, "
 "respectively."
 msgstr ""
 "Fehler beim Rangedatei interpretieren, erwarte Ionenanzahl bzw. Rangeanzahl."
 
-#: ../src/backend/APT/APTRanges.cpp:44
+#: ../src/backend/APT/APTRanges.cpp:48
 msgid ""
 "Range file appears to be empty, check file is a proper range file and is not "
 "empty."
@@ -4595,15 +4707,15 @@ msgstr ""
 "Rangedatei scheint leer zu sein. Prüfe ob die Datei wirklich ein Rangedatei "
 "und nicht leer ist."
 
-#: ../src/backend/APT/APTRanges.cpp:45
+#: ../src/backend/APT/APTRanges.cpp:49
 msgid "Error reading the long name for ion."
 msgstr "Fehler beim Lesen des langen Namens für Ion."
 
-#: ../src/backend/APT/APTRanges.cpp:46
+#: ../src/backend/APT/APTRanges.cpp:50
 msgid "Error reading the short name for ion."
 msgstr "Fehler beim Lesen des kurzen Namens für Ion."
 
-#: ../src/backend/APT/APTRanges.cpp:47
+#: ../src/backend/APT/APTRanges.cpp:51
 msgid ""
 "Error reading colour data in the file, expecting 3 decimal values, space "
 "separated."
@@ -4611,33 +4723,39 @@ msgstr ""
 "Fehler beim Lesen der Farbinformationen in der Datei. Erwarte 3, durch "
 "Leerzeichen getrennte, Dezimalwerte."
 
-#: ../src/backend/APT/APTRanges.cpp:48
+#: ../src/backend/APT/APTRanges.cpp:52
 msgid ""
 "Tried skipping to table separator line (line with dashes), but did not find "
 "it."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:49
+#: ../src/backend/APT/APTRanges.cpp:53
+msgid ""
+"Number of ions in the table header did not match the number specified at the "
+"start of the file"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:54
 msgid ""
 "Unexpected failure whilst trying to skip over range lead-in data (bit before "
 "range start value)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:50
+#: ../src/backend/APT/APTRanges.cpp:55
 msgid ""
 "Range table had an incorrect number of entries, should be 2 or 3 + number of "
 "ranges"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:51
+#: ../src/backend/APT/APTRanges.cpp:56
 msgid "Unable to read range start and end values"
 msgstr "Kann Anfangs und Endwert des Range nicht lesen"
 
-#: ../src/backend/APT/APTRanges.cpp:52
+#: ../src/backend/APT/APTRanges.cpp:57
 msgid "Unable to read range table entry"
 msgstr "Kann Rangetabelleneintrag nich lesen"
 
-#: ../src/backend/APT/APTRanges.cpp:53
+#: ../src/backend/APT/APTRanges.cpp:58
 msgid ""
 "Error reading file, unexpected format, are you sure it is a proper range "
 "file?"
@@ -4645,27 +4763,31 @@ msgstr ""
 "Fehler beim Lesen der Datei: Unerwartetes Format, sind Sie sicher, dass dies "
 "eine korrekte Rangedatei ist?"
 
-#: ../src/backend/APT/APTRanges.cpp:54
+#: ../src/backend/APT/APTRanges.cpp:59
 msgid ""
 "Too many ranges appeared to have range entries with no usable data (eg, all "
 "blank)"
 msgstr "Zu viele Ranges scheinen  ungültige Einträge zu haben (z.B. alle leer)"
 
-#: ../src/backend/APT/APTRanges.cpp:55
+#: ../src/backend/APT/APTRanges.cpp:60
 msgid ""
 "Range file appears to contain malformed data, check things like start and "
 "ends of m/c are not equal or flipped."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:56
+#: ../src/backend/APT/APTRanges.cpp:61
 msgid "Range file appears to be inconsistent (eg, overlapping ranges)"
 msgstr "Rangedatei schein inkonsistent zu sein (z.B. überlappende Ranges)"
 
-#: ../src/backend/APT/APTRanges.cpp:57
+#: ../src/backend/APT/APTRanges.cpp:62
 msgid "No ion name mapping found  for multiple ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:811
+#: ../src/backend/APT/APTRanges.cpp:63
+msgid "Polyatomic extension range matches multiple masses in first section"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:1273
 msgid ""
 "Range headings do not match order of the ions listed in the name "
 "specifications. The name specification ordering will be used when reading "
@@ -4686,7 +4808,7 @@ msgstr "Voxel"
 msgid "Ion. Transform"
 msgstr "Ion. Transformieren"
 
-#: ../src/backend/filters/ionColour.h:60
+#: ../src/backend/filters/ionColour.h:59
 msgid "Spectral Colour"
 msgstr "Spectral Farbe"
 
@@ -4710,7 +4832,7 @@ msgstr "POS-Daten"
 msgid "Ext. Program"
 msgstr "Ext. Programm"
 
-#: ../src/backend/filters/rangeFile.h:79
+#: ../src/backend/filters/rangeFile.h:89
 msgid "Ranging"
 msgstr "Ranging"
 

-- 
3depict



More information about the debian-science-commits mailing list